diff --git a/debian/modules/control b/debian/modules/control index f27ca7c..8331ff5 100644 --- a/debian/modules/control +++ b/debian/modules/control @@ -18,7 +18,7 @@ Files-Excluded: .gitignore .gitattributes .travis.yml Module: http-lua Homepage: https://github.com/openresty/lua-nginx-module -Version: 0.10.13 +Version: 0.10.15 Patch: openssl-1.1.0.patch discover-luajit-2.1.patch diff --git a/debian/modules/http-lua/README.markdown b/debian/modules/http-lua/README.markdown index 15ad00e..ed0c72d 100644 --- a/debian/modules/http-lua/README.markdown +++ b/debian/modules/http-lua/README.markdown @@ -8,6 +8,8 @@ Name ngx_http_lua_module - Embed the power of Lua into Nginx HTTP Servers. +This module is a core component of OpenResty. If you are using this module, then you are essentially using OpenResty :) + *This module is not distributed with the Nginx source.* See [the installation instructions](#installation). Table of Contents @@ -23,7 +25,6 @@ Table of Contents * [Installation](#installation) * [Building as a dynamic module](#building-as-a-dynamic-module) * [C Macro Configurations](#c-macro-configurations) - * [Installation on Ubuntu 11.10](#installation-on-ubuntu-1110) * [Community](#community) * [English Mailing List](#english-mailing-list) * [Chinese Mailing List](#chinese-mailing-list) @@ -62,7 +63,7 @@ Production ready. Version ======= -This document describes ngx_lua [v0.10.13](https://github.com/openresty/lua-nginx-module/tags) released on 22 April 2018. +This document describes ngx_lua [v0.10.15](https://github.com/openresty/lua-nginx-module/tags) released on March 14th, 2019. Synopsis ======== @@ -187,7 +188,9 @@ Synopsis Description =========== -This module embeds Lua, via the standard Lua 5.1 interpreter or [LuaJIT 2.0/2.1](http://luajit.org/luajit.html), into Nginx and by leveraging Nginx's subrequests, allows the integration of the powerful Lua threads (Lua coroutines) into the Nginx event model. +This module is a core component of OpenResty. If you are using this module, then you are essentially using OpenResty :) + +This module embeds Lua, via [LuaJIT 2.0/2.1](http://luajit.org/luajit.html), into Nginx and by leveraging Nginx's subrequests, allows the integration of the powerful Lua threads (Lua coroutines) into the Nginx event model. Unlike [Apache's mod_lua](https://httpd.apache.org/docs/trunk/mod/mod_lua.html) and [Lighttpd's mod_magnet](http://redmine.lighttpd.net/wiki/1/Docs:ModMagnet), Lua code executed using this module can be *100% non-blocking* on network traffic as long as the [Nginx API for Lua](#nginx-api-for-lua) provided by this module is used to handle requests to upstream services such as MySQL, PostgreSQL, Memcached, Redis, or upstream HTTP web services. @@ -265,11 +268,11 @@ Nginx cores older than 1.6.0 (exclusive) are *not* supported. Installation ============ -It is *highly* recommended to use [OpenResty releases](http://openresty.org) which integrate Nginx, ngx_lua, LuaJIT 2.1, as well as other powerful companion Nginx modules and Lua libraries. It is discouraged to build this module with nginx yourself since it is tricky to set up exactly right. Also, the stock nginx cores have various limitations and long standing bugs that can make some of this modules' features become disabled, not work properly, or run slower. The same applies to LuaJIT as well. OpenResty includes its own version of LuaJIT which gets specifically optimized and enhanced for the OpenResty environment. +It is *highly* recommended to use [OpenResty releases](http://openresty.org) which integrate Nginx, ngx_lua, OpenResty's LuaJIT 2.1 branch version, as well as other powerful companion Nginx modules and Lua libraries. It is discouraged to build this module with nginx yourself since it is tricky to set up exactly right. Also, the stock nginx cores have various limitations and long standing bugs that can make some of this modules' features become disabled, not work properly, or run slower. The same applies to LuaJIT as well. OpenResty includes its own version of LuaJIT which gets specifically optimized and enhanced for the OpenResty environment. Alternatively, ngx_lua can be manually compiled into Nginx: -1. Install LuaJIT 2.0 or 2.1 (recommended) or Lua 5.1 (Lua 5.2 is *not* supported yet). LuaJIT can be downloaded from the [LuaJIT project website](http://luajit.org/download.html) and Lua 5.1, from the [Lua project website](http://www.lua.org/). Some distribution package managers also distribute LuaJIT and/or Lua. +1. LuaJIT can be downloaded from the [latest release of OpenResty's LuaJIT branch version](https://github.com/openresty/luajit2/releases). The official LuaJIT 2.0 and 2.1 releases are also supported, although the performance will be significantly lower in many cases. 1. Download the latest version of the ngx_devel_kit (NDK) module [HERE](https://github.com/simplresty/ngx_devel_kit/tags). 1. Download the latest version of ngx_lua [HERE](https://github.com/openresty/lua-nginx-module/tags). 1. Download the latest version of Nginx [HERE](http://nginx.org/) (See [Nginx Compatibility](#nginx-compatibility)) @@ -345,29 +348,6 @@ To enable one or more of these macros, just pass extra C compiler options to the ./configure --with-cc-opt="-DNGX_LUA_USE_ASSERT -DNGX_LUA_ABORT_AT_PANIC" -[Back to TOC](#table-of-contents) - -Installation on Ubuntu 11.10 ----------------------------- - -Note that it is recommended to use LuaJIT 2.0 or LuaJIT 2.1 instead of the standard Lua 5.1 interpreter wherever possible. - -If the standard Lua 5.1 interpreter is required however, run the following command to install it from the Ubuntu repository: - -```bash - - apt-get install -y lua5.1 liblua5.1-0 liblua5.1-0-dev -``` - -Everything should be installed correctly, except for one small tweak. - -Library name `liblua.so` has been changed in liblua5.1 package, it only comes with `liblua5.1.so`, which needs to be symlinked to `/usr/lib` so it could be found during the configuration process. - -```bash - - ln -s /usr/lib/x86_64-linux-gnu/liblua5.1.so /usr/lib/liblua.so -``` - [Back to TOC](#table-of-contents) Community @@ -411,7 +391,7 @@ Lua/LuaJIT bytecode support As from the `v0.5.0rc32` release, all `*_by_lua_file` configure directives (such as [content_by_lua_file](#content_by_lua_file)) support loading Lua 5.1 and LuaJIT 2.0/2.1 raw bytecode files directly. -Please note that the bytecode format used by LuaJIT 2.0/2.1 is not compatible with that used by the standard Lua 5.1 interpreter. So if using LuaJIT 2.0/2.1 with ngx_lua, LuaJIT compatible bytecode files must be generated as shown: +Please note that the bytecode format used by LuaJIT 2.0/2.1 is not compatible with that used by the standard Lua 5.1 interpreter. So if you are using LuaJIT 2.0/2.1 with ngx_lua, LuaJIT compatible bytecode files must be generated as shown: ```bash @@ -431,20 +411,6 @@ Please refer to the official LuaJIT documentation on the `-b` option for more de Also, the bytecode files generated by LuaJIT 2.1 is *not* compatible with LuaJIT 2.0, and vice versa. The support for LuaJIT 2.1 bytecode was first added in ngx_lua v0.9.3. -Similarly, if using the standard Lua 5.1 interpreter with ngx_lua, Lua compatible bytecode files must be generated using the `luac` commandline utility as shown: - -```bash - - luac -o /path/to/output_file.luac /path/to/input_file.lua -``` - -Unlike as with LuaJIT, debug information is included in standard Lua 5.1 bytecode files by default. This can be striped out by specifying the `-s` option as shown: - -```bash - - luac -s -o /path/to/output_file.luac /path/to/input_file.lua -``` - Attempts to load standard Lua 5.1 bytecode files into ngx_lua instances linked to LuaJIT 2.0/2.1 or vice versa, will result in an error message, such as that below, being logged into the Nginx `error.log` file: @@ -642,8 +608,7 @@ This issue is due to limitations in the Nginx event model and only appears to af Lua Coroutine Yielding/Resuming ------------------------------- -* Because Lua's `dofile` and `require` builtins are currently implemented as C functions in both Lua 5.1 and LuaJIT 2.0/2.1, if the Lua file being loaded by `dofile` or `require` invokes [ngx.location.capture*](#ngxlocationcapture), [ngx.exec](#ngxexec), [ngx.exit](#ngxexit), or other API functions requiring yielding in the *top-level* scope of the Lua file, then the Lua error "attempt to yield across C-call boundary" will be raised. To avoid this, put these calls requiring yielding into your own Lua functions in the Lua file instead of the top-level scope of the file. -* As the standard Lua 5.1 interpreter's VM is not fully resumable, the methods [ngx.location.capture](#ngxlocationcapture), [ngx.location.capture_multi](#ngxlocationcapture_multi), [ngx.redirect](#ngxredirect), [ngx.exec](#ngxexec), and [ngx.exit](#ngxexit) cannot be used within the context of a Lua [pcall()](http://www.lua.org/manual/5.1/manual.html#pdf-pcall) or [xpcall()](http://www.lua.org/manual/5.1/manual.html#pdf-xpcall) or even the first line of the `for ... in ...` statement when the standard Lua 5.1 interpreter is used and the `attempt to yield across metamethod/C-call boundary` error will be produced. Please use LuaJIT 2.x, which supports a fully resumable VM, to avoid this. +* Because Lua's `dofile` and `require` builtins are currently implemented as C functions in LuaJIT 2.0/2.1, if the Lua file being loaded by `dofile` or `require` invokes [ngx.location.capture*](#ngxlocationcapture), [ngx.exec](#ngxexec), [ngx.exit](#ngxexit), or other API functions requiring yielding in the *top-level* scope of the Lua file, then the Lua error "attempt to yield across C-call boundary" will be raised. To avoid this, put these calls requiring yielding into your own Lua functions in the Lua file instead of the top-level scope of the file. [Back to TOC](#table-of-contents) @@ -995,7 +960,7 @@ This module is licensed under the BSD license. Copyright (C) 2009-2017, by Xiaozhe Wang (chaoslawful) . -Copyright (C) 2009-2018, by Yichun "agentzh" Zhang (章亦春) , OpenResty Inc. +Copyright (C) 2009-2019, by Yichun "agentzh" Zhang (章亦春) , OpenResty Inc. All rights reserved. @@ -1039,6 +1004,7 @@ See Also Directives ========== +* [lua_load_resty_core](#lua_load_resty_core) * [lua_capture_error_log](#lua_capture_error_log) * [lua_use_default_type](#lua_use_default_type) * [lua_malloc_trim](#lua_malloc_trim) @@ -1104,6 +1070,7 @@ Directives * [lua_check_client_abort](#lua_check_client_abort) * [lua_max_pending_timers](#lua_max_pending_timers) * [lua_max_running_timers](#lua_max_running_timers) +* [lua_sa_restart](#lua_sa_restart) The basic building blocks of scripting Nginx with Lua are directives. Directives are used to specify when the user Lua code is run and @@ -1113,6 +1080,38 @@ how the result will be used. Below is a diagram showing the order in which direc [Back to TOC](#table-of-contents) +lua_load_resty_core +------------------- + +**syntax:** *lua_load_resty_core on|off* + +**default:** *lua_load_resty_core on* + +**context:** *http* + +Controls whether the `resty.core` module (from +[lua-resty-core](https://github.com/openresty/lua-resty-core)) should be loaded +or not. When enabled, this directive is equivalent to executing the following +when the Lua VM is created: + +```lua + + require "resty.core" +``` + +Note that usage of the `resty.core` module is recommended, as its +FFI implementation is both faster, safer, and more complete than the Lua C API +of the ngx_lua module. + +It must also be noted that the Lua C API of the ngx_lua module will eventually +be removed, and usage of the FFI-based API (i.e. the `resty.core` +module) will become mandatory. This directive only aims at providing a +temporary backwards-compatibility mode in case of edge-cases. + +This directive was first introduced in the `v0.10.15` release. + +[Back to TOC](#directives) + lua_capture_error_log --------------------- **syntax:** *lua_capture_error_log size* @@ -2602,14 +2601,14 @@ SSL session resumption can then get immediately initiated and bypass the full SS Please note that TLS session tickets are very different and it is the clients' responsibility to cache the SSL session state when session tickets are used. SSL session resumptions based on TLS session tickets would happen automatically without going through this hook (nor the -[ssl_session_store_by_lua_block](#ssl_session_store_by_lua) hook). This hook is mainly +[ssl_session_store_by_lua*](#ssl_session_store_by_lua_block) hook). This hook is mainly for older or less capable SSL clients that can only do SSL sessions by session IDs. When [ssl_certificate_by_lua*](#ssl_certificate_by_lua_block) is specified at the same time, this hook usually runs before [ssl_certificate_by_lua*](#ssl_certificate_by_lua_block). When the SSL session is found and successfully loaded for the current SSL connection, SSL session resumption will happen and thus bypass the [ssl_certificate_by_lua*](#ssl_certificate_by_lua_block) -hook completely. In this case, NGINX also bypasses the [ssl_session_store_by_lua_block](#ssl_session_store_by_lua) +hook completely. In this case, NGINX also bypasses the [ssl_session_store_by_lua*](#ssl_session_store_by_lua_block) hook, for obvious reasons. To easily test this hook locally with a modern web browser, you can temporarily put the following line @@ -3108,6 +3107,23 @@ This directive was first introduced in the `v0.8.0` release. [Back to TOC](#directives) +lua_sa_restart +-------------- + +**syntax:** *lua_sa_restart on|off* + +**default:** *lua_sa_restart on* + +**context:** *http* + +When enabled, this module will set the `SA_RESTART` flag on nginx workers signal dispositions. + +This allows Lua I/O primitives to not be interrupted by nginx's handling of various signals. + +This directive was first introduced in the `v0.10.14` release. + +[Back to TOC](#directives) + Nginx API for Lua ================= @@ -3221,6 +3237,7 @@ Nginx API for Lua * [tcpsock:sslhandshake](#tcpsocksslhandshake) * [tcpsock:send](#tcpsocksend) * [tcpsock:receive](#tcpsockreceive) +* [tcpsock:receiveany](#tcpsockreceiveany) * [tcpsock:receiveuntil](#tcpsockreceiveuntil) * [tcpsock:close](#tcpsockclose) * [tcpsock:settimeout](#tcpsocksettimeout) @@ -4302,7 +4319,7 @@ ngx.req.get_method ------------------ **syntax:** *method_name = ngx.req.get_method()* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, balancer_by_lua** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, balancer_by_lua*, log_by_lua** Retrieves the current request's request method name. Strings like `"GET"` and `"POST"` are returned instead of numerical [method constants](#http-method-constants). @@ -4887,7 +4904,7 @@ This function returns `nil` if 1. the request body has been read into disk temporary files, 1. or the request body has zero size. -If the request body has not been read yet, call [ngx.req.read_body](#ngxreqread_body) first (or turned on [lua_need_request_body](#lua_need_request_body) to force this module to read the request body. This is not recommended however). +If the request body has not been read yet, call [ngx.req.read_body](#ngxreqread_body) first (or turn on [lua_need_request_body](#lua_need_request_body) to force this module to read the request body. This is not recommended however). If the request body has been read into disk files, try calling the [ngx.req.get_body_file](#ngxreqget_body_file) function instead. @@ -4911,7 +4928,7 @@ Retrieves the file name for the in-file request body data. Returns `nil` if the The returned file is read only and is usually cleaned up by Nginx's memory pool. It should not be manually modified, renamed, or removed in Lua code. -If the request body has not been read yet, call [ngx.req.read_body](#ngxreqread_body) first (or turned on [lua_need_request_body](#lua_need_request_body) to force this module to read the request body. This is not recommended however). +If the request body has not been read yet, call [ngx.req.read_body](#ngxreqread_body) first (or turn on [lua_need_request_body](#lua_need_request_body) to force this module to read the request body. This is not recommended however). If the request body has been read into memory, try calling the [ngx.req.get_body_data](#ngxreqget_body_data) function instead. @@ -4931,7 +4948,9 @@ ngx.req.set_body_data Set the current request's request body using the in-memory data specified by the `data` argument. -If the current request's request body has not been read, then it will be properly discarded. When the current request's request body has been read into memory or buffered into a disk file, then the old request body's memory will be freed or the disk file will be cleaned up immediately, respectively. +If the request body has not been read yet, call [ngx.req.read_body](#ngxreqread_body) first (or turn on [lua_need_request_body](#lua_need_request_body) to force this module to read the request body. This is not recommended however). Additionally, the request body must not have been previously discarded by [ngx.req.discard_body](#ngxreqdiscard_body). + +Whether the previous request body has been read into memory or buffered into a disk file, it will be freed or the disk file will be cleaned up immediately, respectively. This function was first introduced in the `v0.3.1rc18` release. @@ -4947,11 +4966,13 @@ ngx.req.set_body_file Set the current request's request body using the in-file data specified by the `file_name` argument. +If the request body has not been read yet, call [ngx.req.read_body](#ngxreqread_body) first (or turn on [lua_need_request_body](#lua_need_request_body) to force this module to read the request body. This is not recommended however). Additionally, the request body must not have been previously discarded by [ngx.req.discard_body](#ngxreqdiscard_body). + If the optional `auto_clean` argument is given a `true` value, then this file will be removed at request completion or the next time this function or [ngx.req.set_body_data](#ngxreqset_body_data) are called in the same request. The `auto_clean` is default to `false`. Please ensure that the file specified by the `file_name` argument exists and is readable by an Nginx worker process by setting its permission properly to avoid Lua exception errors. -If the current request's request body has not been read, then it will be properly discarded. When the current request's request body has been read into memory or buffered into a disk file, then the old request body's memory will be freed or the disk file will be cleaned up immediately, respectively. +Whether the previous request body has been read into memory or buffered into a disk file, it will be freed or the disk file will be cleaned up immediately, respectively. This function was first introduced in the `v0.3.1rc18` release. @@ -6717,7 +6738,7 @@ ngx.shared.DICT.flush_expired Flushes out the expired items in the dictionary, up to the maximal number specified by the optional `max_count` argument. When the `max_count` argument is given `0` or not given at all, then it means unlimited. Returns the number of items that have actually been flushed. -Unlike the [flush_all](#ngxshareddictflush_all) method, this method actually free up the memory used by the expired items. +Unlike the [flush_all](#ngxshareddictflush_all) method, this method actually frees up the memory used by the expired items. This feature was first introduced in the `v0.6.3` release. @@ -7002,6 +7023,7 @@ Creates and returns a TCP or stream-oriented unix domain socket object (also kno * [settimeout](#tcpsocksettimeout) * [settimeouts](#tcpsocksettimeouts) * [setoption](#tcpsocksetoption) +* [receiveany](#tcpsockreceiveany) * [receiveuntil](#tcpsockreceiveuntil) * [setkeepalive](#tcpsocksetkeepalive) * [getreusedtimes](#tcpsockgetreusedtimes) @@ -7106,6 +7128,43 @@ An optional Lua table can be specified as the last argument to this method to sp * `pool` specify a custom name for the connection pool being used. If omitted, then the connection pool name will be generated from the string template `":"` or `""`. +* `pool_size` + specify the size of the connection pool. If omitted and no + `backlog` option was provided, no pool will be created. If omitted + but `backlog` was provided, the pool will be created with a default + size equal to the value of the [lua_socket_pool_size](#lua_socket_pool_size) + directive. + The connection pool holds up to `pool_size` alive connections + ready to be reused by subsequent calls to [connect](#tcpsockconnect), but + note that there is no upper limit to the total number of opened connections + outside of the pool. If you need to restrict the total number of opened + connections, specify the `backlog` option. + When the connection pool would exceed its size limit, the least recently used + (kept-alive) connection already in the pool will be closed to make room for + the current connection. + Note that the cosocket connection pool is per Nginx worker process rather + than per Nginx server instance, so the size limit specified here also applies + to every single Nginx worker process. Also note that the size of the connection + pool cannot be changed once it has been created. + This option was first introduced in the `v0.10.14` release. + +* `backlog` + if specified, this module will limit the total number of opened connections + for this pool. No more connections than `pool_size` can be opened + for this pool at any time. If the connection pool is full, subsequent + connect operations will be queued into a queue equal to this option's + value (the "backlog" queue). + If the number of queued connect operations is equal to `backlog`, + subsequent connect operations will fail and return `nil` plus the + error string `"too many waiting connect operations"`. + The queued connect operations will be resumed once the number of connections + in the pool is less than `pool_size`. + The queued connect operation will abort once they have been queued for more + than `connect_timeout`, controlled by + [settimeouts](#tcpsocksettimeouts), and will return `nil` plus + the error string `"timeout"`. + This option was first introduced in the `v0.10.14` release. + The support for the options table argument was first introduced in the `v0.5.7` release. This method was first introduced in the `v0.5.0rc1` release. @@ -7231,6 +7290,40 @@ This feature was first introduced in the `v0.5.0rc1` release. [Back to TOC](#nginx-api-for-lua) +tcpsock:receiveany +------------------ +**syntax:** *data, err = tcpsock:receiveany(max)* + +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua** + +Returns any data received by the connected socket, at most `max` bytes. + +This method is a synchronous operation just like the [send](#tcpsocksend) method and is 100% nonblocking. + +In case of success, it returns the data received; in case of error, it returns `nil` with a string describing the error. + +If the received data is more than this size, this method will return with exactly this size of data. +The remaining data in the underlying receive buffer could be returned in the next reading operation. + +Timeout for the reading operation is controlled by the [lua_socket_read_timeout](#lua_socket_read_timeout) config directive and the [settimeouts](#tcpsocksettimeouts) method. And the latter takes priority. For example: + +```lua + + sock:settimeouts(1000, 1000, 1000) -- one second timeout for connect/read/write + local data, err = sock:receiveany(10 * 1024 * 1024) -- read any data, at most 10K + if not data then + ngx.say("failed to read any data: ", err) + return + end + ngx.say("successfully read: ", data) +``` + +This method doesn't automatically close the current connection when the read timeout error occurs. For other connection errors, this method always automatically closes the connection. + +This feature was first introduced in the `v0.10.14` release. + +[Back to TOC](#nginx-api-for-lua) + tcpsock:receiveuntil -------------------- **syntax:** *iterator = tcpsock:receiveuntil(pattern, options?)* @@ -7403,13 +7496,31 @@ Puts the current socket's connection immediately into the cosocket built-in conn The first optional argument, `timeout`, can be used to specify the maximal idle timeout (in milliseconds) for the current connection. If omitted, the default setting in the [lua_socket_keepalive_timeout](#lua_socket_keepalive_timeout) config directive will be used. If the `0` value is given, then the timeout interval is unlimited. -The second optional argument, `size`, can be used to specify the maximal number of connections allowed in the connection pool for the current server (i.e., the current host-port pair or the unix domain socket file path). Note that the size of the connection pool cannot be changed once the pool is created. When this argument is omitted, the default setting in the [lua_socket_pool_size](#lua_socket_pool_size) config directive will be used. - -When the connection pool exceeds the available size limit, the least recently used (idle) connection already in the pool will be closed to make room for the current connection. - -Note that the cosocket connection pool is per Nginx worker process rather than per Nginx server instance, so the size limit specified here also applies to every single Nginx worker process. - -Idle connections in the pool will be monitored for any exceptional events like connection abortion or unexpected incoming data on the line, in which cases the connection in question will be closed and removed from the pool. +The second optional argument `size` is considered deprecated since +the `v0.10.14` release of this module, in favor of the +`pool_size` option of the [connect](#tcpsockconnect) method. +Since the `v0.10.14` release, this option will only take effect if +the call to [connect](#tcpsockconnect) did not already create a connection +pool. +When this option takes effect (no connection pool was previously created by +[connect](#tcpsockconnect)), it will specify the size of the connection pool, +and create it. +If omitted (and no pool was previously created), the default size is the value +of the [lua_socket_pool_size](#lua_socket_pool_size) directive. +The connection pool holds up to `size` alive connections ready to be +reused by subsequent calls to [connect](#tcpsockconnect), but note that there +is no upper limit to the total number of opened connections outside of the +pool. +When the connection pool would exceed its size limit, the least recently used +(kept-alive) connection already in the pool will be closed to make room for +the current connection. +Note that the cosocket connection pool is per Nginx worker process rather +than per Nginx server instance, so the size limit specified here also applies +to every single Nginx worker process. Also note that the size of the connection +pool cannot be changed once it has been created. +If you need to restrict the total number of opened connections, specify both +the `pool_size` and `backlog` option in the call to +[connect](#tcpsockconnect). In case of success, this method returns `1`; otherwise, it returns `nil` and a string describing the error. @@ -8181,7 +8292,7 @@ This Lua module does not ship with this ngx_lua module itself rather it is shipp the [lua-resty-core](https://github.com/openresty/lua-resty-core) library. -Please refer to the [documentation](https://github.com/openresty/lua-resty-core/blob/ocsp-cert-by-lua-2/lib/ngx/ocsp.md) +Please refer to the [documentation](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/ocsp.md) for this `ngx.ocsp` Lua module for more details. This feature requires at least ngx_lua `v0.10.0`. diff --git a/debian/modules/http-lua/config b/debian/modules/http-lua/config index 044deb9..e1d5e35 100644 --- a/debian/modules/http-lua/config +++ b/debian/modules/http-lua/config @@ -361,6 +361,8 @@ HTTP_LUA_SRCS=" \ $ngx_addon_dir/src/ngx_http_lua_ssl_session_fetchby.c \ $ngx_addon_dir/src/ngx_http_lua_ssl.c \ $ngx_addon_dir/src/ngx_http_lua_log_ringbuf.c \ + $ngx_addon_dir/src/ngx_http_lua_input_filters.c \ + $ngx_addon_dir/src/ngx_http_lua_pipe.c \ " HTTP_LUA_DEPS=" \ @@ -422,6 +424,8 @@ HTTP_LUA_DEPS=" \ $ngx_addon_dir/src/ngx_http_lua_ssl_session_fetchby.h \ $ngx_addon_dir/src/ngx_http_lua_ssl.h \ $ngx_addon_dir/src/ngx_http_lua_log_ringbuf.h \ + $ngx_addon_dir/src/ngx_http_lua_input_filters.h \ + $ngx_addon_dir/src/ngx_http_lua_pipe.h \ " CFLAGS="$CFLAGS -DNDK_SET_VAR" @@ -474,6 +478,17 @@ ngx_feature_test='setsockopt(1, SOL_SOCKET, SO_PASSCRED, NULL, 0);' . auto/feature +ngx_feature="SA_RESTART" +ngx_feature_libs= +ngx_feature_name="NGX_HTTP_LUA_HAVE_SA_RESTART" +ngx_feature_run=no +ngx_feature_incs="#include " +ngx_feature_path= +ngx_feature_test='struct sigaction act; + act.sa_flags |= SA_RESTART;' + +. auto/feature + ngx_feature="__attribute__(constructor)" ngx_feature_libs= ngx_feature_name="NGX_HTTP_LUA_HAVE_CONSTRUCTOR" @@ -512,6 +527,36 @@ CC_TEST_FLAGS="$SAVED_CC_TEST_FLAGS" # ---------------------------------------- +ngx_feature="pipe2" +ngx_feature_libs= +ngx_feature_name="NGX_HTTP_LUA_HAVE_PIPE2" +ngx_feature_run=no +ngx_feature_incs="#include " +ngx_feature_test="int fd[2]; pipe2(fd, O_CLOEXEC|O_NONBLOCK);" +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="signalfd" +ngx_feature_libs= +ngx_feature_name="NGX_HTTP_LUA_HAVE_SIGNALFD" +ngx_feature_run=no +ngx_feature_incs="#include " +ngx_feature_test="sigset_t set; signalfd(-1, &set, SFD_NONBLOCK|SFD_CLOEXEC);" +SAVED_CC_TEST_FLAGS="$CC_TEST_FLAGS" +CC_TEST_FLAGS="-Werror -Wall $CC_TEST_FLAGS" + +. auto/feature + +CC_TEST_FLAGS="$SAVED_CC_TEST_FLAGS" + +# ---------------------------------------- + if test -n "$ngx_module_link"; then ngx_module_type=HTTP_AUX_FILTER ngx_module_name=$ngx_addon_name diff --git a/debian/modules/http-lua/doc/HttpLuaModule.wiki b/debian/modules/http-lua/doc/HttpLuaModule.wiki index e3c61e2..ff9b269 100644 --- a/debian/modules/http-lua/doc/HttpLuaModule.wiki +++ b/debian/modules/http-lua/doc/HttpLuaModule.wiki @@ -2,6 +2,8 @@ ngx_http_lua_module - Embed the power of Lua into Nginx HTTP Servers. +This module is a core component of OpenResty. If you are using this module, then you are essentially using OpenResty :) + ''This module is not distributed with the Nginx source.'' See [[#Installation|the installation instructions]]. = Status = @@ -10,7 +12,7 @@ Production ready. = Version = -This document describes ngx_lua [https://github.com/openresty/lua-nginx-module/tags v0.10.13] released on 22 April 2018. +This document describes ngx_lua [https://github.com/openresty/lua-nginx-module/tags v0.10.15] released on March 14th, 2019. = Synopsis = @@ -130,7 +132,9 @@ This document describes ngx_lua [https://github.com/openresty/lua-nginx-module/t = Description = -This module embeds Lua, via the standard Lua 5.1 interpreter or [http://luajit.org/luajit.html LuaJIT 2.0/2.1], into Nginx and by leveraging Nginx's subrequests, allows the integration of the powerful Lua threads (Lua coroutines) into the Nginx event model. +This module is a core component of OpenResty. If you are using this module, then you are essentially using OpenResty :) + +This module embeds Lua, via [http://luajit.org/luajit.html LuaJIT 2.0/2.1], into Nginx and by leveraging Nginx's subrequests, allows the integration of the powerful Lua threads (Lua coroutines) into the Nginx event model. Unlike [https://httpd.apache.org/docs/trunk/mod/mod_lua.html Apache's mod_lua] and [http://redmine.lighttpd.net/wiki/1/Docs:ModMagnet Lighttpd's mod_magnet], Lua code executed using this module can be ''100% non-blocking'' on network traffic as long as the [[#Nginx API for Lua|Nginx API for Lua]] provided by this module is used to handle requests to upstream services such as MySQL, PostgreSQL, Memcached, Redis, or upstream HTTP web services. @@ -199,11 +203,11 @@ Nginx cores older than 1.6.0 (exclusive) are *not* supported. = Installation = -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. The same applies to LuaJIT as well. OpenResty includes its own version of LuaJIT which gets specifically optimized and enhanced for the OpenResty environment. +It is *highly* recommended to use [http://openresty.org OpenResty releases] which integrate Nginx, ngx_lua, OpenResty's LuaJIT 2.1 branch version, as well as other powerful companion Nginx modules and Lua libraries. It is discouraged to build this module with nginx yourself since it is tricky to set up exactly right. Also, the stock nginx cores have various limitations and long standing bugs that can make some of this modules' features become disabled, not work properly, or run slower. The same applies to LuaJIT as well. OpenResty includes its own version of LuaJIT which gets specifically optimized and enhanced for the OpenResty environment. Alternatively, ngx_lua can be manually compiled into Nginx: -# Install LuaJIT 2.0 or 2.1 (recommended) or Lua 5.1 (Lua 5.2 is ''not'' supported yet). LuaJIT can be downloaded from the [http://luajit.org/download.html LuaJIT project website] and Lua 5.1, from the [http://www.lua.org/ Lua project website]. Some distribution package managers also distribute LuaJIT and/or Lua. +# LuaJIT can be downloaded from the [https://github.com/openresty/luajit2/releases latest release of OpenResty's LuaJIT branch version]. The official LuaJIT 2.0 and 2.1 releases are also supported, although the performance will be significantly lower in many cases. # Download the latest version of the ngx_devel_kit (NDK) module [https://github.com/simplresty/ngx_devel_kit/tags HERE]. # Download the latest version of ngx_lua [https://github.com/openresty/lua-nginx-module/tags HERE]. # Download the latest version of Nginx [http://nginx.org/ HERE] (See [[#Nginx Compatibility|Nginx Compatibility]]) @@ -271,24 +275,6 @@ To enable one or more of these macros, just pass extra C compiler options to the ./configure --with-cc-opt="-DNGX_LUA_USE_ASSERT -DNGX_LUA_ABORT_AT_PANIC" -== Installation on Ubuntu 11.10 == - -Note that it is recommended to use LuaJIT 2.0 or LuaJIT 2.1 instead of the standard Lua 5.1 interpreter wherever possible. - -If the standard Lua 5.1 interpreter is required however, run the following command to install it from the Ubuntu repository: - - -apt-get install -y lua5.1 liblua5.1-0 liblua5.1-0-dev - - -Everything should be installed correctly, except for one small tweak. - -Library name liblua.so has been changed in liblua5.1 package, it only comes with liblua5.1.so, which needs to be symlinked to /usr/lib so it could be found during the configuration process. - - -ln -s /usr/lib/x86_64-linux-gnu/liblua5.1.so /usr/lib/liblua.so - - = Community = == English Mailing List == @@ -314,7 +300,7 @@ Please submit bug reports, wishlists, or patches by As from the v0.5.0rc32 release, all *_by_lua_file configure directives (such as [[#content_by_lua_file|content_by_lua_file]]) support loading Lua 5.1 and LuaJIT 2.0/2.1 raw bytecode files directly. -Please note that the bytecode format used by LuaJIT 2.0/2.1 is not compatible with that used by the standard Lua 5.1 interpreter. So if using LuaJIT 2.0/2.1 with ngx_lua, LuaJIT compatible bytecode files must be generated as shown: +Please note that the bytecode format used by LuaJIT 2.0/2.1 is not compatible with that used by the standard Lua 5.1 interpreter. So if you are using LuaJIT 2.0/2.1 with ngx_lua, LuaJIT compatible bytecode files must be generated as shown: /path/to/luajit/bin/luajit -b /path/to/input_file.lua /path/to/output_file.ljbc @@ -332,18 +318,6 @@ http://luajit.org/running.html#opt_b Also, the bytecode files generated by LuaJIT 2.1 is ''not'' compatible with LuaJIT 2.0, and vice versa. The support for LuaJIT 2.1 bytecode was first added in ngx_lua v0.9.3. -Similarly, if using the standard Lua 5.1 interpreter with ngx_lua, Lua compatible bytecode files must be generated using the luac commandline utility as shown: - - - luac -o /path/to/output_file.luac /path/to/input_file.lua - - -Unlike as with LuaJIT, debug information is included in standard Lua 5.1 bytecode files by default. This can be striped out by specifying the -s option as shown: - - - luac -s -o /path/to/output_file.luac /path/to/input_file.lua - - Attempts to load standard Lua 5.1 bytecode files into ngx_lua instances linked to LuaJIT 2.0/2.1 or vice versa, will result in an error message, such as that below, being logged into the Nginx error.log file: @@ -510,8 +484,7 @@ However, later attempts to manipulate the cosocket object will fail and return t This issue is due to limitations in the Nginx event model and only appears to affect Mac OS X. == Lua Coroutine Yielding/Resuming == -* Because Lua's dofile and require builtins are currently implemented as C functions in both Lua 5.1 and LuaJIT 2.0/2.1, if the Lua file being loaded by dofile or require invokes [[#ngx.location.capture|ngx.location.capture*]], [[#ngx.exec|ngx.exec]], [[#ngx.exit|ngx.exit]], or other API functions requiring yielding in the *top-level* scope of the Lua file, then the Lua error "attempt to yield across C-call boundary" will be raised. To avoid this, put these calls requiring yielding into your own Lua functions in the Lua file instead of the top-level scope of the file. -* As the standard Lua 5.1 interpreter's VM is not fully resumable, the methods [[#ngx.location.capture|ngx.location.capture]], [[#ngx.location.capture_multi|ngx.location.capture_multi]], [[#ngx.redirect|ngx.redirect]], [[#ngx.exec|ngx.exec]], and [[#ngx.exit|ngx.exit]] cannot be used within the context of a Lua [http://www.lua.org/manual/5.1/manual.html#pdf-pcall pcall()] or [http://www.lua.org/manual/5.1/manual.html#pdf-xpcall xpcall()] or even the first line of the for ... in ... statement when the standard Lua 5.1 interpreter is used and the attempt to yield across metamethod/C-call boundary error will be produced. Please use LuaJIT 2.x, which supports a fully resumable VM, to avoid this. +* Because Lua's dofile and require builtins are currently implemented as C functions in LuaJIT 2.0/2.1, if the Lua file being loaded by dofile or require invokes [[#ngx.location.capture|ngx.location.capture*]], [[#ngx.exec|ngx.exec]], [[#ngx.exit|ngx.exit]], or other API functions requiring yielding in the *top-level* scope of the Lua file, then the Lua error "attempt to yield across C-call boundary" will be raised. To avoid this, put these calls requiring yielding into your own Lua functions in the Lua file instead of the top-level scope of the file. == Lua Variable Scope == Care must be taken when importing modules and this form should be used: @@ -817,7 +790,7 @@ This module is licensed under the BSD license. Copyright (C) 2009-2017, by Xiaozhe Wang (chaoslawful) . -Copyright (C) 2009-2018, by Yichun "agentzh" Zhang (章亦春) , OpenResty Inc. +Copyright (C) 2009-2019, by Yichun "agentzh" Zhang (章亦春) , OpenResty Inc. All rights reserved. @@ -862,6 +835,34 @@ how the result will be used. Below is a diagram showing the order in which direc ![Lua Nginx Modules Directives](https://cloud.githubusercontent.com/assets/2137369/15272097/77d1c09e-1a37-11e6-97ef-d9767035fc3e.png) +== lua_load_resty_core == + +'''syntax:''' ''lua_load_resty_core on|off'' + +'''default:''' ''lua_load_resty_core on'' + +'''context:''' ''http'' + +Controls whether the resty.core module (from +[https://github.com/openresty/lua-resty-core lua-resty-core]) should be loaded +or not. When enabled, this directive is equivalent to executing the following +when the Lua VM is created: + + + require "resty.core" + + +Note that usage of the resty.core module is recommended, as its +FFI implementation is both faster, safer, and more complete than the Lua C API +of the ngx_lua module. + +It must also be noted that the Lua C API of the ngx_lua module will eventually +be removed, and usage of the FFI-based API (i.e. the resty.core +module) will become mandatory. This directive only aims at providing a +temporary backwards-compatibility mode in case of edge-cases. + +This directive was first introduced in the v0.10.15 release. + == lua_capture_error_log == '''syntax:''' ''lua_capture_error_log size'' @@ -2196,14 +2197,14 @@ SSL session resumption can then get immediately initiated and bypass the full SS Please note that TLS session tickets are very different and it is the clients' responsibility to cache the SSL session state when session tickets are used. SSL session resumptions based on TLS session tickets would happen automatically without going through this hook (nor the -[[#ssl_session_store_by_lua*|ssl_session_store_by_lua_block]] hook). This hook is mainly +[[#ssl_session_store_by_lua_block|ssl_session_store_by_lua*]] hook). This hook is mainly for older or less capable SSL clients that can only do SSL sessions by session IDs. When [[#ssl_certificate_by_lua_block|ssl_certificate_by_lua*]] is specified at the same time, this hook usually runs before [[#ssl_certificate_by_lua_block|ssl_certificate_by_lua*]]. When the SSL session is found and successfully loaded for the current SSL connection, SSL session resumption will happen and thus bypass the [[#ssl_certificate_by_lua_block|ssl_certificate_by_lua*]] -hook completely. In this case, NGINX also bypasses the [[#ssl_session_store_by_lua*|ssl_session_store_by_lua_block]] +hook completely. In this case, NGINX also bypasses the [[#ssl_session_store_by_lua_block|ssl_session_store_by_lua*]] hook, for obvious reasons. To easily test this hook locally with a modern web browser, you can temporarily put the following line @@ -2626,6 +2627,20 @@ When exceeding this limit, Nginx will stop running the callbacks of newly expire This directive was first introduced in the v0.8.0 release. +== lua_sa_restart == + +'''syntax:''' ''lua_sa_restart on|off'' + +'''default:''' ''lua_sa_restart on'' + +'''context:''' ''http'' + +When enabled, this module will set the `SA_RESTART` flag on nginx workers signal dispositions. + +This allows Lua I/O primitives to not be interrupted by nginx's handling of various signals. + +This directive was first introduced in the v0.10.14 release. + = Nginx API for Lua = @@ -3563,7 +3578,7 @@ This method does not work in HTTP/2 requests yet. == ngx.req.get_method == '''syntax:''' ''method_name = ngx.req.get_method()'' -'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, balancer_by_lua*'' +'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, balancer_by_lua*, log_by_lua*'' Retrieves the current request's request method name. Strings like "GET" and "POST" are returned instead of numerical [[#HTTP method constants|method constants]]. @@ -4071,7 +4086,7 @@ This function returns nil if # the request body has been read into disk temporary files, # or the request body has zero size. -If the request body has not been read yet, call [[#ngx.req.read_body|ngx.req.read_body]] first (or turned on [[#lua_need_request_body|lua_need_request_body]] to force this module to read the request body. This is not recommended however). +If the request body has not been read yet, call [[#ngx.req.read_body|ngx.req.read_body]] first (or turn on [[#lua_need_request_body|lua_need_request_body]] to force this module to read the request body. This is not recommended however). If the request body has been read into disk files, try calling the [[#ngx.req.get_body_file|ngx.req.get_body_file]] function instead. @@ -4092,7 +4107,7 @@ Retrieves the file name for the in-file request body data. Returns nildata argument. -If the current request's request body has not been read, then it will be properly discarded. When the current request's request body has been read into memory or buffered into a disk file, then the old request body's memory will be freed or the disk file will be cleaned up immediately, respectively. +If the request body has not been read yet, call [[#ngx.req.read_body|ngx.req.read_body]] first (or turn on [[#lua_need_request_body|lua_need_request_body]] to force this module to read the request body. This is not recommended however). Additionally, the request body must not have been previously discarded by [[#ngx.req.discard_body|ngx.req.discard_body]]. + +Whether the previous request body has been read into memory or buffered into a disk file, it will be freed or the disk file will be cleaned up immediately, respectively. This function was first introduced in the v0.3.1rc18 release. @@ -4122,11 +4139,13 @@ See also [[#ngx.req.set_body_file|ngx.req.set_body_file]]. Set the current request's request body using the in-file data specified by the file_name argument. +If the request body has not been read yet, call [[#ngx.req.read_body|ngx.req.read_body]] first (or turn on [[#lua_need_request_body|lua_need_request_body]] to force this module to read the request body. This is not recommended however). Additionally, the request body must not have been previously discarded by [[#ngx.req.discard_body|ngx.req.discard_body]]. + If the optional auto_clean argument is given a true value, then this file will be removed at request completion or the next time this function or [[#ngx.req.set_body_data|ngx.req.set_body_data]] are called in the same request. The auto_clean is default to false. Please ensure that the file specified by the file_name argument exists and is readable by an Nginx worker process by setting its permission properly to avoid Lua exception errors. -If the current request's request body has not been read, then it will be properly discarded. When the current request's request body has been read into memory or buffered into a disk file, then the old request body's memory will be freed or the disk file will be cleaned up immediately, respectively. +Whether the previous request body has been read into memory or buffered into a disk file, it will be freed or the disk file will be cleaned up immediately, respectively. This function was first introduced in the v0.3.1rc18 release. @@ -5648,7 +5667,7 @@ See also [[#ngx.shared.DICT.flush_expired|ngx.shared.DICT.flush_expired]] and [[ Flushes out the expired items in the dictionary, up to the maximal number specified by the optional max_count argument. When the max_count argument is given 0 or not given at all, then it means unlimited. Returns the number of items that have actually been flushed. -Unlike the [[#ngx.shared.DICT.flush_all|flush_all]] method, this method actually free up the memory used by the expired items. +Unlike the [[#ngx.shared.DICT.flush_all|flush_all]] method, this method actually frees up the memory used by the expired items. This feature was first introduced in the v0.6.3 release. @@ -5894,6 +5913,7 @@ Creates and returns a TCP or stream-oriented unix domain socket object (also kno * [[#tcpsock:settimeout|settimeout]] * [[#tcpsock:settimeouts|settimeouts]] * [[#tcpsock:setoption|setoption]] +* [[#tcpsock:receiveany|receiveany]] * [[#tcpsock:receiveuntil|receiveuntil]] * [[#tcpsock:setkeepalive|setkeepalive]] * [[#tcpsock:getreusedtimes|getreusedtimes]] @@ -5991,6 +6011,43 @@ An optional Lua table can be specified as the last argument to this method to sp * pool : specify a custom name for the connection pool being used. If omitted, then the connection pool name will be generated from the string template ":" or "". +* pool_size +: specify the size of the connection pool. If omitted and no +: backlog option was provided, no pool will be created. If omitted +: but backlog was provided, the pool will be created with a default +: size equal to the value of the [[#lua_socket_pool_size|lua_socket_pool_size]] +: directive. +: The connection pool holds up to pool_size alive connections +: ready to be reused by subsequent calls to [[#tcpsock:connect|connect]], but +: note that there is no upper limit to the total number of opened connections +: outside of the pool. If you need to restrict the total number of opened +: connections, specify the backlog option. +: When the connection pool would exceed its size limit, the least recently used +: (kept-alive) connection already in the pool will be closed to make room for +: the current connection. +: Note that the cosocket connection pool is per Nginx worker process rather +: than per Nginx server instance, so the size limit specified here also applies +: to every single Nginx worker process. Also note that the size of the connection +: pool cannot be changed once it has been created. +: This option was first introduced in the v0.10.14 release. + +* backlog +: if specified, this module will limit the total number of opened connections +: for this pool. No more connections than pool_size can be opened +: for this pool at any time. If the connection pool is full, subsequent +: connect operations will be queued into a queue equal to this option's +: value (the "backlog" queue). +: If the number of queued connect operations is equal to backlog, +: subsequent connect operations will fail and return nil plus the +: error string "too many waiting connect operations". +: The queued connect operations will be resumed once the number of connections +: in the pool is less than pool_size. +: The queued connect operation will abort once they have been queued for more +: than connect_timeout, controlled by +: [[#tcpsock:settimeouts|settimeouts]], and will return nil plus +: the error string "timeout". +: This option was first introduced in the v0.10.14 release. + The support for the options table argument was first introduced in the v0.5.7 release. This method was first introduced in the v0.5.0rc1 release. @@ -6103,6 +6160,36 @@ Since the v0.8.8 release, this method no longer automatically close This feature was first introduced in the v0.5.0rc1 release. +== tcpsock:receiveany == +'''syntax:''' ''data, err = tcpsock:receiveany(max)'' + +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*'' + +Returns any data received by the connected socket, at most max bytes. + +This method is a synchronous operation just like the [[#tcpsock:send|send]] method and is 100% nonblocking. + +In case of success, it returns the data received; in case of error, it returns nil with a string describing the error. + +If the received data is more than this size, this method will return with exactly this size of data. +The remaining data in the underlying receive buffer could be returned in the next reading operation. + +Timeout for the reading operation is controlled by the [[#lua_socket_read_timeout|lua_socket_read_timeout]] config directive and the [[#tcpsock:settimeouts|settimeouts]] method. And the latter takes priority. For example: + + + sock:settimeouts(1000, 1000, 1000) -- one second timeout for connect/read/write + local data, err = sock:receiveany(10 * 1024 * 1024) -- read any data, at most 10K + if not data then + ngx.say("failed to read any data: ", err) + return + end + ngx.say("successfully read: ", data) + + +This method doesn't automatically close the current connection when the read timeout error occurs. For other connection errors, this method always automatically closes the connection. + +This feature was first introduced in the v0.10.14 release. + == tcpsock:receiveuntil == '''syntax:''' ''iterator = tcpsock:receiveuntil(pattern, options?)'' @@ -6255,13 +6342,31 @@ Puts the current socket's connection immediately into the cosocket built-in conn The first optional argument, timeout, can be used to specify the maximal idle timeout (in milliseconds) for the current connection. If omitted, the default setting in the [[#lua_socket_keepalive_timeout|lua_socket_keepalive_timeout]] config directive will be used. If the 0 value is given, then the timeout interval is unlimited. -The second optional argument, size, can be used to specify the maximal number of connections allowed in the connection pool for the current server (i.e., the current host-port pair or the unix domain socket file path). Note that the size of the connection pool cannot be changed once the pool is created. When this argument is omitted, the default setting in the [[#lua_socket_pool_size|lua_socket_pool_size]] config directive will be used. - -When the connection pool exceeds the available size limit, the least recently used (idle) connection already in the pool will be closed to make room for the current connection. - -Note that the cosocket connection pool is per Nginx worker process rather than per Nginx server instance, so the size limit specified here also applies to every single Nginx worker process. - -Idle connections in the pool will be monitored for any exceptional events like connection abortion or unexpected incoming data on the line, in which cases the connection in question will be closed and removed from the pool. +The second optional argument size is considered deprecated since +the v0.10.14 release of this module, in favor of the +pool_size option of the [[#tcpsock:connect|connect]] method. +Since the v0.10.14 release, this option will only take effect if +the call to [[#tcpsock:connect|connect]] did not already create a connection +pool. +When this option takes effect (no connection pool was previously created by +[[#tcpsock:connect|connect]]), it will specify the size of the connection pool, +and create it. +If omitted (and no pool was previously created), the default size is the value +of the [[#lua_socket_pool_size|lua_socket_pool_size]] directive. +The connection pool holds up to size alive connections ready to be +reused by subsequent calls to [[#tcpsock:connect|connect]], but note that there +is no upper limit to the total number of opened connections outside of the +pool. +When the connection pool would exceed its size limit, the least recently used +(kept-alive) connection already in the pool will be closed to make room for +the current connection. +Note that the cosocket connection pool is per Nginx worker process rather +than per Nginx server instance, so the size limit specified here also applies +to every single Nginx worker process. Also note that the size of the connection +pool cannot be changed once it has been created. +If you need to restrict the total number of opened connections, specify both +the pool_size and backlog option in the call to +[[#tcpsock:connect|connect]]. In case of success, this method returns 1; otherwise, it returns nil and a string describing the error. @@ -6950,7 +7055,7 @@ This Lua module does not ship with this ngx_lua module itself rather it is shipp the [https://github.com/openresty/lua-resty-core lua-resty-core] library. -Please refer to the [https://github.com/openresty/lua-resty-core/blob/ocsp-cert-by-lua-2/lib/ngx/ocsp.md documentation] +Please refer to the [https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/ocsp.md documentation] for this ngx.ocsp Lua module for more details. This feature requires at least ngx_lua v0.10.0. diff --git a/debian/modules/http-lua/src/api/ngx_http_lua_api.h b/debian/modules/http-lua/src/api/ngx_http_lua_api.h index c7c0e6b..129eb99 100644 --- a/debian/modules/http-lua/src/api/ngx_http_lua_api.h +++ b/debian/modules/http-lua/src/api/ngx_http_lua_api.h @@ -19,7 +19,7 @@ /* Public API for other Nginx modules */ -#define ngx_http_lua_version 10013 +#define ngx_http_lua_version 10015 typedef struct { diff --git a/debian/modules/http-lua/src/ngx_http_lua_accessby.c b/debian/modules/http-lua/src/ngx_http_lua_accessby.c index 56bf0fa..d3fe294 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_accessby.c +++ b/debian/modules/http-lua/src/ngx_http_lua_accessby.c @@ -60,7 +60,7 @@ ngx_http_lua_access_handler(ngx_http_request_t *r) #endif if (cur_ph < last_ph) { - dd("swaping the contents of cur_ph and last_ph..."); + dd("swapping the contents of cur_ph and last_ph..."); tmp = *cur_ph; @@ -261,9 +261,11 @@ ngx_http_lua_access_by_chunk(lua_State *L, ngx_http_request_t *r) /* move code closure to new coroutine */ lua_xmove(L, co, 1); +#ifndef OPENRESTY_LUAJIT /* set closure's env table to new coroutine's globals table */ ngx_http_lua_get_globals_table(co); lua_setfenv(co, -2); +#endif /* save nginx request in coroutine globals table */ ngx_http_lua_set_req(co, r); diff --git a/debian/modules/http-lua/src/ngx_http_lua_api.c b/debian/modules/http-lua/src/ngx_http_lua_api.c index 7b590e7..ac014f2 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_api.c +++ b/debian/modules/http-lua/src/ngx_http_lua_api.c @@ -195,7 +195,7 @@ ngx_http_lua_shared_memory_init(ngx_shm_zone_t *shm_zone, void *data) lmcf->shm_zones_inited++; if (lmcf->shm_zones_inited == lmcf->shm_zones->nelts - && lmcf->init_handler) + && lmcf->init_handler && !ngx_test_config) { saved_cycle = ngx_cycle; ngx_cycle = ctx->cycle; diff --git a/debian/modules/http-lua/src/ngx_http_lua_balancer.c b/debian/modules/http-lua/src/ngx_http_lua_balancer.c index fdf2af3..3ecd592 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_balancer.c +++ b/debian/modules/http-lua/src/ngx_http_lua_balancer.c @@ -362,6 +362,8 @@ ngx_http_lua_balancer_by_chunk(lua_State *L, ngx_http_request_t *r) /* init nginx context in Lua VM */ ngx_http_lua_set_req(L, r); + +#ifndef OPENRESTY_LUAJIT ngx_http_lua_create_new_globals_table(L, 0 /* narr */, 1 /* nrec */); /* {{{ make new env inheriting main thread's globals table */ @@ -372,6 +374,7 @@ ngx_http_lua_balancer_by_chunk(lua_State *L, ngx_http_request_t *r) /* }}} */ lua_setfenv(L, -2); /* set new running env for the code closure */ +#endif /* OPENRESTY_LUAJIT */ lua_pushcfunction(L, ngx_http_lua_traceback); lua_insert(L, 1); /* put it under chunk and args */ diff --git a/debian/modules/http-lua/src/ngx_http_lua_bodyfilterby.c b/debian/modules/http-lua/src/ngx_http_lua_bodyfilterby.c index 2b3c38f..f3af14c 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_bodyfilterby.c +++ b/debian/modules/http-lua/src/ngx_http_lua_bodyfilterby.c @@ -32,10 +32,6 @@ static void ngx_http_lua_body_filter_by_lua_env(lua_State *L, static ngx_http_output_body_filter_pt ngx_http_next_body_filter; -/* key for the ngx_chain_t *in pointer in the Lua thread */ -#define ngx_http_lua_chain_key "__ngx_cl" - - /** * Set environment table for the given code closure. * @@ -51,12 +47,14 @@ static void ngx_http_lua_body_filter_by_lua_env(lua_State *L, ngx_http_request_t *r, ngx_chain_t *in) { - /* set nginx request pointer to current lua thread's globals table */ + ngx_http_lua_main_conf_t *lmcf; + ngx_http_lua_set_req(L, r); - lua_pushlightuserdata(L, in); - lua_setglobal(L, ngx_http_lua_chain_key); + lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); + lmcf->body_filter_chain = in; +#ifndef OPENRESTY_LUAJIT /** * we want to create empty environment for current script * @@ -79,6 +77,7 @@ ngx_http_lua_body_filter_by_lua_env(lua_State *L, ngx_http_request_t *r, /* }}} */ lua_setfenv(L, -2); /* set new running env for the code closure */ +#endif /* OPENRESTY_LUAJIT */ } @@ -236,8 +235,8 @@ ngx_http_lua_body_filter(ngx_http_request_t *r, ngx_chain_t *in) ngx_int_t rc; uint16_t old_context; ngx_http_cleanup_t *cln; - lua_State *L; ngx_chain_t *out; + ngx_http_lua_main_conf_t *lmcf; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua body filter for user lua code, uri \"%V\"", &r->uri); @@ -299,11 +298,8 @@ ngx_http_lua_body_filter(ngx_http_request_t *r, ngx_chain_t *in) return NGX_ERROR; } - L = ngx_http_lua_get_lua_vm(r, ctx); - - lua_getglobal(L, ngx_http_lua_chain_key); - out = lua_touserdata(L, -1); - lua_pop(L, 1); + lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); + out = lmcf->body_filter_chain; if (in == out) { return ngx_http_next_body_filter(r, in); @@ -345,7 +341,7 @@ ngx_http_lua_body_filter_init(void) int -ngx_http_lua_body_filter_param_get(lua_State *L) +ngx_http_lua_body_filter_param_get(lua_State *L, ngx_http_request_t *r) { u_char *data, *p; size_t size; @@ -354,6 +350,8 @@ ngx_http_lua_body_filter_param_get(lua_State *L) int idx; ngx_chain_t *in; + ngx_http_lua_main_conf_t *lmcf; + idx = luaL_checkint(L, 2); dd("index: %d", idx); @@ -363,8 +361,8 @@ ngx_http_lua_body_filter_param_get(lua_State *L) return 1; } - lua_getglobal(L, ngx_http_lua_chain_key); - in = lua_touserdata(L, -1); + lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); + in = lmcf->body_filter_chain; if (idx == 2) { /* asking for the eof argument */ @@ -442,6 +440,8 @@ ngx_http_lua_body_filter_param_set(lua_State *L, ngx_http_request_t *r, ngx_chain_t *cl; ngx_chain_t *in; + ngx_http_lua_main_conf_t *lmcf; + idx = luaL_checkint(L, 2); dd("index: %d", idx); @@ -450,13 +450,13 @@ ngx_http_lua_body_filter_param_set(lua_State *L, ngx_http_request_t *r, return luaL_error(L, "bad index: %d", idx); } + lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); + if (idx == 2) { /* overwriting the eof flag */ last = lua_toboolean(L, 3); - lua_getglobal(L, ngx_http_lua_chain_key); - in = lua_touserdata(L, -1); - lua_pop(L, 1); + in = lmcf->body_filter_chain; if (last) { ctx->seen_last_in_filter = 1; @@ -521,9 +521,7 @@ ngx_http_lua_body_filter_param_set(lua_State *L, ngx_http_request_t *r, case LUA_TNIL: /* discard the buffers */ - lua_getglobal(L, ngx_http_lua_chain_key); /* key val */ - in = lua_touserdata(L, -1); - lua_pop(L, 1); + in = lmcf->body_filter_chain; last = 0; @@ -557,9 +555,7 @@ ngx_http_lua_body_filter_param_set(lua_State *L, ngx_http_request_t *r, lua_typename(L, type)); } - lua_getglobal(L, ngx_http_lua_chain_key); - in = lua_touserdata(L, -1); - lua_pop(L, 1); + in = lmcf->body_filter_chain; last = 0; @@ -625,8 +621,8 @@ done: } } - lua_pushlightuserdata(L, cl); - lua_setglobal(L, ngx_http_lua_chain_key); + lmcf->body_filter_chain = cl; + return 0; } diff --git a/debian/modules/http-lua/src/ngx_http_lua_bodyfilterby.h b/debian/modules/http-lua/src/ngx_http_lua_bodyfilterby.h index 6a4b306..b108202 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_bodyfilterby.h +++ b/debian/modules/http-lua/src/ngx_http_lua_bodyfilterby.h @@ -21,7 +21,7 @@ ngx_int_t ngx_http_lua_body_filter_inline(ngx_http_request_t *r, ngx_chain_t *in); ngx_int_t ngx_http_lua_body_filter_file(ngx_http_request_t *r, ngx_chain_t *in); -int ngx_http_lua_body_filter_param_get(lua_State *L); +int ngx_http_lua_body_filter_param_get(lua_State *L, ngx_http_request_t *r); int ngx_http_lua_body_filter_param_set(lua_State *L, ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx); diff --git a/debian/modules/http-lua/src/ngx_http_lua_cache.c b/debian/modules/http-lua/src/ngx_http_lua_cache.c index 5ea3069..5b29527 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_cache.c +++ b/debian/modules/http-lua/src/ngx_http_lua_cache.c @@ -35,11 +35,14 @@ static ngx_int_t ngx_http_lua_cache_load_code(ngx_log_t *log, lua_State *L, const char *key) { +#ifndef OPENRESTY_LUAJIT int rc; u_char *err; +#endif /* get code cache table */ - lua_pushlightuserdata(L, &ngx_http_lua_code_cache_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + code_cache_key)); lua_rawget(L, LUA_REGISTRYINDEX); /* sp++ */ dd("Code cache table to load: %p", lua_topointer(L, -1)); @@ -52,6 +55,10 @@ ngx_http_lua_cache_load_code(ngx_log_t *log, lua_State *L, lua_getfield(L, -1, key); /* sp++ */ if (lua_isfunction(L, -1)) { +#ifdef OPENRESTY_LUAJIT + lua_remove(L, -2); /* sp-- */ + return NGX_OK; +#else /* call closure factory to gen new closure */ rc = lua_pcall(L, 0, 1, 0); if (rc == 0) { @@ -73,6 +80,7 @@ ngx_http_lua_cache_load_code(ngx_log_t *log, lua_State *L, key, err); lua_pop(L, 2); return NGX_ERROR; +#endif /* OPENRESTY_LUAJIT */ } dd("Value associated with given key in code cache table is not code " @@ -102,10 +110,13 @@ ngx_http_lua_cache_load_code(ngx_log_t *log, lua_State *L, static ngx_int_t ngx_http_lua_cache_store_code(lua_State *L, const char *key) { +#ifndef OPENRESTY_LUAJIT int rc; +#endif /* get code cache table */ - lua_pushlightuserdata(L, &ngx_http_lua_code_cache_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + code_cache_key)); lua_rawget(L, LUA_REGISTRYINDEX); dd("Code cache table to store: %p", lua_topointer(L, -1)); @@ -121,12 +132,14 @@ ngx_http_lua_cache_store_code(lua_State *L, const char *key) /* remove cache table, leave closure factory at top of stack */ lua_pop(L, 1); /* closure */ +#ifndef OPENRESTY_LUAJIT /* call closure factory to generate new closure */ rc = lua_pcall(L, 0, 1, 0); if (rc != 0) { dd("Error: failed to call closure factory!!"); return NGX_ERROR; } +#endif return NGX_OK; } @@ -143,7 +156,8 @@ ngx_http_lua_cache_loadbuffer(ngx_log_t *log, lua_State *L, n = lua_gettop(L); - dd("XXX cache key: [%s]", cache_key); + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, + "looking up Lua code cache with key '%s'", cache_key); rc = ngx_http_lua_cache_load_code(log, L, (char *) cache_key); if (rc == NGX_OK) { @@ -227,7 +241,8 @@ ngx_http_lua_cache_loadfile(ngx_log_t *log, lua_State *L, dd("CACHE file key already pre-calculated"); } - dd("XXX cache key for file: [%s]", cache_key); + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, + "looking up Lua code cache with key '%s'", cache_key); rc = ngx_http_lua_cache_load_code(log, L, (char *) cache_key); if (rc == NGX_OK) { diff --git a/debian/modules/http-lua/src/ngx_http_lua_clfactory.c b/debian/modules/http-lua/src/ngx_http_lua_clfactory.c index 041f046..754ed8d 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_clfactory.c +++ b/debian/modules/http-lua/src/ngx_http_lua_clfactory.c @@ -15,11 +15,13 @@ #include "ngx_http_lua_clfactory.h" +#ifndef OPENRESTY_LUAJIT #define CLFACTORY_BEGIN_CODE "return function() " #define CLFACTORY_BEGIN_SIZE (sizeof(CLFACTORY_BEGIN_CODE) - 1) #define CLFACTORY_END_CODE "\nend" #define CLFACTORY_END_SIZE (sizeof(CLFACTORY_END_CODE) - 1) +#endif /* @@ -59,6 +61,7 @@ * length(Instruction) = 4 or 8 * little endian or big endian */ +#ifndef OPENRESTY_LUAJIT #define LUA_LITTLE_ENDIAN_4BYTES_CODE \ "\x24\x00\x00\x00\x1e\x00\x00\x01\x1e\x00\x80\x00" #define LUA_LITTLE_ENDIAN_8BYTES_CODE \ @@ -75,6 +78,7 @@ #define LUA_BIG_ENDIAN_8BYTES_CODE_LEN (8 + 8 + 8) #define LUAC_HEADERSIZE 12 #define LUAC_VERSION 0x51 +#endif /* OPENRESTY_LUAJIT */ /* @@ -147,6 +151,7 @@ * --------------------- */ +#ifndef OPENRESTY_LUAJIT #define POS_SOURCE_STR_LEN LUAC_HEADERSIZE #define POS_START_LINE (POS_SOURCE_STR_LEN + sizeof(size_t)) #define POS_LAST_LINE (POS_START_LINE + sizeof(int)) @@ -160,6 +165,7 @@ (POS_BYTECODE + LUA_LITTLE_ENDIAN_8BYTES_CODE_LEN \ + sizeof(int) + sizeof(int)) #define MAX_END_CODE_SIZE (sizeof(int) + sizeof(int) + sizeof(int)) +#endif /* OPENRESTY_LUAJIT */ /* * taken from chaoslawful: @@ -225,6 +231,7 @@ /* bytecode for luajit 2.0 */ +#ifndef OPENRESTY_LUAJIT #define LJ20_LITTLE_ENDIAN_CODE_STRIPPED \ "\x14\x03\x00\x01\x00\x01\x00\x03" \ "\x31\x00\x00\x00\x30\x00\x00\x80\x48\x00\x02\x00" \ @@ -275,6 +282,7 @@ #define LJ21_BCDUMP_VERSION 2 #define LJ20_BCDUMP_VERSION 1 #define LJ_SIGNATURE "\x1b\x4c\x4a" +#endif /* OPENRESTY_LUAJIT */ typedef enum { @@ -292,10 +300,11 @@ enum { typedef struct { ngx_http_lua_clfactory_file_type_e file_type; - int sent_begin; - int sent_end; int extraline; FILE *f; +#ifndef OPENRESTY_LUAJIT + int sent_begin; + int sent_end; size_t begin_code_len; size_t end_code_len; size_t rest_len; @@ -307,13 +316,16 @@ typedef struct { char *ptr; char str[MAX_END_CODE_SIZE]; } end_code; +#endif /* OPENRESTY_LUAJIT */ char buff[NGX_LUA_READER_BUFSIZE]; } ngx_http_lua_clfactory_file_ctx_t; typedef struct { +#ifndef OPENRESTY_LUAJIT int sent_begin; int sent_end; +#endif const char *s; size_t size; } ngx_http_lua_clfactory_buffer_ctx_t; @@ -325,9 +337,12 @@ static int ngx_http_lua_clfactory_errfile(lua_State *L, const char *what, int fname_index); static const char *ngx_http_lua_clfactory_getS(lua_State *L, void *ud, size_t *size); +#ifndef OPENRESTY_LUAJIT static long ngx_http_lua_clfactory_file_size(FILE *f); +#endif +#ifndef OPENRESTY_LUAJIT int ngx_http_lua_clfactory_bytecode_prepare(lua_State *L, ngx_http_lua_clfactory_file_ctx_t *lf, int fname_index) @@ -593,6 +608,7 @@ error: return LUA_ERRFILE; } +#endif /* OPENRESTY_LUAJIT */ ngx_int_t @@ -612,10 +628,12 @@ ngx_http_lua_clfactory_loadfile(lua_State *L, const char *filename) lf.extraline = 0; lf.file_type = NGX_LUA_TEXT_FILE; +#ifndef OPENRESTY_LUAJIT lf.begin_code.ptr = CLFACTORY_BEGIN_CODE; lf.begin_code_len = CLFACTORY_BEGIN_SIZE; lf.end_code.ptr = CLFACTORY_END_CODE; lf.end_code_len = CLFACTORY_END_SIZE; +#endif lua_pushfstring(L, "@%s", filename); @@ -683,20 +701,27 @@ ngx_http_lua_clfactory_loadfile(lua_State *L, const char *filename) /* skip eventual `#!...' */ } +#ifndef OPENRESTY_LUAJIT status = ngx_http_lua_clfactory_bytecode_prepare(L, &lf, fname_index); if (status != 0) { return status; } +#endif lf.extraline = 0; } +#ifndef OPENRESTY_LUAJIT if (lf.file_type == NGX_LUA_TEXT_FILE) { ungetc(c, lf.f); } lf.sent_begin = lf.sent_end = 0; + +#else + ungetc(c, lf.f); +#endif status = lua_load(L, ngx_http_lua_clfactory_getF, &lf, lua_tostring(L, -1)); @@ -725,8 +750,10 @@ ngx_http_lua_clfactory_loadbuffer(lua_State *L, const char *buff, ls.s = buff; ls.size = size; +#ifndef OPENRESTY_LUAJIT ls.sent_begin = 0; ls.sent_end = 0; +#endif return lua_load(L, ngx_http_lua_clfactory_getS, &ls, name); } @@ -735,7 +762,9 @@ ngx_http_lua_clfactory_loadbuffer(lua_State *L, const char *buff, static const char * ngx_http_lua_clfactory_getF(lua_State *L, void *ud, size_t *size) { +#ifndef OPENRESTY_LUAJIT char *buf; +#endif size_t num; ngx_http_lua_clfactory_file_ctx_t *lf; @@ -748,6 +777,7 @@ ngx_http_lua_clfactory_getF(lua_State *L, void *ud, size_t *size) return "\n"; } +#ifndef OPENRESTY_LUAJIT if (lf->sent_begin == 0) { lf->sent_begin = 1; *size = lf->begin_code_len; @@ -761,12 +791,14 @@ ngx_http_lua_clfactory_getF(lua_State *L, void *ud, size_t *size) return buf; } +#endif /* OPENRESTY_LUAJIT */ num = fread(lf->buff, 1, sizeof(lf->buff), lf->f); dd("fread returned %d", (int) num); if (num == 0) { +#ifndef OPENRESTY_LUAJIT if (lf->sent_end == 0) { lf->sent_end = 1; *size = lf->end_code_len; @@ -780,11 +812,13 @@ ngx_http_lua_clfactory_getF(lua_State *L, void *ud, size_t *size) return buf; } +#endif /* OPENRESTY_LUAJIT */ *size = 0; return NULL; } +#ifndef OPENRESTY_LUAJIT if (lf->file_type == NGX_LUA_BT_LJ) { /* skip the footer(\x00) in luajit */ @@ -800,6 +834,7 @@ ngx_http_lua_clfactory_getF(lua_State *L, void *ud, size_t *size) } } } +#endif /* OPENRESTY_LUAJIT */ *size = num; return lf->buff; @@ -833,19 +868,23 @@ ngx_http_lua_clfactory_getS(lua_State *L, void *ud, size_t *size) { ngx_http_lua_clfactory_buffer_ctx_t *ls = ud; +#ifndef OPENRESTY_LUAJIT if (ls->sent_begin == 0) { ls->sent_begin = 1; *size = CLFACTORY_BEGIN_SIZE; return CLFACTORY_BEGIN_CODE; } +#endif if (ls->size == 0) { +#ifndef OPENRESTY_LUAJIT if (ls->sent_end == 0) { ls->sent_end = 1; *size = CLFACTORY_END_SIZE; return CLFACTORY_END_CODE; } +#endif return NULL; } @@ -857,6 +896,7 @@ ngx_http_lua_clfactory_getS(lua_State *L, void *ud, size_t *size) } +#ifndef OPENRESTY_LUAJIT static long ngx_http_lua_clfactory_file_size(FILE *f) { @@ -882,6 +922,7 @@ ngx_http_lua_clfactory_file_size(FILE *f) return len; } +#endif /* OPENRESTY_LUAJIT */ /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/debian/modules/http-lua/src/ngx_http_lua_common.h b/debian/modules/http-lua/src/ngx_http_lua_common.h index 01ef2be..dae5245 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_common.h +++ b/debian/modules/http-lua/src/ngx_http_lua_common.h @@ -17,7 +17,7 @@ #include #include -#include +#include #include #include @@ -140,6 +140,15 @@ typedef struct { #endif +#if (NGX_PTR_SIZE >= 8 && !defined(_WIN64)) +#define ngx_http_lua_lightudata_mask(ludata) \ + ((void *) ((uintptr_t) (&ngx_http_lua_##ludata) & ((1UL << 47) - 1))) + +#else +#define ngx_http_lua_lightudata_mask(ludata) (&ngx_http_lua_##ludata) +#endif + + typedef struct ngx_http_lua_main_conf_s ngx_http_lua_main_conf_t; typedef union ngx_http_lua_srv_conf_u ngx_http_lua_srv_conf_t; @@ -173,6 +182,8 @@ struct ngx_http_lua_main_conf_s { ngx_cycle_t *cycle; ngx_pool_t *pool; + ngx_flag_t load_resty_core; + ngx_int_t max_pending_timers; ngx_int_t pending_timers; @@ -208,9 +219,31 @@ struct ngx_http_lua_main_conf_s { ngx_str_t init_worker_src; ngx_http_lua_balancer_peer_data_t *balancer_peer_data; - /* balancer_by_lua does not support yielding and - * there cannot be any conflicts among concurrent requests, - * thus it is safe to store the peer data in the main conf. + /* neither yielding nor recursion is possible in + * balancer_by_lua*, so there cannot be any races among + * concurrent requests and it is safe to store the peer + * data pointer in the main conf. + */ + + ngx_chain_t *body_filter_chain; + /* neither yielding nor recursion is possible in + * body_filter_by_lua*, so there cannot be any races among + * concurrent requests when storing the chain + * data pointer in the main conf. + */ + + ngx_http_variable_value_t *setby_args; + /* neither yielding nor recursion is possible in + * set_by_lua*, so there cannot be any races among + * concurrent requests when storing the args pointer + * in the main conf. + */ + + size_t setby_nargs; + /* neither yielding nor recursion is possible in + * set_by_lua*, so there cannot be any races among + * concurrent requests when storing the nargs in the + * main conf. */ ngx_uint_t shm_zones_inited; @@ -227,6 +260,10 @@ struct ngx_http_lua_main_conf_s { ngx_int_t busy_buf_ptr_count; #endif + ngx_int_t host_var_index; + + ngx_flag_t set_sa_restart; + unsigned requires_header_filter:1; unsigned requires_body_filter:1; unsigned requires_capture_filter:1; @@ -444,7 +481,7 @@ typedef struct { typedef struct ngx_http_lua_ctx_s { - /* for lua_coce_cache off: */ + /* for lua_code_cache off: */ ngx_http_lua_vm_state_t *vm_state; ngx_http_request_t *request; @@ -531,6 +568,8 @@ typedef struct ngx_http_lua_ctx_s { unsigned headers_set:1; /* whether the user has set custom response headers */ + unsigned mime_set:1; /* whether the user has set Content-Type + response header */ unsigned entered_rewrite_phase:1; unsigned entered_access_phase:1; diff --git a/debian/modules/http-lua/src/ngx_http_lua_contentby.c b/debian/modules/http-lua/src/ngx_http_lua_contentby.c index ecd6c0e..274c9ad 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_contentby.c +++ b/debian/modules/http-lua/src/ngx_http_lua_contentby.c @@ -63,9 +63,11 @@ ngx_http_lua_content_by_chunk(lua_State *L, ngx_http_request_t *r) /* move code closure to new coroutine */ lua_xmove(L, co, 1); +#ifndef OPENRESTY_LUAJIT /* set closure's env table to new coroutine's globals table */ ngx_http_lua_get_globals_table(co); lua_setfenv(co, -2); +#endif /* save nginx request in coroutine globals table */ ngx_http_lua_set_req(co, r); diff --git a/debian/modules/http-lua/src/ngx_http_lua_control.c b/debian/modules/http-lua/src/ngx_http_lua_control.c index 6ac2cbf..5cd1d64 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_control.c +++ b/debian/modules/http-lua/src/ngx_http_lua_control.c @@ -432,7 +432,8 @@ ngx_http_lua_on_abort(lua_State *L) ngx_http_lua_coroutine_create_helper(L, r, ctx, &coctx); - lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + coroutines_key)); lua_rawget(L, LUA_REGISTRYINDEX); lua_pushvalue(L, -2); diff --git a/debian/modules/http-lua/src/ngx_http_lua_coroutine.c b/debian/modules/http-lua/src/ngx_http_lua_coroutine.c index b790814..99a2423 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_coroutine.c +++ b/debian/modules/http-lua/src/ngx_http_lua_coroutine.c @@ -104,11 +104,15 @@ ngx_http_lua_coroutine_create_helper(lua_State *L, ngx_http_request_t *r, coctx->co = co; coctx->co_status = NGX_HTTP_LUA_CO_SUSPENDED; +#ifdef OPENRESTY_LUAJIT + ngx_http_lua_set_req(co, r); +#else /* make new coroutine share globals of the parent coroutine. * NOTE: globals don't have to be separated! */ ngx_http_lua_get_globals_table(L); lua_xmove(L, co, 1); ngx_http_lua_set_globals_table(co); +#endif lua_xmove(vm, L, 1); /* move coroutine from main thread to L */ @@ -288,15 +292,27 @@ ngx_http_lua_inject_coroutine_api(ngx_log_t *log, lua_State *L) { const char buf[] = "local keys = {'create', 'yield', 'resume', 'status'}\n" +#ifdef OPENRESTY_LUAJIT + "local get_req = require 'thread.exdata'\n" +#else "local getfenv = getfenv\n" +#endif "for _, key in ipairs(keys) do\n" "local std = coroutine['_' .. key]\n" "local ours = coroutine['__' .. key]\n" "local raw_ctx = ngx._phase_ctx\n" "coroutine[key] = function (...)\n" +#ifdef OPENRESTY_LUAJIT + "local r = get_req()\n" +#else "local r = getfenv(0).__ngx_req\n" - "if r then\n" +#endif + "if r ~= nil then\n" +#ifdef OPENRESTY_LUAJIT + "local ctx = raw_ctx()\n" +#else "local ctx = raw_ctx(r)\n" +#endif /* ignore header and body filters */ "if ctx ~= 0x020 and ctx ~= 0x040 then\n" "return ours(...)\n" diff --git a/debian/modules/http-lua/src/ngx_http_lua_directive.c b/debian/modules/http-lua/src/ngx_http_lua_directive.c index fb8c6dc..a989c26 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_directive.c +++ b/debian/modules/http-lua/src/ngx_http_lua_directive.c @@ -1304,11 +1304,12 @@ ngx_http_lua_gen_chunk_name(ngx_conf_t *cf, const char *tag, size_t tag_len, found: - ngx_snprintf(out, len, "=%*s(%*s:%d)%Z", - tag_len, tag, cf->conf_file->file.name.data - + cf->conf_file->file.name.len - p, - p, cf->conf_file->line); - *chunkname_len = len; + p = ngx_snprintf(out, len, "=%*s(%*s:%d)%Z", + tag_len, tag, cf->conf_file->file.name.data + + cf->conf_file->file.name.len - p, + p, cf->conf_file->line); + + *chunkname_len = p - out - 1; /* exclude the trailing '\0' byte */ return out; } diff --git a/debian/modules/http-lua/src/ngx_http_lua_headerfilterby.c b/debian/modules/http-lua/src/ngx_http_lua_headerfilterby.c index b504530..a0acd4a 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_headerfilterby.c +++ b/debian/modules/http-lua/src/ngx_http_lua_headerfilterby.c @@ -42,9 +42,9 @@ static ngx_http_output_header_filter_pt ngx_http_next_header_filter; static void ngx_http_lua_header_filter_by_lua_env(lua_State *L, ngx_http_request_t *r) { - /* set nginx request pointer to current lua thread's globals table */ ngx_http_lua_set_req(L, r); +#ifndef OPENRESTY_LUAJIT /** * we want to create empty environment for current script * @@ -68,6 +68,7 @@ ngx_http_lua_header_filter_by_lua_env(lua_State *L, ngx_http_request_t *r) /* }}} */ lua_setfenv(L, -2); /* set new running env for the code closure */ +#endif /* OPENRESTY_LUAJIT */ } diff --git a/debian/modules/http-lua/src/ngx_http_lua_headers.c b/debian/modules/http-lua/src/ngx_http_lua_headers.c index b833577..e3f48bc 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_headers.c +++ b/debian/modules/http-lua/src/ngx_http_lua_headers.c @@ -442,7 +442,8 @@ ngx_http_lua_ngx_req_get_headers(lua_State *L) lua_createtable(L, 0, count); if (!raw) { - lua_pushlightuserdata(L, &ngx_http_lua_headers_metatable_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + headers_metatable_key)); lua_rawget(L, LUA_REGISTRYINDEX); lua_setmetatable(L, -2); } @@ -504,7 +505,6 @@ ngx_http_lua_ngx_resp_get_headers(lua_State *L) 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; @@ -543,17 +543,6 @@ ngx_http_lua_ngx_resp_get_headers(lua_State *L) 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; @@ -566,7 +555,8 @@ ngx_http_lua_ngx_resp_get_headers(lua_State *L) lua_createtable(L, 0, count + 2); if (!raw) { - lua_pushlightuserdata(L, &ngx_http_lua_headers_metatable_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + headers_metatable_key)); lua_rawget(L, LUA_REGISTRYINDEX); lua_setmetatable(L, -2); } @@ -694,7 +684,6 @@ ngx_http_lua_ngx_header_get(lua_State *L) 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) { @@ -737,18 +726,7 @@ 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); + return ngx_http_lua_get_output_header(L, r, ctx, &key); } @@ -811,16 +789,7 @@ ngx_http_lua_ngx_header_set(lua_State *L) } } - 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; - } + ctx->headers_set = 1; if (lua_type(L, 3) == LUA_TNIL) { ngx_str_null(&value); @@ -845,7 +814,7 @@ ngx_http_lua_ngx_header_set(lua_State *L) ngx_memcpy(value.data, p, len); value.len = len; - rc = ngx_http_lua_set_output_header(r, key, value, + rc = ngx_http_lua_set_output_header(r, ctx, key, value, i == 1 /* override */); if (rc == NGX_ERROR) { @@ -872,7 +841,7 @@ ngx_http_lua_ngx_header_set(lua_State *L) dd("key: %.*s, value: %.*s", (int) key.len, key.data, (int) value.len, value.data); - rc = ngx_http_lua_set_output_header(r, key, value, 1 /* override */); + rc = ngx_http_lua_set_output_header(r, ctx, key, value, 1 /* override */); if (rc == NGX_ERROR) { return luaL_error(L, "failed to set header %s (error: %d)", @@ -1081,7 +1050,8 @@ ngx_http_lua_create_headers_metatable(ngx_log_t *log, lua_State *L) "local new_key = string.gsub(string.lower(key), '_', '-')\n" "if new_key ~= key then return tb[new_key] else return nil end"; - lua_pushlightuserdata(L, &ngx_http_lua_headers_metatable_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + headers_metatable_key)); /* metatable for ngx.req.get_headers(_, true) and * ngx.resp.get_headers(_, true) */ @@ -1241,15 +1211,7 @@ ngx_http_lua_ffi_set_resp_header(ngx_http_request_t *r, const u_char *key_data, } } - if (!ctx->headers_set) { - rc = ngx_http_lua_set_content_type(r); - if (rc != NGX_OK) { - *errmsg = "failed to set default content type"; - return NGX_ERROR; - } - - ctx->headers_set = 1; - } + ctx->headers_set = 1; if (is_nil) { value.data = NULL; @@ -1276,7 +1238,7 @@ ngx_http_lua_ffi_set_resp_header(ngx_http_request_t *r, const u_char *key_data, ngx_memcpy(value.data, p, len); value.len = len; - rc = ngx_http_lua_set_output_header(r, key, value, + rc = ngx_http_lua_set_output_header(r, ctx, key, value, override && i == 0); if (rc == NGX_ERROR) { @@ -1302,7 +1264,7 @@ ngx_http_lua_ffi_set_resp_header(ngx_http_request_t *r, const u_char *key_data, dd("key: %.*s, value: %.*s", (int) key.len, key.data, (int) value.len, value.data); - rc = ngx_http_lua_set_output_header(r, key, value, override); + rc = ngx_http_lua_set_output_header(r, ctx, key, value, override); if (rc == NGX_ERROR) { *errmsg = "failed to set header"; @@ -1370,7 +1332,8 @@ ngx_http_lua_ffi_req_header_set_single_value(ngx_http_request_t *r, int ngx_http_lua_ffi_get_resp_header(ngx_http_request_t *r, const u_char *key, size_t key_len, - u_char *key_buf, ngx_http_lua_ffi_str_t *values, int max_nvalues) + u_char *key_buf, ngx_http_lua_ffi_str_t *values, int max_nvalues, + char **errmsg) { int found; u_char c, *p; @@ -1387,19 +1350,10 @@ ngx_http_lua_ffi_get_resp_header(ngx_http_request_t *r, ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); if (ctx == NULL) { - /* *errmsg = "no ctx found"; */ + *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) @@ -1425,6 +1379,7 @@ ngx_http_lua_ffi_get_resp_header(ngx_http_request_t *r, { p = ngx_palloc(r->pool, NGX_OFF_T_LEN); if (p == NULL) { + *errmsg = "no memory"; return NGX_ERROR; } @@ -1438,8 +1393,8 @@ ngx_http_lua_ffi_get_resp_header(ngx_http_request_t *r, break; case 12: - if (r->headers_out.content_type.len - && ngx_strncasecmp(key_buf, (u_char *) "Content-Type", 12) == 0) + if (ngx_strncasecmp(key_buf, (u_char *) "Content-Type", 12) == 0 + && r->headers_out.content_type.len) { values[0].data = r->headers_out.content_type.data; values[0].len = r->headers_out.content_type.len; diff --git a/debian/modules/http-lua/src/ngx_http_lua_headers_in.c b/debian/modules/http-lua/src/ngx_http_lua_headers_in.c index 4852b2f..c52cd13 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_headers_in.c +++ b/debian/modules/http-lua/src/ngx_http_lua_headers_in.c @@ -432,10 +432,14 @@ static ngx_int_t ngx_http_set_host_header(ngx_http_request_t *r, ngx_http_lua_header_val_t *hv, ngx_str_t *value) { - ngx_str_t host; + ngx_str_t host; + ngx_http_lua_main_conf_t *lmcf; + ngx_http_variable_value_t *var; dd("server new value len: %d", (int) value->len); + lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); + if (value->len) { host= *value; @@ -449,6 +453,10 @@ ngx_http_set_host_header(ngx_http_request_t *r, ngx_http_lua_header_val_t *hv, r->headers_in.server = *value; } + var = &r->variables[lmcf->host_var_index]; + var->valid = 0; + var->not_found = 0; + return ngx_http_set_builtin_header(r, hv, value); } diff --git a/debian/modules/http-lua/src/ngx_http_lua_headers_out.c b/debian/modules/http-lua/src/ngx_http_lua_headers_out.c index b908eae..cf94bd0 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_headers_out.c +++ b/debian/modules/http-lua/src/ngx_http_lua_headers_out.c @@ -106,6 +106,12 @@ static ngx_http_lua_set_header_t ngx_http_lua_set_handlers[] = { offsetof(ngx_http_headers_out_t, cache_control), ngx_http_set_builtin_multi_header }, +#if defined(nginx_version) && nginx_version >= 1013009 + { ngx_string("Link"), + offsetof(ngx_http_headers_out_t, link), + ngx_http_set_builtin_multi_header }, +#endif + { ngx_null_string, 0, ngx_http_set_header } }; @@ -476,8 +482,8 @@ ngx_http_clear_builtin_header(ngx_http_request_t *r, ngx_int_t -ngx_http_lua_set_output_header(ngx_http_request_t *r, ngx_str_t key, - ngx_str_t value, unsigned override) +ngx_http_lua_set_output_header(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx, + ngx_str_t key, ngx_str_t value, unsigned override) { ngx_http_lua_header_val_t hv; ngx_http_lua_set_header_t *handlers = ngx_http_lua_set_handlers; @@ -508,6 +514,10 @@ ngx_http_lua_set_output_header(ngx_http_request_t *r, ngx_str_t key, hv.offset = handlers[i].offset; hv.handler = handlers[i].handler; + if (hv.handler == ngx_http_set_content_type_header) { + ctx->mime_set = 1; + } + break; } @@ -528,7 +538,7 @@ ngx_http_lua_set_output_header(ngx_http_request_t *r, ngx_str_t key, int ngx_http_lua_get_output_header(lua_State *L, ngx_http_request_t *r, - ngx_str_t *key) + ngx_http_lua_ctx_t *ctx, ngx_str_t *key) { ngx_table_elt_t *h; ngx_list_part_t *part; @@ -550,8 +560,8 @@ ngx_http_lua_get_output_header(lua_State *L, ngx_http_request_t *r, break; case 12: - if (r->headers_out.content_type.len - && ngx_strncasecmp(key->data, (u_char *) "Content-Type", 12) == 0) + if (ngx_strncasecmp(key->data, (u_char *) "Content-Type", 12) == 0 + && r->headers_out.content_type.len) { lua_pushlstring(L, (char *) r->headers_out.content_type.data, r->headers_out.content_type.len); diff --git a/debian/modules/http-lua/src/ngx_http_lua_headers_out.h b/debian/modules/http-lua/src/ngx_http_lua_headers_out.h index ef5e6d4..6ec1fe3 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_headers_out.h +++ b/debian/modules/http-lua/src/ngx_http_lua_headers_out.h @@ -12,10 +12,10 @@ #include "ngx_http_lua_common.h" -ngx_int_t ngx_http_lua_set_output_header(ngx_http_request_t *r, ngx_str_t key, - ngx_str_t value, unsigned override); +ngx_int_t ngx_http_lua_set_output_header(ngx_http_request_t *r, + ngx_http_lua_ctx_t *ctx, ngx_str_t key, ngx_str_t value, unsigned override); int ngx_http_lua_get_output_header(lua_State *L, ngx_http_request_t *r, - ngx_str_t *key); + ngx_http_lua_ctx_t *ctx, ngx_str_t *key); #endif /* _NGX_HTTP_LUA_HEADERS_OUT_H_INCLUDED_ */ diff --git a/debian/modules/http-lua/src/ngx_http_lua_initworkerby.c b/debian/modules/http-lua/src/ngx_http_lua_initworkerby.c index 4a722a0..76acdc3 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_initworkerby.c +++ b/debian/modules/http-lua/src/ngx_http_lua_initworkerby.c @@ -12,6 +12,7 @@ #include "ngx_http_lua_initworkerby.h" #include "ngx_http_lua_util.h" +#include "ngx_http_lua_pipe.h" static u_char *ngx_http_lua_log_init_worker_error(ngx_log_t *log, @@ -25,6 +26,7 @@ ngx_http_lua_init_worker(ngx_cycle_t *cycle) void *cur, *prev; ngx_uint_t i; ngx_conf_t conf; + ngx_conf_file_t cf_file; ngx_cycle_t *fake_cycle; ngx_module_t **modules; ngx_open_file_t *file, *ofile; @@ -64,8 +66,21 @@ ngx_http_lua_init_worker(ngx_cycle_t *cycle) return NGX_OK; } + +#ifdef HAVE_NGX_LUA_PIPE + if (ngx_http_lua_pipe_add_signal_handler(cycle) != NGX_OK) { + return NGX_ERROR; + } +#endif + #endif /* NGX_WIN32 */ +#if (NGX_HTTP_LUA_HAVE_SA_RESTART) + if (lmcf->set_sa_restart) { + ngx_http_lua_set_sa_restart(ngx_cycle->log); + } +#endif + if (lmcf->init_worker_handler == NULL) { return NGX_OK; } @@ -166,6 +181,10 @@ ngx_http_lua_init_worker(ngx_cycle_t *cycle) conf.pool = fake_cycle->pool; conf.log = cycle->log; + ngx_memzero(&cf_file, sizeof(cf_file)); + cf_file.file.name = cycle->conf_file; + conf.conf_file = &cf_file; + http_ctx.loc_conf = ngx_pcalloc(conf.pool, sizeof(void *) * ngx_http_max_module); if (http_ctx.loc_conf == NULL) { diff --git a/debian/modules/http-lua/src/ngx_http_lua_input_filters.c b/debian/modules/http-lua/src/ngx_http_lua_input_filters.c new file mode 100644 index 0000000..87a9d8c --- /dev/null +++ b/debian/modules/http-lua/src/ngx_http_lua_input_filters.c @@ -0,0 +1,137 @@ + +/* + * Copyright (C) by OpenResty Inc. + */ + + +#ifndef DDEBUG +#define DDEBUG 0 +#endif +#include "ddebug.h" + + +#include "ngx_http_lua_common.h" + + +ngx_int_t +ngx_http_lua_read_bytes(ngx_buf_t *src, ngx_chain_t *buf_in, size_t *rest, + ssize_t bytes, ngx_log_t *log) +{ + if (bytes == 0) { + return NGX_ERROR; + } + + if ((size_t) bytes >= *rest) { + + buf_in->buf->last += *rest; + src->pos += *rest; + *rest = 0; + + return NGX_OK; + } + + /* bytes < *rest */ + + buf_in->buf->last += bytes; + src->pos += bytes; + *rest -= bytes; + + return NGX_AGAIN; +} + + +ngx_int_t +ngx_http_lua_read_all(ngx_buf_t *src, ngx_chain_t *buf_in, ssize_t bytes, + ngx_log_t *log) +{ + if (bytes == 0) { + return NGX_OK; + } + + buf_in->buf->last += bytes; + src->pos += bytes; + + return NGX_AGAIN; +} + + +ngx_int_t +ngx_http_lua_read_any(ngx_buf_t *src, ngx_chain_t *buf_in, size_t *max, + ssize_t bytes, ngx_log_t *log) +{ + if (bytes == 0) { + return NGX_ERROR; + } + + if (bytes >= (ssize_t) *max) { + bytes = (ssize_t) *max; + } + + buf_in->buf->last += bytes; + src->pos += bytes; + + return NGX_OK; +} + + +ngx_int_t +ngx_http_lua_read_line(ngx_buf_t *src, ngx_chain_t *buf_in, ssize_t bytes, + ngx_log_t *log) +{ + u_char *dst; + u_char c; +#if (NGX_DEBUG) + u_char *begin; +#endif + +#if (NGX_DEBUG) + begin = src->pos; +#endif + + if (bytes == 0) { + return NGX_ERROR; + } + + dd("already read: %p: %.*s", buf_in, + (int) (buf_in->buf->last - buf_in->buf->pos), buf_in->buf->pos); + + dd("data read: %.*s", (int) bytes, src->pos); + + dst = buf_in->buf->last; + + while (bytes--) { + + c = *src->pos++; + + switch (c) { + case '\n': + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, log, 0, + "lua read the final line part: \"%*s\"", + src->pos - 1 - begin, begin); + + buf_in->buf->last = dst; + + dd("read a line: %p: %.*s", buf_in, + (int) (buf_in->buf->last - buf_in->buf->pos), buf_in->buf->pos); + + return NGX_OK; + + case '\r': + /* ignore it */ + break; + + default: + *dst++ = c; + break; + } + } + +#if (NGX_DEBUG) + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, log, 0, + "lua read partial line data: %*s", dst - begin, begin); +#endif + + buf_in->buf->last = dst; + + return NGX_AGAIN; +} diff --git a/debian/modules/http-lua/src/ngx_http_lua_input_filters.h b/debian/modules/http-lua/src/ngx_http_lua_input_filters.h new file mode 100644 index 0000000..046d40f --- /dev/null +++ b/debian/modules/http-lua/src/ngx_http_lua_input_filters.h @@ -0,0 +1,29 @@ + +/* + * Copyright (C) by OpenResty Inc. + */ + + +#ifndef _NGX_HTTP_LUA_INPUT_FILTERS_H_INCLUDED_ +#define _NGX_HTTP_LUA_INPUT_FILTERS_H_INCLUDED_ + + +#include "ngx_http_lua_common.h" + + +ngx_int_t ngx_http_lua_read_bytes(ngx_buf_t *src, ngx_chain_t *buf_in, + size_t *rest, ssize_t bytes, ngx_log_t *log); + +ngx_int_t ngx_http_lua_read_all(ngx_buf_t *src, ngx_chain_t *buf_in, + ssize_t bytes, ngx_log_t *log); + +ngx_int_t ngx_http_lua_read_any(ngx_buf_t *src, ngx_chain_t *buf_in, + size_t *max, ssize_t bytes, ngx_log_t *log); + +ngx_int_t ngx_http_lua_read_line(ngx_buf_t *src, ngx_chain_t *buf_in, + ssize_t bytes, ngx_log_t *log); + + +#endif /* _NGX_HTTP_LUA_INPUT_FILTERS_H_INCLUDED_ */ + +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/debian/modules/http-lua/src/ngx_http_lua_logby.c b/debian/modules/http-lua/src/ngx_http_lua_logby.c index 0f1d2f3..32d1cba 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_logby.c +++ b/debian/modules/http-lua/src/ngx_http_lua_logby.c @@ -38,9 +38,9 @@ static ngx_int_t ngx_http_lua_log_by_chunk(lua_State *L, ngx_http_request_t *r); static void ngx_http_lua_log_by_lua_env(lua_State *L, ngx_http_request_t *r) { - /* set nginx request pointer to current lua thread's globals table */ ngx_http_lua_set_req(L, r); +#ifndef OPENRESTY_LUAJIT /** * we want to create empty environment for current script * @@ -64,6 +64,7 @@ ngx_http_lua_log_by_lua_env(lua_State *L, ngx_http_request_t *r) /* }}} */ lua_setfenv(L, -2); /* set new running env for the code closure */ +#endif /* OPENRESTY_LUAJIT */ } diff --git a/debian/modules/http-lua/src/ngx_http_lua_misc.c b/debian/modules/http-lua/src/ngx_http_lua_misc.c index f96e2f2..145ca9b 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_misc.c +++ b/debian/modules/http-lua/src/ngx_http_lua_misc.c @@ -286,6 +286,33 @@ ngx_http_lua_ffi_headers_sent(ngx_http_request_t *r) return r->header_sent ? 1 : 0; } + + +int +ngx_http_lua_ffi_get_conf_env(u_char *name, u_char **env_buf, size_t *name_len) +{ + ngx_uint_t i; + ngx_str_t *var; + ngx_core_conf_t *ccf; + + ccf = (ngx_core_conf_t *) ngx_get_conf(ngx_cycle->conf_ctx, + ngx_core_module); + + var = ccf->env.elts; + + for (i = 0; i < ccf->env.nelts; i++) { + if (var[i].data[var[i].len] == '=' + && ngx_strncmp(name, var[i].data, var[i].len) == 0) + { + *env_buf = var[i].data; + *name_len = var[i].len; + + return NGX_OK; + } + } + + return NGX_DECLINED; +} #endif /* NGX_LUA_NO_FFI_API */ diff --git a/debian/modules/http-lua/src/ngx_http_lua_module.c b/debian/modules/http-lua/src/ngx_http_lua_module.c index ae8bc0e..2a3f5d5 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_module.c +++ b/debian/modules/http-lua/src/ngx_http_lua_module.c @@ -29,6 +29,7 @@ #include "ngx_http_lua_ssl_session_storeby.h" #include "ngx_http_lua_ssl_session_fetchby.h" #include "ngx_http_lua_headers.h" +#include "ngx_http_lua_pipe.h" static void *ngx_http_lua_create_main_conf(ngx_conf_t *cf); @@ -76,6 +77,13 @@ static ngx_conf_bitmask_t ngx_http_lua_ssl_protocols[] = { static ngx_command_t ngx_http_lua_cmds[] = { + { ngx_string("lua_load_resty_core"), + NGX_HTTP_MAIN_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_HTTP_MAIN_CONF_OFFSET, + offsetof(ngx_http_lua_main_conf_t, load_resty_core), + NULL }, + { ngx_string("lua_max_running_timers"), NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1, ngx_conf_set_num_slot, @@ -104,6 +112,13 @@ static ngx_command_t ngx_http_lua_cmds[] = { 0, NULL }, + { ngx_string("lua_sa_restart"), + NGX_HTTP_MAIN_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_HTTP_MAIN_CONF_OFFSET, + offsetof(ngx_http_lua_main_conf_t, set_sa_restart), + NULL }, + #if (NGX_PCRE) { ngx_string("lua_regex_cache_max_entries"), NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1, @@ -638,9 +653,19 @@ ngx_http_lua_init(ngx_conf_t *cf) #if !defined(NGX_LUA_NO_FFI_API) || nginx_version >= 1011011 ngx_pool_cleanup_t *cln; #endif + ngx_str_t name = ngx_string("host"); + + if (ngx_process == NGX_PROCESS_SIGNALLER || ngx_test_config) { + return NGX_OK; + } lmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_lua_module); + lmcf->host_var_index = ngx_http_get_variable_index(cf, &name); + if (lmcf->host_var_index == NGX_ERROR) { + return NGX_ERROR; + } + if (ngx_http_lua_prev_cycle != ngx_cycle) { ngx_http_lua_prev_cycle = ngx_cycle; multi_http_blocks = 0; @@ -725,6 +750,11 @@ ngx_http_lua_init(ngx_conf_t *cf) cln->data = lmcf; cln->handler = ngx_http_lua_sema_mm_cleanup; + +#ifdef HAVE_NGX_LUA_PIPE + ngx_http_lua_pipe_init(); +#endif + #endif #if nginx_version >= 1011011 @@ -740,6 +770,19 @@ ngx_http_lua_init(ngx_conf_t *cf) if (lmcf->lua == NULL) { dd("initializing lua vm"); +#ifndef OPENRESTY_LUAJIT + if (ngx_process != NGX_PROCESS_SIGNALLER && !ngx_test_config) { + ngx_log_error(NGX_LOG_ALERT, cf->log, 0, + "detected a LuaJIT version which is not OpenResty's" + "; many optimizations will be disabled and " + "performance will be compromised (see " + "https://github.com/openresty/luajit2 for " + "OpenResty's LuaJIT or, even better, consider using " + "the OpenResty releases from https://openresty.org/" + "en/download.html)"); + } +#endif + ngx_http_lua_content_length_hash = ngx_http_lua_hash_literal("content-length"); ngx_http_lua_location_hash = ngx_http_lua_hash_literal("location"); @@ -841,6 +884,7 @@ ngx_http_lua_create_main_conf(ngx_conf_t *cf) */ lmcf->pool = cf->pool; + lmcf->load_resty_core = NGX_CONF_UNSET; lmcf->max_pending_timers = NGX_CONF_UNSET; lmcf->max_running_timers = NGX_CONF_UNSET; #if (NGX_PCRE) @@ -850,6 +894,8 @@ ngx_http_lua_create_main_conf(ngx_conf_t *cf) lmcf->postponed_to_rewrite_phase_end = NGX_CONF_UNSET; lmcf->postponed_to_access_phase_end = NGX_CONF_UNSET; + lmcf->set_sa_restart = NGX_CONF_UNSET; + #if (NGX_HTTP_LUA_HAVE_MALLOC_TRIM) lmcf->malloc_trim_cycle = NGX_CONF_UNSET_UINT; #endif @@ -872,6 +918,10 @@ ngx_http_lua_init_main_conf(ngx_conf_t *cf, void *conf) { ngx_http_lua_main_conf_t *lmcf = conf; + if (lmcf->load_resty_core == NGX_CONF_UNSET) { + lmcf->load_resty_core = 1; + } + #if (NGX_PCRE) if (lmcf->regex_cache_max_entries == NGX_CONF_UNSET) { lmcf->regex_cache_max_entries = 1024; @@ -890,6 +940,12 @@ ngx_http_lua_init_main_conf(ngx_conf_t *cf, void *conf) lmcf->max_running_timers = 256; } +#if (NGX_HTTP_LUA_HAVE_SA_RESTART) + if (lmcf->set_sa_restart == NGX_CONF_UNSET) { + lmcf->set_sa_restart = 1; + } +#endif + #if (NGX_HTTP_LUA_HAVE_MALLOC_TRIM) if (lmcf->malloc_trim_cycle == NGX_CONF_UNSET_UINT) { lmcf->malloc_trim_cycle = 1000; /* number of reqs */ diff --git a/debian/modules/http-lua/src/ngx_http_lua_ndk.c b/debian/modules/http-lua/src/ngx_http_lua_ndk.c index 24b80b4..6344183 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_ndk.c +++ b/debian/modules/http-lua/src/ngx_http_lua_ndk.c @@ -186,6 +186,47 @@ ngx_http_lua_inject_ndk_api(lua_State *L) } +int +ngx_http_lua_ffi_ndk_lookup_directive(const u_char *var_data, + size_t var_len, ndk_set_var_value_pt *func) +{ + *func = ngx_http_lookup_ndk_set_var_directive((u_char *) var_data, var_len); + + if (*func == NULL) { + return NGX_ERROR; + } + + return NGX_OK; +} + + +int +ngx_http_lua_ffi_ndk_set_var_get(ngx_http_request_t *r, + ndk_set_var_value_pt func, const u_char *arg_data, size_t arg_len, + ngx_http_lua_ffi_str_t *value) +{ + ngx_int_t rc; + ngx_str_t res; + ngx_http_variable_value_t arg; + + ngx_memzero(&arg, sizeof(ngx_http_variable_value_t)); + arg.valid = 1; + + arg.data = (u_char *) arg_data; + arg.len = arg_len; + + rc = func(r, &res, &arg); + + if (rc != NGX_OK) { + return rc; + } + + value->data = res.data; + value->len = res.len; + return NGX_OK; +} + + #endif /* defined(NDK) && NDK */ /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/debian/modules/http-lua/src/ngx_http_lua_pipe.c b/debian/modules/http-lua/src/ngx_http_lua_pipe.c new file mode 100644 index 0000000..8c8221f --- /dev/null +++ b/debian/modules/http-lua/src/ngx_http_lua_pipe.c @@ -0,0 +1,2475 @@ + +/* + * Copyright (C) by OpenResty Inc. + */ + + +#ifndef DDEBUG +#define DDEBUG 0 +#endif +#include "ddebug.h" + + +#include "ngx_http_lua_common.h" +#include "ngx_http_lua_input_filters.h" +#include "ngx_http_lua_util.h" +#include "ngx_http_lua_pipe.h" +#if (NGX_HTTP_LUA_HAVE_SIGNALFD) +#include +#endif + + +#ifdef HAVE_NGX_LUA_PIPE +static ngx_rbtree_node_t *ngx_http_lua_pipe_lookup_pid(ngx_rbtree_key_t key); +#if !(NGX_HTTP_LUA_HAVE_SIGNALFD) +static void ngx_http_lua_pipe_sigchld_handler(int signo, siginfo_t *siginfo, + void *ucontext); +#endif +static void ngx_http_lua_pipe_sigchld_event_handler(ngx_event_t *ev); +static ssize_t ngx_http_lua_pipe_fd_read(ngx_connection_t *c, u_char *buf, + size_t size); +static ssize_t ngx_http_lua_pipe_fd_write(ngx_connection_t *c, u_char *buf, + size_t size); +static ngx_int_t ngx_http_lua_pipe_close_helper( + ngx_http_lua_pipe_ctx_t *pipe_ctx, ngx_event_t *ev, int forced); +static ngx_int_t ngx_http_lua_pipe_close_stdin(ngx_http_lua_pipe_t *pipe, + int forced); +static ngx_int_t ngx_http_lua_pipe_close_stdout(ngx_http_lua_pipe_t *pipe, + int forced); +static ngx_int_t ngx_http_lua_pipe_close_stderr(ngx_http_lua_pipe_t *pipe, + int forced); +static void ngx_http_lua_pipe_proc_finalize(ngx_http_lua_ffi_pipe_proc_t *proc, + int forced); +static ngx_int_t ngx_http_lua_pipe_get_lua_ctx(ngx_http_request_t *r, + ngx_http_lua_ctx_t **ctx, u_char *errbuf, size_t *errbuf_size); +static void ngx_http_lua_pipe_put_error(ngx_http_lua_pipe_ctx_t *pipe_ctx, + u_char *errbuf, size_t *errbuf_size); +static void ngx_http_lua_pipe_put_data(ngx_http_lua_pipe_t *pipe, + ngx_http_lua_pipe_ctx_t *pipe_ctx, u_char **buf, size_t *buf_size); +static ngx_int_t ngx_http_lua_pipe_add_input_buffer(ngx_http_lua_pipe_t *pipe, + ngx_http_lua_pipe_ctx_t *pipe_ctx); +static ngx_int_t ngx_http_lua_pipe_read_all(void *data, ssize_t bytes); +static ngx_int_t ngx_http_lua_pipe_read_bytes(void *data, ssize_t bytes); +static ngx_int_t ngx_http_lua_pipe_read_line(void *data, ssize_t bytes); +static ngx_int_t ngx_http_lua_pipe_read_any(void *data, ssize_t bytes); +static ngx_int_t ngx_http_lua_pipe_read(ngx_http_lua_pipe_t *pipe, + ngx_http_lua_pipe_ctx_t *pipe_ctx); +static ngx_int_t ngx_http_lua_pipe_init_ctx( + ngx_http_lua_pipe_ctx_t **pipe_ctx_pt, int fd, ngx_pool_t *pool, + u_char *errbuf, size_t *errbuf_size); +static ngx_int_t ngx_http_lua_pipe_write(ngx_http_lua_pipe_t *pipe, + ngx_http_lua_pipe_ctx_t *pipe_ctx); +static int ngx_http_lua_pipe_read_stdout_retval( + ngx_http_lua_ffi_pipe_proc_t *proc, lua_State *L); +static int ngx_http_lua_pipe_read_stderr_retval( + ngx_http_lua_ffi_pipe_proc_t *proc, lua_State *L); +static int ngx_http_lua_pipe_read_retval_helper( + ngx_http_lua_ffi_pipe_proc_t *proc, lua_State *L, int from_stderr); +static int ngx_http_lua_pipe_write_retval(ngx_http_lua_ffi_pipe_proc_t *proc, + lua_State *L); +static int ngx_http_lua_pipe_wait_retval(ngx_http_lua_ffi_pipe_proc_t *proc, + lua_State *L); +static void ngx_http_lua_pipe_resume_helper(ngx_event_t *ev, + ngx_http_lua_co_ctx_t *wait_co_ctx); +static void ngx_http_lua_pipe_resume_read_stdout_handler(ngx_event_t *ev); +static void ngx_http_lua_pipe_resume_read_stderr_handler(ngx_event_t *ev); +static void ngx_http_lua_pipe_resume_write_handler(ngx_event_t *ev); +static void ngx_http_lua_pipe_resume_wait_handler(ngx_event_t *ev); +static ngx_int_t ngx_http_lua_pipe_resume(ngx_http_request_t *r); +static void ngx_http_lua_pipe_dummy_event_handler(ngx_event_t *ev); +static void ngx_http_lua_pipe_clear_event(ngx_event_t *ev); +static void ngx_http_lua_pipe_proc_read_stdout_cleanup(void *data); +static void ngx_http_lua_pipe_proc_read_stderr_cleanup(void *data); +static void ngx_http_lua_pipe_proc_write_cleanup(void *data); +static void ngx_http_lua_pipe_proc_wait_cleanup(void *data); + + +static ngx_rbtree_t ngx_http_lua_pipe_rbtree; +static ngx_rbtree_node_t ngx_http_lua_pipe_proc_sentinel; + + +#if (NGX_HTTP_LUA_HAVE_SIGNALFD) +static int ngx_http_lua_signalfd; +static struct signalfd_siginfo ngx_http_lua_pipe_notification; + +#define ngx_http_lua_read_sigfd ngx_http_lua_signalfd + +#else +static int ngx_http_lua_sigchldfd[2]; +static u_char ngx_http_lua_pipe_notification[1]; + +#define ngx_http_lua_read_sigfd ngx_http_lua_sigchldfd[0] +#define ngx_http_lua_write_sigfd ngx_http_lua_sigchldfd[1] +#endif + + +static ngx_connection_t *ngx_http_lua_sigfd_conn = NULL; + + +/* The below signals are ignored by Nginx. + * We need to reset them for the spawned child processes. */ +ngx_http_lua_pipe_signal_t ngx_signals[] = { + { SIGSYS, "SIGSYS" }, + { SIGPIPE, "SIGPIPE" }, + { 0, NULL } +}; + + +enum { + PIPE_ERR_CLOSED = 1, + PIPE_ERR_SYSCALL, + PIPE_ERR_NOMEM, + PIPE_ERR_TIMEOUT, + PIPE_ERR_ADD_READ_EV, + PIPE_ERR_ADD_WRITE_EV +}; + + +enum { + PIPE_READ_ALL = 0, + PIPE_READ_BYTES, + PIPE_READ_LINE, + PIPE_READ_ANY +}; + + +#define REASON_EXIT "exit" +#define REASON_SIGNAL "signal" +#define REASON_UNKNOWN "unknown" + +#define REASON_RUNNING_CODE 0 +#define REASON_EXIT_CODE 1 +#define REASON_SIGNAL_CODE 2 +#define REASON_UNKNOWN_CODE 3 + + +void +ngx_http_lua_pipe_init(void) +{ + ngx_rbtree_init(&ngx_http_lua_pipe_rbtree, + &ngx_http_lua_pipe_proc_sentinel, ngx_rbtree_insert_value); +} + + +ngx_int_t +ngx_http_lua_pipe_add_signal_handler(ngx_cycle_t *cycle) +{ + ngx_event_t *rev; +#if (NGX_HTTP_LUA_HAVE_SIGNALFD) + sigset_t set; + +#else + int rc; + struct sigaction sa; +#endif + +#if (NGX_HTTP_LUA_HAVE_SIGNALFD) + if (sigemptyset(&set) != 0) { + ngx_log_error(NGX_LOG_ERR, cycle->log, ngx_errno, + "lua pipe init signal set failed"); + return NGX_ERROR; + } + + if (sigaddset(&set, SIGCHLD) != 0) { + ngx_log_error(NGX_LOG_ERR, cycle->log, ngx_errno, + "lua pipe add SIGCHLD to signal set failed"); + return NGX_ERROR; + } + + if (sigprocmask(SIG_BLOCK, &set, NULL) != 0) { + ngx_log_error(NGX_LOG_ERR, cycle->log, ngx_errno, + "lua pipe block SIGCHLD failed"); + return NGX_ERROR; + } + + ngx_http_lua_signalfd = signalfd(-1, &set, SFD_NONBLOCK|SFD_CLOEXEC); + if (ngx_http_lua_signalfd < 0) { + ngx_log_error(NGX_LOG_ERR, cycle->log, ngx_errno, + "lua pipe create signalfd instance failed"); + return NGX_ERROR; + } + +#else /* !(NGX_HTTP_LUA_HAVE_SIGNALFD) */ +# if (NGX_HTTP_LUA_HAVE_PIPE2) + rc = pipe2(ngx_http_lua_sigchldfd, O_NONBLOCK|O_CLOEXEC); +# else + rc = pipe(ngx_http_lua_sigchldfd); +# endif + + if (rc == -1) { + ngx_log_error(NGX_LOG_ERR, cycle->log, ngx_errno, + "lua pipe init SIGCHLD fd failed"); + return NGX_ERROR; + } + +# if !(NGX_HTTP_LUA_HAVE_PIPE2) + if (ngx_nonblocking(ngx_http_lua_read_sigfd) == -1) { + ngx_log_error(NGX_LOG_ERR, cycle->log, ngx_errno, "lua pipe " + ngx_nonblocking_n " SIGCHLD read fd failed"); + goto failed; + } + + if (ngx_nonblocking(ngx_http_lua_write_sigfd) == -1) { + ngx_log_error(NGX_LOG_ERR, cycle->log, ngx_errno, "lua pipe " + ngx_nonblocking_n " SIGCHLD write fd failed"); + goto failed; + } + + /* it's ok not to set the pipe fd with O_CLOEXEC. This requires + * extra syscall */ +# endif /* !(NGX_HTTP_LUA_HAVE_PIPE2) */ +#endif /* NGX_HTTP_LUA_HAVE_SIGNALFD */ + + ngx_http_lua_sigfd_conn = ngx_get_connection(ngx_http_lua_read_sigfd, + cycle->log); + if (ngx_http_lua_sigfd_conn == NULL) { + goto failed; + } + + ngx_http_lua_sigfd_conn->log = cycle->log; + ngx_http_lua_sigfd_conn->recv = ngx_http_lua_pipe_fd_read; + rev = ngx_http_lua_sigfd_conn->read; + rev->log = ngx_http_lua_sigfd_conn->log; + rev->handler = ngx_http_lua_pipe_sigchld_event_handler; + +#ifdef HAVE_SOCKET_CLOEXEC_PATCH + rev->skip_socket_leak_check = 1; +#endif + + if (ngx_handle_read_event(rev, 0) == NGX_ERROR) { + goto failed; + } + +#if !(NGX_HTTP_LUA_HAVE_SIGNALFD) + ngx_memzero(&sa, sizeof(struct sigaction)); + sa.sa_sigaction = ngx_http_lua_pipe_sigchld_handler; + sa.sa_flags = SA_SIGINFO; + + if (sigemptyset(&sa.sa_mask) != 0) { + ngx_log_error(NGX_LOG_ERR, cycle->log, ngx_errno, + "lua pipe init signal mask failed"); + goto failed; + } + + if (sigaction(SIGCHLD, &sa, NULL) == -1) { + ngx_log_error(NGX_LOG_ERR, cycle->log, ngx_errno, + "lua pipe sigaction(SIGCHLD) failed"); + goto failed; + } +#endif + + return NGX_OK; + +failed: + + if (ngx_http_lua_sigfd_conn != NULL) { + ngx_close_connection(ngx_http_lua_sigfd_conn); + ngx_http_lua_sigfd_conn = NULL; + } + + if (close(ngx_http_lua_read_sigfd) == -1) { + ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, + "lua pipe close the read sigfd failed"); + } + +#if !(NGX_HTTP_LUA_HAVE_SIGNALFD) + if (close(ngx_http_lua_write_sigfd) == -1) { + ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, + "lua pipe close the write sigfd failed"); + } +#endif + + return NGX_ERROR; +} + + +static ngx_rbtree_node_t * +ngx_http_lua_pipe_lookup_pid(ngx_rbtree_key_t key) +{ + ngx_rbtree_node_t *node, *sentinel; + + node = ngx_http_lua_pipe_rbtree.root; + sentinel = ngx_http_lua_pipe_rbtree.sentinel; + + while (node != sentinel) { + if (key < node->key) { + node = node->left; + continue; + } + + if (key > node->key) { + node = node->right; + continue; + } + + return node; + } + + return NULL; +} + + +#if !(NGX_HTTP_LUA_HAVE_SIGNALFD) +static void +ngx_http_lua_pipe_sigchld_handler(int signo, siginfo_t *siginfo, + void *ucontext) +{ + ngx_err_t err, saved_err; + ngx_int_t n; + + saved_err = ngx_errno; + + for ( ;; ) { + n = write(ngx_http_lua_write_sigfd, ngx_http_lua_pipe_notification, + sizeof(ngx_http_lua_pipe_notification)); + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, ngx_cycle->log, 0, + "lua pipe SIGCHLD fd write siginfo:%p", siginfo); + + if (n >= 0) { + break; + } + + err = ngx_errno; + + if (err != NGX_EINTR) { + if (err != NGX_EAGAIN) { + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, err, + "lua pipe SIGCHLD fd write failed"); + } + + break; + } + + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ngx_cycle->log, err, + "lua pipe SIGCHLD fd write was interrupted"); + } + + ngx_set_errno(saved_err); +} +#endif + + +static void +ngx_http_lua_pipe_sigchld_event_handler(ngx_event_t *ev) +{ + int n; + int status; + ngx_pid_t pid; + ngx_connection_t *c = ev->data; + ngx_rbtree_node_t *node; + ngx_http_lua_pipe_node_t *pipe_node; + + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ngx_cycle->log, 0, + "lua pipe reaping children"); + + for ( ;; ) { +#if (NGX_HTTP_LUA_HAVE_SIGNALFD) + n = c->recv(c, (u_char *) &ngx_http_lua_pipe_notification, +#else + n = c->recv(c, ngx_http_lua_pipe_notification, +#endif + sizeof(ngx_http_lua_pipe_notification)); + + if (n <= 0) { + if (n == NGX_ERROR) { + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, ngx_errno, + "lua pipe SIGCHLD fd read failed"); + } + + break; + } + + for ( ;; ) { + pid = waitpid(-1, &status, WNOHANG); + + if (pid == 0) { + break; + } + + if (pid < 0) { + if (ngx_errno != NGX_ECHILD) { + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, ngx_errno, + "lua pipe waitpid failed"); + } + + break; + } + + /* This log is ported from Nginx's signal handler since we override + * or block it in this implementation. */ + ngx_log_error(NGX_LOG_NOTICE, ngx_cycle->log, 0, + "signal %d (SIGCHLD) received from %P", + SIGCHLD, pid); + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "lua pipe SIGCHLD fd read pid:%P status:%d", pid, + status); + + node = ngx_http_lua_pipe_lookup_pid(pid); + if (node != NULL) { + pipe_node = (ngx_http_lua_pipe_node_t *) &node->color; + if (pipe_node->wait_co_ctx != NULL) { + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "lua pipe resume process:%p waiting for %P", + pipe_node->proc, pid); + + /* + * We need the extra parentheses around the first argument + * of ngx_post_event() just to work around macro issues in + * nginx cores older than 1.7.12 (exclusive). + */ + ngx_post_event((&pipe_node->wait_co_ctx->sleep), + &ngx_posted_events); + } + + pipe_node->proc->pipe->dead = 1; + + if (WIFSIGNALED(status)) { + pipe_node->status = WTERMSIG(status); + pipe_node->reason_code = REASON_SIGNAL_CODE; + + } else if (WIFEXITED(status)) { + pipe_node->status = WEXITSTATUS(status); + pipe_node->reason_code = REASON_EXIT_CODE; + + } else { + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, + "lua pipe unknown exit status %d from " + "process %P", status, pid); + pipe_node->status = status; + pipe_node->reason_code = REASON_UNKNOWN_CODE; + } + } + } + } +} + + +static ssize_t +ngx_http_lua_pipe_fd_read(ngx_connection_t *c, u_char *buf, size_t size) +{ + ssize_t n; + ngx_err_t err; + ngx_event_t *rev; + + rev = c->read; + + do { + n = read(c->fd, buf, size); + + err = ngx_errno; + + ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, + "read: fd:%d %z of %uz", c->fd, n, size); + + if (n == 0) { + rev->ready = 0; + rev->eof = 1; + return 0; + } + + if (n > 0) { + if ((size_t) n < size + && !(ngx_event_flags & NGX_USE_GREEDY_EVENT)) + { + rev->ready = 0; + } + + return n; + } + + if (err == NGX_EAGAIN || err == NGX_EINTR) { + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err, + "read() not ready"); + n = NGX_AGAIN; + + } else { + n = ngx_connection_error(c, err, "read() failed"); + break; + } + + } while (err == NGX_EINTR); + + rev->ready = 0; + + if (n == NGX_ERROR) { + rev->error = 1; + } + + return n; +} + + +static ssize_t +ngx_http_lua_pipe_fd_write(ngx_connection_t *c, u_char *buf, size_t size) +{ + ssize_t n; + ngx_err_t err; + ngx_event_t *wev; + + wev = c->write; + + do { + n = write(c->fd, buf, size); + + ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, + "write: fd:%d %z of %uz", c->fd, n, size); + + if (n >= 0) { + if ((size_t) n != size) { + wev->ready = 0; + } + + return n; + } + + err = ngx_errno; + + if (err == NGX_EAGAIN || err == NGX_EINTR) { + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err, + "write() not ready"); + n = NGX_AGAIN; + + } else if (err != NGX_EPIPE) { + n = ngx_connection_error(c, err, "write() failed"); + break; + } + + } while (err == NGX_EINTR); + + wev->ready = 0; + + if (n == NGX_ERROR) { + wev->error = 1; + } + + return n; +} + + +int +ngx_http_lua_ffi_pipe_spawn(ngx_http_lua_ffi_pipe_proc_t *proc, + const char *file, const char **argv, int merge_stderr, size_t buffer_size, + u_char *errbuf, size_t *errbuf_size) +{ + int rc; + int in[2]; + int out[2]; + int err[2]; + int stdin_fd, stdout_fd, stderr_fd; + int errlog_fd, temp_errlog_fd; + ngx_pid_t pid; + ssize_t pool_size; + ngx_pool_t *pool; + ngx_uint_t i; + ngx_listening_t *ls; + ngx_http_lua_pipe_t *pp; + ngx_rbtree_node_t *node; + ngx_http_lua_pipe_node_t *pipe_node; + struct sigaction sa; + ngx_http_lua_pipe_signal_t *sig; + sigset_t set; + + pool_size = ngx_align(NGX_MIN_POOL_SIZE + buffer_size * 2, + NGX_POOL_ALIGNMENT); + + pool = ngx_create_pool(pool_size, ngx_cycle->log); + if (pool == NULL) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "no memory") + - errbuf; + return NGX_ERROR; + } + + pp = ngx_pcalloc(pool, sizeof(ngx_http_lua_pipe_t) + + offsetof(ngx_rbtree_node_t, color) + + sizeof(ngx_http_lua_pipe_node_t)); + if (pp == NULL) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "no memory") + - errbuf; + goto free_pool; + } + + rc = pipe(in); + if (rc == -1) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "pipe failed: %s", + strerror(errno)) + - errbuf; + goto free_pool; + } + + rc = pipe(out); + if (rc == -1) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "pipe failed: %s", + strerror(errno)) + - errbuf; + goto close_in_fd; + } + + if (!merge_stderr) { + rc = pipe(err); + if (rc == -1) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, + "pipe failed: %s", strerror(errno)) + - errbuf; + goto close_in_out_fd; + } + } + + pid = fork(); + if (pid == -1) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "fork failed: %s", + strerror(errno)) + - errbuf; + goto close_in_out_err_fd; + } + + if (pid == 0) { + +#if (NGX_HAVE_CPU_AFFINITY) + /* reset the CPU affinity mask */ + ngx_uint_t log_level; + ngx_cpuset_t child_cpu_affinity; + + if (ngx_process == NGX_PROCESS_WORKER + && ngx_get_cpu_affinity(ngx_worker) != NULL) + { + CPU_ZERO(&child_cpu_affinity); + + for (i = 0; i < (ngx_uint_t) ngx_min(ngx_ncpu, CPU_SETSIZE); i++) { + CPU_SET(i, &child_cpu_affinity); + } + + log_level = ngx_cycle->log->log_level; + ngx_cycle->log->log_level = NGX_LOG_WARN; + ngx_setaffinity(&child_cpu_affinity, ngx_cycle->log); + ngx_cycle->log->log_level = log_level; + } +#endif + + /* reset the handler of ignored signals to the default */ + for (sig = ngx_signals; sig->signo != 0; sig++) { + ngx_memzero(&sa, sizeof(struct sigaction)); + sa.sa_handler = SIG_DFL; + + if (sigemptyset(&sa.sa_mask) != 0) { + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, ngx_errno, + "lua pipe child init signal mask failed"); + exit(EXIT_FAILURE); + } + + if (sigaction(sig->signo, &sa, NULL) == -1) { + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, ngx_errno, + "lua pipe child reset signal handler for %s " + "failed", sig->signame); + exit(EXIT_FAILURE); + } + } + + /* reset signal mask */ + if (sigemptyset(&set) != 0) { + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, ngx_errno, + "lua pipe child init signal set failed"); + exit(EXIT_FAILURE); + } + + if (sigprocmask(SIG_SETMASK, &set, NULL) != 0) { + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, ngx_errno, + "lua pipe child reset signal mask failed"); + exit(EXIT_FAILURE); + } + + /* close listening socket fd */ + ls = ngx_cycle->listening.elts; + for (i = 0; i < ngx_cycle->listening.nelts; i++) { + if (ngx_close_socket(ls[i].fd) == -1) { + ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_socket_errno, + "lua pipe child " ngx_close_socket_n + " %V failed", &ls[i].addr_text); + } + } + + /* close and dup pipefd */ + if (close(in[1]) == -1) { + ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno, + "lua pipe child failed to close the in[1] " + "pipe fd"); + } + + if (close(out[0]) == -1) { + ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno, + "lua pipe child failed to close the out[0] " + "pipe fd"); + } + + if (ngx_cycle->log->file && ngx_cycle->log->file->fd == STDERR_FILENO) { + errlog_fd = ngx_cycle->log->file->fd; + temp_errlog_fd = dup(errlog_fd); + + if (temp_errlog_fd == -1) { + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, ngx_errno, + "lua pipe child dup errlog fd failed"); + exit(EXIT_FAILURE); + } + + if (ngx_cloexec(temp_errlog_fd) == -1) { + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, ngx_errno, + "lua pipe child new errlog fd " ngx_cloexec_n + " failed"); + } + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "lua pipe child dup old errlog fd %d to new fd %d", + ngx_cycle->log->file->fd, temp_errlog_fd); + + ngx_cycle->log->file->fd = temp_errlog_fd; + } + + if (dup2(in[0], STDIN_FILENO) == -1) { + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, ngx_errno, + "lua pipe child dup2 stdin failed"); + exit(EXIT_FAILURE); + } + + if (dup2(out[1], STDOUT_FILENO) == -1) { + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, ngx_errno, + "lua pipe child dup2 stdout failed"); + exit(EXIT_FAILURE); + } + + if (merge_stderr) { + if (dup2(STDOUT_FILENO, STDERR_FILENO) == -1) { + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, ngx_errno, + "lua pipe child dup2 stderr failed"); + exit(EXIT_FAILURE); + } + + } else { + if (close(err[0]) == -1) { + ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno, + "lua pipe child failed to close the err[0] " + "pipe fd"); + } + + if (dup2(err[1], STDERR_FILENO) == -1) { + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, ngx_errno, + "lua pipe child dup2 stderr failed"); + exit(EXIT_FAILURE); + } + } + + if (execvp(file, (char * const *) argv) == -1) { + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, ngx_errno, + "lua pipe child execvp() failed while executing %s", + file); + } + + exit(EXIT_FAILURE); + } + + /* parent process */ + if (close(in[0]) == -1) { + ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno, + "lua pipe: failed to close the in[0] pipe fd"); + } + + stdin_fd = in[1]; + + if (ngx_nonblocking(stdin_fd) == -1) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, + ngx_nonblocking_n " failed: %s", + strerror(errno)) + - errbuf; + goto close_in_out_err_fd; + } + + pp->stdin_fd = stdin_fd; + + if (close(out[1]) == -1) { + ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno, + "lua pipe: failed to close the out[1] pipe fd"); + } + + stdout_fd = out[0]; + + if (ngx_nonblocking(stdout_fd) == -1) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, + ngx_nonblocking_n " failed: %s", + strerror(errno)) + - errbuf; + goto close_in_out_err_fd; + } + + pp->stdout_fd = stdout_fd; + + if (!merge_stderr) { + if (close(err[1]) == -1) { + ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno, + "lua pipe: failed to close the err[1] pipe fd"); + } + + stderr_fd = err[0]; + + if (ngx_nonblocking(stderr_fd) == -1) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, + ngx_nonblocking_n " failed: %s", + strerror(errno)) + - errbuf; + goto close_in_out_err_fd; + } + + pp->stderr_fd = stderr_fd; + } + + node = (ngx_rbtree_node_t *) (pp + 1); + node->key = pid; + pipe_node = (ngx_http_lua_pipe_node_t *) &node->color; + pipe_node->proc = proc; + ngx_rbtree_insert(&ngx_http_lua_pipe_rbtree, node); + + pp->node = node; + pp->pool = pool; + pp->merge_stderr = merge_stderr; + pp->buffer_size = buffer_size; + + proc->_pid = pid; + proc->write_timeout = 10000; + proc->stdout_read_timeout = 10000; + proc->stderr_read_timeout = 10000; + proc->wait_timeout = 10000; + proc->pipe = pp; + + ngx_log_debug4(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "lua pipe spawn process:%p pid:%P merge_stderr:%d " + "buffer_size:%uz", proc, pid, merge_stderr, buffer_size); + return NGX_OK; + +close_in_out_err_fd: + + if (!merge_stderr) { + if (close(err[0]) == -1) { + ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno, + "failed to close the err[0] pipe fd"); + } + + if (close(err[1]) == -1) { + ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno, + "failed to close the err[1] pipe fd"); + } + } + +close_in_out_fd: + + if (close(out[0]) == -1) { + ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno, + "failed to close the out[0] pipe fd"); + } + + if (close(out[1]) == -1) { + ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno, + "failed to close the out[1] pipe fd"); + } + +close_in_fd: + + if (close(in[0]) == -1) { + ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno, + "failed to close the in[0] pipe fd"); + } + + if (close(in[1]) == -1) { + ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno, + "failed to close the in[1] pipe fd"); + } + +free_pool: + + ngx_destroy_pool(pool); + return NGX_ERROR; +} + + +static ngx_int_t +ngx_http_lua_pipe_close_helper(ngx_http_lua_pipe_ctx_t *pipe_ctx, + ngx_event_t *ev, int forced) +{ + if (ev->handler != ngx_http_lua_pipe_dummy_event_handler && !forced) { + ngx_log_debug3(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "lua pipe cannot close fd:%d without " + "forced pipe:%p ev:%p", pipe_ctx->c->fd, pipe_ctx, ev); + return NGX_ERROR; + } + + ngx_close_connection(pipe_ctx->c); + pipe_ctx->c = NULL; + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_lua_pipe_close_stdin(ngx_http_lua_pipe_t *pipe, int forced) +{ + ngx_event_t *wev; + + if (pipe->stdin_ctx == NULL) { + if (pipe->stdin_fd != -1) { + if (close(pipe->stdin_fd) == -1) { + ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno, + "failed to close the stdin pipe fd"); + } + + pipe->stdin_fd = -1; + } + + } else if (pipe->stdin_ctx->c != NULL) { + wev = pipe->stdin_ctx->c->write; + return ngx_http_lua_pipe_close_helper(pipe->stdin_ctx, wev, forced); + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_lua_pipe_close_stdout(ngx_http_lua_pipe_t *pipe, int forced) +{ + ngx_event_t *rev; + + if (pipe->stdout_ctx == NULL) { + if (pipe->stdout_fd != -1) { + if (close(pipe->stdout_fd) == -1) { + ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno, + "failed to close the stdout pipe fd"); + } + + pipe->stdout_fd = -1; + } + + } else if (pipe->stdout_ctx->c != NULL) { + rev = pipe->stdout_ctx->c->read; + return ngx_http_lua_pipe_close_helper(pipe->stdout_ctx, rev, forced); + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_lua_pipe_close_stderr(ngx_http_lua_pipe_t *pipe, int forced) +{ + ngx_event_t *rev; + + if (pipe->stderr_ctx == NULL) { + if (pipe->stderr_fd != -1) { + if (close(pipe->stderr_fd) == -1) { + ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno, + "failed to close the stderr pipe fd"); + } + + pipe->stderr_fd = -1; + } + + } else if (pipe->stderr_ctx->c != NULL) { + rev = pipe->stderr_ctx->c->read; + return ngx_http_lua_pipe_close_helper(pipe->stderr_ctx, rev, forced); + } + + return NGX_OK; +} + + +int +ngx_http_lua_ffi_pipe_proc_shutdown_stdin(ngx_http_lua_ffi_pipe_proc_t *proc, + u_char *errbuf, size_t *errbuf_size) +{ + ngx_int_t rc; + ngx_http_lua_pipe_t *pipe; + + pipe = proc->pipe; + if (pipe == NULL || pipe->closed) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "closed") - errbuf; + return NGX_ERROR; + } + + rc = ngx_http_lua_pipe_close_stdin(pipe, 0); + if (rc != NGX_OK) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "pipe busy writing") + - errbuf; + return NGX_ERROR; + } + + return NGX_OK; +} + + +int +ngx_http_lua_ffi_pipe_proc_shutdown_stdout(ngx_http_lua_ffi_pipe_proc_t *proc, + u_char *errbuf, size_t *errbuf_size) +{ + ngx_int_t rc; + ngx_http_lua_pipe_t *pipe; + + pipe = proc->pipe; + if (pipe == NULL || pipe->closed) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "closed") - errbuf; + return NGX_ERROR; + } + + rc = ngx_http_lua_pipe_close_stdout(pipe, 0); + if (rc != NGX_OK) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "pipe busy reading") + - errbuf; + return NGX_ERROR; + } + + return NGX_OK; +} + + +int +ngx_http_lua_ffi_pipe_proc_shutdown_stderr(ngx_http_lua_ffi_pipe_proc_t *proc, + u_char *errbuf, size_t *errbuf_size) +{ + ngx_http_lua_pipe_t *pipe; + + pipe = proc->pipe; + if (pipe == NULL || pipe->closed) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "closed") - errbuf; + return NGX_ERROR; + } + + if (pipe->merge_stderr) { + /* stdout is used internally as stderr when merge_stderr is true */ + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "merged to stdout") + - errbuf; + return NGX_ERROR; + } + + if (ngx_http_lua_pipe_close_stderr(pipe, 0) != NGX_OK) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "pipe busy reading") + - errbuf; + return NGX_ERROR; + } + + return NGX_OK; +} + + +static void +ngx_http_lua_pipe_proc_finalize(ngx_http_lua_ffi_pipe_proc_t *proc, int forced) +{ + ngx_http_lua_pipe_t *pipe; + + ngx_log_debug3(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "lua pipe finalize process:%p pid:%P forced:%d", proc, + proc->_pid, forced); + pipe = proc->pipe; + + if (pipe->node) { + ngx_rbtree_delete(&ngx_http_lua_pipe_rbtree, pipe->node); + pipe->node = NULL; + } + + pipe->dead = 1; + + ngx_http_lua_pipe_close_stdin(pipe, forced); + ngx_http_lua_pipe_close_stdout(pipe, forced); + + if (!pipe->merge_stderr) { + ngx_http_lua_pipe_close_stderr(pipe, forced); + } + + pipe->closed = 1; +} + + +void +ngx_http_lua_ffi_pipe_proc_destroy(ngx_http_lua_ffi_pipe_proc_t *proc) +{ + ngx_http_lua_pipe_t *pipe; + + pipe = proc->pipe; + if (pipe == NULL) { + return; + } + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "lua pipe destroy process:%p pid:%P", proc, proc->_pid); + + if (!pipe->dead) { + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "lua pipe kill process:%p pid:%P", proc, proc->_pid); + + if (kill(proc->_pid, SIGKILL) == -1) { + if (ngx_errno != ESRCH) { + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, ngx_errno, + "lua pipe failed to kill process:%p pid:%P"); + } + } + } + + ngx_http_lua_pipe_proc_finalize(proc, 1); + ngx_destroy_pool(pipe->pool); + proc->pipe = NULL; +} + + +static ngx_int_t +ngx_http_lua_pipe_get_lua_ctx(ngx_http_request_t *r, + ngx_http_lua_ctx_t **ctx, u_char *errbuf, size_t *errbuf_size) +{ + int rc; + + *ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + if (ctx == NULL) { + return NGX_HTTP_LUA_FFI_NO_REQ_CTX; + } + + rc = ngx_http_lua_ffi_check_context(*ctx, NGX_HTTP_LUA_CONTEXT_REWRITE + | NGX_HTTP_LUA_CONTEXT_ACCESS + | NGX_HTTP_LUA_CONTEXT_CONTENT + | NGX_HTTP_LUA_CONTEXT_TIMER + | NGX_HTTP_LUA_CONTEXT_SSL_CERT + | NGX_HTTP_LUA_CONTEXT_SSL_SESS_FETCH, + errbuf, errbuf_size); + if (rc != NGX_OK) { + return NGX_HTTP_LUA_FFI_BAD_CONTEXT; + } + + return NGX_OK; +} + + +static void +ngx_http_lua_pipe_put_error(ngx_http_lua_pipe_ctx_t *pipe_ctx, u_char *errbuf, + size_t *errbuf_size) +{ + switch (pipe_ctx->err_type) { + + case PIPE_ERR_CLOSED: + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "closed") - errbuf; + break; + + case PIPE_ERR_SYSCALL: + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "%s", + strerror(pipe_ctx->pipe_errno)) + - errbuf; + break; + + case PIPE_ERR_NOMEM: + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "no memory") + - errbuf; + break; + + case PIPE_ERR_TIMEOUT: + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "timeout") + - errbuf; + break; + + case PIPE_ERR_ADD_READ_EV: + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, + "failed to add read event") + - errbuf; + break; + + case PIPE_ERR_ADD_WRITE_EV: + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, + "failed to add write event") + - errbuf; + break; + + default: + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, + "unexpected err type: %d", pipe_ctx->err_type); + ngx_http_lua_assert(NULL); + } +} + + +static void +ngx_http_lua_pipe_put_data(ngx_http_lua_pipe_t *pipe, + ngx_http_lua_pipe_ctx_t *pipe_ctx, u_char **buf, size_t *buf_size) +{ + size_t size = 0; + size_t chunk_size; + size_t nbufs; + u_char *p; + ngx_buf_t *b; + ngx_chain_t *cl; + ngx_chain_t **ll; + + nbufs = 0; + ll = NULL; + + for (cl = pipe_ctx->bufs_in; cl; cl = cl->next) { + b = cl->buf; + chunk_size = b->last - b->pos; + + if (cl->next) { + ll = &cl->next; + } + + size += chunk_size; + + nbufs++; + } + + if (*buf_size < size) { + *buf = NULL; + *buf_size = size; + + return; + } + + *buf_size = size; + + p = *buf; + for (cl = pipe_ctx->bufs_in; cl; cl = cl->next) { + b = cl->buf; + chunk_size = b->last - b->pos; + p = ngx_cpymem(p, b->pos, chunk_size); + } + + if (nbufs > 1 && ll) { + *ll = pipe->free_bufs; + pipe->free_bufs = pipe_ctx->bufs_in; + pipe_ctx->bufs_in = pipe_ctx->buf_in; + } + + if (pipe_ctx->buffer.pos == pipe_ctx->buffer.last) { + pipe_ctx->buffer.pos = pipe_ctx->buffer.start; + pipe_ctx->buffer.last = pipe_ctx->buffer.start; + } + + if (pipe_ctx->bufs_in) { + pipe_ctx->buf_in->buf->last = pipe_ctx->buffer.pos; + pipe_ctx->buf_in->buf->pos = pipe_ctx->buffer.pos; + } +} + + +static ngx_int_t +ngx_http_lua_pipe_add_input_buffer(ngx_http_lua_pipe_t *pipe, + ngx_http_lua_pipe_ctx_t *pipe_ctx) +{ + ngx_chain_t *cl; + + cl = ngx_http_lua_chain_get_free_buf(ngx_cycle->log, pipe->pool, + &pipe->free_bufs, + pipe->buffer_size); + + if (cl == NULL) { + pipe_ctx->err_type = PIPE_ERR_NOMEM; + return NGX_ERROR; + } + + pipe_ctx->buf_in->next = cl; + pipe_ctx->buf_in = cl; + pipe_ctx->buffer = *cl->buf; + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_lua_pipe_read_all(void *data, ssize_t bytes) +{ + ngx_http_lua_pipe_ctx_t *pipe_ctx = data; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, "lua pipe read all"); + return ngx_http_lua_read_all(&pipe_ctx->buffer, pipe_ctx->buf_in, bytes, + ngx_cycle->log); +} + + +static ngx_int_t +ngx_http_lua_pipe_read_bytes(void *data, ssize_t bytes) +{ + ngx_int_t rc; + ngx_http_lua_pipe_ctx_t *pipe_ctx = data; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "lua pipe read bytes %z", bytes); + + rc = ngx_http_lua_read_bytes(&pipe_ctx->buffer, pipe_ctx->buf_in, + &pipe_ctx->rest, bytes, ngx_cycle->log); + if (rc == NGX_ERROR) { + pipe_ctx->err_type = PIPE_ERR_CLOSED; + return NGX_ERROR; + } + + return rc; +} + + +static ngx_int_t +ngx_http_lua_pipe_read_line(void *data, ssize_t bytes) +{ + ngx_int_t rc; + ngx_http_lua_pipe_ctx_t *pipe_ctx = data; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "lua pipe read line"); + rc = ngx_http_lua_read_line(&pipe_ctx->buffer, pipe_ctx->buf_in, bytes, + ngx_cycle->log); + if (rc == NGX_ERROR) { + pipe_ctx->err_type = PIPE_ERR_CLOSED; + return NGX_ERROR; + } + + return rc; +} + + +static ngx_int_t +ngx_http_lua_pipe_read_any(void *data, ssize_t bytes) +{ + ngx_int_t rc; + ngx_http_lua_pipe_ctx_t *pipe_ctx = data; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, "lua pipe read any"); + rc = ngx_http_lua_read_any(&pipe_ctx->buffer, pipe_ctx->buf_in, + &pipe_ctx->rest, bytes, ngx_cycle->log); + if (rc == NGX_ERROR) { + pipe_ctx->err_type = PIPE_ERR_CLOSED; + return NGX_ERROR; + } + + return rc; +} + + +static ngx_int_t +ngx_http_lua_pipe_read(ngx_http_lua_pipe_t *pipe, + ngx_http_lua_pipe_ctx_t *pipe_ctx) +{ + int rc; + int read; + size_t size; + ssize_t n; + ngx_buf_t *b; + ngx_event_t *rev; + ngx_connection_t *c; + + c = pipe_ctx->c; + rev = c->read; + b = &pipe_ctx->buffer; + read = 0; + + for ( ;; ) { + size = b->last - b->pos; + + if (size || pipe_ctx->eof) { + rc = pipe_ctx->input_filter(pipe_ctx->input_filter_ctx, size); + if (rc == NGX_ERROR) { + return NGX_ERROR; + } + + if (rc == NGX_OK) { + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "lua pipe read done pipe:%p", pipe_ctx); + return NGX_OK; + } + + /* rc == NGX_AGAIN */ + continue; + } + + if (read && !rev->ready) { + break; + } + + size = b->end - b->last; + + if (size == 0) { + rc = ngx_http_lua_pipe_add_input_buffer(pipe, pipe_ctx); + if (rc == NGX_ERROR) { + return NGX_ERROR; + } + + b = &pipe_ctx->buffer; + size = (size_t) (b->end - b->last); + } + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "lua pipe try to read data %uz pipe:%p", + size, pipe_ctx); + + n = c->recv(c, b->last, size); + read = 1; + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "lua pipe read data returned %z pipe:%p", n, pipe_ctx); + + if (n == NGX_AGAIN) { + break; + } + + if (n == 0) { + pipe_ctx->eof = 1; + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "lua pipe closed pipe:%p", pipe_ctx); + continue; + } + + if (n == NGX_ERROR) { + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, ngx_errno, + "lua pipe read data error pipe:%p", pipe_ctx); + + pipe_ctx->err_type = PIPE_ERR_SYSCALL; + pipe_ctx->pipe_errno = ngx_errno; + return NGX_ERROR; + } + + b->last += n; + } + + return NGX_AGAIN; +} + + +static ngx_int_t +ngx_http_lua_pipe_init_ctx(ngx_http_lua_pipe_ctx_t **pipe_ctx_pt, int fd, + ngx_pool_t *pool, u_char *errbuf, size_t *errbuf_size) +{ + ngx_connection_t *c; + + if (fd == -1) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "closed") - errbuf; + return NGX_ERROR; + } + + *pipe_ctx_pt = ngx_pcalloc(pool, sizeof(ngx_http_lua_pipe_ctx_t)); + if (*pipe_ctx_pt == NULL) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "no memory") + - errbuf; + return NGX_ERROR; + } + + c = ngx_get_connection(fd, ngx_cycle->log); + if (c == NULL) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "no connection") + - errbuf; + return NGX_ERROR; + } + + c->log = ngx_cycle->log; + c->recv = ngx_http_lua_pipe_fd_read; + c->read->handler = ngx_http_lua_pipe_dummy_event_handler; + c->read->log = c->log; + +#ifdef HAVE_SOCKET_CLOEXEC_PATCH + c->read->skip_socket_leak_check = 1; +#endif + + c->send = ngx_http_lua_pipe_fd_write; + c->write->handler = ngx_http_lua_pipe_dummy_event_handler; + c->write->log = c->log; + (*pipe_ctx_pt)->c = c; + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "lua pipe init pipe ctx:%p fd:*%d", *pipe_ctx_pt, fd); + + return NGX_OK; +} + + +int +ngx_http_lua_ffi_pipe_proc_read(ngx_http_request_t *r, + ngx_http_lua_ffi_pipe_proc_t *proc, int from_stderr, int reader_type, + size_t length, u_char **buf, size_t *buf_size, u_char *errbuf, + size_t *errbuf_size) +{ + int rc; + ngx_msec_t timeout; + ngx_event_t *rev; + ngx_connection_t *c; + ngx_http_lua_ctx_t *ctx; + ngx_http_lua_pipe_t *pipe; + ngx_http_lua_co_ctx_t *wait_co_ctx; + ngx_http_lua_pipe_ctx_t *pipe_ctx; + + rc = ngx_http_lua_pipe_get_lua_ctx(r, &ctx, errbuf, errbuf_size); + if (rc != NGX_OK) { + return rc; + } + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua pipe read process:%p pid:%P", proc, proc->_pid); + + pipe = proc->pipe; + if (pipe == NULL || pipe->closed) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "closed") - errbuf; + return NGX_ERROR; + } + + if (pipe->merge_stderr && from_stderr) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "merged to stdout") + - errbuf; + return NGX_ERROR; + } + + if (from_stderr) { + if (pipe->stderr_ctx == NULL) { + if (ngx_http_lua_pipe_init_ctx(&pipe->stderr_ctx, pipe->stderr_fd, + pipe->pool, errbuf, + errbuf_size) + != NGX_OK) + { + return NGX_ERROR; + } + + } else { + pipe->stderr_ctx->err_type = 0; + } + + pipe_ctx = pipe->stderr_ctx; + + } else { + if (pipe->stdout_ctx == NULL) { + if (ngx_http_lua_pipe_init_ctx(&pipe->stdout_ctx, pipe->stdout_fd, + pipe->pool, errbuf, + errbuf_size) + != NGX_OK) + { + return NGX_ERROR; + } + + } else { + pipe->stdout_ctx->err_type = 0; + } + + pipe_ctx = pipe->stdout_ctx; + } + + c = pipe_ctx->c; + if (c == NULL) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "closed") - errbuf; + return NGX_ERROR; + } + + rev = c->read; + if (rev->handler != ngx_http_lua_pipe_dummy_event_handler) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "pipe busy reading") + - errbuf; + return NGX_ERROR; + } + + pipe_ctx->input_filter_ctx = pipe_ctx; + + switch (reader_type) { + + case PIPE_READ_ALL: + pipe_ctx->input_filter = ngx_http_lua_pipe_read_all; + break; + + case PIPE_READ_BYTES: + pipe_ctx->input_filter = ngx_http_lua_pipe_read_bytes; + break; + + case PIPE_READ_LINE: + pipe_ctx->input_filter = ngx_http_lua_pipe_read_line; + break; + + case PIPE_READ_ANY: + pipe_ctx->input_filter = ngx_http_lua_pipe_read_any; + break; + + default: + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, + "unexpected reader_type: %d", reader_type); + ngx_http_lua_assert(NULL); + } + + pipe_ctx->rest = length; + + if (pipe_ctx->bufs_in == NULL) { + pipe_ctx->bufs_in = + ngx_http_lua_chain_get_free_buf(ngx_cycle->log, pipe->pool, + &pipe->free_bufs, + pipe->buffer_size); + + if (pipe_ctx->bufs_in == NULL) { + pipe_ctx->err_type = PIPE_ERR_NOMEM; + goto error; + } + + pipe_ctx->buf_in = pipe_ctx->bufs_in; + pipe_ctx->buffer = *pipe_ctx->buf_in->buf; + } + + rc = ngx_http_lua_pipe_read(pipe, pipe_ctx); + if (rc == NGX_ERROR) { + goto error; + } + + if (rc == NGX_OK) { + ngx_http_lua_pipe_put_data(pipe, pipe_ctx, buf, buf_size); + return NGX_OK; + } + + /* rc == NGX_AGAIN */ + wait_co_ctx = ctx->cur_co_ctx; + + c->data = wait_co_ctx; + if (ngx_handle_read_event(rev, 0) != NGX_OK) { + pipe_ctx->err_type = PIPE_ERR_ADD_READ_EV; + goto error; + } + + wait_co_ctx->data = proc; + + if (from_stderr) { + rev->handler = ngx_http_lua_pipe_resume_read_stderr_handler; + wait_co_ctx->cleanup = ngx_http_lua_pipe_proc_read_stderr_cleanup; + timeout = proc->stderr_read_timeout; + + } else { + rev->handler = ngx_http_lua_pipe_resume_read_stdout_handler; + wait_co_ctx->cleanup = ngx_http_lua_pipe_proc_read_stdout_cleanup; + timeout = proc->stdout_read_timeout; + } + + if (timeout > 0) { + ngx_add_timer(rev, timeout); + ngx_log_debug5(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua pipe add timer for reading: %d(ms) process:%p " + "pid:%P pipe:%p ev:%p", timeout, proc, proc->_pid, pipe, + rev); + } + + ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua pipe read yielding process:%p pid:%P pipe:%p", proc, + proc->_pid, pipe); + + return NGX_AGAIN; + +error: + + if (pipe_ctx->bufs_in) { + ngx_http_lua_pipe_put_data(pipe, pipe_ctx, buf, buf_size); + ngx_http_lua_pipe_put_error(pipe_ctx, errbuf, errbuf_size); + return NGX_DECLINED; + } + + ngx_http_lua_pipe_put_error(pipe_ctx, errbuf, errbuf_size); + + return NGX_ERROR; +} + + +/* + * ngx_http_lua_ffi_pipe_get_read_result should only be called just after + * ngx_http_lua_ffi_pipe_proc_read, so we omit most of the sanity check already + * done in ngx_http_lua_ffi_pipe_proc_read. + */ +int +ngx_http_lua_ffi_pipe_get_read_result(ngx_http_request_t *r, + ngx_http_lua_ffi_pipe_proc_t *proc, int from_stderr, u_char **buf, + size_t *buf_size, u_char *errbuf, size_t *errbuf_size) +{ + ngx_http_lua_pipe_t *pipe; + ngx_http_lua_pipe_ctx_t *pipe_ctx; + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua pipe get read result process:%p pid:%P", proc, + proc->_pid); + + pipe = proc->pipe; + pipe_ctx = from_stderr ? pipe->stderr_ctx : pipe->stdout_ctx; + + if (!pipe_ctx->err_type) { + ngx_http_lua_pipe_put_data(pipe, pipe_ctx, buf, buf_size); + return NGX_OK; + } + + if (pipe_ctx->bufs_in) { + ngx_http_lua_pipe_put_data(pipe, pipe_ctx, buf, buf_size); + ngx_http_lua_pipe_put_error(pipe_ctx, errbuf, errbuf_size); + return NGX_DECLINED; + } + + ngx_http_lua_pipe_put_error(pipe_ctx, errbuf, errbuf_size); + + return NGX_ERROR; +} + + +static ngx_int_t +ngx_http_lua_pipe_write(ngx_http_lua_pipe_t *pipe, + ngx_http_lua_pipe_ctx_t *pipe_ctx) +{ + size_t size; + ngx_int_t n; + ngx_buf_t *b; + ngx_connection_t *c; + + c = pipe_ctx->c; + b = pipe_ctx->buf_in->buf; + + for ( ;; ) { + size = b->last - b->pos; + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "lua pipe try to write data %uz pipe:%p", size, + pipe_ctx); + + n = c->send(c, b->pos, size); + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "lua pipe write returned %i pipe:%p", n, pipe_ctx); + + if (n >= 0) { + b->pos += n; + + if (b->pos == b->last) { + b->pos = b->start; + b->last = b->start; + + if (!pipe->free_bufs) { + pipe->free_bufs = pipe_ctx->buf_in; + + } else { + pipe->free_bufs->next = pipe_ctx->buf_in; + } + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "lua pipe write done pipe:%p", pipe_ctx); + return NGX_OK; + } + + continue; + } + + /* NGX_ERROR || NGX_AGAIN */ + break; + } + + if (n == NGX_ERROR) { + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, ngx_errno, + "lua pipe write data error pipe:%p", pipe_ctx); + + if (ngx_errno == NGX_EPIPE) { + pipe_ctx->err_type = PIPE_ERR_CLOSED; + + } else { + pipe_ctx->err_type = PIPE_ERR_SYSCALL; + pipe_ctx->pipe_errno = ngx_errno; + } + + return NGX_ERROR; + } + + return NGX_AGAIN; +} + + +ssize_t +ngx_http_lua_ffi_pipe_proc_write(ngx_http_request_t *r, + ngx_http_lua_ffi_pipe_proc_t *proc, const u_char *data, size_t len, + u_char *errbuf, size_t *errbuf_size) +{ + int rc; + ngx_buf_t *b; + ngx_msec_t timeout; + ngx_chain_t *cl; + ngx_event_t *wev; + ngx_http_lua_ctx_t *ctx; + ngx_http_lua_pipe_t *pipe; + ngx_http_lua_co_ctx_t *wait_co_ctx; + ngx_http_lua_pipe_ctx_t *pipe_ctx; + + rc = ngx_http_lua_pipe_get_lua_ctx(r, &ctx, errbuf, errbuf_size); + if (rc != NGX_OK) { + return rc; + } + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua pipe write process:%p pid:%P", proc, proc->_pid); + + pipe = proc->pipe; + if (pipe == NULL || pipe->closed) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "closed") - errbuf; + return NGX_ERROR; + } + + if (pipe->stdin_ctx == NULL) { + if (ngx_http_lua_pipe_init_ctx(&pipe->stdin_ctx, pipe->stdin_fd, + pipe->pool, errbuf, + errbuf_size) + != NGX_OK) + { + return NGX_ERROR; + } + + } else { + pipe->stdin_ctx->err_type = 0; + } + + pipe_ctx = pipe->stdin_ctx; + if (pipe_ctx->c == NULL) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "closed") - errbuf; + return NGX_ERROR; + } + + wev = pipe_ctx->c->write; + if (wev->handler != ngx_http_lua_pipe_dummy_event_handler) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "pipe busy writing") + - errbuf; + return NGX_ERROR; + } + + pipe_ctx->rest = len; + + cl = ngx_http_lua_chain_get_free_buf(ngx_cycle->log, pipe->pool, + &pipe->free_bufs, len); + if (cl == NULL) { + pipe_ctx->err_type = PIPE_ERR_NOMEM; + goto error; + } + + pipe_ctx->buf_in = cl; + b = pipe_ctx->buf_in->buf; + b->last = ngx_copy(b->last, data, len); + + rc = ngx_http_lua_pipe_write(pipe, pipe_ctx); + if (rc == NGX_ERROR) { + goto error; + } + + if (rc == NGX_OK) { + return len; + } + + /* rc == NGX_AGAIN */ + wait_co_ctx = ctx->cur_co_ctx; + pipe_ctx->c->data = wait_co_ctx; + + wev->handler = ngx_http_lua_pipe_resume_write_handler; + if (ngx_handle_write_event(wev, 0) != NGX_OK) { + pipe_ctx->err_type = PIPE_ERR_ADD_WRITE_EV; + goto error; + } + + wait_co_ctx->data = proc; + wait_co_ctx->cleanup = ngx_http_lua_pipe_proc_write_cleanup; + timeout = proc->write_timeout; + + if (timeout > 0) { + ngx_add_timer(wev, timeout); + ngx_log_debug5(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua pipe add timer for writing: %d(ms) process:%p " + "pid:%P pipe:%p ev:%p", timeout, proc, proc->_pid, pipe, + wev); + } + + ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua pipe write yielding process:%p pid:%P pipe:%p", proc, + proc->_pid, pipe); + + return NGX_AGAIN; + +error: + + ngx_http_lua_pipe_put_error(pipe_ctx, errbuf, errbuf_size); + return NGX_ERROR; +} + + +/* + * ngx_http_lua_ffi_pipe_get_write_result should only be called just after + * ngx_http_lua_ffi_pipe_proc_write, so we omit most of the sanity check + * already done in ngx_http_lua_ffi_pipe_proc_write. + */ +ssize_t +ngx_http_lua_ffi_pipe_get_write_result(ngx_http_request_t *r, + ngx_http_lua_ffi_pipe_proc_t *proc, u_char *errbuf, size_t *errbuf_size) +{ + ngx_http_lua_pipe_t *pipe; + ngx_http_lua_pipe_ctx_t *pipe_ctx; + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua pipe get write result process:%p pid:%P", proc, + proc->_pid); + + pipe = proc->pipe; + pipe_ctx = pipe->stdin_ctx; + + if (pipe_ctx->err_type) { + ngx_http_lua_pipe_put_error(pipe_ctx, errbuf, errbuf_size); + return NGX_ERROR; + } + + return pipe_ctx->rest; +} + + +int +ngx_http_lua_ffi_pipe_proc_wait(ngx_http_request_t *r, + ngx_http_lua_ffi_pipe_proc_t *proc, char **reason, int *status, + u_char *errbuf, size_t *errbuf_size) +{ + int rc; + ngx_rbtree_node_t *node; + ngx_http_lua_ctx_t *ctx; + ngx_http_lua_pipe_t *pipe; + ngx_http_lua_co_ctx_t *wait_co_ctx; + ngx_http_lua_pipe_node_t *pipe_node; + + rc = ngx_http_lua_pipe_get_lua_ctx(r, &ctx, errbuf, errbuf_size); + if (rc != NGX_OK) { + return rc; + } + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua pipe wait process:%p pid:%P", proc, proc->_pid); + + pipe = proc->pipe; + if (pipe == NULL || pipe->closed) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "exited") - errbuf; + return NGX_ERROR; + } + + node = pipe->node; + pipe_node = (ngx_http_lua_pipe_node_t *) &node->color; + if (pipe_node->wait_co_ctx) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "pipe busy waiting") + - errbuf; + return NGX_ERROR; + } + + if (pipe_node->reason_code == REASON_RUNNING_CODE) { + wait_co_ctx = ctx->cur_co_ctx; + wait_co_ctx->data = proc; + ngx_memzero(&wait_co_ctx->sleep, sizeof(ngx_event_t)); + wait_co_ctx->sleep.handler = ngx_http_lua_pipe_resume_wait_handler; + wait_co_ctx->sleep.data = wait_co_ctx; + wait_co_ctx->sleep.log = r->connection->log; + wait_co_ctx->cleanup = ngx_http_lua_pipe_proc_wait_cleanup; + + pipe_node->wait_co_ctx = wait_co_ctx; + + if (proc->wait_timeout > 0) { + ngx_add_timer(&wait_co_ctx->sleep, proc->wait_timeout); + ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua pipe add timer for waiting: %d(ms) process:%p " + "pid:%P ev:%p", proc->wait_timeout, proc, + proc->_pid, &wait_co_ctx->sleep); + } + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua pipe wait yielding process:%p pid:%P", proc, + proc->_pid); + + return NGX_AGAIN; + } + + *status = pipe_node->status; + + switch (pipe_node->reason_code) { + + case REASON_EXIT_CODE: + *reason = REASON_EXIT; + break; + + case REASON_SIGNAL_CODE: + *reason = REASON_SIGNAL; + break; + + default: + *reason = REASON_UNKNOWN; + } + + ngx_http_lua_pipe_proc_finalize(proc, 0); + + if (*status == 0) { + return NGX_OK; + } + + return NGX_DECLINED; +} + + +int +ngx_http_lua_ffi_pipe_proc_kill(ngx_http_lua_ffi_pipe_proc_t *proc, int signal, + u_char *errbuf, size_t *errbuf_size) +{ + ngx_pid_t pid; + ngx_http_lua_pipe_t *pipe; + + pipe = proc->pipe; + + if (pipe == NULL || pipe->dead) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "exited") - errbuf; + return NGX_ERROR; + } + + pid = proc->_pid; + + if (kill(pid, signal) == -1) { + switch (ngx_errno) { + case EINVAL: + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "invalid signal") + - errbuf; + break; + + case ESRCH: + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "exited") + - errbuf; + break; + + default: + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "%s", + strerror(ngx_errno)) + - errbuf; + } + + return NGX_ERROR; + } + + return NGX_OK; +} + + +static int +ngx_http_lua_pipe_read_stdout_retval(ngx_http_lua_ffi_pipe_proc_t *proc, + lua_State *L) +{ + return ngx_http_lua_pipe_read_retval_helper(proc, L, 0); +} + + +static int +ngx_http_lua_pipe_read_stderr_retval(ngx_http_lua_ffi_pipe_proc_t *proc, + lua_State *L) +{ + return ngx_http_lua_pipe_read_retval_helper(proc, L, 1); +} + + +static int +ngx_http_lua_pipe_read_retval_helper(ngx_http_lua_ffi_pipe_proc_t *proc, + lua_State *L, int from_stderr) +{ + int rc; + ngx_msec_t timeout; + ngx_event_t *rev; + ngx_http_lua_pipe_t *pipe; + ngx_http_lua_pipe_ctx_t *pipe_ctx; + + pipe = proc->pipe; + if (from_stderr) { + pipe_ctx = pipe->stderr_ctx; + + } else { + pipe_ctx = pipe->stdout_ctx; + } + + if (pipe->timeout) { + pipe->timeout = 0; + pipe_ctx->err_type = PIPE_ERR_TIMEOUT; + return 0; + } + + rc = ngx_http_lua_pipe_read(pipe, pipe_ctx); + if (rc != NGX_AGAIN) { + return 0; + } + + rev = pipe_ctx->c->read; + + if (from_stderr) { + rev->handler = ngx_http_lua_pipe_resume_read_stderr_handler; + timeout = proc->stderr_read_timeout; + + } else { + rev->handler = ngx_http_lua_pipe_resume_read_stdout_handler; + timeout = proc->stdout_read_timeout; + } + + if (timeout > 0) { + ngx_add_timer(rev, timeout); + ngx_log_debug5(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "lua pipe add timer for reading: %d(ms) proc:%p " + "pid:%P pipe:%p ev:%p", timeout, proc, proc->_pid, pipe, + rev); + } + + ngx_log_debug3(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "lua pipe read yielding process:%p pid:%P pipe:%p", proc, + proc->_pid, pipe); + + return NGX_AGAIN; +} + + +static int +ngx_http_lua_pipe_write_retval(ngx_http_lua_ffi_pipe_proc_t *proc, + lua_State *L) +{ + int rc; + ngx_msec_t timeout; + ngx_event_t *wev; + ngx_http_lua_pipe_t *pipe; + ngx_http_lua_pipe_ctx_t *pipe_ctx; + + pipe = proc->pipe; + pipe_ctx = pipe->stdin_ctx; + + if (pipe->timeout) { + pipe->timeout = 0; + pipe_ctx->err_type = PIPE_ERR_TIMEOUT; + return 0; + } + + rc = ngx_http_lua_pipe_write(pipe, pipe_ctx); + if (rc != NGX_AGAIN) { + return 0; + } + + wev = pipe_ctx->c->write; + wev->handler = ngx_http_lua_pipe_resume_write_handler; + timeout = proc->write_timeout; + + if (timeout > 0) { + ngx_add_timer(wev, timeout); + ngx_log_debug5(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "lua pipe add timer for writing: %d(ms) proc:%p " + "pid:%P pipe:%p ev:%p", timeout, proc, proc->_pid, pipe, + wev); + } + + ngx_log_debug3(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "lua pipe write yielding process:%p pid:%P pipe:%p", proc, + proc->_pid, pipe); + + return NGX_AGAIN; +} + + +static int +ngx_http_lua_pipe_wait_retval(ngx_http_lua_ffi_pipe_proc_t *proc, lua_State *L) +{ + int nret; + ngx_rbtree_node_t *node; + ngx_http_lua_pipe_t *pipe; + ngx_http_lua_pipe_node_t *pipe_node; + + pipe = proc->pipe; + node = pipe->node; + pipe_node = (ngx_http_lua_pipe_node_t *) &node->color; + pipe_node->wait_co_ctx = NULL; + + if (pipe->timeout) { + pipe->timeout = 0; + lua_pushnil(L); + lua_pushliteral(L, "timeout"); + return 2; + } + + ngx_http_lua_pipe_proc_finalize(pipe_node->proc, 0); + + if (pipe_node->status == 0) { + lua_pushboolean(L, 1); + lua_pushliteral(L, REASON_EXIT); + lua_pushinteger(L, pipe_node->status); + nret = 3; + + } else { + lua_pushboolean(L, 0); + + switch (pipe_node->reason_code) { + + case REASON_EXIT_CODE: + lua_pushliteral(L, REASON_EXIT); + break; + + case REASON_SIGNAL_CODE: + lua_pushliteral(L, REASON_SIGNAL); + break; + + default: + lua_pushliteral(L, REASON_UNKNOWN); + } + + lua_pushinteger(L, pipe_node->status); + nret = 3; + } + + return nret; +} + + +static void +ngx_http_lua_pipe_resume_helper(ngx_event_t *ev, + ngx_http_lua_co_ctx_t *wait_co_ctx) +{ + ngx_connection_t *c; + ngx_http_request_t *r; + ngx_http_lua_ctx_t *ctx; + ngx_http_lua_pipe_t *pipe; + ngx_http_lua_ffi_pipe_proc_t *proc; + + if (ev->timedout) { + proc = wait_co_ctx->data; + pipe = proc->pipe; + pipe->timeout = 1; + ev->timedout = 0; + } + + ngx_http_lua_pipe_clear_event(ev); + + r = ngx_http_lua_get_req(wait_co_ctx->co); + c = r->connection; + + ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + ngx_http_lua_assert(ctx != NULL); + + ctx->cur_co_ctx = wait_co_ctx; + + if (ctx->entered_content_phase) { + (void) ngx_http_lua_pipe_resume(r); + + } else { + ctx->resume_handler = ngx_http_lua_pipe_resume; + ngx_http_core_run_phases(r); + } + + ngx_http_run_posted_requests(c); +} + + +static void +ngx_http_lua_pipe_resume_read_stdout_handler(ngx_event_t *ev) +{ + ngx_connection_t *c = ev->data; + ngx_http_lua_co_ctx_t *wait_co_ctx; + ngx_http_lua_pipe_t *pipe; + ngx_http_lua_ffi_pipe_proc_t *proc; + + wait_co_ctx = c->data; + proc = wait_co_ctx->data; + pipe = proc->pipe; + pipe->retval_handler = ngx_http_lua_pipe_read_stdout_retval; + ngx_http_lua_pipe_resume_helper(ev, wait_co_ctx); +} + + +static void +ngx_http_lua_pipe_resume_read_stderr_handler(ngx_event_t *ev) +{ + ngx_connection_t *c = ev->data; + ngx_http_lua_co_ctx_t *wait_co_ctx; + ngx_http_lua_pipe_t *pipe; + ngx_http_lua_ffi_pipe_proc_t *proc; + + wait_co_ctx = c->data; + proc = wait_co_ctx->data; + pipe = proc->pipe; + pipe->retval_handler = ngx_http_lua_pipe_read_stderr_retval; + ngx_http_lua_pipe_resume_helper(ev, wait_co_ctx); +} + + +static void +ngx_http_lua_pipe_resume_write_handler(ngx_event_t *ev) +{ + ngx_connection_t *c = ev->data; + ngx_http_lua_co_ctx_t *wait_co_ctx; + ngx_http_lua_pipe_t *pipe; + ngx_http_lua_ffi_pipe_proc_t *proc; + + wait_co_ctx = c->data; + proc = wait_co_ctx->data; + pipe = proc->pipe; + pipe->retval_handler = ngx_http_lua_pipe_write_retval; + ngx_http_lua_pipe_resume_helper(ev, wait_co_ctx); +} + + +static void +ngx_http_lua_pipe_resume_wait_handler(ngx_event_t *ev) +{ + ngx_http_lua_co_ctx_t *wait_co_ctx = ev->data; + ngx_http_lua_pipe_t *pipe; + ngx_http_lua_ffi_pipe_proc_t *proc; + + proc = wait_co_ctx->data; + pipe = proc->pipe; + pipe->retval_handler = ngx_http_lua_pipe_wait_retval; + ngx_http_lua_pipe_resume_helper(ev, wait_co_ctx); +} + + +static ngx_int_t +ngx_http_lua_pipe_resume(ngx_http_request_t *r) +{ + int nret; + lua_State *vm; + ngx_int_t rc; + ngx_uint_t nreqs; + ngx_connection_t *c; + ngx_http_lua_ctx_t *ctx; + ngx_http_lua_pipe_t *pipe; + ngx_http_lua_ffi_pipe_proc_t *proc; + + ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + if (ctx == NULL) { + return NGX_ERROR; + } + + ctx->resume_handler = ngx_http_lua_wev_handler; + ctx->cur_co_ctx->cleanup = NULL; + + proc = ctx->cur_co_ctx->data; + pipe = proc->pipe; + nret = pipe->retval_handler(proc, ctx->cur_co_ctx->co); + if (nret == NGX_AGAIN) { + return NGX_DONE; + } + + c = r->connection; + vm = ngx_http_lua_get_lua_vm(r, ctx); + nreqs = c->requests; + + rc = ngx_http_lua_run_thread(vm, r, ctx, nret); + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua run thread returned %d", rc); + + if (rc == NGX_AGAIN) { + return ngx_http_lua_run_posted_threads(c, vm, r, ctx, nreqs); + } + + if (rc == NGX_DONE) { + ngx_http_lua_finalize_request(r, NGX_DONE); + return ngx_http_lua_run_posted_threads(c, vm, r, ctx, nreqs); + } + + /* rc == NGX_ERROR || rc >= NGX_OK */ + + if (ctx->entered_content_phase) { + ngx_http_lua_finalize_request(r, rc); + return NGX_DONE; + } + + return rc; +} + + +static void +ngx_http_lua_pipe_dummy_event_handler(ngx_event_t *ev) +{ + /* do nothing */ +} + + +static void +ngx_http_lua_pipe_clear_event(ngx_event_t *ev) +{ + ev->handler = ngx_http_lua_pipe_dummy_event_handler; + + if (ev->timer_set) { + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ev->log, 0, + "lua pipe del timer for ev:%p", ev); + ngx_del_timer(ev); + } + + if (ev->posted) { + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ev->log, 0, + "lua pipe del posted event for ev:%p", ev); + ngx_delete_posted_event(ev); + } +} + + +static void +ngx_http_lua_pipe_proc_read_stdout_cleanup(void *data) +{ + ngx_event_t *rev; + ngx_connection_t *c; + ngx_http_lua_co_ctx_t *wait_co_ctx = data; + ngx_http_lua_ffi_pipe_proc_t *proc; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "lua pipe proc read stdout cleanup"); + + proc = wait_co_ctx->data; + c = proc->pipe->stdout_ctx->c; + if (c) { + rev = c->read; + ngx_http_lua_pipe_clear_event(rev); + } + + wait_co_ctx->cleanup = NULL; +} + + +static void +ngx_http_lua_pipe_proc_read_stderr_cleanup(void *data) +{ + ngx_event_t *rev; + ngx_connection_t *c; + ngx_http_lua_co_ctx_t *wait_co_ctx = data; + ngx_http_lua_ffi_pipe_proc_t *proc; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "lua pipe proc read stderr cleanup"); + + proc = wait_co_ctx->data; + c = proc->pipe->stderr_ctx->c; + if (c) { + rev = c->read; + ngx_http_lua_pipe_clear_event(rev); + } + + wait_co_ctx->cleanup = NULL; +} + + +static void +ngx_http_lua_pipe_proc_write_cleanup(void *data) +{ + ngx_event_t *wev; + ngx_connection_t *c; + ngx_http_lua_co_ctx_t *wait_co_ctx = data; + ngx_http_lua_ffi_pipe_proc_t *proc; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "lua pipe proc write cleanup"); + + proc = wait_co_ctx->data; + c = proc->pipe->stdin_ctx->c; + if (c) { + wev = c->write; + ngx_http_lua_pipe_clear_event(wev); + } + + wait_co_ctx->cleanup = NULL; +} + + +static void +ngx_http_lua_pipe_proc_wait_cleanup(void *data) +{ + ngx_rbtree_node_t *node; + ngx_http_lua_co_ctx_t *wait_co_ctx = data; + ngx_http_lua_pipe_node_t *pipe_node; + ngx_http_lua_ffi_pipe_proc_t *proc; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "lua pipe proc wait cleanup"); + + proc = wait_co_ctx->data; + node = proc->pipe->node; + pipe_node = (ngx_http_lua_pipe_node_t *) &node->color; + pipe_node->wait_co_ctx = NULL; + + ngx_http_lua_pipe_clear_event(&wait_co_ctx->sleep); + + wait_co_ctx->cleanup = NULL; +} + + +#endif /* HAVE_NGX_LUA_PIPE */ + +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/debian/modules/http-lua/src/ngx_http_lua_pipe.h b/debian/modules/http-lua/src/ngx_http_lua_pipe.h new file mode 100644 index 0000000..b5cea89 --- /dev/null +++ b/debian/modules/http-lua/src/ngx_http_lua_pipe.h @@ -0,0 +1,95 @@ + +/* + * Copyright (C) by OpenResty Inc. + */ + + +#ifndef _NGX_HTTP_LUA_PIPE_H_INCLUDED_ +#define _NGX_HTTP_LUA_PIPE_H_INCLUDED_ + + +#include "ngx_http_lua_common.h" + + +typedef ngx_int_t (*ngx_http_lua_pipe_input_filter)(void *data, ssize_t bytes); + + +typedef struct { + ngx_connection_t *c; + ngx_http_lua_pipe_input_filter input_filter; + void *input_filter_ctx; + size_t rest; + ngx_chain_t *buf_in; + ngx_chain_t *bufs_in; + ngx_buf_t buffer; + ngx_err_t pipe_errno; + unsigned err_type:16; + unsigned eof:1; +} ngx_http_lua_pipe_ctx_t; + + +typedef struct ngx_http_lua_pipe_s ngx_http_lua_pipe_t; + + +typedef struct { + ngx_pid_t _pid; + ngx_msec_t write_timeout; + ngx_msec_t stdout_read_timeout; + ngx_msec_t stderr_read_timeout; + ngx_msec_t wait_timeout; + /* pipe hides the implementation from the Lua binding */ + ngx_http_lua_pipe_t *pipe; +} ngx_http_lua_ffi_pipe_proc_t; + + +typedef int (*ngx_http_lua_pipe_retval_handler)( + ngx_http_lua_ffi_pipe_proc_t *proc, lua_State *L); + + +struct ngx_http_lua_pipe_s { + ngx_pool_t *pool; + ngx_chain_t *free_bufs; + ngx_rbtree_node_t *node; + int stdin_fd; + int stdout_fd; + int stderr_fd; + ngx_http_lua_pipe_ctx_t *stdin_ctx; + ngx_http_lua_pipe_ctx_t *stdout_ctx; + ngx_http_lua_pipe_ctx_t *stderr_ctx; + ngx_http_lua_pipe_retval_handler retval_handler; + size_t buffer_size; + unsigned closed:1; + unsigned dead:1; + unsigned timeout:1; + unsigned merge_stderr:1; +}; + + +typedef struct { + u_char color; + u_char reason_code; + int status; + ngx_http_lua_co_ctx_t *wait_co_ctx; + ngx_http_lua_ffi_pipe_proc_t *proc; +} ngx_http_lua_pipe_node_t; + + +typedef struct { + int signo; + char *signame; +} ngx_http_lua_pipe_signal_t; + + +#if !(NGX_WIN32) && !defined(NGX_LUA_NO_FFI_API) \ + && defined(HAVE_SOCKET_CLOEXEC_PATCH) +#define HAVE_NGX_LUA_PIPE 1 + + +void ngx_http_lua_pipe_init(void); +ngx_int_t ngx_http_lua_pipe_add_signal_handler(ngx_cycle_t *cycle); +#endif + + +#endif /* _NGX_HTTP_LUA_PIPE_H_INCLUDED_ */ + +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/debian/modules/http-lua/src/ngx_http_lua_regex.c b/debian/modules/http-lua/src/ngx_http_lua_regex.c index 843d1e4..8f3373b 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_regex.c +++ b/debian/modules/http-lua/src/ngx_http_lua_regex.c @@ -15,7 +15,6 @@ #include "ngx_http_lua_regex.h" #include "ngx_http_lua_pcrefix.h" #include "ngx_http_lua_script.h" -#include "ngx_http_lua_pcrefix.h" #include "ngx_http_lua_util.h" @@ -249,7 +248,8 @@ ngx_http_lua_ngx_re_match_helper(lua_State *L, int wantcaps) dd("server pool %p", lmcf->pool); - lua_pushlightuserdata(L, &ngx_http_lua_regex_cache_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + regex_cache_key)); lua_rawget(L, LUA_REGISTRYINDEX); /* table */ lua_pushliteral(L, "m"); @@ -720,7 +720,8 @@ ngx_http_lua_ngx_re_gmatch(lua_State *L) dd("server pool %p", lmcf->pool); - lua_pushlightuserdata(L, &ngx_http_lua_regex_cache_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + regex_cache_key)); lua_rawget(L, LUA_REGISTRYINDEX); /* table */ lua_pushliteral(L, "m"); @@ -1388,7 +1389,8 @@ ngx_http_lua_ngx_re_sub_helper(lua_State *L, unsigned global) dd("server pool %p", lmcf->pool); - lua_pushlightuserdata(L, &ngx_http_lua_regex_cache_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + regex_cache_key)); lua_rawget(L, LUA_REGISTRYINDEX); /* table */ lua_pushliteral(L, "s"); diff --git a/debian/modules/http-lua/src/ngx_http_lua_rewriteby.c b/debian/modules/http-lua/src/ngx_http_lua_rewriteby.c index 1bbe87c..1de9968 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_rewriteby.c +++ b/debian/modules/http-lua/src/ngx_http_lua_rewriteby.c @@ -62,7 +62,7 @@ ngx_http_lua_rewrite_handler(ngx_http_request_t *r) #endif if (cur_ph < last_ph) { - dd("swaping the contents of cur_ph and last_ph..."); + dd("swapping the contents of cur_ph and last_ph..."); tmp = *cur_ph; @@ -261,9 +261,11 @@ ngx_http_lua_rewrite_by_chunk(lua_State *L, ngx_http_request_t *r) /* move code closure to new coroutine */ lua_xmove(L, co, 1); +#ifndef OPENRESTY_LUAJIT /* set closure's env table to new coroutine's globals table */ ngx_http_lua_get_globals_table(co); lua_setfenv(co, -2); +#endif /* save nginx request in coroutine globals table */ ngx_http_lua_set_req(co, r); diff --git a/debian/modules/http-lua/src/ngx_http_lua_script.c b/debian/modules/http-lua/src/ngx_http_lua_script.c index 95ebadf..c675a16 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_script.c +++ b/debian/modules/http-lua/src/ngx_http_lua_script.c @@ -329,7 +329,7 @@ ngx_http_lua_script_add_copy_code(ngx_http_lua_script_compile_t *sc, return NGX_ERROR; } - code->code = (ngx_http_lua_script_code_pt) + code->code = (ngx_http_lua_script_code_pt) (void *) ngx_http_lua_script_copy_len_code; code->len = len; @@ -399,7 +399,7 @@ ngx_http_lua_script_add_capture_code(ngx_http_lua_script_compile_t *sc, return NGX_ERROR; } - code->code = (ngx_http_lua_script_code_pt) + code->code = (ngx_http_lua_script_code_pt) (void *) ngx_http_lua_script_copy_capture_len_code; code->n = 2 * n; diff --git a/debian/modules/http-lua/src/ngx_http_lua_setby.c b/debian/modules/http-lua/src/ngx_http_lua_setby.c index 2e8762a..d4288b5 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_setby.c +++ b/debian/modules/http-lua/src/ngx_http_lua_setby.c @@ -30,13 +30,6 @@ static void ngx_http_lua_set_by_lua_env(lua_State *L, ngx_http_request_t *r, size_t nargs, ngx_http_variable_value_t *args); -/* keys in Lua thread for fetching args and nargs in set_by_lua* */ - -#define ngx_http_lua_nargs_key "__ngx_nargs" - -#define ngx_http_lua_args_key "__ngx_args" - - ngx_int_t ngx_http_lua_set_by_chunk(lua_State *L, ngx_http_request_t *r, ngx_str_t *val, ngx_http_variable_value_t *args, size_t nargs, ngx_str_t *script) @@ -134,23 +127,24 @@ ngx_http_lua_set_by_chunk(lua_State *L, ngx_http_request_t *r, ngx_str_t *val, int -ngx_http_lua_setby_param_get(lua_State *L) +ngx_http_lua_setby_param_get(lua_State *L, ngx_http_request_t *r) { int idx; int n; ngx_http_variable_value_t *v; + ngx_http_lua_main_conf_t *lmcf; idx = luaL_checkint(L, 2); idx--; - /* get number of args from globals */ - lua_getglobal(L, ngx_http_lua_nargs_key); - n = (int) lua_tointeger(L, -1); + lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); - /* get args from globals */ - lua_getglobal(L, ngx_http_lua_args_key); - v = lua_touserdata(L, -1); + /* get number of args from lmcf */ + n = lmcf->setby_nargs; + + /* get args from lmcf */ + v = lmcf->setby_args; if (idx < 0 || idx > n - 1) { lua_pushnil(L); @@ -178,15 +172,16 @@ static void ngx_http_lua_set_by_lua_env(lua_State *L, ngx_http_request_t *r, size_t nargs, ngx_http_variable_value_t *args) { - /* set nginx request pointer to current lua thread's globals table */ + ngx_http_lua_main_conf_t *lmcf; + ngx_http_lua_set_req(L, r); - lua_pushinteger(L, nargs); - lua_setglobal(L, ngx_http_lua_nargs_key); + lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); - lua_pushlightuserdata(L, args); - lua_setglobal(L, ngx_http_lua_args_key); + lmcf->setby_nargs = nargs; + lmcf->setby_args = args; +#ifndef OPENRESTY_LUAJIT /** * we want to create empty environment for current script * @@ -211,6 +206,7 @@ ngx_http_lua_set_by_lua_env(lua_State *L, ngx_http_request_t *r, size_t nargs, /* }}} */ lua_setfenv(L, -2); /* set new running env for the code closure */ +#endif } /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/debian/modules/http-lua/src/ngx_http_lua_setby.h b/debian/modules/http-lua/src/ngx_http_lua_setby.h index da71753..f43eef7 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_setby.h +++ b/debian/modules/http-lua/src/ngx_http_lua_setby.h @@ -7,7 +7,7 @@ ngx_int_t ngx_http_lua_set_by_chunk(lua_State *L, ngx_http_request_t *r, ngx_str_t *val, ngx_http_variable_value_t *args, size_t nargs, ngx_str_t *script); -int ngx_http_lua_setby_param_get(lua_State *L); +int ngx_http_lua_setby_param_get(lua_State *L, ngx_http_request_t *r); #endif /* _NGX_HTTP_LUA_SET_BY_H_INCLUDED_ */ diff --git a/debian/modules/http-lua/src/ngx_http_lua_shdict.c b/debian/modules/http-lua/src/ngx_http_lua_shdict.c index 5fb7930..b017bea 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_shdict.c +++ b/debian/modules/http-lua/src/ngx_http_lua_shdict.c @@ -325,6 +325,7 @@ ngx_http_lua_inject_shdict_api(ngx_http_lua_main_conf_t *lmcf, lua_State *L) ngx_http_lua_shdict_ctx_t *ctx; ngx_uint_t i; ngx_shm_zone_t **zone; + ngx_shm_zone_t **zone_udata; if (lmcf->shdict_zones != NULL) { lua_createtable(L, 0, lmcf->shdict_zones->nelts /* nrec */); @@ -396,7 +397,9 @@ ngx_http_lua_inject_shdict_api(ngx_http_lua_main_conf_t *lmcf, lua_State *L) lua_createtable(L, 1 /* narr */, 0 /* nrec */); /* table of zone[i] */ - lua_pushlightuserdata(L, zone[i]); /* shared mt key ud */ + zone_udata = lua_newuserdata(L, sizeof(ngx_shm_zone_t *)); + /* shared mt key ud */ + *zone_udata = zone[i]; lua_rawseti(L, -2, SHDICT_USERDATA_INDEX); /* {zone[i]} */ lua_pushvalue(L, -3); /* shared mt key ud mt */ lua_setmetatable(L, -2); /* shared mt key ud */ @@ -431,11 +434,17 @@ static ngx_inline ngx_shm_zone_t * ngx_http_lua_shdict_get_zone(lua_State *L, int index) { ngx_shm_zone_t *zone; + ngx_shm_zone_t **zone_udata; lua_rawgeti(L, index, SHDICT_USERDATA_INDEX); - zone = lua_touserdata(L, -1); + zone_udata = lua_touserdata(L, -1); lua_pop(L, 1); + if (zone_udata == NULL) { + return NULL; + } + + zone = *zone_udata; return zone; } @@ -2209,6 +2218,17 @@ ngx_http_lua_find_zone(u_char *name_data, size_t name_len) #ifndef NGX_LUA_NO_FFI_API +ngx_shm_zone_t * +ngx_http_lua_ffi_shdict_udata_to_zone(void *zone_udata) +{ + if (zone_udata == NULL) { + return NULL; + } + + return *(ngx_shm_zone_t **) zone_udata; +} + + int ngx_http_lua_ffi_shdict_store(ngx_shm_zone_t *zone, int op, u_char *key, size_t key_len, int value_type, u_char *str_value_buf, @@ -2225,10 +2245,6 @@ ngx_http_lua_ffi_shdict_store(ngx_shm_zone_t *zone, int op, u_char *key, ngx_http_lua_shdict_ctx_t *ctx; ngx_http_lua_shdict_node_t *sd; - if (zone == NULL) { - return NGX_ERROR; - } - dd("exptime: %ld", exptime); ctx = zone->data; @@ -2490,10 +2506,6 @@ ngx_http_lua_ffi_shdict_get(ngx_shm_zone_t *zone, u_char *key, ngx_http_lua_shdict_node_t *sd; ngx_str_t value; - if (zone == NULL) { - return NGX_ERROR; - } - *err = NULL; ctx = zone->data; @@ -2636,10 +2648,6 @@ ngx_http_lua_ffi_shdict_incr(ngx_shm_zone_t *zone, u_char *key, u_char *p; ngx_queue_t *queue, *q; - if (zone == NULL) { - return NGX_ERROR; - } - if (init_ttl > 0) { tp = ngx_timeofday(); } @@ -2915,10 +2923,6 @@ ngx_http_lua_ffi_shdict_get_ttl(ngx_shm_zone_t *zone, u_char *key, ngx_http_lua_shdict_ctx_t *ctx; ngx_http_lua_shdict_node_t *sd; - if (zone == NULL) { - return NGX_ERROR; - } - ctx = zone->data; hash = ngx_crc32_short(key, key_len); @@ -2959,10 +2963,6 @@ ngx_http_lua_ffi_shdict_set_expire(ngx_shm_zone_t *zone, u_char *key, ngx_http_lua_shdict_ctx_t *ctx; ngx_http_lua_shdict_node_t *sd; - if (zone == NULL) { - return NGX_ERROR; - } - if (exptime > 0) { tp = ngx_timeofday(); } diff --git a/debian/modules/http-lua/src/ngx_http_lua_socket_tcp.c b/debian/modules/http-lua/src/ngx_http_lua_socket_tcp.c index efdf427..87461e6 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_socket_tcp.c +++ b/debian/modules/http-lua/src/ngx_http_lua_socket_tcp.c @@ -11,6 +11,7 @@ #include "ngx_http_lua_socket_tcp.h" +#include "ngx_http_lua_input_filters.h" #include "ngx_http_lua_util.h" #include "ngx_http_lua_uthread.h" #include "ngx_http_lua_output.h" @@ -24,6 +25,7 @@ static int ngx_http_lua_socket_tcp_connect(lua_State *L); static int ngx_http_lua_socket_tcp_sslhandshake(lua_State *L); #endif static int ngx_http_lua_socket_tcp_receive(lua_State *L); +static int ngx_http_lua_socket_tcp_receiveany(lua_State *L); static int ngx_http_lua_socket_tcp_send(lua_State *L); static int ngx_http_lua_socket_tcp_close(lua_State *L); static int ngx_http_lua_socket_tcp_setoption(lua_State *L); @@ -69,6 +71,8 @@ static int ngx_http_lua_socket_tcp_conn_retval_handler(ngx_http_request_t *r, ngx_http_lua_socket_tcp_upstream_t *u, lua_State *L); static void ngx_http_lua_socket_dummy_handler(ngx_http_request_t *r, ngx_http_lua_socket_tcp_upstream_t *u); +static int ngx_http_lua_socket_tcp_receive_helper(ngx_http_request_t *r, + ngx_http_lua_socket_tcp_upstream_t *u, lua_State *L); static ngx_int_t ngx_http_lua_socket_tcp_read(ngx_http_request_t *r, ngx_http_lua_socket_tcp_upstream_t *u); static int ngx_http_lua_socket_tcp_receive_retval_handler(ngx_http_request_t *r, @@ -86,6 +90,7 @@ static int ngx_http_lua_socket_write_error_retval_handler(ngx_http_request_t *r, static ngx_int_t ngx_http_lua_socket_read_all(void *data, ssize_t bytes); static ngx_int_t ngx_http_lua_socket_read_until(void *data, ssize_t bytes); static ngx_int_t ngx_http_lua_socket_read_chunk(void *data, ssize_t bytes); +static ngx_int_t ngx_http_lua_socket_read_any(void *data, ssize_t bytes); static int ngx_http_lua_socket_tcp_receiveuntil(lua_State *L); static int ngx_http_lua_socket_receiveuntil_iterator(lua_State *L); static ngx_int_t ngx_http_lua_socket_compile_pattern(u_char *data, size_t len, @@ -95,12 +100,28 @@ static int ngx_http_lua_req_socket(lua_State *L); static void ngx_http_lua_req_socket_rev_handler(ngx_http_request_t *r); static int ngx_http_lua_socket_tcp_getreusedtimes(lua_State *L); static int ngx_http_lua_socket_tcp_setkeepalive(lua_State *L); +static void ngx_http_lua_socket_tcp_create_socket_pool(lua_State *L, + ngx_http_request_t *r, ngx_str_t key, ngx_int_t pool_size, + ngx_int_t backlog, ngx_http_lua_socket_pool_t **spool); static ngx_int_t ngx_http_lua_get_keepalive_peer(ngx_http_request_t *r, - lua_State *L, int key_index, ngx_http_lua_socket_tcp_upstream_t *u); static void ngx_http_lua_socket_keepalive_dummy_handler(ngx_event_t *ev); +static int ngx_http_lua_socket_tcp_connect_helper(lua_State *L, + ngx_http_lua_socket_tcp_upstream_t *u, ngx_http_request_t *r, + ngx_http_lua_ctx_t *ctx, u_char *host_ref, size_t host_len, in_port_t port, + unsigned resuming); +static void ngx_http_lua_socket_tcp_conn_op_timeout_handler( + ngx_event_t *ev); +static int ngx_http_lua_socket_tcp_conn_op_timeout_retval_handler( + ngx_http_request_t *r, ngx_http_lua_socket_tcp_upstream_t *u, lua_State *L); +static void ngx_http_lua_socket_tcp_resume_conn_op( + ngx_http_lua_socket_pool_t *spool); +static void ngx_http_lua_socket_tcp_conn_op_ctx_cleanup(void *data); +static void ngx_http_lua_socket_tcp_conn_op_resume_handler(ngx_event_t *ev); static ngx_int_t ngx_http_lua_socket_keepalive_close_handler(ngx_event_t *ev); static void ngx_http_lua_socket_keepalive_rev_handler(ngx_event_t *ev); +static int ngx_http_lua_socket_tcp_conn_op_resume_retval_handler( + ngx_http_request_t *r, ngx_http_lua_socket_tcp_upstream_t *u, lua_State *L); static int ngx_http_lua_socket_tcp_upstream_destroy(lua_State *L); static int ngx_http_lua_socket_downstream_destroy(lua_State *L); static ngx_int_t ngx_http_lua_socket_push_input_data(ngx_http_request_t *r, @@ -113,11 +134,13 @@ static ngx_int_t ngx_http_lua_socket_add_input_buffer(ngx_http_request_t *r, ngx_http_lua_socket_tcp_upstream_t *u); static ngx_int_t ngx_http_lua_socket_insert_buffer(ngx_http_request_t *r, ngx_http_lua_socket_tcp_upstream_t *u, u_char *pat, size_t prefix); +static ngx_int_t ngx_http_lua_socket_tcp_conn_op_resume(ngx_http_request_t *r); static ngx_int_t ngx_http_lua_socket_tcp_conn_resume(ngx_http_request_t *r); static ngx_int_t ngx_http_lua_socket_tcp_read_resume(ngx_http_request_t *r); static ngx_int_t ngx_http_lua_socket_tcp_write_resume(ngx_http_request_t *r); static ngx_int_t ngx_http_lua_socket_tcp_resume_helper(ngx_http_request_t *r, int socket_op); +static void ngx_http_lua_tcp_queue_conn_op_cleanup(void *data); static void ngx_http_lua_tcp_resolve_cleanup(void *data); static void ngx_http_lua_coctx_cleanup(void *data); static void ngx_http_lua_socket_free_pool(ngx_log_t *log, @@ -150,7 +173,8 @@ enum { enum { SOCKET_OP_CONNECT, SOCKET_OP_READ, - SOCKET_OP_WRITE + SOCKET_OP_WRITE, + SOCKET_OP_RESUME_CONN }; @@ -229,7 +253,8 @@ ngx_http_lua_inject_socket_tcp_api(ngx_log_t *log, lua_State *L) lua_setfield(L, -2, "socket"); /* {{{req socket object metatable */ - lua_pushlightuserdata(L, &ngx_http_lua_req_socket_metatable_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + req_socket_metatable_key)); lua_createtable(L, 0 /* narr */, 5 /* nrec */); lua_pushcfunction(L, ngx_http_lua_socket_tcp_receive); @@ -251,7 +276,8 @@ ngx_http_lua_inject_socket_tcp_api(ngx_log_t *log, lua_State *L) /* }}} */ /* {{{raw req socket object metatable */ - lua_pushlightuserdata(L, &ngx_http_lua_raw_req_socket_metatable_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + raw_req_socket_metatable_key)); lua_createtable(L, 0 /* narr */, 6 /* nrec */); lua_pushcfunction(L, ngx_http_lua_socket_tcp_receive); @@ -276,7 +302,8 @@ ngx_http_lua_inject_socket_tcp_api(ngx_log_t *log, lua_State *L) /* }}} */ /* {{{tcp object metatable */ - lua_pushlightuserdata(L, &ngx_http_lua_tcp_socket_metatable_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + tcp_socket_metatable_key)); lua_createtable(L, 0 /* narr */, 12 /* nrec */); lua_pushcfunction(L, ngx_http_lua_socket_tcp_connect); @@ -292,6 +319,9 @@ ngx_http_lua_inject_socket_tcp_api(ngx_log_t *log, lua_State *L) lua_pushcfunction(L, ngx_http_lua_socket_tcp_receive); lua_setfield(L, -2, "receive"); + lua_pushcfunction(L, ngx_http_lua_socket_tcp_receiveany); + lua_setfield(L, -2, "receiveany"); + lua_pushcfunction(L, ngx_http_lua_socket_tcp_receiveuntil); lua_setfield(L, -2, "receiveuntil"); @@ -322,7 +352,8 @@ ngx_http_lua_inject_socket_tcp_api(ngx_log_t *log, lua_State *L) /* }}} */ /* {{{upstream userdata metatable */ - lua_pushlightuserdata(L, &ngx_http_lua_upstream_udata_metatable_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + upstream_udata_metatable_key)); lua_createtable(L, 0 /* narr */, 1 /* nrec */); /* metatable */ lua_pushcfunction(L, ngx_http_lua_socket_tcp_upstream_destroy); lua_setfield(L, -2, "__gc"); @@ -330,7 +361,8 @@ ngx_http_lua_inject_socket_tcp_api(ngx_log_t *log, lua_State *L) /* }}} */ /* {{{downstream userdata metatable */ - lua_pushlightuserdata(L, &ngx_http_lua_downstream_udata_metatable_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + downstream_udata_metatable_key)); lua_createtable(L, 0 /* narr */, 1 /* nrec */); /* metatable */ lua_pushcfunction(L, ngx_http_lua_socket_downstream_destroy); lua_setfield(L, -2, "__gc"); @@ -338,7 +370,8 @@ ngx_http_lua_inject_socket_tcp_api(ngx_log_t *log, lua_State *L) /* }}} */ /* {{{socket pool userdata metatable */ - lua_pushlightuserdata(L, &ngx_http_lua_pool_udata_metatable_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + pool_udata_metatable_key)); lua_createtable(L, 0, 1); /* metatable */ lua_pushcfunction(L, ngx_http_lua_socket_shutdown_pool); lua_setfield(L, -2, "__gc"); @@ -346,7 +379,8 @@ ngx_http_lua_inject_socket_tcp_api(ngx_log_t *log, lua_State *L) /* }}} */ /* {{{socket compiled pattern userdata metatable */ - lua_pushlightuserdata(L, &ngx_http_lua_pattern_udata_metatable_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + pattern_udata_metatable_key)); lua_createtable(L, 0 /* narr */, 1 /* nrec */); /* metatable */ lua_pushcfunction(L, ngx_http_lua_socket_cleanup_compiled_pattern); lua_setfield(L, -2, "__gc"); @@ -356,7 +390,8 @@ ngx_http_lua_inject_socket_tcp_api(ngx_log_t *log, lua_State *L) #if (NGX_HTTP_SSL) /* {{{ssl session userdata metatable */ - lua_pushlightuserdata(L, &ngx_http_lua_ssl_session_metatable_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + ssl_session_metatable_key)); lua_createtable(L, 0 /* narr */, 1 /* nrec */); /* metatable */ lua_pushcfunction(L, ngx_http_lua_ssl_free_session); lua_setfield(L, -2, "__gc"); @@ -404,7 +439,8 @@ ngx_http_lua_socket_tcp(lua_State *L) | NGX_HTTP_LUA_CONTEXT_SSL_SESS_FETCH); lua_createtable(L, 5 /* narr */, 1 /* nrec */); - lua_pushlightuserdata(L, &ngx_http_lua_tcp_socket_metatable_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + tcp_socket_metatable_key)); lua_rawget(L, LUA_REGISTRYINDEX); lua_setmetatable(L, -2); @@ -414,31 +450,421 @@ ngx_http_lua_socket_tcp(lua_State *L) } +static void +ngx_http_lua_socket_tcp_create_socket_pool(lua_State *L, ngx_http_request_t *r, + ngx_str_t key, ngx_int_t pool_size, ngx_int_t backlog, + ngx_http_lua_socket_pool_t **spool) +{ + u_char *p; + size_t size, key_len; + ngx_int_t i; + ngx_http_lua_socket_pool_t *sp; + ngx_http_lua_socket_pool_item_t *items; + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua tcp socket connection pool size: %i, backlog: %i", + pool_size, backlog); + + key_len = ngx_align(key.len + 1, sizeof(void *)); + + size = sizeof(ngx_http_lua_socket_pool_t) - 1 + key_len + + sizeof(ngx_http_lua_socket_pool_item_t) * pool_size; + + /* before calling this function, the Lua stack is: + * -1 key + * -2 pools + */ + sp = lua_newuserdata(L, size); + if (sp == NULL) { + luaL_error(L, "no memory"); + return; + } + + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + pool_udata_metatable_key)); + lua_rawget(L, LUA_REGISTRYINDEX); + lua_setmetatable(L, -2); + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua tcp socket keepalive create connection pool for key" + " \"%V\"", &key); + + /* a new socket pool with metatable is push to the stack, so now we have: + * -1 sp + * -2 key + * -3 pools + * + * it is time to set pools[key] to sp. + */ + lua_rawset(L, -3); + + /* clean up the stack for consistency's sake */ + lua_pop(L, 1); + + sp->backlog = backlog; + sp->size = pool_size; + sp->connections = 0; + sp->lua_vm = ngx_http_lua_get_lua_vm(r, NULL); + + ngx_queue_init(&sp->cache_connect_op); + ngx_queue_init(&sp->wait_connect_op); + ngx_queue_init(&sp->cache); + ngx_queue_init(&sp->free); + + p = ngx_copy(sp->key, key.data, key.len); + *p++ = '\0'; + + items = (ngx_http_lua_socket_pool_item_t *) (sp->key + key_len); + + dd("items: %p", items); + + ngx_http_lua_assert((void *) items == ngx_align_ptr(items, sizeof(void *))); + + for (i = 0; i < pool_size; i++) { + ngx_queue_insert_head(&sp->free, &items[i].queue); + items[i].socket_pool = sp; + } + + *spool = sp; +} + + +static int +ngx_http_lua_socket_tcp_connect_helper(lua_State *L, + ngx_http_lua_socket_tcp_upstream_t *u, ngx_http_request_t *r, + ngx_http_lua_ctx_t *ctx, u_char *host_ref, size_t host_len, in_port_t port, + unsigned resuming) +{ + int n; + int host_size; + int saved_top; + ngx_int_t rc; + ngx_str_t host; + ngx_str_t *conn_op_host; + ngx_url_t url; + ngx_queue_t *q; + ngx_resolver_ctx_t *rctx, temp; + ngx_http_lua_co_ctx_t *coctx; + ngx_http_core_loc_conf_t *clcf; + ngx_http_lua_socket_pool_t *spool; + ngx_http_lua_socket_tcp_conn_op_ctx_t *conn_op_ctx; + + spool = u->socket_pool; + if (spool != NULL) { + rc = ngx_http_lua_get_keepalive_peer(r, u); + + if (rc == NGX_OK) { + lua_pushinteger(L, 1); + return 1; + } + + /* rc == NGX_DECLINED */ + + spool->connections++; + + /* check if backlog is enabled and + * don't queue resuming connection operation */ + if (spool->backlog >= 0 && !resuming) { + + dd("lua tcp socket %s connections %ld", + spool->key, spool->connections); + + if (spool->connections > spool->size + spool->backlog) { + spool->connections--; + lua_pushnil(L); + lua_pushliteral(L, "too many waiting connect operations"); + return 2; + } + + if (spool->connections > spool->size) { + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, u->peer.log, 0, + "lua tcp socket queue connect operation for " + "connection pool \"%s\", connections: %i", + spool->key, spool->connections); + + host_size = sizeof(u_char) * + (ngx_max(host_len, NGX_INET_ADDRSTRLEN) + 1); + + if (!ngx_queue_empty(&spool->cache_connect_op)) { + q = ngx_queue_last(&spool->cache_connect_op); + ngx_queue_remove(q); + conn_op_ctx = ngx_queue_data( + q, ngx_http_lua_socket_tcp_conn_op_ctx_t, queue); + + conn_op_host = &conn_op_ctx->host; + if (host_len > conn_op_host->len + && host_len > NGX_INET_ADDRSTRLEN) + { + ngx_free(conn_op_host->data); + conn_op_host->data = ngx_alloc(host_size, + ngx_cycle->log); + if (conn_op_host->data == NULL) { + ngx_free(conn_op_ctx); + goto no_memory_and_not_resuming; + } + } + + } else { + conn_op_ctx = ngx_alloc( + sizeof(ngx_http_lua_socket_tcp_conn_op_ctx_t), + ngx_cycle->log); + if (conn_op_ctx == NULL) { + goto no_memory_and_not_resuming; + } + + conn_op_host = &conn_op_ctx->host; + conn_op_host->data = ngx_alloc(host_size, ngx_cycle->log); + if (conn_op_host->data == NULL) { + ngx_free(conn_op_ctx); + goto no_memory_and_not_resuming; + } + } + + conn_op_ctx->cleanup = NULL; + + ngx_memcpy(conn_op_host->data, host_ref, host_len); + conn_op_host->data[host_len] = '\0'; + conn_op_host->len = host_len; + + conn_op_ctx->port = port; + + u->write_co_ctx = ctx->cur_co_ctx; + + conn_op_ctx->u = u; + ctx->cur_co_ctx->cleanup = + ngx_http_lua_tcp_queue_conn_op_cleanup; + ctx->cur_co_ctx->data = conn_op_ctx; + + ngx_memzero(&conn_op_ctx->event, sizeof(ngx_event_t)); + conn_op_ctx->event.handler = + ngx_http_lua_socket_tcp_conn_op_timeout_handler; + conn_op_ctx->event.data = conn_op_ctx; + conn_op_ctx->event.log = ngx_cycle->log; + + ngx_add_timer(&conn_op_ctx->event, u->connect_timeout); + + ngx_queue_insert_tail(&spool->wait_connect_op, + &conn_op_ctx->queue); + + ngx_log_debug3(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "lua tcp socket queued connect operation for " + "%d(ms), u: %p, ctx: %p", + u->connect_timeout, conn_op_ctx->u, conn_op_ctx); + + return lua_yield(L, 0); + } + } + + } /* end spool != NULL */ + + host.data = ngx_palloc(r->pool, host_len + 1); + if (host.data == NULL) { + return luaL_error(L, "no memory"); + } + + host.len = host_len; + + ngx_memcpy(host.data, host_ref, host_len); + host.data[host_len] = '\0'; + + ngx_memzero(&url, sizeof(ngx_url_t)); + url.url = host; + url.default_port = port; + url.no_resolve = 1; + + coctx = ctx->cur_co_ctx; + + if (ngx_parse_url(r->pool, &url) != NGX_OK) { + lua_pushnil(L); + + if (url.err) { + lua_pushfstring(L, "failed to parse host name \"%s\": %s", + url.url.data, url.err); + + } else { + lua_pushfstring(L, "failed to parse host name \"%s\"", + url.url.data); + } + + goto failed; + } + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua tcp socket connect timeout: %M", u->connect_timeout); + + u->resolved = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_resolved_t)); + if (u->resolved == NULL) { + if (resuming) { + lua_pushnil(L); + lua_pushliteral(L, "no memory"); + goto failed; + } + + goto no_memory_and_not_resuming; + } + + if (url.addrs && url.addrs[0].sockaddr) { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua tcp socket network address given directly"); + + u->resolved->sockaddr = url.addrs[0].sockaddr; + u->resolved->socklen = url.addrs[0].socklen; + u->resolved->naddrs = 1; + u->resolved->host = url.addrs[0].name; + + } else { + u->resolved->host = host; + u->resolved->port = url.default_port; + } + + if (u->resolved->sockaddr) { + rc = ngx_http_lua_socket_resolve_retval_handler(r, u, L); + if (rc == NGX_AGAIN && !resuming) { + return lua_yield(L, 0); + } + + if (rc > 1) { + goto failed; + } + + return rc; + } + + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + + temp.name = host; + rctx = ngx_resolve_start(clcf->resolver, &temp); + if (rctx == NULL) { + u->ft_type |= NGX_HTTP_LUA_SOCKET_FT_RESOLVER; + lua_pushnil(L); + lua_pushliteral(L, "failed to start the resolver"); + goto failed; + } + + if (rctx == NGX_NO_RESOLVER) { + u->ft_type |= NGX_HTTP_LUA_SOCKET_FT_RESOLVER; + lua_pushnil(L); + lua_pushfstring(L, "no resolver defined to resolve \"%s\"", host.data); + goto failed; + } + + rctx->name = host; +#if !defined(nginx_version) || nginx_version < 1005008 + rctx->type = NGX_RESOLVE_A; +#endif + rctx->handler = ngx_http_lua_socket_resolve_handler; + rctx->data = u; + rctx->timeout = clcf->resolver_timeout; + + u->resolved->ctx = rctx; + u->write_co_ctx = ctx->cur_co_ctx; + + ngx_http_lua_cleanup_pending_operation(coctx); + coctx->cleanup = ngx_http_lua_tcp_resolve_cleanup; + coctx->data = u; + + saved_top = lua_gettop(L); + + if (ngx_resolve_name(rctx) != NGX_OK) { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua tcp socket fail to run resolver immediately"); + + u->ft_type |= NGX_HTTP_LUA_SOCKET_FT_RESOLVER; + + coctx->cleanup = NULL; + coctx->data = NULL; + + u->resolved->ctx = NULL; + lua_pushnil(L); + lua_pushfstring(L, "%s could not be resolved", host.data); + goto failed; + } + + if (u->conn_waiting) { + dd("resolved and already connecting"); + + if (resuming) { + return NGX_AGAIN; + } + + return lua_yield(L, 0); + } + + n = lua_gettop(L) - saved_top; + if (n) { + dd("errors occurred during resolving or connecting" + "or already connected"); + + if (n > 1) { + goto failed; + } + + return n; + } + + /* still resolving */ + + u->conn_waiting = 1; + u->write_prepare_retvals = ngx_http_lua_socket_resolve_retval_handler; + + dd("setting data to %p", u); + + if (ctx->entered_content_phase) { + r->write_event_handler = ngx_http_lua_content_wev_handler; + + } else { + r->write_event_handler = ngx_http_core_run_phases; + } + + if (resuming) { + return NGX_AGAIN; + } + + return lua_yield(L, 0); + +failed: + + if (spool != NULL) { + spool->connections--; + ngx_http_lua_socket_tcp_resume_conn_op(spool); + } + + return 2; + +no_memory_and_not_resuming: + + if (spool != NULL) { + spool->connections--; + ngx_http_lua_socket_tcp_resume_conn_op(spool); + } + + return luaL_error(L, "no memory"); +} + + static int ngx_http_lua_socket_tcp_connect(lua_State *L) { ngx_http_request_t *r; ngx_http_lua_ctx_t *ctx; - ngx_str_t host; int port; - ngx_resolver_ctx_t *rctx, temp; - ngx_http_core_loc_conf_t *clcf; - int saved_top; int n; u_char *p; size_t len; - ngx_url_t url; - ngx_int_t rc; ngx_http_lua_loc_conf_t *llcf; ngx_peer_connection_t *pc; int connect_timeout, send_timeout, read_timeout; unsigned custom_pool; int key_index; + ngx_int_t backlog; + ngx_int_t pool_size; + ngx_str_t key; const char *msg; - ngx_http_lua_co_ctx_t *coctx; ngx_http_lua_socket_tcp_upstream_t *u; + ngx_http_lua_socket_pool_t *spool; + n = lua_gettop(L); if (n != 2 && n != 3 && n != 4) { return luaL_error(L, "ngx.socket connect: expecting 2, 3, or 4 " @@ -466,13 +892,54 @@ ngx_http_lua_socket_tcp_connect(lua_State *L) p = (u_char *) luaL_checklstring(L, 2, &len); + backlog = -1; key_index = 2; + pool_size = 0; custom_pool = 0; + llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); if (lua_type(L, n) == LUA_TTABLE) { /* found the last optional option table */ + lua_getfield(L, n, "pool_size"); + + if (lua_isnumber(L, -1)) { + pool_size = (ngx_int_t) lua_tointeger(L, -1); + + if (pool_size <= 0) { + msg = lua_pushfstring(L, "bad \"pool_size\" option value: %i", + pool_size); + return luaL_argerror(L, n, msg); + } + + } else if (!lua_isnil(L, -1)) { + msg = lua_pushfstring(L, "bad \"pool_size\" option type: %s", + lua_typename(L, lua_type(L, -1))); + return luaL_argerror(L, n, msg); + } + + lua_pop(L, 1); + + lua_getfield(L, n, "backlog"); + + if (lua_isnumber(L, -1)) { + backlog = (ngx_int_t) lua_tointeger(L, -1); + + if (backlog < 0) { + msg = lua_pushfstring(L, "bad \"backlog\" option value: %i", + backlog); + return luaL_argerror(L, n, msg); + } + + /* use default value for pool size if only backlog specified */ + if (pool_size == 0) { + pool_size = llcf->pool_size; + } + } + + lua_pop(L, 1); + lua_getfield(L, n, "pool"); switch (lua_type(L, -1)) { @@ -572,7 +1039,8 @@ ngx_http_lua_socket_tcp_connect(lua_State *L) } #if 1 - lua_pushlightuserdata(L, &ngx_http_lua_upstream_udata_metatable_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + upstream_udata_metatable_key)); lua_rawget(L, LUA_REGISTRYINDEX); lua_setmetatable(L, -2); #endif @@ -582,12 +1050,8 @@ ngx_http_lua_socket_tcp_connect(lua_State *L) ngx_memzero(u, sizeof(ngx_http_lua_socket_tcp_upstream_t)); - coctx = ctx->cur_co_ctx; - u->request = r; /* set the controlling request */ - llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); - u->conf = llcf; pc = &u->peer; @@ -628,163 +1092,28 @@ ngx_http_lua_socket_tcp_connect(lua_State *L) u->read_timeout = u->conf->read_timeout; } - rc = ngx_http_lua_get_keepalive_peer(r, L, key_index, u); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask(socket_pool_key)); + lua_rawget(L, LUA_REGISTRYINDEX); /* table */ + lua_pushvalue(L, key_index); /* key */ - if (rc == NGX_OK) { - lua_pushinteger(L, 1); - return 1; + lua_rawget(L, -2); + spool = lua_touserdata(L, -1); + lua_pop(L, 1); + + if (spool != NULL) { + u->socket_pool = spool; + + } else if (pool_size > 0) { + lua_pushvalue(L, key_index); + key.data = (u_char *) lua_tolstring(L, -1, &key.len); + + ngx_http_lua_socket_tcp_create_socket_pool(L, r, key, pool_size, + backlog, &spool); + u->socket_pool = spool; } - if (rc == NGX_ERROR) { - lua_pushnil(L); - lua_pushliteral(L, "error in get keepalive peer"); - return 2; - } - - /* rc == NGX_DECLINED */ - - /* TODO: we should avoid this in-pool allocation */ - - host.data = ngx_palloc(r->pool, len + 1); - if (host.data == NULL) { - return luaL_error(L, "no memory"); - } - - host.len = len; - - ngx_memcpy(host.data, p, len); - host.data[len] = '\0'; - - ngx_memzero(&url, sizeof(ngx_url_t)); - - url.url.len = host.len; - url.url.data = host.data; - url.default_port = (in_port_t) port; - url.no_resolve = 1; - - if (ngx_parse_url(r->pool, &url) != NGX_OK) { - lua_pushnil(L); - - if (url.err) { - lua_pushfstring(L, "failed to parse host name \"%s\": %s", - host.data, url.err); - - } else { - lua_pushfstring(L, "failed to parse host name \"%s\"", host.data); - } - - return 2; - } - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua tcp socket connect timeout: %M", u->connect_timeout); - - u->resolved = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_resolved_t)); - if (u->resolved == NULL) { - return luaL_error(L, "no memory"); - } - - if (url.addrs && url.addrs[0].sockaddr) { - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua tcp socket network address given directly"); - - u->resolved->sockaddr = url.addrs[0].sockaddr; - u->resolved->socklen = url.addrs[0].socklen; - u->resolved->naddrs = 1; - u->resolved->host = url.addrs[0].name; - - } else { - u->resolved->host = host; - u->resolved->port = (in_port_t) port; - } - - if (u->resolved->sockaddr) { - rc = ngx_http_lua_socket_resolve_retval_handler(r, u, L); - if (rc == NGX_AGAIN) { - return lua_yield(L, 0); - } - - return rc; - } - - clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); - - temp.name = host; - rctx = ngx_resolve_start(clcf->resolver, &temp); - if (rctx == NULL) { - u->ft_type |= NGX_HTTP_LUA_SOCKET_FT_RESOLVER; - lua_pushnil(L); - lua_pushliteral(L, "failed to start the resolver"); - return 2; - } - - if (rctx == NGX_NO_RESOLVER) { - u->ft_type |= NGX_HTTP_LUA_SOCKET_FT_RESOLVER; - lua_pushnil(L); - lua_pushfstring(L, "no resolver defined to resolve \"%s\"", host.data); - return 2; - } - - rctx->name = host; -#if !defined(nginx_version) || nginx_version < 1005008 - rctx->type = NGX_RESOLVE_A; -#endif - rctx->handler = ngx_http_lua_socket_resolve_handler; - rctx->data = u; - rctx->timeout = clcf->resolver_timeout; - - u->resolved->ctx = rctx; - u->write_co_ctx = ctx->cur_co_ctx; - - ngx_http_lua_cleanup_pending_operation(coctx); - coctx->cleanup = ngx_http_lua_tcp_resolve_cleanup; - coctx->data = u; - - saved_top = lua_gettop(L); - - if (ngx_resolve_name(rctx) != NGX_OK) { - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua tcp socket fail to run resolver immediately"); - - u->ft_type |= NGX_HTTP_LUA_SOCKET_FT_RESOLVER; - - coctx->cleanup = NULL; - coctx->data = NULL; - - u->resolved->ctx = NULL; - lua_pushnil(L); - lua_pushfstring(L, "%s could not be resolved", host.data); - - return 2; - } - - if (u->conn_waiting) { - dd("resolved and already connecting"); - return lua_yield(L, 0); - } - - n = lua_gettop(L) - saved_top; - if (n) { - dd("errors occurred during resolving or connecting" - "or already connected"); - return n; - } - - /* still resolving */ - - u->conn_waiting = 1; - u->write_prepare_retvals = ngx_http_lua_socket_resolve_retval_handler; - - dd("setting data to %p", u); - - if (ctx->entered_content_phase) { - r->write_event_handler = ngx_http_lua_content_wev_handler; - - } else { - r->write_event_handler = ngx_http_core_run_phases; - } - - return lua_yield(L, 0); + return ngx_http_lua_socket_tcp_connect_helper(L, u, r, ctx, p, + len, port, 0); } @@ -1638,7 +1967,8 @@ ngx_http_lua_ssl_handshake_retval_handler(ngx_http_request_t *r, "lua ssl save session: %p", ssl_session); /* set up the __gc metamethod */ - lua_pushlightuserdata(L, &ngx_http_lua_ssl_session_metatable_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + ssl_session_metatable_key)); lua_rawget(L, LUA_REGISTRYINDEX); lua_setmetatable(L, -2); } @@ -1755,20 +2085,173 @@ ngx_http_lua_socket_tcp_conn_retval_handler(ngx_http_request_t *r, } +static int +ngx_http_lua_socket_tcp_receive_helper(ngx_http_request_t *r, + ngx_http_lua_socket_tcp_upstream_t *u, lua_State *L) +{ + ngx_int_t rc; + ngx_http_lua_ctx_t *ctx; + ngx_http_lua_co_ctx_t *coctx; + + u->input_filter_ctx = u; + + ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + + if (u->bufs_in == NULL) { + u->bufs_in = + ngx_http_lua_chain_get_free_buf(r->connection->log, r->pool, + &ctx->free_recv_bufs, + u->conf->buffer_size); + + if (u->bufs_in == NULL) { + return luaL_error(L, "no memory"); + } + + u->buf_in = u->bufs_in; + u->buffer = *u->buf_in->buf; + } + + dd("tcp receive: buf_in: %p, bufs_in: %p", u->buf_in, u->bufs_in); + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua tcp socket read timeout: %M", u->read_timeout); + + if (u->raw_downstream || u->body_downstream) { + r->read_event_handler = ngx_http_lua_req_socket_rev_handler; + } + + u->read_waiting = 0; + u->read_co_ctx = NULL; + + rc = ngx_http_lua_socket_tcp_read(r, u); + + if (rc == NGX_ERROR) { + dd("read failed: %d", (int) u->ft_type); + rc = ngx_http_lua_socket_tcp_receive_retval_handler(r, u, L); + dd("tcp receive retval returned: %d", (int) rc); + return rc; + } + + if (rc == NGX_OK) { + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua tcp socket receive done in a single run"); + + return ngx_http_lua_socket_tcp_receive_retval_handler(r, u, L); + } + + /* rc == NGX_AGAIN */ + + u->read_event_handler = ngx_http_lua_socket_read_handler; + + coctx = ctx->cur_co_ctx; + + ngx_http_lua_cleanup_pending_operation(coctx); + coctx->cleanup = ngx_http_lua_coctx_cleanup; + coctx->data = u; + + if (ctx->entered_content_phase) { + r->write_event_handler = ngx_http_lua_content_wev_handler; + + } else { + r->write_event_handler = ngx_http_core_run_phases; + } + + u->read_co_ctx = coctx; + u->read_waiting = 1; + u->read_prepare_retvals = ngx_http_lua_socket_tcp_receive_retval_handler; + + dd("setting data to %p, coctx:%p", u, coctx); + + if (u->raw_downstream || u->body_downstream) { + ctx->downstream = u; + } + + return lua_yield(L, 0); +} + + +static int +ngx_http_lua_socket_tcp_receiveany(lua_State *L) +{ + int n; + lua_Integer bytes; + ngx_http_request_t *r; + ngx_http_lua_loc_conf_t *llcf; + ngx_http_lua_socket_tcp_upstream_t *u; + + n = lua_gettop(L); + if (n != 2) { + return luaL_error(L, "expecting 2 arguments " + "(including the object), but got %d", n); + } + + r = ngx_http_lua_get_req(L); + if (r == NULL) { + return luaL_error(L, "no request found"); + } + + luaL_checktype(L, 1, LUA_TTABLE); + + lua_rawgeti(L, 1, SOCKET_CTX_INDEX); + u = lua_touserdata(L, -1); + + if (u == NULL || u->peer.connection == NULL || u->read_closed) { + + llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); + + if (llcf->log_socket_errors) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "attempt to receive data on a closed socket: u:%p, " + "c:%p, ft:%d eof:%d", + u, u ? u->peer.connection : NULL, + u ? (int) u->ft_type : 0, u ? (int) u->eof : 0); + } + + lua_pushnil(L); + lua_pushliteral(L, "closed"); + return 2; + } + + if (u->request != r) { + return luaL_error(L, "bad request"); + } + + ngx_http_lua_socket_check_busy_connecting(r, u, L); + ngx_http_lua_socket_check_busy_reading(r, u, L); + + if (!lua_isnumber(L, 2)) { + return luaL_argerror(L, 2, "bad max argument"); + } + + bytes = lua_tointeger(L, 2); + if (bytes <= 0) { + return luaL_argerror(L, 2, "bad max argument"); + } + + u->input_filter = ngx_http_lua_socket_read_any; + u->rest = (size_t) bytes; + u->length = u->rest; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua tcp socket calling receiveany() method to read at " + "most %uz bytes", u->rest); + + return ngx_http_lua_socket_tcp_receive_helper(r, u, L); +} + + static int ngx_http_lua_socket_tcp_receive(lua_State *L) { ngx_http_request_t *r; ngx_http_lua_socket_tcp_upstream_t *u; - ngx_int_t rc; - ngx_http_lua_ctx_t *ctx; int n; ngx_str_t pat; lua_Integer bytes; char *p; int typ; ngx_http_lua_loc_conf_t *llcf; - ngx_http_lua_co_ctx_t *coctx; n = lua_gettop(L); if (n != 1 && n != 2) { @@ -1883,119 +2366,27 @@ ngx_http_lua_socket_tcp_receive(lua_State *L) u->rest = 0; } - u->input_filter_ctx = u; - - ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); - - if (u->bufs_in == NULL) { - u->bufs_in = - ngx_http_lua_chain_get_free_buf(r->connection->log, r->pool, - &ctx->free_recv_bufs, - u->conf->buffer_size); - - if (u->bufs_in == NULL) { - return luaL_error(L, "no memory"); - } - - u->buf_in = u->bufs_in; - u->buffer = *u->buf_in->buf; - } - - dd("tcp receive: buf_in: %p, bufs_in: %p", u->buf_in, u->bufs_in); - - if (u->raw_downstream || u->body_downstream) { - r->read_event_handler = ngx_http_lua_req_socket_rev_handler; - } - - u->read_waiting = 0; - u->read_co_ctx = NULL; - - rc = ngx_http_lua_socket_tcp_read(r, u); - - if (rc == NGX_ERROR) { - dd("read failed: %d", (int) u->ft_type); - rc = ngx_http_lua_socket_tcp_receive_retval_handler(r, u, L); - dd("tcp receive retval returned: %d", (int) rc); - return rc; - } - - if (rc == NGX_OK) { - - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua tcp socket receive done in a single run"); - - return ngx_http_lua_socket_tcp_receive_retval_handler(r, u, L); - } - - /* rc == NGX_AGAIN */ - - u->read_event_handler = ngx_http_lua_socket_read_handler; - - coctx = ctx->cur_co_ctx; - - ngx_http_lua_cleanup_pending_operation(coctx); - coctx->cleanup = ngx_http_lua_coctx_cleanup; - coctx->data = u; - - if (ctx->entered_content_phase) { - r->write_event_handler = ngx_http_lua_content_wev_handler; - - } else { - r->write_event_handler = ngx_http_core_run_phases; - } - - u->read_co_ctx = coctx; - u->read_waiting = 1; - u->read_prepare_retvals = ngx_http_lua_socket_tcp_receive_retval_handler; - - dd("setting data to %p, coctx:%p", u, coctx); - - if (u->raw_downstream || u->body_downstream) { - ctx->downstream = u; - } - - return lua_yield(L, 0); + return ngx_http_lua_socket_tcp_receive_helper(r, u, L); } static ngx_int_t ngx_http_lua_socket_read_chunk(void *data, ssize_t bytes) { + ngx_int_t rc; ngx_http_lua_socket_tcp_upstream_t *u = data; - ngx_buf_t *b; -#if (NGX_DEBUG) - ngx_http_request_t *r; - - r = u->request; -#endif - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, u->request->connection->log, 0, "lua tcp socket read chunk %z", bytes); - if (bytes == 0) { + rc = ngx_http_lua_read_bytes(&u->buffer, u->buf_in, &u->rest, + bytes, u->request->connection->log); + if (rc == NGX_ERROR) { u->ft_type |= NGX_HTTP_LUA_SOCKET_FT_CLOSED; return NGX_ERROR; } - b = &u->buffer; - - if (bytes >= (ssize_t) u->rest) { - - u->buf_in->buf->last += u->rest; - b->pos += u->rest; - u->rest = 0; - - return NGX_OK; - } - - /* bytes < u->rest */ - - u->buf_in->buf->last += bytes; - b->pos += bytes; - u->rest -= bytes; - - return NGX_AGAIN; + return rc; } @@ -2004,26 +2395,10 @@ ngx_http_lua_socket_read_all(void *data, ssize_t bytes) { ngx_http_lua_socket_tcp_upstream_t *u = data; - ngx_buf_t *b; -#if (NGX_DEBUG) - ngx_http_request_t *r; - - r = u->request; -#endif - - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, u->request->connection->log, 0, "lua tcp socket read all"); - - if (bytes == 0) { - return NGX_OK; - } - - b = &u->buffer; - - u->buf_in->buf->last += bytes; - b->pos += bytes; - - return NGX_AGAIN; + return ngx_http_lua_read_all(&u->buffer, u->buf_in, bytes, + u->request->connection->log); } @@ -2032,72 +2407,40 @@ ngx_http_lua_socket_read_line(void *data, ssize_t bytes) { ngx_http_lua_socket_tcp_upstream_t *u = data; - ngx_buf_t *b; - u_char *dst; - u_char c; -#if (NGX_DEBUG) - u_char *begin; -#endif + ngx_int_t rc; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, u->request->connection->log, 0, "lua tcp socket read line"); - if (bytes == 0) { + rc = ngx_http_lua_read_line(&u->buffer, u->buf_in, bytes, + u->request->connection->log); + if (rc == NGX_ERROR) { u->ft_type |= NGX_HTTP_LUA_SOCKET_FT_CLOSED; return NGX_ERROR; } - b = &u->buffer; + return rc; +} -#if (NGX_DEBUG) - begin = b->pos; -#endif - dd("already read: %p: %.*s", u->buf_in, - (int) (u->buf_in->buf->last - u->buf_in->buf->pos), - u->buf_in->buf->pos); +static ngx_int_t +ngx_http_lua_socket_read_any(void *data, ssize_t bytes) +{ + ngx_http_lua_socket_tcp_upstream_t *u = data; - dd("data read: %.*s", (int) bytes, b->pos); + ngx_int_t rc; - dst = u->buf_in->buf->last; + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, u->request->connection->log, 0, + "lua tcp socket read any"); - while (bytes--) { - - c = *b->pos++; - - switch (c) { - case '\n': - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, u->request->connection->log, 0, - "lua tcp socket read the final line part: \"%*s\"", - b->pos - 1 - begin, begin); - - u->buf_in->buf->last = dst; - - dd("read a line: %p: %.*s", u->buf_in, - (int) (u->buf_in->buf->last - u->buf_in->buf->pos), - u->buf_in->buf->pos); - - return NGX_OK; - - case '\r': - /* ignore it */ - break; - - default: - *dst++ = c; - break; - } + rc = ngx_http_lua_read_any(&u->buffer, u->buf_in, &u->rest, bytes, + u->request->connection->log); + if (rc == NGX_ERROR) { + u->ft_type |= NGX_HTTP_LUA_SOCKET_FT_CLOSED; + return NGX_ERROR; } -#if (NGX_DEBUG) - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, u->request->connection->log, 0, - "lua tcp socket read partial line data: %*s", - dst - begin, begin); -#endif - - u->buf_in->buf->last = dst; - - return NGX_AGAIN; + return rc; } @@ -3539,6 +3882,267 @@ ngx_http_lua_socket_tcp_finalize_write_part(ngx_http_request_t *r, } +static void +ngx_http_lua_socket_tcp_conn_op_timeout_handler(ngx_event_t *ev) +{ + ngx_http_lua_socket_tcp_upstream_t *u; + ngx_http_lua_ctx_t *ctx; + ngx_connection_t *c; + ngx_http_request_t *r; + ngx_http_lua_co_ctx_t *coctx; + ngx_http_lua_loc_conf_t *llcf; + ngx_http_lua_socket_tcp_conn_op_ctx_t *conn_op_ctx; + + conn_op_ctx = ev->data; + ngx_queue_remove(&conn_op_ctx->queue); + + u = conn_op_ctx->u; + r = u->request; + + coctx = u->write_co_ctx; + coctx->cleanup = NULL; + /* note that we store conn_op_ctx in coctx->data instead of u */ + coctx->data = conn_op_ctx; + u->write_co_ctx = NULL; + + llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); + + if (llcf->log_socket_errors) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "lua tcp socket queued connect timed out," + " when trying to connect to %V:%ud", + &conn_op_ctx->host, conn_op_ctx->port); + } + + ngx_queue_insert_head(&u->socket_pool->cache_connect_op, + &conn_op_ctx->queue); + u->socket_pool->connections--; + + ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + if (ctx == NULL) { + return; + } + + ctx->cur_co_ctx = coctx; + + ngx_http_lua_assert(coctx && (!ngx_http_lua_is_thread(ctx) + || coctx->co_ref >= 0)); + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua tcp socket waking up the current request"); + + u->write_prepare_retvals = + ngx_http_lua_socket_tcp_conn_op_timeout_retval_handler; + + c = r->connection; + + if (ctx->entered_content_phase) { + (void) ngx_http_lua_socket_tcp_conn_op_resume(r); + + } else { + ctx->resume_handler = ngx_http_lua_socket_tcp_conn_op_resume; + ngx_http_core_run_phases(r); + } + + ngx_http_run_posted_requests(c); +} + + +static int +ngx_http_lua_socket_tcp_conn_op_timeout_retval_handler(ngx_http_request_t *r, + ngx_http_lua_socket_tcp_upstream_t *u, lua_State *L) +{ + lua_pushnil(L); + lua_pushliteral(L, "timeout"); + return 2; +} + + +static void +ngx_http_lua_socket_tcp_resume_conn_op(ngx_http_lua_socket_pool_t *spool) +{ + ngx_queue_t *q; + ngx_http_lua_socket_tcp_conn_op_ctx_t *conn_op_ctx; + +#if (NGX_DEBUG) + ngx_http_lua_assert(spool->connections >= 0); + +#else + if (spool->connections < 0) { + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, + "lua tcp socket connections count mismatched for " + "connection pool \"%s\", connections: %i, size: %i", + spool->key, spool->connections, spool->size); + spool->connections = 0; + } +#endif + + /* we manually destroy wait_connect_op before triggering connect + * operation resumption, so that there is no resumption happens when Nginx + * is exiting. + */ + if (ngx_queue_empty(&spool->wait_connect_op)) { + return; + } + + q = ngx_queue_head(&spool->wait_connect_op); + conn_op_ctx = ngx_queue_data(q, ngx_http_lua_socket_tcp_conn_op_ctx_t, + queue); + ngx_log_debug4(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "lua tcp socket post connect operation resumption " + "u: %p, ctx: %p for connection pool \"%s\", " + "connections: %i", + conn_op_ctx->u, conn_op_ctx, spool->key, spool->connections); + + if (conn_op_ctx->event.timer_set) { + ngx_del_timer(&conn_op_ctx->event); + } + + conn_op_ctx->event.handler = + ngx_http_lua_socket_tcp_conn_op_resume_handler; + + ngx_post_event((&conn_op_ctx->event), &ngx_posted_events); +} + + +static void +ngx_http_lua_socket_tcp_conn_op_ctx_cleanup(void *data) +{ + ngx_http_lua_socket_tcp_upstream_t *u; + ngx_http_lua_socket_tcp_conn_op_ctx_t *conn_op_ctx = data; + + u = conn_op_ctx->u; + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, u->request->connection->log, 0, + "cleanup lua tcp socket conn_op_ctx: \"%V\"", + &u->request->uri); + + ngx_queue_insert_head(&u->socket_pool->cache_connect_op, + &conn_op_ctx->queue); +} + + +static void +ngx_http_lua_socket_tcp_conn_op_resume_handler(ngx_event_t *ev) +{ + ngx_queue_t *q; + ngx_connection_t *c; + ngx_http_lua_ctx_t *ctx; + ngx_http_request_t *r; + ngx_http_cleanup_t *cln; + ngx_http_lua_co_ctx_t *coctx; + ngx_http_lua_socket_pool_t *spool; + ngx_http_lua_socket_tcp_upstream_t *u; + ngx_http_lua_socket_tcp_conn_op_ctx_t *conn_op_ctx; + + conn_op_ctx = ev->data; + u = conn_op_ctx->u; + r = u->request; + spool = u->socket_pool; + + if (ngx_queue_empty(&spool->wait_connect_op)) { +#if (NGX_DEBUG) + ngx_http_lua_assert(!(spool->backlog >= 0 + && spool->connections > spool->size)); + +#else + if (spool->backlog >= 0 && spool->connections > spool->size) { + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, + "lua tcp socket connections count mismatched for " + "connection pool \"%s\", connections: %i, size: %i", + spool->key, spool->connections, spool->size); + spool->connections = spool->size; + } +#endif + + return; + } + + q = ngx_queue_head(&spool->wait_connect_op); + ngx_queue_remove(q); + + coctx = u->write_co_ctx; + coctx->cleanup = NULL; + /* note that we store conn_op_ctx in coctx->data instead of u */ + coctx->data = conn_op_ctx; + /* clear ngx_http_lua_tcp_queue_conn_op_cleanup */ + u->write_co_ctx = NULL; + + ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + if (ctx == NULL) { + ngx_queue_insert_head(&spool->cache_connect_op, + &conn_op_ctx->queue); + return; + } + + ctx->cur_co_ctx = coctx; + + ngx_http_lua_assert(coctx && (!ngx_http_lua_is_thread(ctx) + || coctx->co_ref >= 0)); + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua tcp socket waking up the current request"); + + u->write_prepare_retvals = + ngx_http_lua_socket_tcp_conn_op_resume_retval_handler; + + c = r->connection; + + if (ctx->entered_content_phase) { + (void) ngx_http_lua_socket_tcp_conn_op_resume(r); + + } else { + cln = ngx_http_lua_cleanup_add(r, 0); + if (cln != NULL) { + cln->handler = ngx_http_lua_socket_tcp_conn_op_ctx_cleanup; + cln->data = conn_op_ctx; + conn_op_ctx->cleanup = &cln->handler; + } + + ctx->resume_handler = ngx_http_lua_socket_tcp_conn_op_resume; + ngx_http_core_run_phases(r); + } + + ngx_http_run_posted_requests(c); +} + + +static int +ngx_http_lua_socket_tcp_conn_op_resume_retval_handler(ngx_http_request_t *r, + ngx_http_lua_socket_tcp_upstream_t *u, lua_State *L) +{ + int nret; + ngx_http_lua_ctx_t *ctx; + ngx_http_lua_co_ctx_t *coctx; + ngx_http_lua_socket_tcp_conn_op_ctx_t *conn_op_ctx; + + ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + if (ctx == NULL) { + return NGX_ERROR; + } + + coctx = ctx->cur_co_ctx; + dd("coctx: %p", coctx); + conn_op_ctx = coctx->data; + if (conn_op_ctx->cleanup != NULL) { + *conn_op_ctx->cleanup = NULL; + ngx_http_lua_cleanup_free(r, conn_op_ctx->cleanup); + conn_op_ctx->cleanup = NULL; + } + + /* decrease pending connect operation counter */ + u->socket_pool->connections--; + + nret = ngx_http_lua_socket_tcp_connect_helper(L, u, r, ctx, + conn_op_ctx->host.data, + conn_op_ctx->host.len, + conn_op_ctx->port, 1); + ngx_queue_insert_head(&u->socket_pool->cache_connect_op, + &conn_op_ctx->queue); + + return nret; +} + + static void ngx_http_lua_socket_tcp_finalize(ngx_http_request_t *r, ngx_http_lua_socket_tcp_upstream_t *u) @@ -3589,21 +4193,21 @@ ngx_http_lua_socket_tcp_finalize(ngx_http_request_t *r, ngx_http_lua_socket_tcp_close_connection(c); u->peer.connection = NULL; - - if (!u->reused) { - return; - } + u->conn_closed = 1; spool = u->socket_pool; if (spool == NULL) { return; } - spool->active_connections--; + spool->connections--; - if (spool->active_connections == 0) { + if (spool->connections == 0) { ngx_http_lua_socket_free_pool(r->connection->log, spool); + return; } + + ngx_http_lua_socket_tcp_resume_conn_op(spool); } } @@ -3775,7 +4379,8 @@ ngx_http_lua_socket_tcp_receiveuntil(lua_State *L) return luaL_error(L, "no memory"); } - lua_pushlightuserdata(L, &ngx_http_lua_pattern_udata_metatable_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + pattern_udata_metatable_key)); lua_rawget(L, LUA_REGISTRYINDEX); lua_setmetatable(L, -2); @@ -4430,10 +5035,12 @@ ngx_http_lua_req_socket(lua_State *L) lua_createtable(L, 2 /* narr */, 3 /* nrec */); /* the object */ if (raw) { - lua_pushlightuserdata(L, &ngx_http_lua_raw_req_socket_metatable_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + raw_req_socket_metatable_key)); } else { - lua_pushlightuserdata(L, &ngx_http_lua_req_socket_metatable_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + req_socket_metatable_key)); } lua_rawget(L, LUA_REGISTRYINDEX); @@ -4445,7 +5052,8 @@ ngx_http_lua_req_socket(lua_State *L) } #if 1 - lua_pushlightuserdata(L, &ngx_http_lua_downstream_udata_metatable_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + downstream_udata_metatable_key)); lua_rawget(L, LUA_REGISTRYINDEX); lua_setmetatable(L, -2); #endif @@ -4572,20 +5180,18 @@ ngx_http_lua_socket_tcp_setkeepalive(lua_State *L) ngx_http_lua_socket_tcp_upstream_t *u; ngx_connection_t *c; ngx_http_lua_socket_pool_t *spool; - size_t size, key_len; ngx_str_t key; - ngx_uint_t i; ngx_queue_t *q; ngx_peer_connection_t *pc; - u_char *p; ngx_http_request_t *r; ngx_msec_t timeout; - ngx_uint_t pool_size; + ngx_int_t pool_size; int n; ngx_int_t rc; ngx_buf_t *b; + const char *msg; - ngx_http_lua_socket_pool_item_t *items, *item; + ngx_http_lua_socket_pool_item_t *item; n = lua_gettop(L); @@ -4596,17 +5202,6 @@ ngx_http_lua_socket_tcp_setkeepalive(lua_State *L) luaL_checktype(L, 1, LUA_TTABLE); - lua_pushlightuserdata(L, &ngx_http_lua_socket_pool_key); - lua_rawget(L, LUA_REGISTRYINDEX); - - lua_rawgeti(L, 1, SOCKET_KEY_INDEX); - key.data = (u_char *) lua_tolstring(L, -1, &key.len); - if (key.data == NULL) { - lua_pushnil(L); - lua_pushliteral(L, "key not found"); - return 2; - } - lua_rawgeti(L, 1, SOCKET_CTX_INDEX); u = lua_touserdata(L, -1); lua_pop(L, 1); @@ -4617,7 +5212,7 @@ ngx_http_lua_socket_tcp_setkeepalive(lua_State *L) return 2; } - /* stack: obj cache key */ + /* stack: obj timeout? size? */ pc = &u->peer; c = pc->connection; @@ -4669,9 +5264,32 @@ ngx_http_lua_socket_tcp_setkeepalive(lua_State *L) return 2; } + if (ngx_terminate || ngx_exiting) { + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0, + "lua tcp socket set keepalive while process exiting, " + "closing connection %p", c); + + ngx_http_lua_socket_tcp_finalize(r, u); + lua_pushinteger(L, 1); + return 1; + } + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0, "lua tcp socket set keepalive: saving connection %p", c); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask(socket_pool_key)); + lua_rawget(L, LUA_REGISTRYINDEX); + + /* stack: obj timeout? size? pools */ + + lua_rawgeti(L, 1, SOCKET_KEY_INDEX); + key.data = (u_char *) lua_tolstring(L, -1, &key.len); + if (key.data == NULL) { + lua_pushnil(L); + lua_pushliteral(L, "key not found"); + return 2; + } + dd("saving connection to key %s", lua_tostring(L, -1)); lua_pushvalue(L, -1); @@ -4679,7 +5297,7 @@ ngx_http_lua_socket_tcp_setkeepalive(lua_State *L) spool = lua_touserdata(L, -1); lua_pop(L, 1); - /* stack: obj timeout? size? cache key */ + /* stack: obj timeout? size? pools cache_key */ llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); @@ -4693,82 +5311,49 @@ ngx_http_lua_socket_tcp_setkeepalive(lua_State *L) pool_size = llcf->pool_size; } - if (pool_size == 0) { - lua_pushnil(L); - lua_pushliteral(L, "zero pool size"); - return 2; + if (pool_size <= 0) { + msg = lua_pushfstring(L, "bad \"pool_size\" option value: %i", + pool_size); + return luaL_argerror(L, n, msg); } - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua tcp socket connection pool size: %ui", pool_size); - - key_len = ngx_align(key.len + 1, sizeof(void *)); - - size = sizeof(ngx_http_lua_socket_pool_t) + key_len - 1 - + sizeof(ngx_http_lua_socket_pool_item_t) - * pool_size; - - spool = lua_newuserdata(L, size); - if (spool == NULL) { - return luaL_error(L, "no memory"); - } - - lua_pushlightuserdata(L, &ngx_http_lua_pool_udata_metatable_key); - lua_rawget(L, LUA_REGISTRYINDEX); - lua_setmetatable(L, -2); - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0, - "lua tcp socket keepalive create connection pool for key" - " \"%s\"", lua_tostring(L, -2)); - - lua_rawset(L, -3); - - spool->active_connections = 0; - spool->lua_vm = ngx_http_lua_get_lua_vm(r, NULL); - - ngx_queue_init(&spool->cache); - ngx_queue_init(&spool->free); - - p = ngx_copy(spool->key, key.data, key.len); - *p++ = '\0'; - - items = (ngx_http_lua_socket_pool_item_t *) (spool->key + key_len); - - dd("items: %p", items); - - ngx_http_lua_assert((void *) items == ngx_align_ptr(items, - sizeof(void *))); - - for (i = 0; i < pool_size; i++) { - ngx_queue_insert_head(&spool->free, &items[i].queue); - items[i].socket_pool = spool; - } + ngx_http_lua_socket_tcp_create_socket_pool(L, r, key, pool_size, -1, + &spool); } if (ngx_queue_empty(&spool->free)) { q = ngx_queue_last(&spool->cache); ngx_queue_remove(q); - spool->active_connections--; item = ngx_queue_data(q, ngx_http_lua_socket_pool_item_t, queue); ngx_http_lua_socket_tcp_close_connection(item->connection); + /* only decrease the counter for connections which were counted */ + if (u->socket_pool != NULL) { + u->socket_pool->connections--; + } + } else { q = ngx_queue_head(&spool->free); ngx_queue_remove(q); item = ngx_queue_data(q, ngx_http_lua_socket_pool_item_t, queue); + + /* we should always increase connections after getting connected, + * and decrease connections after getting closed. + * however, we don't create connection pool in previous connect method. + * so we increase connections here for backward compatibility. + */ + if (u->socket_pool == NULL) { + spool->connections++; + } } item->connection = c; ngx_queue_insert_head(&spool->cache, q); - if (!u->reused) { - spool->active_connections++; - } - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, pc->log, 0, "lua tcp socket clear current socket connection"); @@ -4837,48 +5422,33 @@ ngx_http_lua_socket_tcp_setkeepalive(lua_State *L) ngx_http_lua_socket_tcp_finalize(r, u); #endif + /* since we set u->peer->connection to NULL previously, the connect + * operation won't be resumed in the ngx_http_lua_socket_tcp_finalize. + * Therefore we need to resume it here. + */ + ngx_http_lua_socket_tcp_resume_conn_op(spool); + lua_pushinteger(L, 1); return 1; } static ngx_int_t -ngx_http_lua_get_keepalive_peer(ngx_http_request_t *r, lua_State *L, - int key_index, ngx_http_lua_socket_tcp_upstream_t *u) +ngx_http_lua_get_keepalive_peer(ngx_http_request_t *r, + ngx_http_lua_socket_tcp_upstream_t *u) { ngx_http_lua_socket_pool_item_t *item; ngx_http_lua_socket_pool_t *spool; ngx_http_cleanup_t *cln; ngx_queue_t *q; - int top; ngx_peer_connection_t *pc; ngx_connection_t *c; - top = lua_gettop(L); - - if (key_index < 0) { - key_index = top + key_index + 1; - } - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua tcp socket pool get keepalive peer"); pc = &u->peer; - - lua_pushlightuserdata(L, &ngx_http_lua_socket_pool_key); - lua_rawget(L, LUA_REGISTRYINDEX); /* table */ - lua_pushvalue(L, key_index); /* key */ - lua_rawget(L, -2); - - spool = lua_touserdata(L, -1); - if (spool == NULL) { - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, pc->log, 0, - "lua tcp socket keepalive connection pool not found"); - lua_settop(L, top); - return NGX_DECLINED; - } - - u->socket_pool = spool; + spool = u->socket_pool; if (!ngx_queue_empty(&spool->cache)) { q = ngx_queue_head(&spool->cache); @@ -4923,7 +5493,6 @@ ngx_http_lua_get_keepalive_peer(ngx_http_request_t *r, lua_State *L, cln = ngx_http_lua_cleanup_add(r, 0); if (cln == NULL) { u->ft_type |= NGX_HTTP_LUA_SOCKET_FT_ERROR; - lua_settop(L, top); return NGX_ERROR; } @@ -4932,16 +5501,12 @@ ngx_http_lua_get_keepalive_peer(ngx_http_request_t *r, lua_State *L, u->cleanup = &cln->handler; } - lua_settop(L, top); - return NGX_OK; } ngx_log_debug0(NGX_LOG_DEBUG_HTTP, pc->log, 0, "lua tcp socket keepalive: connection pool empty"); - lua_settop(L, top); - return NGX_DECLINED; } @@ -5013,13 +5578,15 @@ close: ngx_queue_remove(&item->queue); ngx_queue_insert_head(&spool->free, &item->queue); - spool->active_connections--; + spool->connections--; - dd("keepalive: active connections: %u", - (unsigned) spool->active_connections); + dd("keepalive: connections: %u", (unsigned) spool->connections); - if (spool->active_connections == 0) { + if (spool->connections == 0) { ngx_http_lua_socket_free_pool(ev->log, spool); + + } else { + ngx_http_lua_socket_tcp_resume_conn_op(spool); } return NGX_DECLINED; @@ -5037,7 +5604,7 @@ ngx_http_lua_socket_free_pool(ngx_log_t *log, ngx_http_lua_socket_pool_t *spool) L = spool->lua_vm; - lua_pushlightuserdata(L, &ngx_http_lua_socket_pool_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask(socket_pool_key)); lua_rawget(L, LUA_REGISTRYINDEX); lua_pushstring(L, (char *) spool->key); lua_pushnil(L); @@ -5049,9 +5616,10 @@ ngx_http_lua_socket_free_pool(ngx_log_t *log, ngx_http_lua_socket_pool_t *spool) static void ngx_http_lua_socket_shutdown_pool_helper(ngx_http_lua_socket_pool_t *spool) { - ngx_queue_t *q; - ngx_connection_t *c; - ngx_http_lua_socket_pool_item_t *item; + ngx_queue_t *q; + ngx_connection_t *c; + ngx_http_lua_socket_pool_item_t *item; + ngx_http_lua_socket_tcp_conn_op_ctx_t *conn_op_ctx; while (!ngx_queue_empty(&spool->cache)) { q = ngx_queue_head(&spool->cache); @@ -5065,7 +5633,29 @@ ngx_http_lua_socket_shutdown_pool_helper(ngx_http_lua_socket_pool_t *spool) ngx_queue_insert_head(&spool->free, q); } - spool->active_connections = 0; + while (!ngx_queue_empty(&spool->cache_connect_op)) { + q = ngx_queue_head(&spool->cache_connect_op); + ngx_queue_remove(q); + conn_op_ctx = ngx_queue_data(q, ngx_http_lua_socket_tcp_conn_op_ctx_t, + queue); + ngx_http_lua_socket_tcp_free_conn_op_ctx(conn_op_ctx); + } + + while (!ngx_queue_empty(&spool->wait_connect_op)) { + q = ngx_queue_head(&spool->wait_connect_op); + ngx_queue_remove(q); + conn_op_ctx = ngx_queue_data(q, ngx_http_lua_socket_tcp_conn_op_ctx_t, + queue); + + if (conn_op_ctx->event.timer_set) { + ngx_del_timer(&conn_op_ctx->event); + } + + ngx_http_lua_socket_tcp_free_conn_op_ctx(conn_op_ctx); + } + + /* spool->connections will be decreased down to zero in + * ngx_http_lua_socket_tcp_finalize */ } @@ -5319,6 +5909,13 @@ static ngx_int_t ngx_http_lua_socket_insert_buffer(ngx_http_request_t *r, } +static ngx_int_t +ngx_http_lua_socket_tcp_conn_op_resume(ngx_http_request_t *r) +{ + return ngx_http_lua_socket_tcp_resume_helper(r, SOCKET_OP_RESUME_CONN); +} + + static ngx_int_t ngx_http_lua_socket_tcp_conn_resume(ngx_http_request_t *r) { @@ -5343,13 +5940,14 @@ ngx_http_lua_socket_tcp_write_resume(ngx_http_request_t *r) static ngx_int_t ngx_http_lua_socket_tcp_resume_helper(ngx_http_request_t *r, int socket_op) { - int nret; - lua_State *vm; - ngx_int_t rc; - ngx_uint_t nreqs; - ngx_connection_t *c; - ngx_http_lua_ctx_t *ctx; - ngx_http_lua_co_ctx_t *coctx; + int nret; + lua_State *vm; + ngx_int_t rc; + ngx_uint_t nreqs; + ngx_connection_t *c; + ngx_http_lua_ctx_t *ctx; + ngx_http_lua_co_ctx_t *coctx; + ngx_http_lua_socket_tcp_conn_op_ctx_t *conn_op_ctx; ngx_http_lua_socket_tcp_retval_handler prepare_retvals; @@ -5369,15 +5967,22 @@ ngx_http_lua_socket_tcp_resume_helper(ngx_http_request_t *r, int socket_op) dd("coctx: %p", coctx); - u = coctx->data; - switch (socket_op) { + + case SOCKET_OP_RESUME_CONN: + conn_op_ctx = coctx->data; + u = conn_op_ctx->u; + prepare_retvals = u->write_prepare_retvals; + break; + case SOCKET_OP_CONNECT: case SOCKET_OP_WRITE: + u = coctx->data; prepare_retvals = u->write_prepare_retvals; break; case SOCKET_OP_READ: + u = coctx->data; prepare_retvals = u->read_prepare_retvals; break; @@ -5391,6 +5996,15 @@ ngx_http_lua_socket_tcp_resume_helper(ngx_http_request_t *r, int socket_op) "u:%p", prepare_retvals, u); nret = prepare_retvals(r, u, ctx->cur_co_ctx->co); + if (socket_op == SOCKET_OP_CONNECT + && nret > 1 + && !u->conn_closed + && u->socket_pool != NULL) + { + u->socket_pool->connections--; + ngx_http_lua_socket_tcp_resume_conn_op(u->socket_pool); + } + if (nret == NGX_AGAIN) { return NGX_DONE; } @@ -5422,6 +6036,36 @@ ngx_http_lua_socket_tcp_resume_helper(ngx_http_request_t *r, int socket_op) } +static void +ngx_http_lua_tcp_queue_conn_op_cleanup(void *data) +{ + ngx_http_lua_co_ctx_t *coctx = data; + ngx_http_lua_socket_tcp_upstream_t *u; + ngx_http_lua_socket_tcp_conn_op_ctx_t *conn_op_ctx; + + conn_op_ctx = coctx->data; + u = conn_op_ctx->u; + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "lua tcp socket abort queueing, conn_op_ctx: %p, u: %p", + conn_op_ctx, u); + + if (conn_op_ctx->event.posted) { + ngx_delete_posted_event(&conn_op_ctx->event); + + } else if (conn_op_ctx->event.timer_set) { + ngx_del_timer(&conn_op_ctx->event); + } + + ngx_queue_remove(&conn_op_ctx->queue); + ngx_queue_insert_head(&u->socket_pool->cache_connect_op, + &conn_op_ctx->queue); + + u->socket_pool->connections--; + ngx_http_lua_socket_tcp_resume_conn_op(u->socket_pool); +} + + static void ngx_http_lua_tcp_resolve_cleanup(void *data) { @@ -5437,6 +6081,11 @@ ngx_http_lua_tcp_resolve_cleanup(void *data) return; } + if (u->socket_pool != NULL) { + u->socket_pool->connections--; + ngx_http_lua_socket_tcp_resume_conn_op(u->socket_pool); + } + rctx = u->resolved->ctx; if (rctx == NULL) { return; @@ -5496,7 +6145,8 @@ ngx_http_lua_cleanup_conn_pools(lua_State *L) { ngx_http_lua_socket_pool_t *spool; - lua_pushlightuserdata(L, &ngx_http_lua_socket_pool_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + socket_pool_key)); lua_rawget(L, LUA_REGISTRYINDEX); /* table */ lua_pushnil(L); /* first key */ diff --git a/debian/modules/http-lua/src/ngx_http_lua_socket_tcp.h b/debian/modules/http-lua/src/ngx_http_lua_socket_tcp.h index dbdee41..091e437 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_socket_tcp.h +++ b/debian/modules/http-lua/src/ngx_http_lua_socket_tcp.h @@ -35,17 +35,39 @@ typedef void (*ngx_http_lua_socket_tcp_upstream_handler_pt) (ngx_http_request_t *r, ngx_http_lua_socket_tcp_upstream_t *u); +typedef struct { + ngx_event_t event; + ngx_queue_t queue; + ngx_str_t host; + ngx_http_cleanup_pt *cleanup; + ngx_http_lua_socket_tcp_upstream_t *u; + in_port_t port; +} ngx_http_lua_socket_tcp_conn_op_ctx_t; + + +#define ngx_http_lua_socket_tcp_free_conn_op_ctx(conn_op_ctx) \ + ngx_free(conn_op_ctx->host.data); \ + ngx_free(conn_op_ctx) + + typedef struct { lua_State *lua_vm; - /* active connections == out-of-pool reused connections - * + in-pool connections */ - ngx_uint_t active_connections; + ngx_int_t size; + ngx_queue_t cache_connect_op; + ngx_queue_t wait_connect_op; + + /* connections == active connections + pending connect operations, + * while active connections == out-of-pool reused connections + * + in-pool connections */ + ngx_int_t connections; /* queues of ngx_http_lua_socket_pool_item_t: */ ngx_queue_t cache; ngx_queue_t free; + ngx_int_t backlog; + u_char key[1]; } ngx_http_lua_socket_pool_t; @@ -104,6 +126,7 @@ struct ngx_http_lua_socket_tcp_upstream_s { unsigned raw_downstream:1; unsigned read_closed:1; unsigned write_closed:1; + unsigned conn_closed:1; #if (NGX_HTTP_SSL) unsigned ssl_verify:1; unsigned ssl_session_reuse:1; diff --git a/debian/modules/http-lua/src/ngx_http_lua_socket_udp.c b/debian/modules/http-lua/src/ngx_http_lua_socket_udp.c index 8927f41..cbc32d6 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_socket_udp.c +++ b/debian/modules/http-lua/src/ngx_http_lua_socket_udp.c @@ -81,7 +81,8 @@ ngx_http_lua_inject_socket_udp_api(ngx_log_t *log, lua_State *L) lua_setfield(L, -2, "udp"); /* ngx socket */ /* udp socket object metatable */ - lua_pushlightuserdata(L, &ngx_http_lua_socket_udp_metatable_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + socket_udp_metatable_key)); lua_createtable(L, 0 /* narr */, 6 /* nrec */); lua_pushcfunction(L, ngx_http_lua_socket_udp_setpeername); @@ -105,7 +106,8 @@ ngx_http_lua_inject_socket_udp_api(ngx_log_t *log, lua_State *L) /* }}} */ /* udp socket object metatable */ - lua_pushlightuserdata(L, &ngx_http_lua_udp_udata_metatable_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + udp_udata_metatable_key)); lua_createtable(L, 0 /* narr */, 1 /* nrec */); /* metatable */ lua_pushcfunction(L, ngx_http_lua_socket_udp_upstream_destroy); lua_setfield(L, -2, "__gc"); @@ -144,7 +146,8 @@ ngx_http_lua_socket_udp(lua_State *L) | NGX_HTTP_LUA_CONTEXT_SSL_CERT); lua_createtable(L, 3 /* narr */, 1 /* nrec */); - lua_pushlightuserdata(L, &ngx_http_lua_socket_udp_metatable_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + socket_udp_metatable_key)); lua_rawget(L, LUA_REGISTRYINDEX); lua_setmetatable(L, -2); @@ -263,7 +266,8 @@ ngx_http_lua_socket_udp_setpeername(lua_State *L) } #if 1 - lua_pushlightuserdata(L, &ngx_http_lua_udp_udata_metatable_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + udp_udata_metatable_key)); lua_rawget(L, LUA_REGISTRYINDEX); lua_setmetatable(L, -2); #endif diff --git a/debian/modules/http-lua/src/ngx_http_lua_ssl_certby.c b/debian/modules/http-lua/src/ngx_http_lua_ssl_certby.c index 453a5c7..622d0a5 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_ssl_certby.c +++ b/debian/modules/http-lua/src/ngx_http_lua_ssl_certby.c @@ -498,9 +498,11 @@ ngx_http_lua_ssl_cert_by_chunk(lua_State *L, ngx_http_request_t *r) /* move code closure to new coroutine */ lua_xmove(L, co, 1); +#ifndef OPENRESTY_LUAJIT /* set closure's env table to new coroutine's globals table */ ngx_http_lua_get_globals_table(co); lua_setfenv(co, -2); +#endif /* save nginx request in coroutine globals table */ ngx_http_lua_set_req(co, r); diff --git a/debian/modules/http-lua/src/ngx_http_lua_ssl_session_fetchby.c b/debian/modules/http-lua/src/ngx_http_lua_ssl_session_fetchby.c index 0b88a87..303efb4 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_ssl_session_fetchby.c +++ b/debian/modules/http-lua/src/ngx_http_lua_ssl_session_fetchby.c @@ -505,9 +505,11 @@ ngx_http_lua_ssl_sess_fetch_by_chunk(lua_State *L, ngx_http_request_t *r) /* move code closure to new coroutine */ lua_xmove(L, co, 1); +#ifndef OPENRESTY_LUAJIT /* set closure's env table to new coroutine's globals table */ ngx_http_lua_get_globals_table(co); lua_setfenv(co, -2); +#endif /* save nginx request in coroutine globals table */ ngx_http_lua_set_req(co, r); diff --git a/debian/modules/http-lua/src/ngx_http_lua_ssl_session_storeby.c b/debian/modules/http-lua/src/ngx_http_lua_ssl_session_storeby.c index 7609c39..a02f729 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_ssl_session_storeby.c +++ b/debian/modules/http-lua/src/ngx_http_lua_ssl_session_storeby.c @@ -380,6 +380,8 @@ ngx_http_lua_ssl_sess_store_by_chunk(lua_State *L, ngx_http_request_t *r) /* init nginx context in Lua VM */ ngx_http_lua_set_req(L, r); + +#ifndef OPENRESTY_LUAJIT ngx_http_lua_create_new_globals_table(L, 0 /* narr */, 1 /* nrec */); /* {{{ make new env inheriting main thread's globals table */ @@ -390,6 +392,7 @@ ngx_http_lua_ssl_sess_store_by_chunk(lua_State *L, ngx_http_request_t *r) /* }}} */ lua_setfenv(L, -2); /* set new running env for the code closure */ +#endif lua_pushcfunction(L, ngx_http_lua_traceback); lua_insert(L, 1); /* put it under chunk and args */ diff --git a/debian/modules/http-lua/src/ngx_http_lua_string.c b/debian/modules/http-lua/src/ngx_http_lua_string.c index 239b232..bdadeb4 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_string.c +++ b/debian/modules/http-lua/src/ngx_http_lua_string.c @@ -762,6 +762,20 @@ ngx_http_lua_ffi_escape_uri(const u_char *src, size_t len, u_char *dst) ngx_http_lua_escape_uri(dst, (u_char *) src, len, NGX_ESCAPE_URI_COMPONENT); } + +void +ngx_http_lua_ffi_str_replace_char(u_char *buf, size_t len, const u_char find, + const u_char replace) +{ + while (len) { + if (*buf == find) { + *buf = replace; + } + + buf++; + len--; + } +} #endif /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/debian/modules/http-lua/src/ngx_http_lua_subrequest.c b/debian/modules/http-lua/src/ngx_http_lua_subrequest.c index 826a43c..f312b65 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_subrequest.c +++ b/debian/modules/http-lua/src/ngx_http_lua_subrequest.c @@ -1031,6 +1031,14 @@ ngx_http_lua_post_subrequest(ngx_http_request_t *r, void *data, ngx_int_t rc) dd("pr_coctx status: %d", (int) pr_coctx->sr_statuses[ctx->index]); /* copy subrequest response headers */ + if (ctx->headers_set) { + rc = ngx_http_lua_set_content_type(r, ctx); + if (rc != NGX_OK) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "failed to set default content type: %i", rc); + return NGX_ERROR; + } + } pr_coctx->sr_headers[ctx->index] = &r->headers_out; diff --git a/debian/modules/http-lua/src/ngx_http_lua_timer.c b/debian/modules/http-lua/src/ngx_http_lua_timer.c index 596b2f7..e92c211 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_timer.c +++ b/debian/modules/http-lua/src/ngx_http_lua_timer.c @@ -220,6 +220,7 @@ ngx_http_lua_ngx_timer_helper(lua_State *L, int every) ngx_http_lua_probe_user_coroutine_create(r, L, co); +#ifndef OPENRESTY_LUAJIT lua_createtable(co, 0, 0); /* the new globals table */ /* co stack: global_tb */ @@ -232,6 +233,7 @@ ngx_http_lua_ngx_timer_helper(lua_State *L, int every) /* co stack: global_tb */ ngx_http_lua_set_globals_table(co); +#endif /* co stack: */ @@ -251,12 +253,15 @@ ngx_http_lua_ngx_timer_helper(lua_State *L, int every) /* L stack: time func [args] thread */ /* co stack: func */ +#ifndef OPENRESTY_LUAJIT ngx_http_lua_get_globals_table(co); lua_setfenv(co, -2); +#endif /* co stack: func */ - lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + coroutines_key)); lua_rawget(L, LUA_REGISTRYINDEX); /* L stack: time func [args] thread coroutines */ @@ -345,6 +350,9 @@ ngx_http_lua_ngx_timer_helper(lua_State *L, int every) ngx_add_timer(ev, delay); + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "created timer (co: %p delay: %M ms)", tctx->co, delay); + lua_pushinteger(L, 1); return 1; @@ -358,7 +366,8 @@ nomem: ngx_free(ev); } - lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + coroutines_key)); lua_rawget(L, LUA_REGISTRYINDEX); luaL_unref(L, -1, co_ref); @@ -387,6 +396,7 @@ ngx_http_lua_timer_copy(ngx_http_lua_timer_ctx_t *old_tctx) co = lua_newthread(vm); +#ifndef OPENRESTY_LUAJIT lua_createtable(co, 0, 0); /* the new globals table */ /* co stack: global_tb */ @@ -399,6 +409,7 @@ ngx_http_lua_timer_copy(ngx_http_lua_timer_ctx_t *old_tctx) /* co stack: global_tb */ ngx_http_lua_set_globals_table(co); +#endif /* co stack: */ @@ -418,12 +429,15 @@ ngx_http_lua_timer_copy(ngx_http_lua_timer_ctx_t *old_tctx) /* L stack: func [args] thread */ /* co stack: func */ +#ifndef OPENRESTY_LUAJIT ngx_http_lua_get_globals_table(co); lua_setfenv(co, -2); +#endif /* co stack: func */ - lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + coroutines_key)); lua_rawget(L, LUA_REGISTRYINDEX); /* L stack: func [args] thread coroutines */ @@ -498,6 +512,10 @@ ngx_http_lua_timer_copy(ngx_http_lua_timer_ctx_t *old_tctx) ngx_add_timer(ev, tctx->delay); + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "created next timer (co: %p delay: %M ms)", tctx->co, + tctx->delay); + return NGX_OK; nomem: @@ -512,7 +530,8 @@ nomem: /* L stack: func [args] */ - lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + coroutines_key)); lua_rawget(L, LUA_REGISTRYINDEX); luaL_unref(L, -1, co_ref); @@ -568,6 +587,9 @@ ngx_http_lua_timer_handler(ngx_event_t *ev) c = ngx_http_lua_create_fake_connection(tctx.pool); if (c == NULL) { + ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, + "failed to create fake connection to run timer (co: %p)", + tctx.co); goto failed; } @@ -579,6 +601,9 @@ ngx_http_lua_timer_handler(ngx_event_t *ev) r = ngx_http_lua_create_fake_request(c); if (r == NULL) { + ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, + "failed to create fake request to run timer (co: %p)", + tctx.co); goto failed; } @@ -614,6 +639,8 @@ ngx_http_lua_timer_handler(ngx_event_t *ev) ctx = ngx_http_lua_create_ctx(r); if (ctx == NULL) { + ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, + "failed to create ctx to run timer (co: %p)", tctx.co); goto failed; } @@ -622,6 +649,9 @@ ngx_http_lua_timer_handler(ngx_event_t *ev) pcln = ngx_pool_cleanup_add(r->pool, 0); if (pcln == NULL) { + ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, + "failed to add vm cleanup to run timer (co: %p)", + tctx.co); goto failed; } @@ -635,6 +665,9 @@ ngx_http_lua_timer_handler(ngx_event_t *ev) cln = ngx_http_cleanup_add(r, 0); if (cln == NULL) { + ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, + "failed to add request cleanup to run timer (co: %p)", + tctx.co); goto failed; } @@ -692,7 +725,8 @@ ngx_http_lua_timer_handler(ngx_event_t *ev) failed: if (tctx.co_ref && tctx.co) { - lua_pushlightuserdata(tctx.co, &ngx_http_lua_coroutines_key); + lua_pushlightuserdata(tctx.co, ngx_http_lua_lightudata_mask( + coroutines_key)); lua_rawget(tctx.co, LUA_REGISTRYINDEX); luaL_unref(tctx.co, -1, tctx.co_ref); lua_settop(tctx.co, 0); diff --git a/debian/modules/http-lua/src/ngx_http_lua_uthread.c b/debian/modules/http-lua/src/ngx_http_lua_uthread.c index 8195ec0..43517a0 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_uthread.c +++ b/debian/modules/http-lua/src/ngx_http_lua_uthread.c @@ -70,7 +70,8 @@ ngx_http_lua_uthread_spawn(lua_State *L) /* anchor the newly created coroutine into the Lua registry */ - lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + coroutines_key)); lua_rawget(L, LUA_REGISTRYINDEX); lua_pushvalue(L, -2); coctx->co_ref = luaL_ref(L, -2); diff --git a/debian/modules/http-lua/src/ngx_http_lua_util.c b/debian/modules/http-lua/src/ngx_http_lua_util.c index f7a537e..c12262e 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_util.c +++ b/debian/modules/http-lua/src/ngx_http_lua_util.c @@ -70,6 +70,25 @@ #endif +#if (NGX_HTTP_LUA_HAVE_SA_RESTART) +#define NGX_HTTP_LUA_SA_RESTART_SIGS { \ + ngx_signal_value(NGX_RECONFIGURE_SIGNAL), \ + ngx_signal_value(NGX_REOPEN_SIGNAL), \ + ngx_signal_value(NGX_NOACCEPT_SIGNAL), \ + ngx_signal_value(NGX_TERMINATE_SIGNAL), \ + ngx_signal_value(NGX_SHUTDOWN_SIGNAL), \ + ngx_signal_value(NGX_CHANGEBIN_SIGNAL), \ + SIGALRM, \ + SIGINT, \ + SIGIO, \ + SIGCHLD, \ + SIGSYS, \ + SIGPIPE, \ + 0 \ +}; +#endif + + char ngx_http_lua_code_cache_key; char ngx_http_lua_regex_cache_key; char ngx_http_lua_socket_pool_key; @@ -128,6 +147,13 @@ static int ngx_http_lua_get_raw_phase_context(lua_State *L); #define LUA_PATH_SEP ";" #endif + +#if !defined(LUA_DEFAULT_PATH) && (NGX_DEBUG) +#define LUA_DEFAULT_PATH "../lua-resty-core/lib/?.lua;" \ + "../lua-resty-lrucache/lib/?.lua" +#endif + + #define AUX_MARK "\1" @@ -171,6 +197,7 @@ ngx_http_lua_set_path(ngx_cycle_t *cycle, lua_State *L, int tab_idx, } +#ifndef OPENRESTY_LUAJIT /** * Create new table and set _G field to itself. * @@ -185,6 +212,7 @@ ngx_http_lua_create_new_globals_table(lua_State *L, int narr, int nrec) lua_pushvalue(L, -1); lua_setfield(L, -2, "_G"); } +#endif /* OPENRESTY_LUAJIT */ static lua_State * @@ -313,11 +341,13 @@ ngx_http_lua_new_thread(ngx_http_request_t *r, lua_State *L, int *ref) base = lua_gettop(L); - lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + coroutines_key)); lua_rawget(L, LUA_REGISTRYINDEX); co = lua_newthread(L); +#ifndef OPENRESTY_LUAJIT /* {{{ inherit coroutine's globals to main thread's globals table * for print() function will try to find tostring() in current * globals table. @@ -332,6 +362,7 @@ ngx_http_lua_new_thread(ngx_http_request_t *r, lua_State *L, int *ref) ngx_http_lua_set_globals_table(co); /* }}} */ +#endif /* OPENRESTY_LUAJIT */ *ref = luaL_ref(L, -2); @@ -356,7 +387,8 @@ ngx_http_lua_del_thread(ngx_http_request_t *r, lua_State *L, ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua deleting light thread"); - lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + coroutines_key)); lua_rawget(L, LUA_REGISTRYINDEX); ngx_http_lua_probe_thread_delete(r, coctx->co, ctx); @@ -408,7 +440,9 @@ ngx_http_lua_send_header_if_needed(ngx_http_request_t *r, r->headers_out.status = NGX_HTTP_OK; } - if (!ctx->headers_set && ngx_http_lua_set_content_type(r) != NGX_OK) { + if (!ctx->mime_set + && ngx_http_lua_set_content_type(r, ctx) != NGX_OK) + { return NGX_ERROR; } @@ -657,7 +691,8 @@ ngx_http_lua_init_registry(lua_State *L, ngx_log_t *log) /* {{{ register a table to anchor lua coroutines reliably: * {([int]ref) = [cort]} */ - lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + coroutines_key)); lua_createtable(L, 0, 32 /* nrec */); lua_rawset(L, LUA_REGISTRYINDEX); /* }}} */ @@ -668,20 +703,23 @@ ngx_http_lua_init_registry(lua_State *L, ngx_log_t *log) lua_rawset(L, LUA_REGISTRYINDEX); /* create the registry entry for the Lua socket connection pool table */ - lua_pushlightuserdata(L, &ngx_http_lua_socket_pool_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + socket_pool_key)); lua_createtable(L, 0, 8 /* nrec */); lua_rawset(L, LUA_REGISTRYINDEX); #if (NGX_PCRE) /* create the registry entry for the Lua precompiled regex object cache */ - lua_pushlightuserdata(L, &ngx_http_lua_regex_cache_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + regex_cache_key)); lua_createtable(L, 0, 16 /* nrec */); lua_rawset(L, LUA_REGISTRYINDEX); #endif /* {{{ register table to cache user code: * { [(string)cache_key] = } */ - lua_pushlightuserdata(L, &ngx_http_lua_code_cache_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + code_cache_key)); lua_createtable(L, 0, 8 /* nrec */); lua_rawset(L, LUA_REGISTRYINDEX); /* }}} */ @@ -695,9 +733,6 @@ ngx_http_lua_init_globals(lua_State *L, ngx_cycle_t *cycle, ngx_log_debug0(NGX_LOG_DEBUG_HTTP, log, 0, "lua initializing lua globals"); - lua_pushlightuserdata(L, cycle); - lua_setglobal(L, "__ngx_cycle"); - #if defined(NDK) && NDK ngx_http_lua_inject_ndk_api(L); #endif /* defined(NDK) && NDK */ @@ -756,6 +791,52 @@ ngx_http_lua_inject_ngx_api(lua_State *L, ngx_http_lua_main_conf_t *lmcf, lua_setglobal(L, "ngx"); ngx_http_lua_inject_coroutine_api(log, L); + +#ifdef OPENRESTY_LUAJIT + { + int rc; + + const char buf[] = + "local ngx_log = ngx.log\n" + "local ngx_WARN = ngx.WARN\n" + "local tostring = tostring\n" + "local ngx_get_phase = ngx.get_phase\n" + "local traceback = require 'debug'.traceback\n" + "local function newindex(table, key, value)\n" + "rawset(table, key, value)\n" + "local phase = ngx_get_phase()\n" + "if phase == 'init_worker' or phase == 'init' then\n" + "return\n" + "end\n" + "ngx_log(ngx_WARN, 'writing a global lua variable " + "(\\'', tostring(key), '\\') which may lead to " + "race conditions between concurrent requests, so " + "prefer the use of \\'local\\' variables', " + "traceback('', 2))\n" + "end\n" + "setmetatable(_G, { __newindex = newindex })\n" + ; + + rc = luaL_loadbuffer(L, buf, sizeof(buf) - 1, "=_G write guard"); + + if (rc != 0) { + ngx_log_error(NGX_LOG_ERR, log, 0, + "failed to load Lua code (%i): %s", + rc, lua_tostring(L, -1)); + + lua_pop(L, 1); + return; + } + + rc = lua_pcall(L, 0, 0, 0); + if (rc != 0) { + ngx_log_error(NGX_LOG_ERR, log, 0, + "failed to run Lua code (%i): %s", + rc, lua_tostring(L, -1)); + lua_pop(L, 1); + } + } +#endif } @@ -2954,12 +3035,12 @@ ngx_http_lua_param_get(lua_State *L) | NGX_HTTP_LUA_CONTEXT_BODY_FILTER); if (ctx->context & (NGX_HTTP_LUA_CONTEXT_SET)) { - return ngx_http_lua_setby_param_get(L); + return ngx_http_lua_setby_param_get(L, r); } /* ctx->context & (NGX_HTTP_LUA_CONTEXT_BODY_FILTER) */ - return ngx_http_lua_body_filter_param_get(L); + return ngx_http_lua_body_filter_param_get(L, r); } @@ -3156,7 +3237,8 @@ ngx_http_lua_finalize_threads(ngx_http_request_t *r, ngx_http_lua_probe_thread_delete(r, coctx->co, ctx); - lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + coroutines_key)); lua_rawget(L, LUA_REGISTRYINDEX); inited = 1; @@ -3194,7 +3276,8 @@ ngx_http_lua_finalize_threads(ngx_http_request_t *r, ngx_http_lua_probe_thread_delete(r, coctx->co, ctx); if (!inited) { - lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + coroutines_key)); lua_rawget(L, LUA_REGISTRYINDEX); inited = 1; } @@ -3223,7 +3306,8 @@ ngx_http_lua_finalize_threads(ngx_http_request_t *r, ngx_http_lua_probe_thread_delete(r, coctx->co, ctx); if (!inited) { - lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + coroutines_key)); lua_rawget(L, LUA_REGISTRYINDEX); inited = 1; } @@ -3736,6 +3820,7 @@ ngx_http_lua_init_vm(lua_State *parent_vm, ngx_cycle_t *cycle, ngx_pool_t *pool, ngx_http_lua_main_conf_t *lmcf, ngx_log_t *log, ngx_pool_cleanup_t **pcln) { + int rc; lua_State *L; ngx_uint_t i; ngx_pool_cleanup_t *cln; @@ -3778,6 +3863,11 @@ ngx_http_lua_init_vm(lua_State *parent_vm, ngx_cycle_t *cycle, *pcln = cln; } +#ifdef OPENRESTY_LUAJIT + /* load FFI library first since cdata needs it */ + luaopen_ffi(L); +#endif + if (lmcf->preload_hooks) { /* register the 3rd-party module's preload hooks */ @@ -3798,6 +3888,21 @@ ngx_http_lua_init_vm(lua_State *parent_vm, ngx_cycle_t *cycle, lua_pop(L, 2); } + if (lmcf->load_resty_core) { + lua_getglobal(L, "require"); + lua_pushstring(L, "resty.core"); + + rc = lua_pcall(L, 1, 1, 0); + if (rc != 0) { + ngx_log_error(NGX_LOG_ERR, log, 0, + "lua_load_resty_core failed to load the resty.core " + "module from https://github.com/openresty/lua-resty" + "-core; ensure you are using an OpenResty release " + "from https://openresty.org/en/download.html " + "(rc: %i, reason: %s)", rc, lua_tostring(L, -1)); + } + } + return L; } @@ -4041,7 +4146,12 @@ ngx_http_lua_get_raw_phase_context(lua_State *L) ngx_http_request_t *r; ngx_http_lua_ctx_t *ctx; +#ifdef OPENRESTY_LUAJIT + r = lua_getexdata(L); +#else r = lua_touserdata(L, 1); +#endif + if (r == NULL) { return 0; } @@ -4129,4 +4239,32 @@ ngx_http_lua_cleanup_free(ngx_http_request_t *r, ngx_http_cleanup_pt *cleanup) } +#if (NGX_HTTP_LUA_HAVE_SA_RESTART) +void +ngx_http_lua_set_sa_restart(ngx_log_t *log) +{ + int *signo; + int sigs[] = NGX_HTTP_LUA_SA_RESTART_SIGS; + struct sigaction act; + + for (signo = sigs; *signo != 0; signo++) { + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, + "setting SA_RESTART for signal %d", *signo); + + if (sigaction(*signo, NULL, &act) != 0) { + ngx_log_error(NGX_LOG_WARN, log, ngx_errno, "failed to get " + "sigaction for signal %d", *signo); + } + + act.sa_flags |= SA_RESTART; + + if (sigaction(*signo, &act, NULL) != 0) { + ngx_log_error(NGX_LOG_WARN, log, ngx_errno, "failed to set " + "sigaction for signal %d", *signo); + } + } +} +#endif + + /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/debian/modules/http-lua/src/ngx_http_lua_util.h b/debian/modules/http-lua/src/ngx_http_lua_util.h index 7dcc6f7..f08f481 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_util.h +++ b/debian/modules/http-lua/src/ngx_http_lua_util.h @@ -9,6 +9,11 @@ #define _NGX_HTTP_LUA_UTIL_H_INCLUDED_ +#ifdef DDEBUG +#include "ddebug.h" +#endif + + #include "ngx_http_lua_common.h" #include "ngx_http_lua_api.h" @@ -188,7 +193,9 @@ ngx_int_t ngx_http_lua_open_and_stat_file(u_char *name, ngx_chain_t *ngx_http_lua_chain_get_free_buf(ngx_log_t *log, ngx_pool_t *p, ngx_chain_t **free, size_t len); +#ifndef OPENRESTY_LUAJIT void ngx_http_lua_create_new_globals_table(lua_State *L, int narr, int nrec); +#endif int ngx_http_lua_traceback(lua_State *L); @@ -243,6 +250,9 @@ ngx_http_cleanup_t *ngx_http_lua_cleanup_add(ngx_http_request_t *r, void ngx_http_lua_cleanup_free(ngx_http_request_t *r, ngx_http_cleanup_pt *cleanup); +#if (NGX_HTTP_LUA_HAVE_SA_RESTART) +void ngx_http_lua_set_sa_restart(ngx_log_t *log); +#endif #define ngx_http_lua_check_if_abortable(L, ctx) \ if ((ctx)->no_abort) { \ @@ -282,7 +292,9 @@ ngx_http_lua_create_ctx(ngx_http_request_t *r) if (!llcf->enable_code_cache && r->connection->fd != (ngx_socket_t) -1) { lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); +#ifdef DDEBUG dd("lmcf: %p", lmcf); +#endif L = ngx_http_lua_init_vm(lmcf->lua, lmcf->cycle, r->pool, lmcf, r->connection->log, &cln); @@ -323,7 +335,11 @@ ngx_http_lua_get_lua_vm(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx) } lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); + +#ifdef DDEBUG dd("lmcf->lua: %p", lmcf->lua); +#endif + return lmcf->lua; } @@ -334,6 +350,9 @@ ngx_http_lua_get_lua_vm(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx) static ngx_inline ngx_http_request_t * ngx_http_lua_get_req(lua_State *L) { +#ifdef OPENRESTY_LUAJIT + return lua_getexdata(L); +#else ngx_http_request_t *r; lua_getglobal(L, ngx_http_lua_req_key); @@ -341,14 +360,19 @@ ngx_http_lua_get_req(lua_State *L) lua_pop(L, 1); return r; +#endif } static ngx_inline void ngx_http_lua_set_req(lua_State *L, ngx_http_request_t *r) { +#ifdef OPENRESTY_LUAJIT + lua_setexdata(L, (void *) r); +#else lua_pushlightuserdata(L, r); lua_setglobal(L, ngx_http_lua_req_key); +#endif } @@ -387,10 +411,12 @@ ngx_http_lua_hash_str(u_char *src, size_t n) static ngx_inline ngx_int_t -ngx_http_lua_set_content_type(ngx_http_request_t *r) +ngx_http_lua_set_content_type(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx) { ngx_http_lua_loc_conf_t *llcf; + ctx->mime_set = 1; + llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); if (llcf->use_default_type && r->headers_out.status != NGX_HTTP_NOT_MODIFIED) diff --git a/debian/modules/http-lua/src/ngx_http_lua_worker.c b/debian/modules/http-lua/src/ngx_http_lua_worker.c index 461509b..33cfa11 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_worker.c +++ b/debian/modules/http-lua/src/ngx_http_lua_worker.c @@ -153,6 +153,8 @@ ngx_http_lua_ffi_master_pid(void) int ngx_http_lua_ffi_get_process_type(void) { + ngx_core_conf_t *ccf; + #if defined(HAVE_PRIVILEGED_PROCESS_PATCH) && !NGX_WIN32 if (ngx_process == NGX_PROCESS_HELPER) { if (ngx_is_privileged_agent) { @@ -161,6 +163,15 @@ ngx_http_lua_ffi_get_process_type(void) } #endif + if (ngx_process == NGX_PROCESS_SINGLE) { + ccf = (ngx_core_conf_t *) ngx_get_conf(ngx_cycle->conf_ctx, + ngx_core_module); + + if (ccf->master) { + return NGX_PROCESS_MASTER; + } + } + return ngx_process; } diff --git a/debian/modules/http-lua/t/000--init.t b/debian/modules/http-lua/t/000--init.t index dbe2c33..5865755 100644 --- a/debian/modules/http-lua/t/000--init.t +++ b/debian/modules/http-lua/t/000--init.t @@ -10,11 +10,6 @@ $ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211; $ENV{TEST_NGINX_MYSQL_PORT} ||= 3306; our $http_config = <<'_EOC_'; - upstream database { - drizzle_server 127.0.0.1:$TEST_NGINX_MYSQL_PORT protocol=mysql - dbname=ngx_test user=ngx_test password=ngx_test; - } - lua_package_path "../lua-resty-mysql/lib/?.lua;;"; _EOC_ diff --git a/debian/modules/http-lua/t/001-set.t b/debian/modules/http-lua/t/001-set.t index ba8f22c..9e8ee7b 100644 --- a/debian/modules/http-lua/t/001-set.t +++ b/debian/modules/http-lua/t/001-set.t @@ -4,7 +4,7 @@ use Test::Nginx::Socket::Lua; repeat_each(2); -plan tests => repeat_each() * (blocks() * 3 + 4); +plan tests => repeat_each() * (blocks() * 3 + 5); #log_level("warn"); no_long_string(); @@ -46,7 +46,7 @@ helloworld === TEST 3: internal only --- config location /lua { - set_by_lua $res "function fib(n) if n > 2 then return fib(n-1)+fib(n-2) else return 1 end end return fib(10)"; + set_by_lua $res "local function fib(n) if n > 2 then return fib(n-1)+fib(n-2) else return 1 end end return fib(10)"; echo $res; } --- request @@ -76,7 +76,7 @@ GET /lua?a=1&b=2 === TEST 5: fib by arg --- config location /fib { - set_by_lua $res "function fib(n) if n > 2 then return fib(n-1)+fib(n-2) else return 1 end end return fib(tonumber(ngx.arg[1]))" $arg_n; + set_by_lua $res "local function fib(n) if n > 2 then return fib(n-1)+fib(n-2) else return 1 end end return fib(tonumber(ngx.arg[1]))" $arg_n; echo $res; } --- request @@ -592,25 +592,30 @@ failed to run set_by_lua*: unknown reason -=== TEST 37: globals get cleared for every single request +=== TEST 37: globals are shared in all requests. --- config location /lua { - set_by_lua $res ' + set_by_lua_block $res { if not foo then foo = 1 else + ngx.log(ngx.INFO, "old foo: ", foo) foo = foo + 1 end return foo - '; + } echo $res; } --- request GET /lua ---- response_body -1 +--- response_body_like chomp +\A[12] +\z --- no_error_log [error] +--- grep_error_log eval: qr/(old foo: \d+|writing a global lua variable \('\w+'\))/ +--- grep_error_log_out eval +["writing a global lua variable \('foo'\)\n", "old foo: 1\n"] @@ -755,6 +760,8 @@ GET /lua?name=jim --- config location /t { set_by_lua $a ' + local bar + local foo function foo() bar() end diff --git a/debian/modules/http-lua/t/002-content.t b/debian/modules/http-lua/t/002-content.t index cc92d6f..bb569f5 100644 --- a/debian/modules/http-lua/t/002-content.t +++ b/debian/modules/http-lua/t/002-content.t @@ -86,7 +86,7 @@ qr/content_by_lua\(nginx\.conf:\d+\):1: attempt to call field 'echo' \(a nil val location /lua { # NOTE: the newline escape sequence must be double-escaped, as nginx config # parser will unescape first! - content_by_lua 'v = ngx.var["request_uri"] ngx.print("request_uri: ", v, "\\n")'; + content_by_lua 'local v = ngx.var["request_uri"] ngx.print("request_uri: ", v, "\\n")'; } --- request GET /lua?a=1&b=2 @@ -102,7 +102,7 @@ request_uri: /lua?a=1&b=2 } --- user_files >>> test.lua -v = ngx.var["request_uri"] +local v = ngx.var["request_uri"] ngx.print("request_uri: ", v, "\n") --- request GET /lua?a=1&b=2 @@ -154,7 +154,7 @@ result: -0.4090441561579 === TEST 7: read $arg_xxx --- config location = /lua { - content_by_lua 'who = ngx.var.arg_who + content_by_lua 'local who = ngx.var.arg_who ngx.print("Hello, ", who, "!")'; } --- request @@ -171,7 +171,7 @@ Hello, agentzh! } location /lua { - content_by_lua 'res = ngx.location.capture("/other"); ngx.print("status=", res.status, " "); ngx.print("body=", res.body)'; + content_by_lua 'local res = ngx.location.capture("/other"); ngx.print("status=", res.status, " "); ngx.print("body=", res.body)'; } --- request GET /lua @@ -183,7 +183,7 @@ status=200 body=hello, world ei= TEST 9: capture non-existed location --- config location /lua { - content_by_lua 'res = ngx.location.capture("/other"); ngx.print("status=", res.status)'; + content_by_lua 'local res = ngx.location.capture("/other"); ngx.print("status=", res.status)'; } --- request GET /lua @@ -194,7 +194,7 @@ GET /lua === TEST 9: invalid capture location (not as expected...) --- config location /lua { - content_by_lua 'res = ngx.location.capture("*(#*"); ngx.say("res=", res.status)'; + content_by_lua 'local res = ngx.location.capture("*(#*"); ngx.say("res=", res.status)'; } --- request GET /lua @@ -247,7 +247,7 @@ GET /lua ngx.print("num is: ", num, "\\n"); if (num > 0) then - res = ngx.location.capture("/recur?num="..tostring(num - 1)); + local res = ngx.location.capture("/recur?num="..tostring(num - 1)); ngx.print("status=", res.status, " "); ngx.print("body=", res.body, "\\n"); else @@ -271,7 +271,7 @@ end ngx.print("num is: ", num, "\\n"); if (num > 0) then - res = ngx.location.capture("/recur?num="..tostring(num - 1)); + local res = ngx.location.capture("/recur?num="..tostring(num - 1)); ngx.print("status=", res.status, " "); ngx.print("body=", res.body); else @@ -353,7 +353,7 @@ location /sub { } location /parent { set $a 12; - content_by_lua 'res = ngx.location.capture("/sub"); ngx.print(res.body)'; + content_by_lua 'local res = ngx.location.capture("/sub"); ngx.print(res.body)'; } --- request GET /parent @@ -369,7 +369,7 @@ location /sub { location /parent { set $a 12; content_by_lua ' - res = ngx.location.capture( + local res = ngx.location.capture( "/sub", { share_all_vars = true } ); @@ -390,7 +390,7 @@ location /sub { } location /parent { content_by_lua ' - res = ngx.location.capture("/sub", { share_all_vars = true }); + local res = ngx.location.capture("/sub", { share_all_vars = true }); ngx.say(ngx.var.a) '; } @@ -408,7 +408,7 @@ location /sub { } location /parent { content_by_lua ' - res = ngx.location.capture("/sub", { share_all_vars = false }); + local res = ngx.location.capture("/sub", { share_all_vars = false }); ngx.say(ngx.var.a) '; } @@ -427,7 +427,7 @@ GET /parent location /lua { content_by_lua ' - res = ngx.location.capture("/other"); + local res = ngx.location.capture("/other"); ngx.say("type: ", res.header["Content-Type"]); '; } @@ -454,7 +454,7 @@ type: foo/bar location /lua { content_by_lua ' - res = ngx.location.capture("/other"); + local res = ngx.location.capture("/other"); ngx.say("type: ", type(res.header["Set-Cookie"])); ngx.say("len: ", #res.header["Set-Cookie"]); ngx.say("value: ", table.concat(res.header["Set-Cookie"], "|")) @@ -482,7 +482,7 @@ value: a|hello, world|foo location /lua { content_by_lua ' - res = ngx.location.capture("/other"); + local res = ngx.location.capture("/other"); ngx.say("type: ", res.header["Content-Type"]); ngx.say("Bar: ", res.header["Bar"]); '; @@ -507,7 +507,7 @@ Bar: Bah location /lua { content_by_lua ' - res = ngx.location.capture("/other"); + local res = ngx.location.capture("/other"); ngx.say("type: ", res.header["Content-Type"]); ngx.say("Bar: ", res.header["Bar"] or "nil"); '; @@ -524,7 +524,7 @@ Bar: nil --- config location /lua { content_by_lua ' - data = "hello, world" + local data = "hello, world" -- ngx.header["Content-Length"] = #data -- ngx.header.content_length = #data ngx.print(data) @@ -742,7 +742,7 @@ true --- config location /lua { content_by_lua ' - data = "hello,\\nworld\\n" + local data = "hello,\\nworld\\n" ngx.header["Content-Length"] = #data ngx.say("hello,") ngx.flush() @@ -801,7 +801,7 @@ world } --- user_files >>> test.lua -v = ngx.var["request_uri"] +local v = ngx.var["request_uri"] ngx.print("request_uri: ", v, "\n") --- request GET /lua?a=1&b=2 diff --git a/debian/modules/http-lua/t/004-require.t b/debian/modules/http-lua/t/004-require.t index 35e04db..17e1d57 100644 --- a/debian/modules/http-lua/t/004-require.t +++ b/debian/modules/http-lua/t/004-require.t @@ -24,7 +24,7 @@ __DATA__ === TEST 1: sanity --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location /main { echo_location /load; @@ -85,7 +85,7 @@ hello, foo --- request GET /main --- user_files ---- response_body_like: ^[^;]+/servroot/html/\?.so$ +--- response_body_like: ^[^;]+/servroot(_\d+)?/html/\?\.so$ @@ -100,7 +100,7 @@ GET /main } --- request GET /main ---- response_body_like: ^[^;]+/servroot/html/\?.lua;.+\.lua;$ +--- response_body_like: ^[^;]+/servroot(_\d+)?/html/\?\.lua;(.+\.lua)?;*$ @@ -115,7 +115,7 @@ GET /main } --- request GET /main ---- response_body_like: ^[^;]+/servroot/html/\?.so;.+\.so;$ +--- response_body_like: ^[^;]+/servroot(_\d+)?/html/\?\.so;(.+\.so)?;*$ @@ -130,7 +130,7 @@ GET /main } --- request GET /main ---- response_body_like: ^.+\.lua;[^;]+/servroot/html/\?.lua$ +--- response_body_like: ^(.+\.lua)?;*?[^;]+/servroot(_\d+)?/html/\?\.lua$ @@ -145,7 +145,7 @@ GET /main } --- request GET /main ---- response_body_like: ^.+\.so;[^;]+/servroot/html/\?.so$ +--- response_body_like: ^(.+\.so)?;*?[^;]+/servroot(_\d+)?/html/\?\.so$ diff --git a/debian/modules/http-lua/t/005-exit.t b/debian/modules/http-lua/t/005-exit.t index a5a28b3..a416a75 100644 --- a/debian/modules/http-lua/t/005-exit.t +++ b/debian/modules/http-lua/t/005-exit.t @@ -452,7 +452,7 @@ Hi --- config location /lua { content_by_lua ' - function f () + local function f () ngx.say("hello") ngx.exit(200) end diff --git a/debian/modules/http-lua/t/009-log.t b/debian/modules/http-lua/t/009-log.t index 68c057f..cb3895b 100644 --- a/debian/modules/http-lua/t/009-log.t +++ b/debian/modules/http-lua/t/009-log.t @@ -414,6 +414,8 @@ GET /log --- config location /log { content_by_lua ' + local foo + local bar function foo() bar() end @@ -431,7 +433,7 @@ GET /log --- response_body done --- error_log eval -qr/\[error\] \S+: \S+ \[lua\] content_by_lua\(nginx\.conf:\d+\):7: bar\(\): hello, log12343.14159/ +qr/\[error\] \S+: \S+ \[lua\] content_by_lua\(nginx\.conf:\d+\):9: bar\(\): hello, log12343.14159/ @@ -439,6 +441,8 @@ qr/\[error\] \S+: \S+ \[lua\] content_by_lua\(nginx\.conf:\d+\):7: bar\(\): hell --- config location /log { content_by_lua ' + local foo + local bar function foo() return bar(5) end @@ -461,7 +465,7 @@ GET /log --- response_body done --- error_log eval -qr/\[error\] \S+: \S+ \[lua\] content_by_lua\(nginx\.conf:\d+\):8:(?: foo\(\):)? hello, log12343.14159/ +qr/\[error\] \S+: \S+ \[lua\] content_by_lua\(nginx\.conf:\d+\):10:(?: foo\(\):)? hello, log12343.14159/ @@ -472,6 +476,8 @@ qr/\[error\] \S+: \S+ \[lua\] content_by_lua\(nginx\.conf:\d+\):8:(?: foo\(\):)? } --- user_files >>> test.lua +local foo +local bar function foo() bar() end @@ -488,7 +494,7 @@ GET /log --- response_body done --- error_log eval -qr/\[error\] \S+: \S+ \[lua\] test.lua:6: bar\(\): hello, log12343.14159/ +qr/\[error\] \S+: \S+ \[lua\] test.lua:8: bar\(\): hello, log12343.14159/ diff --git a/debian/modules/http-lua/t/011-md5_bin.t b/debian/modules/http-lua/t/011-md5_bin.t index ae7c974..dc0fd9c 100644 --- a/debian/modules/http-lua/t/011-md5_bin.t +++ b/debian/modules/http-lua/t/011-md5_bin.t @@ -156,7 +156,7 @@ d41d8cd98f00b204e9800998ecf8427e --- config location = /t { content_by_lua ' - s = ngx.md5_bin(45) + local s = ngx.md5_bin(45) s = string.gsub(s, ".", function (c) return string.format("%02x", string.byte(c)) end) diff --git a/debian/modules/http-lua/t/013-base64.t b/debian/modules/http-lua/t/013-base64.t index 1cc27de..d1a8d8b 100644 --- a/debian/modules/http-lua/t/013-base64.t +++ b/debian/modules/http-lua/t/013-base64.t @@ -242,4 +242,4 @@ GET /t --- response_body_like: 500 Internal Server Error --- error_code: 500 --- error_log eval -qr/bad argument \#2 to 'encode_base64' \(boolean expected, got number\)|\[error\] .*? boolean argument only/ +qr/bad argument \#2 to 'encode_base64' \(boolean expected, got number\)|\[error\] .*? bad no_padding: boolean expected, got number/ diff --git a/debian/modules/http-lua/t/014-bugs.t b/debian/modules/http-lua/t/014-bugs.t index 9aadff0..dad084e 100644 --- a/debian/modules/http-lua/t/014-bugs.t +++ b/debian/modules/http-lua/t/014-bugs.t @@ -43,7 +43,7 @@ __DATA__ === TEST 1: sanity --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location /load { content_by_lua ' @@ -69,7 +69,7 @@ end === TEST 2: sanity --- http_config -lua_package_path '/home/agentz/rpm/BUILD/lua-yajl-1.1/build/?.so;/home/lz/luax/?.so;./?.so'; +lua_package_cpath '/home/agentz/rpm/BUILD/lua-yajl-1.1/build/?.so;/home/lz/luax/?.so;./?.so'; --- config location = '/report/listBidwordPrices4lzExtra.htm' { content_by_lua ' @@ -112,7 +112,7 @@ GET /report/listBidwordPrices4lzExtra.htm?words=123,156,2532 } location = /main { content_by_lua ' - res = ngx.location.capture("/memc?c=get&k=foo&v=") + local res = ngx.location.capture("/memc?c=get&k=foo&v=") ngx.say("1: ", res.body) res = ngx.location.capture("/memc?c=set&k=foo&v=bar"); @@ -204,7 +204,7 @@ https://github.com/chaoslawful/lua-nginx-module/issues/37 content_by_lua ' -- local yajl = require "yajl" ngx.header["Set-Cookie"] = {} - res = ngx.location.capture("/sub") + local res = ngx.location.capture("/sub") for i,j in pairs(res.header) do ngx.header[i] = j @@ -231,7 +231,7 @@ Set-Cookie: TestCookie2=bar.*" } --- user_files >>> foo.lua -res = {} +local res = {} res = {'good 1', 'good 2', 'good 3'} return ngx.redirect("/somedir/" .. ngx.escape_uri(res[math.random(1,#res)])) --- request @@ -579,7 +579,7 @@ $s -=== TEST 26: unexpected globals sharing by using _G +=== TEST 26: globals sharing by using _G --- config location /test { content_by_lua ' @@ -593,12 +593,12 @@ $s } --- pipelined_requests eval ["GET /test", "GET /test", "GET /test"] ---- response_body eval -["0", "0", "0"] +--- response_body_like eval +[qr/\A[036]\z/, qr/\A[147]\z/, qr/\A[258]\z/] -=== TEST 27: unexpected globals sharing by using _G (set_by_lua*) +=== TEST 27: globals sharing by using _G (set_by_lua*) --- config location /test { set_by_lua $a ' @@ -613,12 +613,12 @@ $s } --- pipelined_requests eval ["GET /test", "GET /test", "GET /test"] ---- response_body eval -["0", "0", "0"] +--- response_body_like eval +[qr/\A[036]\z/, qr/\A[147]\z/, qr/\A[258]\z/] -=== TEST 28: unexpected globals sharing by using _G (log_by_lua*) +=== TEST 28: globals sharing by using _G (log_by_lua*) --- http_config lua_shared_dict log_dict 100k; --- config @@ -633,19 +633,19 @@ $s if _G.t then _G.t = _G.t + 1 else - _G.t = 0 + _G.t = 1 end log_dict:set("cnt", t) '; } --- pipelined_requests eval ["GET /test", "GET /test", "GET /test"] ---- response_body eval -["0", "0", "0"] +--- response_body_like eval +[qr/\A[036]\z/, qr/\A[147]\z/, qr/\A[258]\z/] -=== TEST 29: unexpected globals sharing by using _G (header_filter_by_lua*) +=== TEST 29: globals sharing by using _G (header_filter_by_lua*) --- config location /test { header_filter_by_lua ' @@ -663,12 +663,12 @@ $s } --- pipelined_requests eval ["GET /test", "GET /test", "GET /test"] ---- response_body eval -["0", "0", "0"] +--- response_body_like eval +[qr/\A[036]\z/, qr/\A[147]\z/, qr/\A[258]\z/] -=== TEST 30: unexpected globals sharing by using _G (body_filter_by_lua*) +=== TEST 30: globals sharing by using _G (body_filter_by_lua*) --- config location /test { body_filter_by_lua ' @@ -686,8 +686,9 @@ $s } --- request GET /test ---- response_body -a0 +--- response_body_like eval +qr/\Aa[036] +\z/ --- no_error_log [error] @@ -846,7 +847,7 @@ ok === TEST 37: resolving names with a trailing dot --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location /t { resolver $TEST_NGINX_RESOLVER ipv6=off; @@ -864,7 +865,7 @@ GET /t === TEST 38: resolving names with a trailing dot --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua'; + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;'; server { listen 12354; @@ -891,7 +892,7 @@ args: foo=1&bar=2 === TEST 39: lua_code_cache off + setkeepalive --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config lua_code_cache off; location = /t { diff --git a/debian/modules/http-lua/t/016-resp-header.t b/debian/modules/http-lua/t/016-resp-header.t index 72c1e05..e38202b 100644 --- a/debian/modules/http-lua/t/016-resp-header.t +++ b/debian/modules/http-lua/t/016-resp-header.t @@ -8,7 +8,7 @@ use Test::Nginx::Socket::Lua; repeat_each(2); -plan tests => repeat_each() * (blocks() * 3 + 46); +plan tests => repeat_each() * (blocks() * 3 + 59); #no_diff(); no_long_string(); @@ -630,7 +630,46 @@ Cache-Control: private, no-store -=== TEST 32: set multi values to cache-control and override it with a single value +=== TEST 32: set single value to Link header +--- config + location = /t { + content_by_lua_block { + ngx.header.link = "; rel=preload" + ngx.say("Link: ", ngx.var.sent_http_link) + } + } +--- request +GET /t +--- response_headers +Link: ; rel=preload +--- response_body +Link: ; rel=preload + + + +=== TEST 33: set multi values to Link header +--- config + location = /t { + content_by_lua_block { + ngx.header.link = { + "; rel=preload", + "; rel=preload; as=style" + } + + ngx.say("Link: ", ngx.var.sent_http_link) + } + } +--- request +GET /t +--- response_headers +Link: ; rel=preload, ; rel=preload; as=style +--- response_body_like chop +^Link: ; rel=preload[;,] ; rel=preload; as=style$ +--- skip_nginx: 3: < 1.13.9 + + + +=== TEST 34: set multi values to cache-control and override it with a single value --- config location /lua { content_by_lua ' @@ -650,7 +689,30 @@ Cache-Control: no-cache -=== TEST 33: set multi values to cache-control and override it with multiple values +=== TEST 35: set multi values to Link header and override it with a single value +--- config + location /lua { + content_by_lua_block { + ngx.header.link = { + "; rel=preload", + "; rel=preload; as=style" + } + ngx.header.link = "; rel=preload" + ngx.say("Link: ", ngx.var.sent_http_link) + ngx.say("Link: ", ngx.header.link) + } + } +--- request + GET /lua +--- response_headers +Link: ; rel=preload +--- response_body +Link: ; rel=preload +Link: ; rel=preload + + + +=== TEST 36: set multi values to cache-control and override it with multiple values --- config location /lua { content_by_lua ' @@ -672,7 +734,37 @@ Cache-Control: no-cache[;,] blah[;,] foo$ -=== TEST 34: set the www-authenticate response header +=== TEST 37: set multi values to Link header and override it with multiple values +--- config + location /lua { + content_by_lua_block { + ngx.header.link = { + "; rel=preload", + "; rel=preload; as=style" + } + ngx.header.link = { + "; rel=preload", + "; rel=preload", + "; rel=preload; as=style" + } + ngx.say("Link: ", ngx.var.sent_http_link) + ngx.say("Link: ", table.concat(ngx.header.link, ", ")) + } + } +--- request + GET /lua +--- response_headers +Link: ; rel=preload, ; rel=preload, ; rel=preload; as=style +--- response_body_like chop +^Link: ; rel=preload[;,] ; rel=preload[;,] ; rel=preload; as=style +Link: ; rel=preload[;,] ; rel=preload[;,] ; rel=preload; as=style$ +--- no_error_log +[error] +--- skip_nginx: 4: < 1.13.9 + + + +=== TEST 38: set the www-authenticate response header --- config location /lua { content_by_lua ' @@ -689,7 +781,7 @@ WWW-Authenticate: blah -=== TEST 35: set and clear the www-authenticate response header +=== TEST 39: set and clear the www-authenticate response header --- config location /lua { content_by_lua ' @@ -707,7 +799,7 @@ Foo: nil -=== TEST 36: set multi values to cache-control and override it with multiple values (to reproduce a bug) +=== TEST 40: set multi values to cache-control and override it with multiple values (to reproduce a bug) --- config location /lua { content_by_lua ' @@ -727,7 +819,7 @@ Cache-Control: blah -=== TEST 37: set last-modified and return 304 +=== TEST 41: set last-modified and return 304 --- config location /lua { content_by_lua ' @@ -745,7 +837,7 @@ Last-Modified: Thu, 18 Nov 2010 11:27:35 GMT -=== TEST 38: set last-modified and return 200 +=== TEST 42: set last-modified and return 200 --- config location /lua { content_by_lua ' @@ -764,7 +856,7 @@ Thu, 18 Nov 2010 11:27:35 GMT -=== TEST 39: set response content-encoding header should bypass ngx_http_gzip_filter_module +=== TEST 43: set response content-encoding header should bypass ngx_http_gzip_filter_module --- config default_type text/plain; gzip on; @@ -781,13 +873,16 @@ GET /read --- more_headers Accept-Encoding: gzip --- response_headers -Content-Type: text/plain +Content-Encoding: gzip +--- no_error_log +[error] +http gzip filter --- response_body Hello, world, my dear friend! -=== TEST 40: no transform underscores (write) +=== TEST 44: no transform underscores (write) --- config lua_transform_underscores_in_response_headers off; location = /t { @@ -807,7 +902,7 @@ nil -=== TEST 41: with transform underscores (write) +=== TEST 45: with transform underscores (write) --- config lua_transform_underscores_in_response_headers on; location = /t { @@ -827,7 +922,7 @@ Hello -=== TEST 42: github issue #199: underscores in lua variables +=== TEST 46: github issue #199: underscores in lua variables --- config location /read { content_by_lua ' @@ -860,7 +955,7 @@ something: hello -=== TEST 43: set multiple response header +=== TEST 47: set multiple response header --- config location /read { content_by_lua ' @@ -880,7 +975,7 @@ text/my-plain-50 -=== TEST 44: set multiple response header and then reset and then clear +=== TEST 48: set multiple response header and then reset and then clear --- config location /read { content_by_lua ' @@ -909,7 +1004,7 @@ ok -=== TEST 45: set response content-type header for multiple times +=== TEST 49: set response content-type header for multiple times --- config location /read { content_by_lua ' @@ -927,7 +1022,7 @@ Hi -=== TEST 46: set Last-Modified response header for multiple times +=== TEST 50: set Last-Modified response header for multiple times --- config location /read { content_by_lua ' @@ -945,7 +1040,7 @@ ok -=== TEST 47: set Last-Modified response header and then clear +=== TEST 51: set Last-Modified response header and then clear --- config location /read { content_by_lua ' @@ -963,7 +1058,7 @@ ok -=== TEST 48: github #20: segfault caused by the nasty optimization in the nginx core (write) +=== TEST 52: github #20: segfault caused by the nasty optimization in the nginx core (write) --- config location = /t/ { header_filter_by_lua ' @@ -985,7 +1080,7 @@ Location: http://localhost:$ServerPort/t/ -=== TEST 49: github #20: segfault caused by the nasty optimization in the nginx core (read) +=== TEST 53: github #20: segfault caused by the nasty optimization in the nginx core (read) --- config location = /t/ { header_filter_by_lua ' @@ -1007,7 +1102,7 @@ Location: http://localhost:$ServerPort/t/ -=== TEST 50: github #20: segfault caused by the nasty optimization in the nginx core (read Location) +=== TEST 54: github #20: segfault caused by the nasty optimization in the nginx core (read Location) --- config location = /t/ { header_filter_by_lua ' @@ -1030,7 +1125,7 @@ Foo: /t/ -=== TEST 51: github #20: segfault caused by the nasty optimization in the nginx core (set Foo and read Location) +=== TEST 55: github #20: segfault caused by the nasty optimization in the nginx core (set Foo and read Location) --- config location = /t/ { header_filter_by_lua ' @@ -1054,7 +1149,7 @@ Foo: /t/ -=== TEST 52: case sensitive cache-control header +=== TEST 56: case sensitive cache-control header --- config location /lua { content_by_lua ' @@ -1071,7 +1166,24 @@ Cache-Control: private -=== TEST 53: clear Cache-Control when there was no Cache-Control +=== TEST 57: case sensitive Link header +--- config + location /lua { + content_by_lua_block { + ngx.header["link"] = "; rel=preload" + ngx.say("Link: ", ngx.var.sent_http_link) + } + } +--- request + GET /lua +--- raw_response_headers_like chop +link: ; rel=preload +--- response_body +Link: ; rel=preload + + + +=== TEST 58: clear Cache-Control when there was no Cache-Control --- config location /lua { content_by_lua ' @@ -1088,7 +1200,24 @@ Cache-Control: nil -=== TEST 54: set response content-type header +=== TEST 59: clear Link header when there was no Link +--- config + location /lua { + content_by_lua_block { + ngx.header["Link"] = nil + ngx.say("Link: ", ngx.var.sent_http_link) + } + } +--- request + GET /lua +--- raw_response_headers_unlike eval +qr/Link/i +--- response_body +Link: nil + + + +=== TEST 60: set response content-type header --- config location /read { content_by_lua ' @@ -1107,7 +1236,7 @@ s = content_type -=== TEST 55: set a number header name +=== TEST 61: set a number header name --- config location /lua { content_by_lua ' @@ -1126,7 +1255,7 @@ s = content_type -=== TEST 56: set a number header name (in a table value) +=== TEST 62: set a number header name (in a table value) --- config location /lua { content_by_lua ' @@ -1145,7 +1274,7 @@ foo: 32 -=== TEST 57: random access resp headers +=== TEST 63: random access resp headers --- config location /resp-header { content_by_lua ' @@ -1185,7 +1314,7 @@ bar: baz -=== TEST 58: iterating through raw resp headers +=== TEST 64: iterating through raw resp headers --- config location /resp-header { content_by_lua ' @@ -1221,7 +1350,7 @@ bar: nil -=== TEST 59: removed response headers +=== TEST 65: removed response headers --- config location /resp-header { content_by_lua ' @@ -1254,7 +1383,7 @@ bar: baz -=== TEST 60: built-in Content-Type header +=== TEST 66: built-in Content-Type header --- config location = /t { content_by_lua ' @@ -1287,7 +1416,7 @@ my content_type: text/plain -=== TEST 61: built-in Content-Length header +=== TEST 67: built-in Content-Length header --- config location = /t { content_by_lua ' @@ -1320,7 +1449,7 @@ my content_length: 3 -=== TEST 62: built-in Connection header +=== TEST 68: built-in Connection header --- config location = /t { content_by_lua ' @@ -1351,7 +1480,7 @@ my connection: close -=== TEST 63: built-in Transfer-Encoding header (chunked) +=== TEST 69: built-in Transfer-Encoding header (chunked) --- config location = /t { content_by_lua ' @@ -1383,7 +1512,7 @@ my transfer-encoding: chunked -=== TEST 64: built-in Transfer-Encoding header (none) +=== TEST 70: built-in Transfer-Encoding header (none) --- config location = /t { content_by_lua ' @@ -1416,7 +1545,7 @@ my transfer_encoding: nil -=== TEST 65: set Location (no host) +=== TEST 71: set Location (no host) --- config location = /t { content_by_lua ' @@ -1435,7 +1564,7 @@ Location: /foo/bar -=== TEST 66: set Location (with host) +=== TEST 72: set Location (with host) --- config location = /t { content_by_lua ' @@ -1454,7 +1583,7 @@ Location: http://test.com/foo/bar -=== TEST 67: ngx.header["Content-Type"] with ngx_gzip +=== TEST 73: ngx.header["Content-Type"] with ngx_gzip --- config gzip on; gzip_min_length 1; @@ -1478,7 +1607,7 @@ Content-Type: text/html; charset=utf-8 -=== TEST 68: ngx.header["Content-Type"] with "; blah" +=== TEST 74: ngx.header["Content-Type"] with "; blah" --- config location = /test2 { content_by_lua ' @@ -1498,84 +1627,11 @@ test -=== 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, err = ngx.resp.get_headers() - if err then - ngx.log(ngx.ERR, "err: ", err) - return ngx.exit(500) - end - - ngx.say(h["content-type"]) - } - } ---- request -GET /set/hello.png ---- response_headers -Content-Type: image/png ---- response_body -image/png ---- no_error_log -[error] - - - -=== TEST 72: exceeding max header limit (default 100) +=== TEST 75: exceeding max header limit (default 100) --- config location /resp-header { content_by_lua_block { - for i = 1, 99 do + for i = 1, 100 do ngx.header["Foo" .. i] = "Foo" end @@ -1605,11 +1661,11 @@ lua exceeding response header limit 101 > 100 -=== TEST 73: NOT exceeding max header limit (default 100) +=== TEST 76: NOT exceeding max header limit (default 100) --- config location /resp-header { content_by_lua_block { - for i = 1, 98 do + for i = 1, 99 do ngx.header["Foo" .. i] = "Foo" end @@ -1637,11 +1693,11 @@ lua exceeding response header limit -=== TEST 74: exceeding max header limit (custom limit, 3) +=== TEST 77: exceeding max header limit (custom limit, 3) --- config location /resp-header { content_by_lua_block { - for i = 1, 2 do + for i = 1, 3 do ngx.header["Foo" .. i] = "Foo" end @@ -1671,11 +1727,11 @@ lua exceeding response header limit 4 > 3 -=== TEST 75: NOT exceeding max header limit (custom limit, 3) +=== TEST 78: NOT exceeding max header limit (custom limit, 3) --- config location /resp-header { content_by_lua_block { - for i = 1, 1 do + for i = 1, 2 do ngx.header["Foo" .. i] = "Foo" end @@ -1699,3 +1755,211 @@ found 3 resp headers --- no_error_log [error] lua exceeding response header limit + + + +=== TEST 79: return nil if Content-Type is not set yet +--- config + location /t { + default_type text/html; + content_by_lua_block { + ngx.log(ngx.WARN, "Content-Type: ", ngx.header["content-type"]) + ngx.say("Content-Type: ", ngx.header["content-type"]) + } + } +--- request +GET /t +--- response_headers +Content-Type: text/html +--- response_body +Content-Type: nil +--- no_error_log +[error] +--- error_log +Content-Type: nil + + + +=== TEST 80: don't generate Content-Type when setting other response header +--- config + location = /backend { + content_by_lua_block { + ngx.say("foo") + } + header_filter_by_lua_block { + ngx.header.content_type = nil + } + } + + location = /t { + default_type text/html; + rewrite_by_lua_block { + ngx.header.blah = "foo" + } + proxy_pass http://127.0.0.1:$TEST_NGINX_SERVER_PORT/backend; + } +--- request +GET /t +--- response_body +foo +--- response_headers +blah: foo +!Content-Type +--- no_error_log +[error] + + + +=== TEST 81: don't generate Content-Type when getting other response header +--- config + location = /backend { + content_by_lua_block { + ngx.say("foo") + } + header_filter_by_lua_block { + ngx.header.content_type = nil + } + } + + location = /t { + default_type text/html; + rewrite_by_lua_block { + local h = ngx.header.content_length + } + proxy_pass http://127.0.0.1:$TEST_NGINX_SERVER_PORT/backend; + } +--- request +GET /t +--- response_body +foo +--- response_headers +!Content-Type +--- no_error_log +[error] + + + +=== TEST 82: don't generate Content-Type when getting it +--- config + location = /backend { + content_by_lua_block { + ngx.say("foo") + } + header_filter_by_lua_block { + ngx.header.content_type = nil + } + } + + location /t { + proxy_pass http://127.0.0.1:$TEST_NGINX_SERVER_PORT/backend; + header_filter_by_lua_block { + ngx.log(ngx.WARN, "Content-Type: ", ngx.header["content-type"]) + } + } +--- request +GET /t +--- response_body +foo +--- response_headers +!Content-Type +--- no_error_log +[error] +--- error_log +Content-Type: nil + + + +=== TEST 83: generate default Content-Type when setting other response header +--- config + location = /t { + default_type text/html; + content_by_lua_block { + ngx.header.blah = "foo" + ngx.say("foo") + } + } +--- request +GET /t +--- response_body +foo +--- response_headers +blah: foo +Content-Type: text/html +--- no_error_log +[error] + + + +=== TEST 84: don't generate Content-Type when calling ngx.resp.get_headers() +--- config + location = /backend { + content_by_lua_block { + ngx.say("foo") + } + header_filter_by_lua_block { + ngx.header.content_type = nil + } + } + + location /t { + proxy_pass http://127.0.0.1:$TEST_NGINX_SERVER_PORT/backend; + header_filter_by_lua_block { + local h, err = ngx.resp.get_headers() + if err then + ngx.log(ngx.ERR, "err: ", err) + return + end + + ngx.log(ngx.WARN, "Content-Type: ", h["content-type"]) + } + } +--- request +GET /t +--- response_body +foo +--- response_headers +!Content-Type +--- no_error_log +[error] +--- error_log +Content-Type: nil + + + +=== TEST 85: don't generate default Content-Type when Content-Type is cleared +--- config + location = /t { + default_type text/html; + content_by_lua_block { + ngx.header["Content-Type"] = nil + ngx.say("foo") + } + } +--- request +GET /t +--- response_body +foo +--- response_headers +!Content-Type +--- no_error_log +[error] + + + +=== TEST 86: don't generate default Content-Type when Content-Type is set +--- config + location = /t { + default_type text/html; + content_by_lua_block { + ngx.header["Content-Type"] = "application/json" + ngx.say("foo") + } + } +--- request +GET /t +--- response_body +foo +--- response_headers +Content-Type: application/json +--- no_error_log +[error] diff --git a/debian/modules/http-lua/t/017-exec.t b/debian/modules/http-lua/t/017-exec.t index 544b8bb..a73e93e 100644 --- a/debian/modules/http-lua/t/017-exec.t +++ b/debian/modules/http-lua/t/017-exec.t @@ -382,7 +382,7 @@ hello --- config location /lua { content_by_lua ' - function f () + local function f () ngx.exec("/hi") end @@ -524,7 +524,7 @@ hello --- config location /main { rewrite_by_lua ' - res = ngx.location.capture("/test_loc"); + local res = ngx.location.capture("/test_loc"); ngx.print("hello, ", res.body) '; content_by_lua return; diff --git a/debian/modules/http-lua/t/020-subrequest.t b/debian/modules/http-lua/t/020-subrequest.t index 658a1d2..5a386db 100644 --- a/debian/modules/http-lua/t/020-subrequest.t +++ b/debian/modules/http-lua/t/020-subrequest.t @@ -32,7 +32,7 @@ __DATA__ location /lua { content_by_lua ' - res = ngx.location.capture("/other", + local res = ngx.location.capture("/other", { method = ngx.HTTP_DELETE }); ngx.print(res.body) @@ -62,7 +62,7 @@ lua http subrequest "/other?" location /lua { content_by_lua ' - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { method = ngx.HTTP_DELETE }); ngx.print(res.body) @@ -90,7 +90,7 @@ DELETE location /t { content_by_lua ' - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { method = ngx.HTTP_POST }); ngx.print(res.body) @@ -114,7 +114,7 @@ POST location /lua { content_by_lua ' - res = ngx.location.capture("/other", + local res = ngx.location.capture("/other", { method = ngx.HTTP_HEAD }); ngx.print(res.body) @@ -141,7 +141,7 @@ GET /lua location /lua { content_by_lua ' - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { method = ngx.HTTP_GET }); ngx.print(res.body) @@ -169,7 +169,7 @@ GET location /lua { content_by_lua ' - res = ngx.location.capture("/foo") + local res = ngx.location.capture("/foo") ngx.print(res.body) '; @@ -196,7 +196,7 @@ GET location /lua { content_by_lua ' - res = ngx.location.capture("/foo", {}) + local res = ngx.location.capture("/foo", {}) ngx.print(res.body) '; @@ -226,7 +226,7 @@ GET location /lua { content_by_lua ' - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { method = ngx.HTTP_PUT, body = "hello" }); ngx.print(res.body) @@ -255,7 +255,7 @@ hello location /lua { content_by_lua ' - res = ngx.location.capture("/other", + local res = ngx.location.capture("/other", { method = ngx.HTTP_PUT, body = "hello" }); ngx.print(res.body) @@ -291,7 +291,7 @@ hello location /lua { content_by_lua ' - res = ngx.location.capture("/other", + local res = ngx.location.capture("/other", { method = ngx.HTTP_PUT, body = "hello" }); ngx.print(res.body) @@ -329,7 +329,7 @@ GET location /lua { content_by_lua ' - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { method = ngx.HTTP_POST, body = "hello" }); ngx.print(res.body) @@ -362,7 +362,7 @@ hello content_by_lua ' ngx.location.capture("/flush"); - res = ngx.location.capture("/memc"); + local res = ngx.location.capture("/memc"); ngx.say("GET: " .. res.status); res = ngx.location.capture("/memc", @@ -404,7 +404,7 @@ cached: hello ngx.location.capture("/flush", { share_all_vars = true }); - res = ngx.location.capture("/memc", + local res = ngx.location.capture("/memc", { share_all_vars = true }); ngx.say("GET: " .. res.status); @@ -435,7 +435,7 @@ cached: hello location /lua { content_by_lua ' - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { args = {} }) ngx.print(res.body) '; @@ -456,7 +456,7 @@ GET /lua location /lua { content_by_lua ' - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { args = { ["fo="] = "=>" } }) ngx.print(res.body) '; @@ -478,7 +478,7 @@ fo%3D=%3D%3E location /lua { content_by_lua ' - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { args = { ["fo="] = "=>", ["="] = ":" } }) ngx.print(res.body) @@ -503,7 +503,7 @@ GET /lua location /lua { content_by_lua ' - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { args = { foo = 3, bar = "hello" } }) ngx.print(res.body) @@ -526,7 +526,7 @@ GET /lua location /lua { content_by_lua ' - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { args = { [57] = "hi" } }) ngx.print(res.body) '; @@ -548,7 +548,7 @@ attempt to use a non-string key in the "args" option table location /lua { content_by_lua ' - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { args = { "hi" } }) ngx.print(res.body) '; @@ -570,7 +570,7 @@ attempt to use a non-string key in the "args" option table location /lua { content_by_lua ' - res = ngx.location.capture("/foo?a=3", + local res = ngx.location.capture("/foo?a=3", { args = { b = 4 } }) ngx.print(res.body) '; @@ -592,7 +592,7 @@ a=3&b=4 location /lua { content_by_lua ' - res = ngx.location.capture("/foo?a=3", + local res = ngx.location.capture("/foo?a=3", { args = "b=4" }) ngx.print(res.body) '; @@ -685,7 +685,7 @@ https://github.com/chaoslawful/lua-nginx-module/issues/38 location /lua { content_by_lua ' - res = ngx.location.capture("/other", + local res = ngx.location.capture("/other", { method = ngx.HTTP_GET }); ngx.say("header foo: [", res.body, "]") '; @@ -711,7 +711,7 @@ https://github.com/chaoslawful/lua-nginx-module/issues/38 location /lua { content_by_lua ' - res = ngx.location.capture("/other", + local res = ngx.location.capture("/other", { body = "abc" }); ngx.say("header foo: [", res.body, "]") '; @@ -746,8 +746,8 @@ header foo: [bar] } location /main { content_by_lua ' - res1, res2 = ngx.location.capture_multi({{"/a"}, {"/b"}}) - res3 = ngx.location.capture("/c") + local res1, res2 = ngx.location.capture_multi({{"/a"}, {"/b"}}) + local res3 = ngx.location.capture("/c") ngx.print(res1.body, res2.body, res3.body) '; } @@ -780,7 +780,7 @@ lua reuse free buf memory location /lua { content_by_lua ' - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { method = ngx.HTTP_POST, body = "hello" }); ngx.print(res.body) @@ -801,7 +801,7 @@ hello --- config location /lua { content_by_lua ' - res = ngx.location.capture("/foo.html") + local res = ngx.location.capture("/foo.html") ngx.say(res.status) ngx.say(res.header["Last-Modified"]) @@ -832,7 +832,7 @@ hello, static file$ location /lua { content_by_lua ' local ctx = {} - res = ngx.location.capture("/sub", { ctx = ctx }) + local res = ngx.location.capture("/sub", { ctx = ctx }) ngx.say(ctx.foo); ngx.say(ngx.ctx.foo); @@ -857,7 +857,7 @@ nil } location /lua { content_by_lua ' - res = ngx.location.capture("/sub", { ctx = ngx.ctx }) + local res = ngx.location.capture("/sub", { ctx = ngx.ctx }) ngx.say(ngx.ctx.foo); '; } @@ -885,7 +885,7 @@ bar location /t { content_by_lua ' - res = ngx.location.capture("/memc", + local res = ngx.location.capture("/memc", { method = ngx.HTTP_PUT, body = "hello 1234" }); -- ngx.say("PUT: " .. res.status); @@ -922,7 +922,7 @@ lua reuse free buf chain, but reallocate memory because location /lua { content_by_lua ' - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { method = ngx.HTTP_GET }); ngx.print(res.body) @@ -959,7 +959,7 @@ nil content_by_lua ' ngx.req.read_body() - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { method = ngx.HTTP_GET }); ngx.print(res.body) @@ -996,7 +996,7 @@ nil content_by_lua ' ngx.req.read_body() - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { method = ngx.HTTP_POST }); ngx.print(res.body) @@ -1033,7 +1033,7 @@ hello, world content_by_lua ' ngx.req.read_body() - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { method = ngx.HTTP_PUT }); ngx.print(res.body) @@ -1074,7 +1074,7 @@ lua subrequests cycle while processing "/t" location /lua { content_by_lua ' - res = ngx.location.capture("/other", + local res = ngx.location.capture("/other", { method = ngx.HTTP_OPTIONS }); ngx.print(res.body) @@ -1099,7 +1099,7 @@ OPTIONS location /lua { content_by_lua ' - res = ngx.location.capture("/other", + local res = ngx.location.capture("/other", { method = ngx.HTTP_OPTIONS, body = "hello world" }); ngx.print(res.body) @@ -1151,7 +1151,7 @@ r%5B%5D=http%3A%2F%2Fajax.googleapis.com%3A80%2Fajax%2Flibs%2Fjquery%2F1.7.2%2Fj location /main { content_by_lua ' - res = ngx.location.capture("/sub") + local res = ngx.location.capture("/sub") ngx.say("status: ", res.status) ngx.say("body: ", res.body) '; @@ -1172,7 +1172,7 @@ body: location /main { content_by_lua ' - res = ngx.location.capture("/sub") + local res = ngx.location.capture("/sub") ngx.say("status: ", res.status) ngx.say("body: ", res.body) '; @@ -1196,7 +1196,7 @@ body: location /main { content_by_lua ' - res = ngx.location.capture("/sub") + local res = ngx.location.capture("/sub") ngx.say("status: ", res.status) ngx.say("body: ", res.body) '; @@ -1242,7 +1242,7 @@ F(ngx_http_finalize_request) { location /main { content_by_lua ' - res = ngx.location.capture("/memc") + local res = ngx.location.capture("/memc") ngx.say("status: ", res.status) ngx.say("body: ", res.body) ngx.say("truncated: ", res.truncated) @@ -1312,7 +1312,7 @@ upstream prematurely closed connection location /main { content_by_lua ' - res = ngx.location.capture("/memc") + local res = ngx.location.capture("/memc") ngx.say("status: ", res.status) ngx.say("body: ", res.body) ngx.say("truncated: ", res.truncated) @@ -1385,7 +1385,7 @@ upstream timed out location /main { content_by_lua ' - res = ngx.location.capture("/proxy") + local res = ngx.location.capture("/proxy") ngx.say("status: ", res.status) ngx.say("body: ", res.body) ngx.say("truncated: ", res.truncated) @@ -1445,7 +1445,7 @@ upstream prematurely closed connection location /main { content_by_lua ' - res = ngx.location.capture("/proxy") + local res = ngx.location.capture("/proxy") ngx.say("status: ", res.status) ngx.say("body: ", res.body) ngx.say("truncated: ", res.truncated) @@ -1507,7 +1507,7 @@ upstream timed out location /main { content_by_lua ' - res = ngx.location.capture("/proxy") + local res = ngx.location.capture("/proxy") ngx.say("status: ", res.status) ngx.say("body: ", res.body) ngx.say("truncated: ", res.truncated) @@ -1567,7 +1567,7 @@ truncated: false location /main { content_by_lua ' - res = ngx.location.capture("/proxy") + local res = ngx.location.capture("/proxy") ngx.say("status: ", res.status) ngx.say("body: ", res.body) ngx.say("truncated: ", res.truncated) @@ -1630,7 +1630,7 @@ upstream timed out location /main { content_by_lua ' - res = ngx.location.capture("/proxy") + local res = ngx.location.capture("/proxy") ngx.say("status: ", res.status) ngx.say("body: ", res.body) ngx.say("truncated: ", res.truncated) @@ -1690,7 +1690,7 @@ truncated: false location /main { content_by_lua ' - res = ngx.location.capture("/proxy") + local res = ngx.location.capture("/proxy") ngx.say("status: ", res.status) ngx.say("body: ", res.body) ngx.say("truncated: ", res.truncated) @@ -1756,7 +1756,7 @@ upstream timed out ngx.req.read_body() for i = 1, 2 do - res = ngx.location.capture("/other", + local res = ngx.location.capture("/other", { method = ngx.HTTP_POST }); ngx.say(res.body) @@ -1796,7 +1796,7 @@ hello world ngx.req.read_body() for i = 1, 2 do - res = ngx.location.capture("/other", + local res = ngx.location.capture("/other", { method = ngx.HTTP_POST }); ngx.say(res.body) @@ -1836,7 +1836,7 @@ hello world ngx.req.read_body() for i = 1, 2 do - res = ngx.location.capture("/other", + local res = ngx.location.capture("/other", { method = ngx.HTTP_POST }); ngx.say(res.body) @@ -1916,7 +1916,7 @@ a client request body is buffered to a temporary file location /main { content_by_lua ' - res = ngx.location.capture("/proxy") + local res = ngx.location.capture("/proxy") ngx.say("status: ", res.status) ngx.say("body: ", res.body) ngx.say("truncated: ", res.truncated) @@ -1979,7 +1979,7 @@ upstream prematurely closed connection location /main { content_by_lua ' - res = ngx.location.capture("/proxy") + local res = ngx.location.capture("/proxy") ngx.say("status: ", res.status) ngx.say("body: ", res.body) ngx.say("truncated: ", res.truncated) @@ -2040,7 +2040,7 @@ upstream prematurely closed connection location /main { content_by_lua ' - res = ngx.location.capture("/proxy") + local res = ngx.location.capture("/proxy") ngx.say("status: ", res.status) ngx.say("body: ", res.body) ngx.say("truncated: ", res.truncated) @@ -2102,7 +2102,7 @@ upstream timed out location /main { content_by_lua ' - res = ngx.location.capture("/proxy") + local res = ngx.location.capture("/proxy") ngx.say("status: ", res.status) ngx.say("body: ", res.body) ngx.say("truncated: ", res.truncated) @@ -2160,7 +2160,7 @@ truncated: false location /main { content_by_lua ' - res = ngx.location.capture("/proxy") + local res = ngx.location.capture("/proxy") ngx.say("status: ", res.status) ngx.say("body: ", res.body) ngx.say("truncated: ", res.truncated) @@ -2219,7 +2219,7 @@ truncated: false location /main { content_by_lua ' - res = ngx.location.capture("/proxy") + local res = ngx.location.capture("/proxy") ngx.say("status: ", res.status) ngx.say("body: ", res.body) ngx.say("truncated: ", res.truncated) @@ -2288,7 +2288,7 @@ upstream prematurely closed connection } for i, method in ipairs(methods) do - res = ngx.location.capture("/other", + local res = ngx.location.capture("/other", { method = method }) ngx.print(res.body) end @@ -2324,7 +2324,7 @@ method: TRACE location /lua { content_by_lua ' - res = ngx.location.capture("/other", + local res = ngx.location.capture("/other", { method = ngx.HTTP_DELETE }); ngx.print(res.body) @@ -2353,7 +2353,7 @@ nil location /lua { content_by_lua ' ngx.req.read_body() - res = ngx.location.capture("/other", + local res = ngx.location.capture("/other", { method = ngx.HTTP_DELETE, always_forward_body = true }); ngx.print(res.body) @@ -2382,7 +2382,7 @@ hello world location /lua { content_by_lua ' ngx.req.read_body() - res = ngx.location.capture("/other", + local res = ngx.location.capture("/other", { method = ngx.HTTP_DELETE, always_forward_body = true }); ngx.print(res.body) @@ -2410,7 +2410,7 @@ hello world --- config location = /t { content_by_lua ' - res = ngx.location.capture("/sub") + local res = ngx.location.capture("/sub") ngx.print(res.body) '; } @@ -2603,7 +2603,7 @@ qr/Assertion .*? failed/ location = /t { content_by_lua ' - res = ngx.location.capture("/sub") + local res = ngx.location.capture("/sub") ngx.print(res.body) ngx.say("pr: User-Agent: ", ngx.var.http_user_agent) ngx.say("pr: Host: ", ngx.var.http_host) @@ -2636,7 +2636,7 @@ pr: Host: localhost location = /t { content_by_lua ' - res = ngx.location.capture("/sub") + local res = ngx.location.capture("/sub") ngx.print(res.body) ngx.say("pr: User-Agent: ", ngx.var.http_user_agent) ngx.say("pr: Host: ", ngx.var.http_host) @@ -2669,7 +2669,7 @@ pr: Host: localhost location = /t { content_by_lua ' - res = ngx.location.capture("/sub") + local res = ngx.location.capture("/sub") ngx.print(res.body) ngx.say("pr: User-Agent: ", ngx.var.http_user_agent) ngx.say("pr: Host: ", ngx.var.http_host) @@ -2699,7 +2699,7 @@ pr: Host: localhost location = /t { content_by_lua ' - res = ngx.location.capture("/sub") + local res = ngx.location.capture("/sub") ngx.print(res.body) ngx.say("pr: Cookie: ", ngx.var.http_cookie) '; @@ -2727,7 +2727,7 @@ pr: Cookie: foo; bar location = /t { content_by_lua ' - res = ngx.location.capture("/sub") + local res = ngx.location.capture("/sub") ngx.print(res.body) ngx.say("pr: Cookie: ", ngx.var.http_cookie) '; @@ -2750,7 +2750,7 @@ pr: Cookie: foo; bar --- config location /lua { content_by_lua ' - res = ngx.location.capture("/index.html", + local res = ngx.location.capture("/index.html", { method = ngx.HTTP_HEAD }); ngx.say("content-length: ", res.header["Content-Length"]) ngx.say("body: [", res.body, "]") diff --git a/debian/modules/http-lua/t/023-rewrite/client-abort.t b/debian/modules/http-lua/t/023-rewrite/client-abort.t index 117d17e..0d6f2b3 100644 --- a/debian/modules/http-lua/t/023-rewrite/client-abort.t +++ b/debian/modules/http-lua/t/023-rewrite/client-abort.t @@ -199,7 +199,7 @@ bad things happen location = /sub { proxy_ignore_client_abort on; - proxy_pass http://agentzh.org:12345/; + proxy_pass http://127.0.0.2:12345/; } location = /sleep { @@ -240,7 +240,7 @@ client prematurely closed connection location = /sub { proxy_ignore_client_abort off; - proxy_pass http://agentzh.org:12345/; + proxy_pass http://127.0.0.2:12345/; } --- request GET /t @@ -545,7 +545,7 @@ client prematurely closed connection return end - ok, err = sock:connect("127.0.0.1", $TEST_NGINX_REDIS_PORT) + local ok, err = sock:connect("127.0.0.1", $TEST_NGINX_REDIS_PORT) if not ok then ngx.log(ngx.ERR, "failed to connect: ", err) return diff --git a/debian/modules/http-lua/t/023-rewrite/exec.t b/debian/modules/http-lua/t/023-rewrite/exec.t index edd4607..59691cb 100644 --- a/debian/modules/http-lua/t/023-rewrite/exec.t +++ b/debian/modules/http-lua/t/023-rewrite/exec.t @@ -326,7 +326,7 @@ hello --- config location /main { rewrite_by_lua ' - res = ngx.location.capture("/test_loc"); + local res = ngx.location.capture("/test_loc"); ngx.print("hello, ", res.body) '; content_by_lua return; @@ -354,7 +354,7 @@ hello, bah --- config location /main { rewrite_by_lua ' - res = ngx.location.capture("/test_loc"); + local res = ngx.location.capture("/test_loc"); ngx.print("hello, ", res.body) '; content_by_lua return; diff --git a/debian/modules/http-lua/t/023-rewrite/mixed.t b/debian/modules/http-lua/t/023-rewrite/mixed.t index 0f742b2..5b38d3f 100644 --- a/debian/modules/http-lua/t/023-rewrite/mixed.t +++ b/debian/modules/http-lua/t/023-rewrite/mixed.t @@ -35,7 +35,7 @@ __DATA__ rewrite_by_lua ' ngx.location.capture("/flush"); - res = ngx.location.capture("/memc"); + local res = ngx.location.capture("/memc"); print("rewrite GET: " .. res.status); res = ngx.location.capture("/memc", @@ -49,7 +49,7 @@ __DATA__ content_by_lua ' ngx.location.capture("/flush"); - res = ngx.location.capture("/memc"); + local res = ngx.location.capture("/memc"); ngx.say("content GET: " .. res.status); res = ngx.location.capture("/memc", diff --git a/debian/modules/http-lua/t/023-rewrite/multi-capture.t b/debian/modules/http-lua/t/023-rewrite/multi-capture.t index 083ec78..a0a02b7 100644 --- a/debian/modules/http-lua/t/023-rewrite/multi-capture.t +++ b/debian/modules/http-lua/t/023-rewrite/multi-capture.t @@ -154,7 +154,7 @@ res2.body = b location /main { rewrite_by_lua ' - res = ngx.location.capture("/foo?n=1") + local res = ngx.location.capture("/foo?n=1") ngx.say("top res.status = " .. res.status) ngx.say("top res.body = [" .. res.body .. "]") '; diff --git a/debian/modules/http-lua/t/023-rewrite/req-socket.t b/debian/modules/http-lua/t/023-rewrite/req-socket.t index 87cbbbe..9292385 100644 --- a/debian/modules/http-lua/t/023-rewrite/req-socket.t +++ b/debian/modules/http-lua/t/023-rewrite/req-socket.t @@ -325,7 +325,7 @@ found the end of the stream === TEST 4: attempt to use the req socket across request boundary --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location /t { rewrite_by_lua ' @@ -376,7 +376,7 @@ hello world === TEST 5: receive until on request_body - receiveuntil(1) on the last byte of the body See https://groups.google.com/group/openresty/browse_thread/thread/43cf01da3c681aba for details --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location /t { rewrite_by_lua ' @@ -440,7 +440,7 @@ done === TEST 6: pipelined POST requests --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location /t { rewrite_by_lua ' diff --git a/debian/modules/http-lua/t/023-rewrite/sanity.t b/debian/modules/http-lua/t/023-rewrite/sanity.t index b90aa0e..73a85dc 100644 --- a/debian/modules/http-lua/t/023-rewrite/sanity.t +++ b/debian/modules/http-lua/t/023-rewrite/sanity.t @@ -69,7 +69,7 @@ GET /lua location /lua { # NOTE: the newline escape sequence must be double-escaped, as nginx config # parser will unescape first! - rewrite_by_lua 'v = ngx.var["request_uri"] ngx.print("request_uri: ", v, "\\n")'; + rewrite_by_lua 'local v = ngx.var["request_uri"] ngx.print("request_uri: ", v, "\\n")'; content_by_lua 'ngx.exit(ngx.OK)'; } --- request @@ -87,7 +87,7 @@ request_uri: /lua?a=1&b=2 } --- user_files >>> test.lua -v = ngx.var["request_uri"] +local v = ngx.var["request_uri"] ngx.print("request_uri: ", v, "\n") --- request GET /lua?a=1&b=2 @@ -140,7 +140,7 @@ result: -0.4090441561579 === TEST 7: read $arg_xxx --- config location = /lua { - rewrite_by_lua 'who = ngx.var.arg_who + rewrite_by_lua 'local who = ngx.var.arg_who ngx.print("Hello, ", who, "!")'; content_by_lua 'ngx.exit(ngx.OK)'; } @@ -159,7 +159,7 @@ Hello, agentzh! location /lua { rewrite_by_lua ' -res = ngx.location.capture("/other") +local res = ngx.location.capture("/other") ngx.print("status=", res.status, " ") ngx.print("body=", res.body) '; @@ -175,7 +175,7 @@ status=200 body=hello, world === TEST 9: capture non-existed location --- config location /lua { - rewrite_by_lua 'res = ngx.location.capture("/other"); ngx.print("status=", res.status)'; + rewrite_by_lua 'local res = ngx.location.capture("/other"); ngx.print("status=", res.status)'; content_by_lua 'ngx.exit(ngx.OK)'; } --- request @@ -187,7 +187,7 @@ GET /lua === TEST 10: invalid capture location (not as expected...) --- config location /lua { - rewrite_by_lua 'res = ngx.location.capture("*(#*"); ngx.say("res=", res.status)'; + rewrite_by_lua 'local res = ngx.location.capture("*(#*"); ngx.say("res=", res.status)'; content_by_lua 'ngx.exit(ngx.OK)'; } --- request @@ -270,7 +270,7 @@ end ngx.print("num is: ", num, "\\n"); if (num > 0) then - res = ngx.location.capture("/recur?num="..tostring(num - 1)); + local res = ngx.location.capture("/recur?num="..tostring(num - 1)); ngx.print("status=", res.status, " "); ngx.print("body=", res.body); else @@ -359,7 +359,7 @@ location /sub { } location /parent { set $a 12; - rewrite_by_lua 'res = ngx.location.capture("/sub"); ngx.print(res.body)'; + rewrite_by_lua 'local res = ngx.location.capture("/sub"); ngx.print(res.body)'; content_by_lua 'ngx.exit(ngx.OK)'; } --- request @@ -377,7 +377,7 @@ location /parent { set $a ''; rewrite_by_lua ' ngx.var.a = 12; - res = ngx.location.capture( + local res = ngx.location.capture( "/sub", { share_all_vars = true } ); @@ -399,7 +399,7 @@ location /sub { } location /parent { rewrite_by_lua ' - res = ngx.location.capture("/sub", { share_all_vars = true }); + local res = ngx.location.capture("/sub", { share_all_vars = true }); ngx.say(ngx.var.a) '; @@ -421,7 +421,7 @@ location /sub { location /parent { rewrite_by_lua ' - res = ngx.location.capture("/sub", { share_all_vars = false }); + local res = ngx.location.capture("/sub", { share_all_vars = false }); ngx.say(ngx.var.a) '; content_by_lua return; @@ -441,7 +441,7 @@ GET /parent location /lua { rewrite_by_lua ' - res = ngx.location.capture("/other"); + local res = ngx.location.capture("/other"); ngx.say("type: ", res.header["Content-Type"]); '; @@ -466,7 +466,7 @@ type: foo/bar location /lua { rewrite_by_lua ' - res = ngx.location.capture("/other"); + local res = ngx.location.capture("/other"); ngx.say("type: ", res.header["Content-Type"]); ngx.say("Bar: ", res.header["Bar"]); '; @@ -494,7 +494,7 @@ Bar: Bah location /lua { rewrite_by_lua ' - res = ngx.location.capture("/other"); + local res = ngx.location.capture("/other"); ngx.say("type: ", res.header["Content-Type"]); ngx.say("Bar: ", res.header["Bar"] or "nil"); '; diff --git a/debian/modules/http-lua/t/023-rewrite/socket-keepalive.t b/debian/modules/http-lua/t/023-rewrite/socket-keepalive.t index 489a70f..8b532ea 100644 --- a/debian/modules/http-lua/t/023-rewrite/socket-keepalive.t +++ b/debian/modules/http-lua/t/023-rewrite/socket-keepalive.t @@ -27,7 +27,7 @@ __DATA__ === TEST 1: sanity --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location /t { set $port $TEST_NGINX_MEMCACHED_PORT; @@ -104,7 +104,7 @@ lua tcp socket get keepalive peer: using connection === TEST 2: free up the whole connection pool if no active connections --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location /t { set $port $TEST_NGINX_MEMCACHED_PORT; @@ -177,7 +177,7 @@ received: OK === TEST 3: upstream sockets close prematurely --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config server_tokens off; keepalive_timeout 100ms; @@ -254,7 +254,7 @@ done === TEST 4: http keepalive --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config server_tokens off; location /t { @@ -815,7 +815,7 @@ lua tcp socket keepalive timeout: unlimited === TEST 11: sanity (uds) --- http_config eval " - lua_package_path '$::HtmlDir/?.lua;./?.lua'; + lua_package_path '$::HtmlDir/?.lua;./?.lua;;'; server { listen unix:$::HtmlDir/nginx.sock; default_type 'text/plain'; @@ -953,7 +953,7 @@ lua tcp socket get keepalive peer: using connection === TEST 13: github issue #110: ngx.exit with HTTP_NOT_FOUND causes worker process to exit --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config error_page 404 /404.html; location /t { diff --git a/debian/modules/http-lua/t/023-rewrite/subrequest.t b/debian/modules/http-lua/t/023-rewrite/subrequest.t index 5d1e8f0..cb8523c 100644 --- a/debian/modules/http-lua/t/023-rewrite/subrequest.t +++ b/debian/modules/http-lua/t/023-rewrite/subrequest.t @@ -27,7 +27,7 @@ __DATA__ location /lua { rewrite_by_lua ' - res = ngx.location.capture("/other", + local res = ngx.location.capture("/other", { method = ngx.HTTP_DELETE }); ngx.print(res.body) @@ -54,7 +54,7 @@ DELETE location /lua { rewrite_by_lua ' - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { method = ngx.HTTP_DELETE }); ngx.print(res.body) @@ -82,7 +82,7 @@ DELETE location /lua { rewrite_by_lua ' - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { method = ngx.HTTP_POST }); ngx.print(res.body) @@ -105,7 +105,7 @@ POST location /lua { rewrite_by_lua ' - res = ngx.location.capture("/other", + local res = ngx.location.capture("/other", { method = ngx.HTTP_HEAD }); ngx.print(res.body) @@ -131,7 +131,7 @@ GET /lua location /lua { rewrite_by_lua ' - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { method = ngx.HTTP_GET }); ngx.print(res.body) @@ -158,7 +158,7 @@ GET location /lua { rewrite_by_lua ' - res = ngx.location.capture("/foo") + local res = ngx.location.capture("/foo") ngx.print(res.body) '; @@ -184,7 +184,7 @@ GET location /lua { rewrite_by_lua ' - res = ngx.location.capture("/foo", {}) + local res = ngx.location.capture("/foo", {}) ngx.print(res.body) '; @@ -213,7 +213,7 @@ GET location /lua { rewrite_by_lua ' - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { method = ngx.HTTP_PUT, body = "hello" }); ngx.print(res.body) @@ -241,7 +241,7 @@ hello location /lua { rewrite_by_lua ' - res = ngx.location.capture("/other", + local res = ngx.location.capture("/other", { method = ngx.HTTP_PUT, body = "hello" }); ngx.print(res.body) @@ -276,7 +276,7 @@ hello location /lua { rewrite_by_lua ' - res = ngx.location.capture("/other", + local res = ngx.location.capture("/other", { method = ngx.HTTP_PUT, body = "hello" }); ngx.print(res.body) @@ -313,7 +313,7 @@ GET location /lua { rewrite_by_lua ' - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { method = ngx.HTTP_POST, body = "hello" }); ngx.print(res.body) @@ -345,7 +345,7 @@ hello rewrite_by_lua ' ngx.location.capture("/flush"); - res = ngx.location.capture("/memc"); + local res = ngx.location.capture("/memc"); ngx.say("GET: " .. res.status); res = ngx.location.capture("/memc", @@ -386,7 +386,7 @@ cached: hello ngx.location.capture("/flush", { share_all_vars = true }); - res = ngx.location.capture("/memc", + local res = ngx.location.capture("/memc", { share_all_vars = true }); ngx.say("GET: " .. res.status); @@ -417,7 +417,7 @@ cached: hello location /lua { rewrite_by_lua ' - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { args = {} }) ngx.print(res.body) '; @@ -437,7 +437,7 @@ GET /lua location /lua { rewrite_by_lua ' - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { args = { ["fo="] = "=>" } }) ngx.print(res.body) '; @@ -458,7 +458,7 @@ fo%3D=%3D%3E location /lua { rewrite_by_lua ' - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { args = { ["fo="] = "=>", ["="] = ":" } }) ngx.print(res.body) @@ -480,7 +480,7 @@ GET /lua location /lua { rewrite_by_lua ' - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { args = { foo = 3, bar = "hello" } }) ngx.print(res.body) @@ -502,7 +502,7 @@ GET /lua location /lua { rewrite_by_lua ' - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { args = { [57] = "hi" } }) ngx.print(res.body) '; @@ -523,7 +523,7 @@ GET /lua location /lua { rewrite_by_lua ' - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { args = { "hi" } }) ngx.print(res.body) '; @@ -544,7 +544,7 @@ GET /lua location /lua { rewrite_by_lua ' - res = ngx.location.capture("/foo?a=3", + local res = ngx.location.capture("/foo?a=3", { args = { b = 4 } }) ngx.print(res.body) '; @@ -565,7 +565,7 @@ a=3&b=4 location /lua { rewrite_by_lua ' - res = ngx.location.capture("/foo?a=3", + local res = ngx.location.capture("/foo?a=3", { args = "b=4" }) ngx.print(res.body) '; diff --git a/debian/modules/http-lua/t/023-rewrite/tcp-socket-timeout.t b/debian/modules/http-lua/t/023-rewrite/tcp-socket-timeout.t index 329c045..e713bb5 100644 --- a/debian/modules/http-lua/t/023-rewrite/tcp-socket-timeout.t +++ b/debian/modules/http-lua/t/023-rewrite/tcp-socket-timeout.t @@ -46,7 +46,7 @@ __DATA__ location /t1 { rewrite_by_lua ' local sock = ngx.socket.tcp() - local ok, err = sock:connect("agentzh.org", 12345) + local ok, err = sock:connect("127.0.0.2", 12345) if not ok then ngx.say("failed to connect: ", err) return @@ -63,7 +63,7 @@ GET /t1 failed to connect: timeout --- error_log lua tcp socket connect timeout: 100 -lua tcp socket connect timed out, when connecting to 172.105.207.225:12345 +lua tcp socket connect timed out, when connecting to 127.0.0.2:12345 --- timeout: 10 @@ -79,7 +79,7 @@ lua tcp socket connect timed out, when connecting to 172.105.207.225:12345 rewrite_by_lua ' local sock = ngx.socket.tcp() sock:settimeout(150) - local ok, err = sock:connect("agentzh.org", 12345) + local ok, err = sock:connect("127.0.0.2", 12345) if not ok then ngx.say("failed to connect: ", err) return @@ -114,7 +114,7 @@ lua tcp socket connect timeout: 150 rewrite_by_lua ' local sock = ngx.socket.tcp() sock:settimeout(nil) - local ok, err = sock:connect("agentzh.org", 12345) + local ok, err = sock:connect("127.0.0.2", 12345) if not ok then ngx.say("failed to connect: ", err) return @@ -149,7 +149,7 @@ lua tcp socket connect timeout: 102 rewrite_by_lua ' local sock = ngx.socket.tcp() sock:settimeout(0) - local ok, err = sock:connect("agentzh.org", 12345) + local ok, err = sock:connect("127.0.0.2", 12345) if not ok then ngx.say("failed to connect: ", err) return @@ -185,7 +185,7 @@ lua tcp socket connect timeout: 102 rewrite_by_lua ' local sock = ngx.socket.tcp() sock:settimeout(-1) - local ok, err = sock:connect("agentzh.org", 12345) + local ok, err = sock:connect("127.0.0.2", 12345) if not ok then ngx.say("failed to connect: ", err) return diff --git a/debian/modules/http-lua/t/023-rewrite/tcp-socket.t b/debian/modules/http-lua/t/023-rewrite/tcp-socket.t index 41aeab7..5258487 100644 --- a/debian/modules/http-lua/t/023-rewrite/tcp-socket.t +++ b/debian/modules/http-lua/t/023-rewrite/tcp-socket.t @@ -250,11 +250,11 @@ attempt to send data on a closed socket: } --- request GET /t ---- response_body +--- response_body_like connected: 1 request sent: 56 -first line received: HTTP/1.1 200 OK -second line received: Server: openresty +first line received: HTTP\/1\.1 200 OK +second line received: (?:Date|Server): .*? --- no_error_log [error] @@ -304,7 +304,7 @@ qr/connect\(\) failed \(\d+: Connection refused\)/ location /test { rewrite_by_lua ' local sock = ngx.socket.tcp() - local ok, err = sock:connect("agentzh.org", 12345) + local ok, err = sock:connect("127.0.0.2", 12345) ngx.say("connect: ", ok, " ", err) local bytes @@ -329,7 +329,7 @@ send: nil closed receive: nil closed close: nil closed --- error_log -lua tcp socket connect timed out, when connecting to 172.105.207.225:12345 +lua tcp socket connect timed out, when connecting to 127.0.0.2:12345 --- timeout: 10 @@ -940,7 +940,7 @@ close: 1 nil end end - ok, err = sock:close() + local ok, err = sock:close() ngx.say("close: ", ok, " ", err) '; @@ -1082,7 +1082,7 @@ close: 1 nil === TEST 19: cannot survive across request boundary (send) --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config server_tokens off; location /t { @@ -1143,7 +1143,7 @@ received: OK|failed to send request: closed)\$" === TEST 20: cannot survive across request boundary (receive) --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config server_tokens off; location /t { @@ -1214,7 +1214,7 @@ received: OK|failed to receive a line: closed \[nil\])$/ === TEST 21: cannot survive across request boundary (close) --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config server_tokens off; location /t { @@ -1285,7 +1285,7 @@ received: OK|failed to close: closed)$/ === TEST 22: cannot survive across request boundary (connect) --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config server_tokens off; location /t { @@ -2041,7 +2041,7 @@ close: 1 nil === TEST 33: bad request tries to connect --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config server_tokens off; location = /main { @@ -2097,7 +2097,7 @@ qr/runtime error: rewrite_by_lua\(nginx\.conf:\d+\):7: bad request/ === TEST 34: bad request tries to receive --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config server_tokens off; location = /main { @@ -2156,7 +2156,7 @@ qr/runtime error: rewrite_by_lua\(nginx\.conf:\d+\):14: bad request/ === TEST 35: bad request tries to send --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config server_tokens off; location = /main { @@ -2215,7 +2215,7 @@ qr/runtime error: rewrite_by_lua\(nginx\.conf:\d+\):14: bad request/ === TEST 36: bad request tries to close --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config server_tokens off; location = /main { @@ -2274,7 +2274,7 @@ qr/runtime error: rewrite_by_lua\(nginx\.conf:\d+\):14: bad request/ === TEST 37: bad request tries to set keepalive --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config server_tokens off; location = /main { @@ -2333,7 +2333,7 @@ qr/runtime error: rewrite_by_lua\(nginx\.conf:\d+\):14: bad request/ === TEST 38: bad request tries to receiveuntil --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config server_tokens off; location = /main { diff --git a/debian/modules/http-lua/t/023-rewrite/uthread-exec.t b/debian/modules/http-lua/t/023-rewrite/uthread-exec.t index 2bea7e7..9428bd6 100644 --- a/debian/modules/http-lua/t/023-rewrite/uthread-exec.t +++ b/debian/modules/http-lua/t/023-rewrite/uthread-exec.t @@ -23,7 +23,7 @@ __DATA__ --- config location /lua { rewrite_by_lua ' - function f() + local function f() ngx.exec("/foo") end @@ -59,7 +59,7 @@ i am foo --- config location /lua { rewrite_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.exec("/foo") end @@ -95,7 +95,7 @@ i am foo --- config location /lua { rewrite_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.exec("/foo") end @@ -178,12 +178,12 @@ hello foo --- config location /lua { rewrite_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.exec("/foo") end - function g() + local function g() ngx.sleep(1) end @@ -270,7 +270,7 @@ hello foo location /lua { client_body_timeout 12000ms; rewrite_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.exec("/foo") end diff --git a/debian/modules/http-lua/t/023-rewrite/uthread-exit.t b/debian/modules/http-lua/t/023-rewrite/uthread-exit.t index 6ebbb67..e25f7f8 100644 --- a/debian/modules/http-lua/t/023-rewrite/uthread-exit.t +++ b/debian/modules/http-lua/t/023-rewrite/uthread-exit.t @@ -24,7 +24,7 @@ __DATA__ --- config location /lua { rewrite_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.exit(0) end @@ -87,7 +87,7 @@ hello in thread --- config location /lua { rewrite_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -172,13 +172,13 @@ after --- config location /lua { rewrite_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.say("f") ngx.exit(0) end - function g() + local function g() ngx.sleep(1) ngx.say("g") end @@ -262,7 +262,7 @@ f --- config location /lua { rewrite_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.say("exiting the user thread") ngx.exit(0) @@ -298,10 +298,10 @@ exiting the user thread === TEST 5: exit in user thread (entry thread is still pending on the DNS resolver for ngx.socket.tcp) --- config location /lua { - resolver agentzh.org; + resolver 127.0.0.2:12345; resolver_timeout 12s; rewrite_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.sleep(0.001) ngx.exit(0) @@ -311,7 +311,7 @@ exiting the user thread ngx.thread.spawn(f) ngx.say("after") local sock = ngx.socket.tcp() - local ok, err = sock:connect("agentzh.org", 12345) + local ok, err = sock:connect("127.0.0.2", 12345) if not ok then ngx.say("failed to connect: ", err) return @@ -403,11 +403,11 @@ after === TEST 6: exit in user thread (entry thread is still pending on the DNS resolver for ngx.socket.udp) --- config location /lua { - resolver agentzh.org; + resolver 127.0.0.2:12345; #resolver 127.0.0.1; resolver_timeout 12s; rewrite_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.sleep(0.001) ngx.exit(0) @@ -510,7 +510,7 @@ after --- config location /lua { rewrite_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -521,7 +521,7 @@ after ngx.say("after") local sock = ngx.socket.tcp() sock:settimeout(12000) - local ok, err = sock:connect("172.105.207.225", 12345) + local ok, err = sock:connect("127.0.0.2", 12345) if not ok then ngx.say("failed to connect: ", err) return @@ -600,7 +600,7 @@ after --- config location /lua { rewrite_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -700,7 +700,7 @@ after --- config location /lua { rewrite_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -806,7 +806,7 @@ after --- config location /lua { rewrite_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -901,7 +901,7 @@ after --- config location /lua { rewrite_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -995,7 +995,7 @@ after location /lua { client_body_timeout 12000ms; rewrite_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -1080,7 +1080,7 @@ after location /lua { client_body_timeout 12000ms; rewrite_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -1164,7 +1164,7 @@ attempt to abort with pending subrequests location /lua { client_body_timeout 12000ms; rewrite_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.exit(0) end @@ -1247,7 +1247,7 @@ attempt to abort with pending subrequests location /lua { client_body_timeout 12000ms; rewrite_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.exit(0) end diff --git a/debian/modules/http-lua/t/023-rewrite/uthread-redirect.t b/debian/modules/http-lua/t/023-rewrite/uthread-redirect.t index 83de1a3..0e636f7 100644 --- a/debian/modules/http-lua/t/023-rewrite/uthread-redirect.t +++ b/debian/modules/http-lua/t/023-rewrite/uthread-redirect.t @@ -25,7 +25,7 @@ __DATA__ location /lua { client_body_timeout 12000ms; rewrite_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.redirect(301) end @@ -113,7 +113,7 @@ attempt to abort with pending subrequests --- config location /lua { rewrite_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.redirect(301) end diff --git a/debian/modules/http-lua/t/023-rewrite/uthread-spawn.t b/debian/modules/http-lua/t/023-rewrite/uthread-spawn.t index 5552107..dccef87 100644 --- a/debian/modules/http-lua/t/023-rewrite/uthread-spawn.t +++ b/debian/modules/http-lua/t/023-rewrite/uthread-spawn.t @@ -23,7 +23,7 @@ __DATA__ --- config location /lua { rewrite_by_lua ' - function f() + local function f() ngx.say("hello in thread") end @@ -68,11 +68,11 @@ after --- config location /lua { rewrite_by_lua ' - function f() + local function f() ngx.say("in thread 1") end - function g() + local function g() ngx.say("in thread 2") end @@ -117,7 +117,7 @@ after 2 --- config location /lua { rewrite_by_lua ' - function f() + local function f() ngx.say("before sleep") ngx.sleep(0.1) ngx.say("after sleep") @@ -154,13 +154,13 @@ after sleep --- config location /lua { rewrite_by_lua ' - function f() + local function f() ngx.say("1: before sleep") ngx.sleep(0.2) ngx.say("1: after sleep") end - function g() + local function g() ngx.say("2: before sleep") ngx.sleep(0.1) ngx.say("2: after sleep") @@ -210,7 +210,7 @@ delete thread 2 --- config location /lua { rewrite_by_lua ' - function f() + local function f() ngx.blah() end @@ -241,9 +241,9 @@ qr/lua user thread aborted: runtime error: rewrite_by_lua\(nginx\.conf:\d+\):3: --- config location /lua { rewrite_by_lua ' - function f() + local function f() ngx.say("before capture") - res = ngx.location.capture("/proxy") + local res = ngx.location.capture("/proxy") ngx.say("after capture: ", res.body) end @@ -287,7 +287,7 @@ after capture: hello world --- config location /lua { rewrite_by_lua ' - function f() + local function f() ngx.say("before capture") local res = ngx.location.capture("/proxy?foo") ngx.say("after capture: ", res.body) @@ -340,7 +340,7 @@ after capture: hello foo --- config location /lua { rewrite_by_lua ' - function f() + local function f() ngx.say("before capture") local res = ngx.location.capture("/proxy?foo") ngx.say("after capture: ", res.body) @@ -394,13 +394,13 @@ capture: hello bar --- config location /lua { rewrite_by_lua ' - function f() + local function f() ngx.say("f: before capture") local res = ngx.location.capture("/proxy?foo") ngx.say("f: after capture: ", res.body) end - function g() + local function g() ngx.say("g: before capture") local res = ngx.location.capture("/proxy?bah") ngx.say("g: after capture: ", res.body) @@ -472,7 +472,8 @@ g: after capture: hello bah --- config location /lua { rewrite_by_lua ' - function f() + local g + local function f() ngx.say("before g") ngx.thread.spawn(g) ngx.say("after g") @@ -518,7 +519,8 @@ after g --- config location /lua { rewrite_by_lua ' - function f() + local g + local function f() ngx.say("before g") ngx.thread.spawn(g) ngx.say("after g") @@ -566,7 +568,7 @@ hello in g() location /lua { rewrite_by_lua ' local co - function f() + local function f() co = coroutine.running() ngx.sleep(0.1) end @@ -599,7 +601,7 @@ status: running location /lua { rewrite_by_lua ' local co - function f() + local function f() co = coroutine.running() end @@ -631,7 +633,8 @@ status: zombie location /lua { rewrite_by_lua ' local co - function f() + local g + local function f() co = coroutine.running() local co2 = coroutine.create(g) coroutine.resume(co2) @@ -670,7 +673,8 @@ status: normal --- config location /lua { rewrite_by_lua ' - function f() + local g + local function f() ngx.say("before g") ngx.thread.spawn(g) ngx.say("after g") @@ -717,7 +721,7 @@ after f rewrite_by_lua ' local yield = coroutine.yield - function f() + local function f() local self = coroutine.running() ngx.say("f 1") yield(self) @@ -770,7 +774,7 @@ f 3 rewrite_by_lua ' local yield = coroutine.yield - function f() + local function f() local self = coroutine.running() ngx.say("f 1") yield(self) @@ -779,7 +783,7 @@ f 3 ngx.say("f 3") end - function g() + local function g() local self = coroutine.running() ngx.say("g 1") yield(self) @@ -826,7 +830,7 @@ g 3 --- config location /lua { rewrite_by_lua ' - function f() + local function f() ngx.say("hello in thread") coroutine.yield(coroutine.running) ngx.flush(true) @@ -863,12 +867,12 @@ after --- config location /lua { rewrite_by_lua ' - function f() + local function f() ngx.say("hello from f") ngx.flush(true) end - function g() + local function g() ngx.say("hello from g") ngx.flush(true) end @@ -914,7 +918,7 @@ hello from g --- config location /lua { rewrite_by_lua ' - function f() + local function f() local sock = ngx.socket.tcp() local ok, err = sock:connect("127.0.0.1", $TEST_NGINX_MEMCACHED_PORT) if not ok then @@ -966,7 +970,7 @@ received: OK --- config location /lua { rewrite_by_lua ' - function f() + local function f() local sock = ngx.socket.udp() local ok, err = sock:setpeername("127.0.0.1", 12345) local bytes, err = sock:send("blah") @@ -1027,7 +1031,7 @@ after)$ --- config location /lua { rewrite_by_lua ' - function f() + local function f() ngx.req.read_body() local body = ngx.req.get_body_data() ngx.say("body: ", body) @@ -1073,7 +1077,7 @@ body: hello world)$ --- config location /lua { rewrite_by_lua ' - function f() + local function f() local sock = ngx.req.socket() local body, err = sock:receive(11) if not body then diff --git a/debian/modules/http-lua/t/024-access/client-abort.t b/debian/modules/http-lua/t/024-access/client-abort.t index c16f4ea..83bf0a4 100644 --- a/debian/modules/http-lua/t/024-access/client-abort.t +++ b/debian/modules/http-lua/t/024-access/client-abort.t @@ -200,7 +200,7 @@ bad things happen location = /sub { proxy_ignore_client_abort on; - proxy_pass http://agentzh.org:12345/; + proxy_pass http://127.0.0.2:12345/; } location = /sleep { @@ -241,7 +241,7 @@ client prematurely closed connection location = /sub { proxy_ignore_client_abort off; - proxy_pass http://agentzh.org:12345/; + proxy_pass http://127.0.0.2:12345/; } --- request GET /t @@ -546,7 +546,7 @@ client prematurely closed connection return end - ok, err = sock:connect("127.0.0.1", $TEST_NGINX_REDIS_PORT) + local ok, err = sock:connect("127.0.0.1", $TEST_NGINX_REDIS_PORT) if not ok then ngx.log(ngx.ERR, "failed to connect: ", err) return diff --git a/debian/modules/http-lua/t/024-access/exec.t b/debian/modules/http-lua/t/024-access/exec.t index 43c1a77..d168a47 100644 --- a/debian/modules/http-lua/t/024-access/exec.t +++ b/debian/modules/http-lua/t/024-access/exec.t @@ -326,7 +326,7 @@ hello --- config location /main { access_by_lua ' - res = ngx.location.capture("/test_loc"); + local res = ngx.location.capture("/test_loc"); ngx.print("hello, ", res.body) '; content_by_lua return; diff --git a/debian/modules/http-lua/t/024-access/mixed.t b/debian/modules/http-lua/t/024-access/mixed.t index a9f8039..22f0037 100644 --- a/debian/modules/http-lua/t/024-access/mixed.t +++ b/debian/modules/http-lua/t/024-access/mixed.t @@ -35,7 +35,7 @@ __DATA__ access_by_lua ' ngx.location.capture("/flush"); - res = ngx.location.capture("/memc"); + local res = ngx.location.capture("/memc"); print("access GET: ", res.status); res = ngx.location.capture("/memc", @@ -49,7 +49,7 @@ __DATA__ content_by_lua ' ngx.location.capture("/flush"); - res = ngx.location.capture("/memc"); + local res = ngx.location.capture("/memc"); ngx.say("content GET: " .. res.status); res = ngx.location.capture("/memc", @@ -187,7 +187,7 @@ world\x03\x04\xff rewrite_by_lua ' ngx.location.capture("/flush"); - res = ngx.location.capture("/memc"); + local res = ngx.location.capture("/memc"); print("rewrite GET: " .. res.status); res = ngx.location.capture("/memc", @@ -201,7 +201,7 @@ world\x03\x04\xff access_by_lua ' ngx.location.capture("/flush"); - res = ngx.location.capture("/memc"); + local res = ngx.location.capture("/memc"); print("access GET: " .. res.status); res = ngx.location.capture("/memc", @@ -215,7 +215,7 @@ world\x03\x04\xff content_by_lua ' ngx.location.capture("/flush"); - res = ngx.location.capture("/memc"); + local res = ngx.location.capture("/memc"); ngx.say("content GET: " .. res.status); res = ngx.location.capture("/memc", diff --git a/debian/modules/http-lua/t/024-access/multi-capture.t b/debian/modules/http-lua/t/024-access/multi-capture.t index 930b74d..b1757dd 100644 --- a/debian/modules/http-lua/t/024-access/multi-capture.t +++ b/debian/modules/http-lua/t/024-access/multi-capture.t @@ -154,7 +154,7 @@ res2.body = b location /main { access_by_lua ' - res = ngx.location.capture("/foo?n=1") + local res = ngx.location.capture("/foo?n=1") ngx.say("top res.status = " .. res.status) ngx.say("top res.body = [" .. res.body .. "]") '; diff --git a/debian/modules/http-lua/t/024-access/sanity.t b/debian/modules/http-lua/t/024-access/sanity.t index 7ff177f..e5612a8 100644 --- a/debian/modules/http-lua/t/024-access/sanity.t +++ b/debian/modules/http-lua/t/024-access/sanity.t @@ -69,7 +69,7 @@ GET /lua location /lua { # NOTE: the newline escape sequence must be double-escaped, as nginx config # parser will unescape first! - access_by_lua 'v = ngx.var["request_uri"] ngx.print("request_uri: ", v, "\\n")'; + access_by_lua 'local v = ngx.var["request_uri"] ngx.print("request_uri: ", v, "\\n")'; content_by_lua 'ngx.exit(ngx.OK)'; } --- request @@ -87,7 +87,7 @@ request_uri: /lua?a=1&b=2 } --- user_files >>> test.lua -v = ngx.var["request_uri"] +local v = ngx.var["request_uri"] ngx.print("request_uri: ", v, "\n") --- request GET /lua?a=1&b=2 @@ -140,7 +140,7 @@ result: -0.4090441561579 === TEST 7: read $arg_xxx --- config location = /lua { - access_by_lua 'who = ngx.var.arg_who + access_by_lua 'local who = ngx.var.arg_who ngx.print("Hello, ", who, "!")'; content_by_lua 'ngx.exit(ngx.OK)'; } @@ -159,7 +159,7 @@ Hello, agentzh! location /lua { access_by_lua ' -res = ngx.location.capture("/other") +local res = ngx.location.capture("/other") ngx.print("status=", res.status, " ") ngx.print("body=", res.body) '; @@ -175,7 +175,7 @@ status=200 body=hello, world === TEST 9: capture non-existed location --- config location /lua { - access_by_lua 'res = ngx.location.capture("/other"); ngx.print("status=", res.status)'; + access_by_lua 'local res = ngx.location.capture("/other"); ngx.print("status=", res.status)'; content_by_lua 'ngx.exit(ngx.OK)'; } --- request @@ -187,7 +187,7 @@ GET /lua === TEST 10: invalid capture location (not as expected...) --- config location /lua { - access_by_lua 'res = ngx.location.capture("*(#*"); ngx.say("res=", res.status)'; + access_by_lua 'local res = ngx.location.capture("*(#*"); ngx.say("res=", res.status)'; content_by_lua 'ngx.exit(ngx.OK)'; } --- request @@ -244,7 +244,7 @@ GET /lua ngx.print("num is: ", num, "\\n"); if (num > 0) then - res = ngx.location.capture("/recur?num="..tostring(num - 1)); + local res = ngx.location.capture("/recur?num="..tostring(num - 1)); ngx.print("status=", res.status, " "); ngx.print("body=", res.body, "\\n"); else @@ -271,7 +271,7 @@ access phase not running in subrequests ngx.print("num is: ", num, "\\n"); if (num > 0) then - res = ngx.location.capture("/recur?num="..tostring(num - 1)); + local res = ngx.location.capture("/recur?num="..tostring(num - 1)); ngx.print("status=", res.status, " "); ngx.print("body=", res.body); else @@ -357,7 +357,7 @@ location /sub { } location /parent { set $a 12; - access_by_lua 'res = ngx.location.capture("/sub"); ngx.print(res.body)'; + access_by_lua 'local res = ngx.location.capture("/sub"); ngx.print(res.body)'; content_by_lua 'ngx.exit(ngx.OK)'; } --- request @@ -375,7 +375,7 @@ location /parent { set $a ''; access_by_lua ' ngx.var.a = 12; - res = ngx.location.capture( + local res = ngx.location.capture( "/sub", { share_all_vars = true } ); @@ -397,7 +397,7 @@ location /sub { } location /parent { access_by_lua ' - res = ngx.location.capture("/sub", { share_all_vars = true }); + local res = ngx.location.capture("/sub", { share_all_vars = true }); ngx.say(ngx.var.a) '; @@ -419,7 +419,7 @@ location /sub { location /parent { access_by_lua ' - res = ngx.location.capture("/sub", { share_all_vars = false }); + local res = ngx.location.capture("/sub", { share_all_vars = false }); ngx.say(ngx.var.a) '; content_by_lua return; @@ -439,7 +439,7 @@ GET /parent location /lua { access_by_lua ' - res = ngx.location.capture("/other"); + local res = ngx.location.capture("/other"); ngx.say("type: ", res.header["Content-Type"]); '; @@ -464,7 +464,7 @@ type: foo/bar location /lua { access_by_lua ' - res = ngx.location.capture("/other"); + local res = ngx.location.capture("/other"); ngx.say("type: ", res.header["Content-Type"]); ngx.say("Bar: ", res.header["Bar"]); '; @@ -492,7 +492,7 @@ Bar: Bah location /lua { access_by_lua ' - res = ngx.location.capture("/other"); + local res = ngx.location.capture("/other"); ngx.say("type: ", res.header["Content-Type"]); ngx.say("Bar: ", res.header["Bar"] or "nil"); '; diff --git a/debian/modules/http-lua/t/024-access/subrequest.t b/debian/modules/http-lua/t/024-access/subrequest.t index b6ccf11..665780a 100644 --- a/debian/modules/http-lua/t/024-access/subrequest.t +++ b/debian/modules/http-lua/t/024-access/subrequest.t @@ -27,7 +27,7 @@ __DATA__ location /lua { access_by_lua ' - res = ngx.location.capture("/other", + local res = ngx.location.capture("/other", { method = ngx.HTTP_DELETE }); ngx.print(res.body) @@ -54,7 +54,7 @@ DELETE location /lua { access_by_lua ' - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { method = ngx.HTTP_DELETE }); ngx.print(res.body) @@ -82,7 +82,7 @@ DELETE location /lua { access_by_lua ' - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { method = ngx.HTTP_POST }); ngx.print(res.body) @@ -105,7 +105,7 @@ POST location /lua { access_by_lua ' - res = ngx.location.capture("/other", + local res = ngx.location.capture("/other", { method = ngx.HTTP_HEAD }); ngx.print(res.body) @@ -131,7 +131,7 @@ GET /lua location /lua { access_by_lua ' - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { method = ngx.HTTP_GET }); ngx.print(res.body) @@ -158,7 +158,7 @@ GET location /lua { access_by_lua ' - res = ngx.location.capture("/foo") + local res = ngx.location.capture("/foo") ngx.print(res.body) '; @@ -184,7 +184,7 @@ GET location /lua { access_by_lua ' - res = ngx.location.capture("/foo", {}) + local res = ngx.location.capture("/foo", {}) ngx.print(res.body) '; @@ -213,7 +213,7 @@ GET location /lua { access_by_lua ' - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { method = ngx.HTTP_PUT, body = "hello" }); ngx.print(res.body) @@ -241,7 +241,7 @@ hello location /lua { access_by_lua ' - res = ngx.location.capture("/other", + local res = ngx.location.capture("/other", { method = ngx.HTTP_PUT, body = "hello" }); ngx.print(res.body) @@ -276,7 +276,7 @@ hello location /lua { access_by_lua ' - res = ngx.location.capture("/other", + local res = ngx.location.capture("/other", { method = ngx.HTTP_PUT, body = "hello" }); ngx.print(res.body) @@ -313,7 +313,7 @@ GET location /lua { access_by_lua ' - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { method = ngx.HTTP_POST, body = "hello" }); ngx.print(res.body) @@ -345,7 +345,7 @@ hello access_by_lua ' ngx.location.capture("/flush"); - res = ngx.location.capture("/memc"); + local res = ngx.location.capture("/memc"); ngx.say("GET: " .. res.status); res = ngx.location.capture("/memc", @@ -386,7 +386,7 @@ cached: hello ngx.location.capture("/flush", { share_all_vars = true }); - res = ngx.location.capture("/memc", + local res = ngx.location.capture("/memc", { share_all_vars = true }); ngx.say("GET: " .. res.status); @@ -417,7 +417,7 @@ cached: hello location /lua { access_by_lua ' - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { args = {} }) ngx.print(res.body) '; @@ -437,7 +437,7 @@ GET /lua location /lua { access_by_lua ' - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { args = { ["fo="] = "=>" } }) ngx.print(res.body) '; @@ -458,7 +458,7 @@ fo%3D=%3D%3E location /lua { access_by_lua ' - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { args = { ["fo="] = "=>", ["="] = ":" } }) ngx.print(res.body) @@ -480,7 +480,7 @@ GET /lua location /lua { access_by_lua ' - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { args = { foo = 3, bar = "hello" } }) ngx.print(res.body) @@ -502,7 +502,7 @@ GET /lua location /lua { access_by_lua ' - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { args = { [57] = "hi" } }) ngx.print(res.body) '; @@ -523,7 +523,7 @@ GET /lua location /lua { access_by_lua ' - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { args = { "hi" } }) ngx.print(res.body) '; @@ -544,7 +544,7 @@ GET /lua location /lua { access_by_lua ' - res = ngx.location.capture("/foo?a=3", + local res = ngx.location.capture("/foo?a=3", { args = { b = 4 } }) ngx.print(res.body) '; @@ -565,7 +565,7 @@ a=3&b=4 location /lua { access_by_lua ' - res = ngx.location.capture("/foo?a=3", + local res = ngx.location.capture("/foo?a=3", { args = "b=4" }) ngx.print(res.body) '; diff --git a/debian/modules/http-lua/t/024-access/uthread-exec.t b/debian/modules/http-lua/t/024-access/uthread-exec.t index 7add3d4..9c88eb3 100644 --- a/debian/modules/http-lua/t/024-access/uthread-exec.t +++ b/debian/modules/http-lua/t/024-access/uthread-exec.t @@ -23,7 +23,7 @@ __DATA__ --- config location /lua { access_by_lua ' - function f() + local function f() ngx.exec("/foo") end @@ -59,7 +59,7 @@ i am foo --- config location /lua { access_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.exec("/foo") end @@ -95,7 +95,7 @@ i am foo --- config location /lua { access_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.exec("/foo") end @@ -179,12 +179,12 @@ hello foo --- config location /lua { access_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.exec("/foo") end - function g() + local function g() ngx.sleep(1) end @@ -271,7 +271,7 @@ hello foo location /lua { client_body_timeout 12000ms; access_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.exec("/foo") end diff --git a/debian/modules/http-lua/t/024-access/uthread-exit.t b/debian/modules/http-lua/t/024-access/uthread-exit.t index 02c2a1f..2757237 100644 --- a/debian/modules/http-lua/t/024-access/uthread-exit.t +++ b/debian/modules/http-lua/t/024-access/uthread-exit.t @@ -24,7 +24,7 @@ __DATA__ --- config location /lua { access_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.exit(0) end @@ -87,7 +87,7 @@ hello in thread --- config location /lua { access_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -172,13 +172,13 @@ after --- config location /lua { access_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.say("f") ngx.exit(0) end - function g() + local function g() ngx.sleep(1) ngx.say("g") end @@ -262,7 +262,7 @@ f --- config location /lua { access_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.say("exiting the user thread") ngx.exit(0) @@ -298,10 +298,10 @@ exiting the user thread === TEST 5: exit in user thread (entry thread is still pending on the DNS resolver for ngx.socket.tcp) --- config location /lua { - resolver agentzh.org; + resolver 127.0.0.2:12345; resolver_timeout 12s; access_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.sleep(0.001) ngx.exit(0) @@ -394,10 +394,10 @@ after === TEST 6: exit in user thread (entry thread is still pending on the DNS resolver for ngx.socket.udp) --- config location /lua { - resolver agentzh.org; + resolver 127.0.0.2:12345; resolver_timeout 12s; access_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.sleep(0.001) ngx.exit(0) @@ -491,7 +491,7 @@ after --- config location /lua { access_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -502,7 +502,7 @@ after ngx.say("after") local sock = ngx.socket.tcp() sock:settimeout(12000) - local ok, err = sock:connect("172.105.207.225", 12345) + local ok, err = sock:connect("127.0.0.2", 12345) if not ok then ngx.say("failed to connect: ", err) return @@ -582,7 +582,7 @@ after --- config location /lua { access_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -682,7 +682,7 @@ after --- config location /lua { access_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -788,7 +788,7 @@ after --- config location /lua { access_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -883,7 +883,7 @@ after --- config location /lua { access_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -977,7 +977,7 @@ after location /lua { client_body_timeout 12000ms; access_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -1062,7 +1062,7 @@ after location /lua { client_body_timeout 12000ms; access_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -1146,7 +1146,7 @@ attempt to abort with pending subrequests location /lua { client_body_timeout 12000ms; access_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.exit(0) end @@ -1229,7 +1229,7 @@ attempt to abort with pending subrequests location /lua { client_body_timeout 12000ms; access_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.exit(0) end diff --git a/debian/modules/http-lua/t/024-access/uthread-redirect.t b/debian/modules/http-lua/t/024-access/uthread-redirect.t index 4eb4759..cb99a35 100644 --- a/debian/modules/http-lua/t/024-access/uthread-redirect.t +++ b/debian/modules/http-lua/t/024-access/uthread-redirect.t @@ -25,7 +25,7 @@ __DATA__ location /lua { client_body_timeout 12000ms; access_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.redirect(301) end @@ -113,7 +113,7 @@ attempt to abort with pending subrequests --- config location /lua { access_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.redirect(301) end diff --git a/debian/modules/http-lua/t/024-access/uthread-spawn.t b/debian/modules/http-lua/t/024-access/uthread-spawn.t index 7c7ba3b..bc92ccd 100644 --- a/debian/modules/http-lua/t/024-access/uthread-spawn.t +++ b/debian/modules/http-lua/t/024-access/uthread-spawn.t @@ -23,7 +23,7 @@ __DATA__ --- config location /lua { access_by_lua ' - function f() + local function f() ngx.say("hello in thread") end @@ -68,11 +68,11 @@ after --- config location /lua { access_by_lua ' - function f() + local function f() ngx.say("in thread 1") end - function g() + local function g() ngx.say("in thread 2") end @@ -117,7 +117,7 @@ after 2 --- config location /lua { access_by_lua ' - function f() + local function f() ngx.say("before sleep") ngx.sleep(0.1) ngx.say("after sleep") @@ -154,13 +154,13 @@ after sleep --- config location /lua { access_by_lua ' - function f() + local function f() ngx.say("1: before sleep") ngx.sleep(0.2) ngx.say("1: after sleep") end - function g() + local function g() ngx.say("2: before sleep") ngx.sleep(0.1) ngx.say("2: after sleep") @@ -210,7 +210,7 @@ delete thread 2 --- config location /lua { access_by_lua ' - function f() + local function f() ngx.blah() end @@ -241,9 +241,9 @@ qr/lua user thread aborted: runtime error: access_by_lua\(nginx\.conf:\d+\):3: a --- config location /lua { access_by_lua ' - function f() + local function f() ngx.say("before capture") - res = ngx.location.capture("/proxy") + local res = ngx.location.capture("/proxy") ngx.say("after capture: ", res.body) end @@ -287,7 +287,7 @@ after capture: hello world --- config location /lua { access_by_lua ' - function f() + local function f() ngx.say("before capture") local res = ngx.location.capture("/proxy?foo") ngx.say("after capture: ", res.body) @@ -340,7 +340,7 @@ after capture: hello foo --- config location /lua { access_by_lua ' - function f() + local function f() ngx.say("before capture") local res = ngx.location.capture("/proxy?foo") ngx.say("after capture: ", res.body) @@ -395,13 +395,13 @@ capture: hello bar --- config location /lua { access_by_lua ' - function f() + local function f() ngx.say("f: before capture") local res = ngx.location.capture("/proxy?foo") ngx.say("f: after capture: ", res.body) end - function g() + local function g() ngx.say("g: before capture") local res = ngx.location.capture("/proxy?bah") ngx.say("g: after capture: ", res.body) @@ -473,7 +473,8 @@ g: after capture: hello bah --- config location /lua { access_by_lua ' - function f() + local g + local function f() ngx.say("before g") ngx.thread.spawn(g) ngx.say("after g") @@ -519,7 +520,8 @@ after g --- config location /lua { access_by_lua ' - function f() + local g + local function f() ngx.say("before g") ngx.thread.spawn(g) ngx.say("after g") @@ -567,7 +569,7 @@ hello in g() location /lua { access_by_lua ' local co - function f() + local function f() co = coroutine.running() ngx.sleep(0.1) end @@ -600,7 +602,7 @@ status: running location /lua { access_by_lua ' local co - function f() + local function f() co = coroutine.running() end @@ -632,7 +634,8 @@ status: zombie location /lua { access_by_lua ' local co - function f() + local g + local function f() co = coroutine.running() local co2 = coroutine.create(g) coroutine.resume(co2) @@ -671,7 +674,8 @@ status: normal --- config location /lua { access_by_lua ' - function f() + local g + local function f() ngx.say("before g") ngx.thread.spawn(g) ngx.say("after g") @@ -718,7 +722,7 @@ after f access_by_lua ' local yield = coroutine.yield - function f() + local function f() local self = coroutine.running() ngx.say("f 1") yield(self) @@ -771,7 +775,7 @@ f 3 access_by_lua ' local yield = coroutine.yield - function f() + local function f() local self = coroutine.running() ngx.say("f 1") yield(self) @@ -780,7 +784,7 @@ f 3 ngx.say("f 3") end - function g() + local function g() local self = coroutine.running() ngx.say("g 1") yield(self) @@ -827,7 +831,7 @@ g 3 --- config location /lua { access_by_lua ' - function f() + local function f() ngx.say("hello in thread") coroutine.yield(coroutine.running) ngx.flush(true) @@ -864,12 +868,12 @@ after --- config location /lua { access_by_lua ' - function f() + local function f() ngx.say("hello from f") ngx.flush(true) end - function g() + local function g() ngx.say("hello from g") ngx.flush(true) end @@ -915,7 +919,7 @@ hello from g --- config location /lua { access_by_lua ' - function f() + local function f() local sock = ngx.socket.tcp() local ok, err = sock:connect("127.0.0.1", $TEST_NGINX_MEMCACHED_PORT) if not ok then @@ -967,7 +971,7 @@ received: OK --- config location /lua { access_by_lua ' - function f() + local function f() local sock = ngx.socket.udp() local ok, err = sock:setpeername("127.0.0.1", 12345) local bytes, err = sock:send("blah") @@ -1028,7 +1032,7 @@ after)$ --- config location /lua { access_by_lua ' - function f() + local function f() ngx.req.read_body() local body = ngx.req.get_body_data() ngx.say("body: ", body) @@ -1073,7 +1077,7 @@ body: hello world)$ --- config location /lua { access_by_lua ' - function f() + local function f() local sock = ngx.req.socket() local body, err = sock:receive(11) if not body then diff --git a/debian/modules/http-lua/t/025-codecache.t b/debian/modules/http-lua/t/025-codecache.t index 20791d7..22b78b2 100644 --- a/debian/modules/http-lua/t/025-codecache.t +++ b/debian/modules/http-lua/t/025-codecache.t @@ -4,7 +4,7 @@ use Test::Nginx::Socket::Lua; repeat_each(2); -plan tests => repeat_each() * 155; +plan tests => repeat_each() * 163; #$ENV{LUA_PATH} = $ENV{HOME} . '/work/JSON4Lua-0.9.30/json/?.lua'; @@ -27,7 +27,7 @@ __DATA__ location /update { content_by_lua ' -- os.execute("(echo HERE; pwd) > /dev/stderr") - local f = assert(io.open("t/servroot/html/test.lua", "w")) + local f = assert(io.open("$TEST_NGINX_SERVER_ROOT/html/test.lua", "w")) f:write("ngx.say(101)") f:close() ngx.say("updated") @@ -61,7 +61,7 @@ updated location /update { content_by_lua ' -- os.execute("(echo HERE; pwd) > /dev/stderr") - local f = assert(io.open("t/servroot/html/test.lua", "w")) + local f = assert(io.open("$TEST_NGINX_SERVER_ROOT/html/test.lua", "w")) f:write("ngx.say(101)") f:close() ngx.say("updated") @@ -95,7 +95,7 @@ updated location /update { content_by_lua ' -- os.execute("(echo HERE; pwd) > /dev/stderr") - local f = assert(io.open("t/servroot/html/test.lua", "w")) + local f = assert(io.open("$TEST_NGINX_SERVER_ROOT/html/test.lua", "w")) f:write("ngx.say(101)") f:close() ngx.say("updated") @@ -130,7 +130,7 @@ qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/ location /update { content_by_lua ' -- os.execute("(echo HERE; pwd) > /dev/stderr") - local f = assert(io.open("t/servroot/html/test.lua", "w")) + local f = assert(io.open("$TEST_NGINX_SERVER_ROOT/html/test.lua", "w")) f:write("ngx.say(101)") f:close() ngx.say("updated") @@ -166,7 +166,7 @@ qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/ location /update { content_by_lua ' -- os.execute("(echo HERE; pwd) > /dev/stderr") - local f = assert(io.open("t/servroot/html/test.lua", "w")) + local f = assert(io.open("$TEST_NGINX_SERVER_ROOT/html/test.lua", "w")) f:write("ngx.say(101)") f:close() ngx.say("updated") @@ -193,7 +193,7 @@ qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/ === TEST 6: code cache explicitly off (affects require) + content_by_lua --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location /lua { lua_code_cache off; @@ -204,7 +204,7 @@ qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/ location /update { content_by_lua ' -- os.execute("(echo HERE; pwd) > /dev/stderr") - local f = assert(io.open("t/servroot/html/foo.lua", "w")) + local f = assert(io.open("$TEST_NGINX_SERVER_ROOT/html/foo.lua", "w")) f:write("module(..., package.seeall); ngx.say(102);") f:close() ngx.say("updated") @@ -231,7 +231,7 @@ qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/ === TEST 7: code cache explicitly off (affects require) + content_by_lua_file --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location /lua { lua_code_cache off; @@ -240,7 +240,7 @@ qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/ location /update { content_by_lua ' -- os.execute("(echo HERE; pwd) > /dev/stderr") - local f = assert(io.open("t/servroot/html/foo.lua", "w")) + local f = assert(io.open("$TEST_NGINX_SERVER_ROOT/html/foo.lua", "w")) f:write("module(..., package.seeall); ngx.say(102);") f:close() ngx.say("updated") @@ -269,7 +269,7 @@ qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/ === TEST 8: code cache explicitly off (affects require) + set_by_lua_file --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location /lua { lua_code_cache off; @@ -279,7 +279,7 @@ qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/ location /update { content_by_lua ' -- os.execute("(echo HERE; pwd) > /dev/stderr") - local f = assert(io.open("t/servroot/html/foo.lua", "w")) + local f = assert(io.open("$TEST_NGINX_SERVER_ROOT/html/foo.lua", "w")) f:write("module(..., package.seeall); return 102;") f:close() ngx.say("updated") @@ -308,7 +308,7 @@ qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/ === TEST 9: code cache explicitly on (affects require) + set_by_lua_file --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location /lua { lua_code_cache on; @@ -318,7 +318,7 @@ qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/ location /update { content_by_lua ' -- os.execute("(echo HERE; pwd) > /dev/stderr") - local f = assert(io.open("t/servroot/html/foo.lua", "w")) + local f = assert(io.open("$TEST_NGINX_SERVER_ROOT/html/foo.lua", "w")) f:write("module(..., package.seeall); return 102;") f:close() ngx.say("updated") @@ -355,7 +355,7 @@ updated location /update { content_by_lua ' -- os.execute("(echo HERE; pwd) > /dev/stderr") - local f = assert(io.open("t/servroot/html/test.lua", "w")) + local f = assert(io.open("$TEST_NGINX_SERVER_ROOT/html/test.lua", "w")) f:write("return 101") f:close() ngx.say("updated") @@ -390,7 +390,7 @@ qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/ location /update { content_by_lua ' -- os.execute("(echo HERE; pwd) > /dev/stderr") - local f = assert(io.open("t/servroot/html/test.lua", "w")) + local f = assert(io.open("$TEST_NGINX_SERVER_ROOT/html/test.lua", "w")) f:write("return 101") f:close() ngx.say("updated") @@ -468,7 +468,7 @@ qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/ === TEST 14: no clear builtin lib "string" --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config lua_code_cache off; location /lua { @@ -504,7 +504,7 @@ qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/ === TEST 15: do not skip luarocks --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua'; + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;'; lua_code_cache off;" --- config location /main { @@ -554,7 +554,7 @@ qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/ === TEST 16: do not skip luarocks* --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua'; + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;'; lua_code_cache off;" --- config location /main { @@ -604,7 +604,7 @@ qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/ === TEST 17: clear _G table --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config lua_code_cache off; location /t { @@ -1050,7 +1050,7 @@ qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/, === TEST 29: cosocket connection pool timeout (after Lua VM destroys) --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config lua_code_cache off; location = /t { @@ -1118,7 +1118,7 @@ qr/\blua tcp socket keepalive: free connection pool [0-9A-F]+ for "127.0.0.1:/, === TEST 30: cosocket connection pool timeout (before Lua VM destroys) --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config lua_code_cache off; location = /t { @@ -1244,3 +1244,133 @@ 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", ] + + + +=== TEST 32: make sure inline code keys are correct +GitHub issue #1428 +--- config +include ../html/a/proxy.conf; +include ../html/b/proxy.conf; +include ../html/c/proxy.conf; + +location /t { + echo_location /a/; + echo_location /b/; + echo_location /a/; + echo_location /c/; +} + +--- user_files +>>> a/proxy.conf +location /a/ { + content_by_lua_block { ngx.say("/a/ is called") } +} + +>>> b/proxy.conf +location /b/ { + content_by_lua_block { ngx.say("/b/ is called") } +} + +>>> c/proxy.conf +location /c/ { + content_by_lua_block { ngx.say("/b/ is called") } +} + +--- request +GET /t +--- response_body +/a/ is called +/b/ is called +/a/ is called +/b/ is called +--- grep_error_log eval: qr/looking up Lua code cache with key '.*?'/ +--- grep_error_log_out eval +[ +"looking up Lua code cache with key '=content_by_lua(proxy.conf:2)nhli_3c7137b8371d10bc148c8f8bb3042ee6' +looking up Lua code cache with key '=content_by_lua(proxy.conf:2)nhli_1dfe09105792ef65c8d576cc486d5e04' +looking up Lua code cache with key '=content_by_lua(proxy.conf:2)nhli_3c7137b8371d10bc148c8f8bb3042ee6' +looking up Lua code cache with key '=content_by_lua(proxy.conf:2)nhli_1dfe09105792ef65c8d576cc486d5e04' +", +"looking up Lua code cache with key '=content_by_lua(proxy.conf:2)nhli_3c7137b8371d10bc148c8f8bb3042ee6' +looking up Lua code cache with key '=content_by_lua(proxy.conf:2)nhli_1dfe09105792ef65c8d576cc486d5e04' +looking up Lua code cache with key '=content_by_lua(proxy.conf:2)nhli_3c7137b8371d10bc148c8f8bb3042ee6' +looking up Lua code cache with key '=content_by_lua(proxy.conf:2)nhli_1dfe09105792ef65c8d576cc486d5e04' +looking up Lua code cache with key '=content_by_lua(proxy.conf:2)nhli_3c7137b8371d10bc148c8f8bb3042ee6' +looking up Lua code cache with key '=content_by_lua(proxy.conf:2)nhli_1dfe09105792ef65c8d576cc486d5e04' +looking up Lua code cache with key '=content_by_lua(proxy.conf:2)nhli_3c7137b8371d10bc148c8f8bb3042ee6' +looking up Lua code cache with key '=content_by_lua(proxy.conf:2)nhli_1dfe09105792ef65c8d576cc486d5e04' +"] +--- log_level: debug +--- no_error_log +[error] + + + +=== TEST 33: make sure Lua code file keys are correct +GitHub issue #1428 +--- config +include ../html/a/proxy.conf; +include ../html/b/proxy.conf; +include ../html/c/proxy.conf; + +location /t { + echo_location /a/; + echo_location /b/; + echo_location /a/; + echo_location /c/; +} + +--- user_files +>>> a.lua +ngx.say("/a/ is called") + +>>> b.lua +ngx.say("/b/ is called") + +>>> c.lua +ngx.say("/b/ is called") + +>>> a/proxy.conf +location /a/ { + content_by_lua_file html/a.lua; +} + +>>> b/proxy.conf +location /b/ { + content_by_lua_file html/b.lua; +} + +>>> c/proxy.conf +location /c/ { + content_by_lua_file html/c.lua; +} + +--- request +GET /t +--- response_body +/a/ is called +/b/ is called +/a/ is called +/b/ is called +--- grep_error_log eval: qr/looking up Lua code cache with key '.*?'/ +--- grep_error_log_out eval +[ +"looking up Lua code cache with key 'nhlf_48a9a7def61143c003a7de1644e026e4' +looking up Lua code cache with key 'nhlf_68f5f4e946c3efd1cc206452b807e8b6' +looking up Lua code cache with key 'nhlf_48a9a7def61143c003a7de1644e026e4' +looking up Lua code cache with key 'nhlf_042c9b3a136fbacbbd0e4b9ad10896b7' +", +"looking up Lua code cache with key 'nhlf_48a9a7def61143c003a7de1644e026e4' +looking up Lua code cache with key 'nhlf_68f5f4e946c3efd1cc206452b807e8b6' +looking up Lua code cache with key 'nhlf_48a9a7def61143c003a7de1644e026e4' +looking up Lua code cache with key 'nhlf_042c9b3a136fbacbbd0e4b9ad10896b7' +looking up Lua code cache with key 'nhlf_48a9a7def61143c003a7de1644e026e4' +looking up Lua code cache with key 'nhlf_68f5f4e946c3efd1cc206452b807e8b6' +looking up Lua code cache with key 'nhlf_48a9a7def61143c003a7de1644e026e4' +looking up Lua code cache with key 'nhlf_042c9b3a136fbacbbd0e4b9ad10896b7' +" +] +--- log_level: debug +--- no_error_log +[error] diff --git a/debian/modules/http-lua/t/027-multi-capture.t b/debian/modules/http-lua/t/027-multi-capture.t index 9227fe5..9299561 100644 --- a/debian/modules/http-lua/t/027-multi-capture.t +++ b/debian/modules/http-lua/t/027-multi-capture.t @@ -151,7 +151,7 @@ res2.body = b location /main { content_by_lua ' - res = ngx.location.capture("/foo?n=1") + local res = ngx.location.capture("/foo?n=1") ngx.say("top res.status = " .. res.status) ngx.say("top res.body = [" .. res.body .. "]") '; @@ -743,7 +743,7 @@ proxy_cache_path conf/cache levels=1:2 keys_zone=STATIC:10m inactive=10m max_siz location = /proxy { proxy_cache STATIC; - proxy_pass http://agentzh.org:12345; + proxy_pass http://127.0.0.2:12345; proxy_cache_key $proxy_host$uri$args; proxy_cache_valid any 1s; #proxy_http_version 1.1; diff --git a/debian/modules/http-lua/t/028-req-header.t b/debian/modules/http-lua/t/028-req-header.t index ca92daa..8ddbb29 100644 --- a/debian/modules/http-lua/t/028-req-header.t +++ b/debian/modules/http-lua/t/028-req-header.t @@ -8,7 +8,7 @@ use Test::Nginx::Socket::Lua; repeat_each(2); -plan tests => repeat_each() * (2 * blocks() + 43); +plan tests => repeat_each() * (2 * blocks() + 44); #no_diff(); no_long_string(); @@ -2008,3 +2008,25 @@ found 3 headers. --- no_error_log lua exceeding request header limit [error] + + + +=== TEST 61: setting Host header clears cached $host variable +--- config + location /req-header { + # this makes $host indexed and cacheable + set $foo $host; + + content_by_lua_block { + ngx.say(ngx.var.host) + ngx.req.set_header("Host", "new"); + ngx.say(ngx.var.host) + } + } +--- request +GET /req-header +--- response_body +localhost +new +--- no_error_log +[error] diff --git a/debian/modules/http-lua/t/030-uri-args.t b/debian/modules/http-lua/t/030-uri-args.t index a9d46ff..7af63c4 100644 --- a/debian/modules/http-lua/t/030-uri-args.t +++ b/debian/modules/http-lua/t/030-uri-args.t @@ -421,7 +421,7 @@ done ngx.req.set_uri_args("hello") ngx.req.set_uri("/bar", true); '; - proxy_pass http://agentzh.org:12345; + proxy_pass http://127.0.0.2:12345; } --- request GET /foo?world @@ -568,7 +568,7 @@ HTTP/1.0 ca%20t=%25 ngx.req.set_uri("/bar", true); ngx.exit(503) '; - proxy_pass http://agentzh.org:12345; + proxy_pass http://127.0.0.2:12345; } --- request GET /foo?world @@ -586,7 +586,7 @@ hello #set $args 'hello'; set $err ''; access_by_lua ' - res, err = pcall(ngx.req.set_uri, "/bar", true); + local res, err = pcall(ngx.req.set_uri, "/bar", true); ngx.var.err = err '; echo "err: $err"; @@ -626,7 +626,7 @@ uri: /bar location /foo { #set $args 'hello'; content_by_lua ' - res, err = pcall(ngx.req.set_uri, "/bar", true); + local res, err = pcall(ngx.req.set_uri, "/bar", true); ngx.say("err: ", err) '; } @@ -665,7 +665,7 @@ uri: /bar location /foo { #set $args 'hello'; set_by_lua $err ' - res, err = pcall(ngx.req.set_uri, "/bar", true); + local res, err = pcall(ngx.req.set_uri, "/bar", true); return err '; echo "err: $err"; @@ -788,7 +788,7 @@ GET /lua location /lua { content_by_lua ' local t = {bar = ngx.shared.dogs, foo = 3} - rc, err = pcall(ngx.encode_args, t) + local rc, err = pcall(ngx.encode_args, t) ngx.say("rc: ", rc, ", err: ", err) '; } @@ -1112,6 +1112,7 @@ HTTP/1.0 a=3&b=5&b=6 --- config location /lua { content_by_lua ' + local err local args = "a=bar&b=foo" args, err = ngx.decode_args(args) @@ -1135,6 +1136,7 @@ b = foo --- config location /lua { content_by_lua ' + local err local args = "a=bar&b=foo&a=baz" args, err = ngx.decode_args(args) @@ -1158,6 +1160,7 @@ b = foo --- config location /lua { content_by_lua ' + local err local args = "" args, err = ngx.decode_args(args) if err then @@ -1178,6 +1181,7 @@ n = 0 --- config location /lua { content_by_lua ' + local err local args = "a&b" args, err = ngx.decode_args(args) if err then @@ -1200,6 +1204,7 @@ b = true --- config location /lua { content_by_lua ' + local err local args = "a=&b=" args, err = ngx.decode_args(args) @@ -1223,6 +1228,7 @@ b = --- config location /lua { content_by_lua ' + local err local args = "a=bar&b=foo" args, err = ngx.decode_args(args, 1) if err then @@ -1246,6 +1252,7 @@ b = nil --- config location /lua { content_by_lua ' + local err local args = "a=bar&b=foo" args, err = ngx.decode_args(args, -1) @@ -1270,7 +1277,7 @@ b = foo location /lua { content_by_lua ' local s = "f+f=bar&B=foo" - args, err = ngx.decode_args(s) + local args, err = ngx.decode_args(s) if err then ngx.say("err: ", err) end @@ -1302,7 +1309,7 @@ s = f+f=bar&B=foo lua_need_request_body on; location /t { content_by_lua ' - function split(s, delimiter) + local function split(s, delimiter) local result = {} local from = 1 local delim_from, delim_to = string.find(s, delimiter, from) diff --git a/debian/modules/http-lua/t/034-match.t b/debian/modules/http-lua/t/034-match.t index ebe5762..473a11f 100644 --- a/debian/modules/http-lua/t/034-match.t +++ b/debian/modules/http-lua/t/034-match.t @@ -21,7 +21,7 @@ __DATA__ --- config location /re { content_by_lua ' - m = ngx.re.match("hello, 1234", "([0-9]+)") + local m = ngx.re.match("hello, 1234", "([0-9]+)") if m then ngx.say(m[0]) else @@ -40,7 +40,7 @@ __DATA__ --- config location /re { content_by_lua ' - m = ngx.re.match("hello, 1234", "(\\\\d+)") + local m = ngx.re.match("hello, 1234", "(\\\\d+)") if m then ngx.say(m[0]) else @@ -59,7 +59,7 @@ __DATA__ --- config location /re { content_by_lua ' - m = ngx.re.match("hello, 1234", "(\\d+)") + local m = ngx.re.match("hello, 1234", "(\\d+)") if m then ngx.say(m[0]) else @@ -80,7 +80,7 @@ __DATA__ --- config location /re { content_by_lua ' - m = ngx.re.match("hello, 1234", "[[\\d+]]") + local m = ngx.re.match("hello, 1234", "[[\\d+]]") if m then ngx.say(m[0]) else @@ -101,7 +101,7 @@ __DATA__ --- config location /re { content_by_lua ' - m = ngx.re.match("hello, 1234", "([0-9]{2})[0-9]+") + local m = ngx.re.match("hello, 1234", "([0-9]{2})[0-9]+") if m then ngx.say(m[0]) ngx.say(m[1]) @@ -122,7 +122,7 @@ __DATA__ --- config location /re { content_by_lua ' - m = ngx.re.match("hello, 1234", "([a-z]+).*?([0-9]{2})[0-9]+", "") + local m = ngx.re.match("hello, 1234", "([a-z]+).*?([0-9]{2})[0-9]+", "") if m then ngx.say(m[0]) ngx.say(m[1]) @@ -145,7 +145,7 @@ hello --- config location /re { content_by_lua ' - m = ngx.re.match("hello, 1234", "([a-z]+).*?([0-9]{2})[0-9]+", "o") + local m = ngx.re.match("hello, 1234", "([a-z]+).*?([0-9]{2})[0-9]+", "o") if m then ngx.say(m[0]) ngx.say(m[1]) @@ -168,7 +168,7 @@ hello --- config location /re { content_by_lua ' - m = ngx.re.match("hello, 1234", "foo") + local m = ngx.re.match("hello, 1234", "foo") if m then ngx.say(m[0]) else @@ -187,7 +187,7 @@ not matched: nil --- config location /re { content_by_lua ' - m = ngx.re.match("hello, 1234", "HELLO") + local m = ngx.re.match("hello, 1234", "HELLO") if m then ngx.say(m[0]) else @@ -206,7 +206,7 @@ not matched: nil --- config location /re { content_by_lua ' - m = ngx.re.match("hello, 1234", "HELLO", "i") + local m = ngx.re.match("hello, 1234", "HELLO", "i") if m then ngx.say(m[0]) else @@ -225,7 +225,7 @@ hello --- config location /re { content_by_lua ' - rc, err = pcall(ngx.re.match, "hello章亦春", "HELLO.{2}", "iu") + local rc, err = pcall(ngx.re.match, "hello章亦春", "HELLO.{2}", "iu") if not rc then ngx.say("FAIL: ", err) return @@ -249,7 +249,7 @@ hello --- config location /re { content_by_lua ' - m = ngx.re.match("hello\\nworld", "^world", "m") + local m = ngx.re.match("hello\\nworld", "^world", "m") if m then ngx.say(m[0]) else @@ -268,7 +268,7 @@ world --- config location /re { content_by_lua ' - m = ngx.re.match("hello\\nworld", ".*", "m") + local m = ngx.re.match("hello\\nworld", ".*", "m") if m then ngx.say(m[0]) else @@ -287,7 +287,7 @@ hello --- config location /re { content_by_lua ' - m = ngx.re.match("hello\\nworld", "^world", "s") + local m = ngx.re.match("hello\\nworld", "^world", "s") if m then ngx.say(m[0]) else @@ -306,7 +306,7 @@ not matched: nil --- config location /re { content_by_lua ' - m = ngx.re.match("hello\\nworld", ".*", "s") + local m = ngx.re.match("hello\\nworld", ".*", "s") if m then ngx.say(m[0]) else @@ -326,7 +326,7 @@ world --- config location /re { content_by_lua ' - m = ngx.re.match("hello\\nworld", "\\\\w \\\\w", "x") + local m = ngx.re.match("hello\\nworld", "\\\\w \\\\w", "x") if m then ngx.say(m[0]) else @@ -372,7 +372,7 @@ error: pcre_compile() failed: missing ) in "(abc" --- config location /re { content_by_lua ' - rc, m = pcall(ngx.re.match, "hello\\nworld", ".*", "Hm") + local rc, m = pcall(ngx.re.match, "hello\\nworld", ".*", "Hm") if rc then if m then ngx.say(m[0]) @@ -395,7 +395,7 @@ error: .*?unknown flag "H" \(flags "Hm"\) --- config location /re { content_by_lua ' - m = ngx.re.match("hello, world", "(world)|(hello)", "x") + local m = ngx.re.match("hello, world", "(world)|(hello)", "x") if m then ngx.say(m[0]) ngx.say(m[1]) @@ -418,7 +418,7 @@ hello --- config location /re { content_by_lua ' - m = ngx.re.match("hello, 1234", "([0-9]+)(h?)") + local m = ngx.re.match("hello, 1234", "([0-9]+)(h?)") if m then ngx.say(m[0]) ngx.say(m[1]) @@ -442,7 +442,7 @@ hello --- config location /re { content_by_lua ' - m = ngx.re.match("hello, 1234", "([0-9]+)", "a") + local m = ngx.re.match("hello, 1234", "([0-9]+)", "a") if m then ngx.say(m[0]) else @@ -461,7 +461,7 @@ not matched! --- config location /re { content_by_lua ' - m = ngx.re.match("1234, hello", "([0-9]+)", "a") + local m = ngx.re.match("1234, hello", "([0-9]+)", "a") if m then ngx.say(m[0]) else @@ -481,7 +481,7 @@ not matched! location /re { content_by_lua ' local ctx = {} - m = ngx.re.match("1234, hello", "([0-9]+)", "", ctx) + local m = ngx.re.match("1234, hello", "([0-9]+)", "", ctx) if m then ngx.say(m[0]) ngx.say(ctx.pos) @@ -504,7 +504,7 @@ not matched! location /re { content_by_lua ' local ctx = { pos = 3 } - m = ngx.re.match("1234, hello", "([0-9]+)", "", ctx) + local m = ngx.re.match("1234, hello", "([0-9]+)", "", ctx) if m then ngx.say(m[0]) ngx.say(ctx.pos) @@ -526,7 +526,7 @@ not matched! --- config location /re { set_by_lua $res ' - m = ngx.re.match("hello, 1234", "([0-9]+)") + local m = ngx.re.match("hello, 1234", "([0-9]+)") if m then return m[0] else @@ -569,7 +569,7 @@ baz } --- user_files >>> a.lua -m = ngx.re.match("hello, 1234", "(\\\s+)") +local m = ngx.re.match("hello, 1234", "(\\\s+)") if m then ngx.say("[", m[0], "]") else @@ -595,7 +595,7 @@ end local uri = "2" local regex = '(?:>[\\w\\s]*)'; ngx.say("regex: ", regex) -m = ngx.re.match(uri, regex, "oi") +local m = ngx.re.match(uri, regex, "oi") if m then ngx.say("[", m[0], "]") else @@ -613,7 +613,7 @@ regex: (?:>[\w\s]*) --- config location /re { content_by_lua ' - m = ngx.re.match("hello, 1234", [[\\d+]]) + local m = ngx.re.match("hello, 1234", [[\\d+]]) if m then ngx.say(m[0]) else @@ -660,7 +660,7 @@ error: pcre_compile() failed: missing ) in "([0-9]+" --- config location /re { content_by_lua ' - m = ngx.re.match("hello, 1234", [[([0-9]+)]]) + local m = ngx.re.match("hello, 1234", [[([0-9]+)]]) if m then ngx.say(m[0]) else @@ -1027,7 +1027,7 @@ exec opts: 0 >>> a.lua local re = [==[(?i:([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:=|<=>|r?like|sounds\s+like|regexp)([\s'\"`´’‘\(\)]*)?\2|([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:!=|<=|>=|<>|<|>|\^|is\s+not|not\s+like|not\s+regexp)([\s'\"`´’‘\(\)]*)?(?!\6)([\d\w]+))]==] -s = string.rep([[ABCDEFG]], 10) +local s = string.rep([[ABCDEFG]], 10) local start = ngx.now() @@ -1067,7 +1067,7 @@ error: pcre_exec() failed: -8 >>> a.lua local re = [==[(?i:([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:=|<=>|r?like|sounds\s+like|regexp)([\s'\"`´’‘\(\)]*)?\2|([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:!=|<=|>=|<>|<|>|\^|is\s+not|not\s+like|not\s+regexp)([\s'\"`´’‘\(\)]*)?(?!\6)([\d\w]+))]==] -s = string.rep([[ABCDEFG]], 10) +local s = string.rep([[ABCDEFG]], 10) local start = ngx.now() @@ -1101,7 +1101,7 @@ failed to match content_by_lua ' local res = {} local s = "hello, 1234" - m = ngx.re.match(s, [[(\\d)(\\d)]], "o", nil, res) + local m = ngx.re.match(s, [[(\\d)(\\d)]], "o", nil, res) if m then ngx.say("1: m size: ", #m) ngx.say("1: res size: ", #res) @@ -1132,11 +1132,12 @@ failed to match === TEST 48: init_by_lua --- http_config init_by_lua ' - m = ngx.re.match("hello, 1234", "(\\\\d+)") + package.loaded.m = ngx.re.match("hello, 1234", "(\\\\d+)") '; --- config location /re { content_by_lua ' + local m = package.loaded.m if m then ngx.say(m[0]) else diff --git a/debian/modules/http-lua/t/035-gmatch.t b/debian/modules/http-lua/t/035-gmatch.t index 0426997..0dfeaea 100644 --- a/debian/modules/http-lua/t/035-gmatch.t +++ b/debian/modules/http-lua/t/035-gmatch.t @@ -123,7 +123,7 @@ nil --- config location /re { content_by_lua ' - it = ngx.re.gmatch("hello, 1234", "([0-9]+)", "a") + local it = ngx.re.gmatch("hello, 1234", "([0-9]+)", "a") ngx.say(it()) '; } @@ -418,7 +418,7 @@ hello content_by_lua ' local a = {} for i = 1, 3 do - it = ngx.re.gmatch("hello, world", "[a-z]+") + local it = ngx.re.gmatch("hello, world", "[a-z]+") it() collectgarbage() table.insert(a, {"hello", "world"}) @@ -482,9 +482,9 @@ end GET /main --- response_body matched -sr failed: 500 ---- error_log -attempt to use ngx.re.gmatch iterator in a request that did not create it +matched +--- no_error_log +[error] @@ -518,7 +518,7 @@ matched: [] location /re { content_by_lua ' local it = ngx.re.gmatch("1234, 1234", "(?[0-9]+)") - m = it() + local m = it() if m then ngx.say(m[0]) ngx.say(m[1]) @@ -555,7 +555,7 @@ matched: [] content_by_lua ' local it = ngx.re.gmatch("1234, abcd, 1234", "(?[0-9]+)|(?[a-z]+)") - m = it() + local m = it() if m then ngx.say(m[0]) ngx.say(m[1]) @@ -599,7 +599,7 @@ abcd location /re { content_by_lua ' local it = ngx.re.gmatch("hello, 1234", "(?[a-z]+), (?[0-9]+)", "D") - m = it() + local m = it() if m then ngx.say(m[0]) ngx.say(m[1]) @@ -825,7 +825,7 @@ exec opts: 0 >>> a.lua local re = [==[(?i:([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:=|<=>|r?like|sounds\s+like|regexp)([\s'\"`´’‘\(\)]*)?\2|([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:!=|<=|>=|<>|<|>|\^|is\s+not|not\s+like|not\s+regexp)([\s'\"`´’‘\(\)]*)?(?!\6)([\d\w]+))]==] -s = string.rep([[ABCDEFG]], 10) +local s = string.rep([[ABCDEFG]], 10) local start = ngx.now() @@ -871,7 +871,7 @@ error: pcre_exec() failed: -8 >>> a.lua local re = [==[(?i:([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:=|<=>|r?like|sounds\s+like|regexp)([\s'\"`´’‘\(\)]*)?\2|([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:!=|<=|>=|<>|<|>|\^|is\s+not|not\s+like|not\s+regexp)([\s'\"`´’‘\(\)]*)?(?!\6)([\d\w]+))]==] -s = string.rep([[ABCDEFG]], 10) +local s = string.rep([[ABCDEFG]], 10) local start = ngx.now() @@ -881,7 +881,7 @@ if not it then return end -res, err = it() +local res, err = it() --[[ ngx.update_time() diff --git a/debian/modules/http-lua/t/036-sub.t b/debian/modules/http-lua/t/036-sub.t index 2b4b075..3e88eba 100644 --- a/debian/modules/http-lua/t/036-sub.t +++ b/debian/modules/http-lua/t/036-sub.t @@ -590,7 +590,7 @@ s: a好 >>> a.lua local re = [==[(?i:([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:=|<=>|r?like|sounds\s+like|regexp)([\s'\"`´’‘\(\)]*)?\2|([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:!=|<=|>=|<>|<|>|\^|is\s+not|not\s+like|not\s+regexp)([\s'\"`´’‘\(\)]*)?(?!\6)([\d\w]+))]==] -s = string.rep([[ABCDEFG]], 10) +local s = string.rep([[ABCDEFG]], 10) local start = ngx.now() @@ -693,7 +693,7 @@ ab.cd location = /t { content_by_lua ' - function test() + local function test() local data = [[ OUTER {FIRST} ]] diff --git a/debian/modules/http-lua/t/037-gsub.t b/debian/modules/http-lua/t/037-gsub.t index 4c5810d..41f86ac 100644 --- a/debian/modules/http-lua/t/037-gsub.t +++ b/debian/modules/http-lua/t/037-gsub.t @@ -511,7 +511,7 @@ s: aa >>> a.lua local re = [==[(?i:([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:=|<=>|r?like|sounds\s+like|regexp)([\s'\"`´’‘\(\)]*)?\2|([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:!=|<=|>=|<>|<|>|\^|is\s+not|not\s+like|not\s+regexp)([\s'\"`´’‘\(\)]*)?(?!\6)([\d\w]+))]==] -s = string.rep([[ABCDEFG]], 10) +local s = string.rep([[ABCDEFG]], 10) local start = ngx.now() diff --git a/debian/modules/http-lua/t/038-match-o.t b/debian/modules/http-lua/t/038-match-o.t index d61ff1f..f6ae010 100644 --- a/debian/modules/http-lua/t/038-match-o.t +++ b/debian/modules/http-lua/t/038-match-o.t @@ -20,7 +20,7 @@ __DATA__ --- config location /re { content_by_lua ' - m = ngx.re.match("hello, 1234", "([0-9]+)", "o") + local m = ngx.re.match("hello, 1234", "([0-9]+)", "o") if m then ngx.say(m[0]) else @@ -39,7 +39,7 @@ __DATA__ --- config location /re { content_by_lua ' - m = ngx.re.match("hello, 1234", "(\\\\d+)", "o") + local m = ngx.re.match("hello, 1234", "(\\\\d+)", "o") if m then ngx.say(m[0]) else @@ -58,7 +58,7 @@ __DATA__ --- config location /re { content_by_lua ' - m = ngx.re.match("hello, 1234", "(\\d+)", "o") + local m = ngx.re.match("hello, 1234", "(\\d+)", "o") if m then ngx.say(m[0]) else @@ -79,7 +79,7 @@ __DATA__ --- config location /re { content_by_lua ' - m = ngx.re.match("hello, 1234", "[[\\d+]]", "o") + local m = ngx.re.match("hello, 1234", "[[\\d+]]", "o") if m then ngx.say(m[0]) else @@ -100,7 +100,7 @@ __DATA__ --- config location /re { content_by_lua ' - m = ngx.re.match("hello, 1234", "([0-9]{2})[0-9]+", "o") + local m = ngx.re.match("hello, 1234", "([0-9]{2})[0-9]+", "o") if m then ngx.say(m[0]) ngx.say(m[1]) @@ -121,7 +121,7 @@ __DATA__ --- config location /re { content_by_lua ' - m = ngx.re.match("hello, 1234", "([a-z]+).*?([0-9]{2})[0-9]+", "o") + local m = ngx.re.match("hello, 1234", "([a-z]+).*?([0-9]{2})[0-9]+", "o") if m then ngx.say(m[0]) ngx.say(m[1]) @@ -144,7 +144,7 @@ hello --- config location /re { content_by_lua ' - m = ngx.re.match("hello, 1234", "foo", "o") + local m = ngx.re.match("hello, 1234", "foo", "o") if m then ngx.say(m[0]) else @@ -163,7 +163,7 @@ not matched: nil --- config location /re { content_by_lua ' - m = ngx.re.match("hello, 1234", "HELLO", "o") + local m = ngx.re.match("hello, 1234", "HELLO", "o") if m then ngx.say(m[0]) else @@ -182,7 +182,7 @@ not matched: nil --- config location /re { content_by_lua ' - m = ngx.re.match("hello, 1234", "HELLO", "oi") + local m = ngx.re.match("hello, 1234", "HELLO", "oi") if m then ngx.say(m[0]) else @@ -224,7 +224,7 @@ this version of PCRE is not compiled with PCRE_UTF8 support|^hello章亦$ --- config location /re { content_by_lua ' - m = ngx.re.match("hello\\nworld", "^world", "mo") + local m = ngx.re.match("hello\\nworld", "^world", "mo") if m then ngx.say(m[0]) else @@ -243,7 +243,7 @@ world --- config location /re { content_by_lua ' - m = ngx.re.match("hello\\nworld", ".*", "om") + local m = ngx.re.match("hello\\nworld", ".*", "om") if m then ngx.say(m[0]) else @@ -262,7 +262,7 @@ hello --- config location /re { content_by_lua ' - m = ngx.re.match("hello\\nworld", "^world", "so") + local m = ngx.re.match("hello\\nworld", "^world", "so") if m then ngx.say(m[0]) else @@ -281,7 +281,7 @@ not matched: nil --- config location /re { content_by_lua ' - m = ngx.re.match("hello\\nworld", ".*", "os") + local m = ngx.re.match("hello\\nworld", ".*", "os") if m then ngx.say(m[0]) else @@ -301,7 +301,7 @@ world --- config location /re { content_by_lua ' - m = ngx.re.match("hello\\nworld", "\\\\w \\\\w", "xo") + local m = ngx.re.match("hello\\nworld", "\\\\w \\\\w", "xo") if m then ngx.say(m[0]) else @@ -347,7 +347,7 @@ error: pcre_compile() failed: missing ) in "(abc" --- config location /re { content_by_lua ' - rc, m = pcall(ngx.re.match, "hello\\nworld", ".*", "Ho") + local rc, m = pcall(ngx.re.match, "hello\\nworld", ".*", "Ho") if rc then if m then ngx.say(m[0]) @@ -370,7 +370,7 @@ error: pcre_compile() failed: missing ) in "(abc" --- config location /re { content_by_lua ' - m = ngx.re.match("hello, world", "(world)|(hello)", "xo") + local m = ngx.re.match("hello, world", "(world)|(hello)", "xo") if m then ngx.say(m[0]) ngx.say(m[1]) @@ -393,7 +393,7 @@ hello --- config location /re { content_by_lua ' - m = ngx.re.match("hello, 1234", "([0-9]+)(h?)", "o") + local m = ngx.re.match("hello, 1234", "([0-9]+)(h?)", "o") if m then ngx.say(m[0]) ngx.say(m[1]) @@ -417,7 +417,7 @@ hello --- config location /re { content_by_lua ' - m = ngx.re.match("hello, 1234", "([0-9]+)", "oa") + local m = ngx.re.match("hello, 1234", "([0-9]+)", "oa") if m then ngx.say(m[0]) else @@ -436,7 +436,7 @@ not matched! --- config location /re { content_by_lua ' - m = ngx.re.match("1234, hello", "([0-9]+)", "ao") + local m = ngx.re.match("1234, hello", "([0-9]+)", "ao") if m then ngx.say(m[0]) else @@ -456,7 +456,7 @@ not matched! location /re { content_by_lua ' local ctx = {} - m = ngx.re.match("1234, hello", "([0-9]+)", "o", ctx) + local m = ngx.re.match("1234, hello", "([0-9]+)", "o", ctx) if m then ngx.say(m[0]) ngx.say(ctx.pos) @@ -479,7 +479,7 @@ not matched! location /re { content_by_lua ' local ctx = { pos = 3 } - m = ngx.re.match("1234, hello", "([0-9]+)", "o", ctx) + local m = ngx.re.match("1234, hello", "([0-9]+)", "o", ctx) if m then ngx.say(m[0]) ngx.say(ctx.pos) @@ -501,7 +501,7 @@ not matched! --- config location /re { set_by_lua $res ' - m = ngx.re.match("hello, 1234", "([0-9]+)", "o") + local m = ngx.re.match("hello, 1234", "([0-9]+)", "o") if m then return m[0] else diff --git a/debian/modules/http-lua/t/041-header-filter.t b/debian/modules/http-lua/t/041-header-filter.t index 7d8ee74..0adc699 100644 --- a/debian/modules/http-lua/t/041-header-filter.t +++ b/debian/modules/http-lua/t/041-header-filter.t @@ -10,7 +10,7 @@ log_level('debug'); repeat_each(2); -plan tests => repeat_each() * 94; +plan tests => repeat_each() * (blocks() * 2 + 13); #no_diff(); #no_long_string(); @@ -416,7 +416,7 @@ lua release ngx.ctx -=== TEST 20: global got cleared for each single request +=== TEST 20: globals are shared by all requests --- config location /lua { set $foo ''; @@ -428,6 +428,7 @@ lua release ngx.ctx if not foo then foo = 1 else + ngx.log(ngx.INFO, "old foo: ", foo) foo = foo + 1 end ngx.var.foo = foo @@ -435,10 +436,13 @@ lua release ngx.ctx } --- request GET /lua ---- response_body -1 +--- response_body_like +^[12]$ --- no_error_log [error] +--- grep_error_log eval: qr/old foo: \d+/ +--- grep_error_log_out eval +["", "old foo: 1\n"] @@ -730,7 +734,8 @@ hello world --- config location /t { header_filter_by_lua ' - function foo() + local bar + local function foo() bar() end diff --git a/debian/modules/http-lua/t/043-shdict.t b/debian/modules/http-lua/t/043-shdict.t index 9183bf5..b0528e5 100644 --- a/debian/modules/http-lua/t/043-shdict.t +++ b/debian/modules/http-lua/t/043-shdict.t @@ -420,7 +420,7 @@ ngx_slab_alloc() failed: no memory in lua_shared_dict zone ngx.say(dogs:get(key)) key = string.rep("a", 65536) - ok, err = dogs:set(key, "world") + local ok, err = dogs:set(key, "world") if not ok then ngx.say("not ok: ", err) return @@ -2048,7 +2048,7 @@ get_stale ok: false, stale: false ngx.say("get not ok: ", err) return end - flags = err + local flags = err ngx.say("get_stale ok: ", data, ", flags: ", flags, ", stale: ", stale) diff --git a/debian/modules/http-lua/t/047-match-jit.t b/debian/modules/http-lua/t/047-match-jit.t index 2417a63..f53a408 100644 --- a/debian/modules/http-lua/t/047-match-jit.t +++ b/debian/modules/http-lua/t/047-match-jit.t @@ -20,7 +20,7 @@ __DATA__ --- config location /re { content_by_lua ' - m = ngx.re.match("hello, 1234", "([0-9]+)", "j") + local m = ngx.re.match("hello, 1234", "([0-9]+)", "j") if m then ngx.say(m[0]) else @@ -41,7 +41,7 @@ pcre JIT compiling result: 1 --- config location /re { content_by_lua ' - m = ngx.re.match("hello, world", "([0-9]+)", "j") + local m = ngx.re.match("hello, world", "([0-9]+)", "j") if m then ngx.say(m[0]) else @@ -62,7 +62,7 @@ pcre JIT compiling result: 1 --- config location /re { content_by_lua ' - m = ngx.re.match("hello, 1234", "([0-9]+)", "jo") + local m = ngx.re.match("hello, 1234", "([0-9]+)", "jo") if m then ngx.say(m[0]) else @@ -87,7 +87,7 @@ qr/pcre JIT compiling result: \d+/ --- config location /re { content_by_lua ' - m = ngx.re.match("hello, world", "([0-9]+)", "jo") + local m = ngx.re.match("hello, world", "([0-9]+)", "jo") if m then ngx.say(m[0]) else @@ -147,7 +147,7 @@ error: pcre_compile() failed: missing ) in "(abc" >>> a.lua local re = [==[(?i:([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:=|<=>|r?like|sounds\s+like|regexp)([\s'\"`´’‘\(\)]*)?\2|([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:!=|<=|>=|<>|<|>|\^|is\s+not|not\s+like|not\s+regexp)([\s'\"`´’‘\(\)]*)?(?!\6)([\d\w]+))]==] -s = string.rep([[ABCDEFG]], 21) +local s = string.rep([[ABCDEFG]], 21) local start = ngx.now() @@ -187,7 +187,7 @@ error: pcre_exec() failed: -8 >>> a.lua local re = [==[(?i:([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:=|<=>|r?like|sounds\s+like|regexp)([\s'\"`´’‘\(\)]*)?\2|([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:!=|<=|>=|<>|<|>|\^|is\s+not|not\s+like|not\s+regexp)([\s'\"`´’‘\(\)]*)?(?!\6)([\d\w]+))]==] -s = string.rep([[ABCDEFG]], 21) +local s = string.rep([[ABCDEFG]], 21) local start = ngx.now() diff --git a/debian/modules/http-lua/t/048-match-dfa.t b/debian/modules/http-lua/t/048-match-dfa.t index 28b5a60..edf3662 100644 --- a/debian/modules/http-lua/t/048-match-dfa.t +++ b/debian/modules/http-lua/t/048-match-dfa.t @@ -20,7 +20,7 @@ __DATA__ --- config location /re { content_by_lua ' - m = ngx.re.match("hello", "(he|hell)", "d") + local m = ngx.re.match("hello", "(he|hell)", "d") if m then ngx.say(m[0]) ngx.say(m[1]) @@ -43,7 +43,7 @@ nil --- config location /re { content_by_lua ' - m = ngx.re.match("hello", "(he|hell)", "do") + local m = ngx.re.match("hello", "(he|hell)", "do") if m then ngx.say(m[0]) ngx.say(m[1]) @@ -66,7 +66,7 @@ nil --- config location /re { content_by_lua ' - m = ngx.re.match("hello", "(he|hell)", "jd") + local m = ngx.re.match("hello", "(he|hell)", "jd") if m then ngx.say(m[0]) else @@ -85,7 +85,7 @@ hell --- config location /re { content_by_lua ' - m = ngx.re.match("world", "(he|hell)", "d") + local m = ngx.re.match("world", "(he|hell)", "d") if m then ngx.say(m[0]) else @@ -104,7 +104,7 @@ not matched! --- config location /re { content_by_lua ' - m = ngx.re.match("hello", "he|hell", "do") + local m = ngx.re.match("hello", "he|hell", "do") if m then ngx.say(m[0]) ngx.say(m[1]) @@ -127,7 +127,7 @@ nil --- config location /re { content_by_lua ' - m = ngx.re.match("world", "([0-9]+)", "do") + local m = ngx.re.match("world", "([0-9]+)", "do") if m then ngx.say(m[0]) else diff --git a/debian/modules/http-lua/t/055-subreq-vars.t b/debian/modules/http-lua/t/055-subreq-vars.t index eb5e24d..1369992 100644 --- a/debian/modules/http-lua/t/055-subreq-vars.t +++ b/debian/modules/http-lua/t/055-subreq-vars.t @@ -28,7 +28,7 @@ __DATA__ location /lua { content_by_lua ' - res = ngx.location.capture("/other", + local res = ngx.location.capture("/other", { vars = { dog = "hello", cat = 32 }}); ngx.print(res.body) @@ -82,7 +82,7 @@ qr/variable "(dog|cat)" cannot be assigned a value \(maybe you forgot to define location /lua { set $dog ''; content_by_lua ' - res = ngx.location.capture("/other", + local res = ngx.location.capture("/other", { vars = { dog = "hello", cat = 32 }}); ngx.print(res.body) @@ -110,7 +110,7 @@ variable "cat" cannot be assigned a value (maybe you forgot to define it first?) set $dog ''; set $cat ''; content_by_lua ' - res = ngx.location.capture("/other", + local res = ngx.location.capture("/other", { vars = { dog = "hello", cat = 32 }}); ngx.print(res.body) @@ -137,7 +137,7 @@ cat = 32 set $dog ''; set $cat ''; content_by_lua ' - res = ngx.location.capture("/other", + local res = ngx.location.capture("/other", { vars = "hello" }); ngx.print(res.body) @@ -165,7 +165,7 @@ Bad vars option value set $dog ''; set $cat ''; content_by_lua ' - res = ngx.location.capture("/other", + local res = ngx.location.capture("/other", { vars = { cat = true } }); ngx.print(res.body) @@ -188,7 +188,7 @@ attempt to use bad variable value type boolean location /lua { content_by_lua ' - res = ngx.location.capture("/other", + local res = ngx.location.capture("/other", { vars = { args = "a=hello&b=32" }}); ngx.print(res.body) @@ -234,7 +234,7 @@ variable "query_string" not changeable location /lua { set $dog 'hello'; content_by_lua ' - res = ngx.location.capture("/other", + local res = ngx.location.capture("/other", { copy_all_vars = true }); ngx.print(res.body) @@ -259,7 +259,7 @@ GET /lua location /lua { set $dog 'hello'; content_by_lua ' - res = ngx.location.capture("/other", + local res = ngx.location.capture("/other", { share_all_vars = true }); ngx.print(res.body) @@ -284,7 +284,7 @@ GET /lua location /lua { set $dog 'hello'; content_by_lua ' - res = ngx.location.capture("/other", + local res = ngx.location.capture("/other", { vars = { dog = "hiya" }, copy_all_vars = true }); ngx.print(res.body) diff --git a/debian/modules/http-lua/t/056-flush.t b/debian/modules/http-lua/t/056-flush.t index 6b697a4..bdd33d4 100644 --- a/debian/modules/http-lua/t/056-flush.t +++ b/debian/modules/http-lua/t/056-flush.t @@ -317,7 +317,7 @@ lua http 1.0 buffering makes ngx.flush() a no-op --- config location /test { content_by_lua ' - function f() + local function f() ngx.say("hello, world") ngx.flush(true) coroutine.yield() diff --git a/debian/modules/http-lua/t/057-flush-timeout.t b/debian/modules/http-lua/t/057-flush-timeout.t index a046539..1f8cfaa 100644 --- a/debian/modules/http-lua/t/057-flush-timeout.t +++ b/debian/modules/http-lua/t/057-flush-timeout.t @@ -127,7 +127,7 @@ del timer 1234 send_timeout 200ms; location /lua { content_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) diff --git a/debian/modules/http-lua/t/058-tcp-socket.t b/debian/modules/http-lua/t/058-tcp-socket.t index 354a876..837006c 100644 --- a/debian/modules/http-lua/t/058-tcp-socket.t +++ b/debian/modules/http-lua/t/058-tcp-socket.t @@ -4,7 +4,7 @@ use Test::Nginx::Socket::Lua; repeat_each(2); -plan tests => repeat_each() * 199; +plan tests => repeat_each() * 219; our $HtmlDir = html_dir; @@ -245,11 +245,11 @@ attempt to send data on a closed socket: --- request GET /t ---- response_body +--- response_body_like connected: 1 request sent: 56 -first line received: HTTP/1.1 200 OK -second line received: Server: openresty +first line received: HTTP\/1\.1 200 OK +second line received: (?:Date|Server): .*? --- no_error_log [error] --- timeout: 10 @@ -298,7 +298,7 @@ qr/connect\(\) failed \(\d+: Connection refused\)/ location /test { content_by_lua ' local sock = ngx.socket.tcp() - local ok, err = sock:connect("agentzh.org", 12345) + local ok, err = sock:connect("127.0.0.2", 12345) ngx.say("connect: ", ok, " ", err) local bytes @@ -321,7 +321,7 @@ send: nil closed receive: nil closed close: nil closed --- error_log -lua tcp socket connect timed out, when connecting to 172.105.207.225:12345 +lua tcp socket connect timed out, when connecting to 127.0.0.2:12345 --- timeout: 10 @@ -914,7 +914,7 @@ close: 1 nil end end - ok, err = sock:close() + local ok, err = sock:close() ngx.say("close: ", ok, " ", err) '; } @@ -961,7 +961,7 @@ close: 1 nil line, err = sock:receive() ngx.say("receive: ", line, " ", err) - ok, err = sock:close() + local ok, err = sock:close() ngx.say("close: ", ok, " ", err) '; } @@ -1057,7 +1057,7 @@ close: 1 nil === TEST 19: cannot survive across request boundary (send) --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config server_tokens off; location /t { @@ -1116,7 +1116,7 @@ received: OK|failed to send request: closed)\$" === TEST 20: cannot survive across request boundary (receive) --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config server_tokens off; location /t { @@ -1191,7 +1191,7 @@ received: OK|failed to receive a line: closed \[nil\])$/ === TEST 21: cannot survive across request boundary (close) --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config server_tokens off; location /t { @@ -1260,7 +1260,7 @@ received: OK|failed to close: closed)$/ === TEST 22: cannot survive across request boundary (connect) --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config server_tokens off; location /t { @@ -2611,7 +2611,7 @@ close: 1 nil local ready = false local fatal = false - function f() + local function f() local line, err, part = sock:receive() if not line then ngx.say("failed to receive the 1st line: ", err, " [", part, "]") @@ -2672,7 +2672,7 @@ lua clean up the timer for pending ngx.sleep === TEST 44: bad request tries to connect --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config server_tokens off; location = /main { @@ -2726,7 +2726,7 @@ qr/runtime error: content_by_lua\(nginx\.conf:\d+\):7: bad request/ === TEST 45: bad request tries to receive --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config server_tokens off; location = /main { @@ -2783,7 +2783,7 @@ qr/runtime error: content_by_lua\(nginx\.conf:\d+\):14: bad request/ === TEST 46: bad request tries to send --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config server_tokens off; location = /main { @@ -2840,7 +2840,7 @@ qr/runtime error: content_by_lua\(nginx\.conf:\d+\):14: bad request/ === TEST 47: bad request tries to close --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config server_tokens off; location = /main { @@ -2897,7 +2897,7 @@ qr/runtime error: content_by_lua\(nginx\.conf:\d+\):14: bad request/ === TEST 48: bad request tries to set keepalive --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config server_tokens off; location = /main { @@ -2954,7 +2954,7 @@ qr/runtime error: content_by_lua\(nginx\.conf:\d+\):14: bad request/ === TEST 49: bad request tries to receiveuntil --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config server_tokens off; location = /main { @@ -3315,7 +3315,7 @@ close: 1 nil local thr = ngx.thread.spawn(function () sock = ngx.socket.tcp() - local ok, err = sock:connect("agentzh.org", 12345) + local ok, err = sock:connect("127.0.0.2", 12345) if not ok then ngx.say("failed to connect: ", err) return @@ -3464,7 +3464,7 @@ lua http cleanup reuse ngx.say("failed to create timer: ", err) end - i = 1 + local i = 1 while not done do local time = 0.005 * i if time > 0.1 then @@ -3545,7 +3545,7 @@ lua http cleanup reuse ngx.say("failed to create timer: ", err) end - i = 1 + local i = 1 while not done do local time = 0.005 * i if time > 0.1 then @@ -3720,10 +3720,10 @@ sudo iptables -I OUTPUT 1 -p udp --dport 10086 -j REJECT } --- request GET /t ---- response_body -failed to connect: www.google.com could not be resolved -failed to connect: www.google.com could not be resolved -failed to connect: www.google.com could not be resolved +--- response_body_like +failed to connect: www.google.com could not be resolved(?: \(\d+: Operation timed out\))? +failed to connect: www.google.com could not be resolved(?: \(\d+: Operation timed out\))? +failed to connect: www.google.com could not be resolved(?: \(\d+: Operation timed out\))? hello! --- error_log eval qr{\[alert\] .*? send\(\) failed \(\d+: Operation not permitted\) while resolving} @@ -3808,3 +3808,315 @@ received: received: truefalsenil --- no_error_log [error] + + + +=== TEST 64: receiveany method in cosocket +--- config + server_tokens off; + location = /t { + set $port $TEST_NGINX_SERVER_PORT; + content_by_lua_block { + local sock = ngx.socket.tcp() + sock:settimeout(500) + assert(sock:connect("127.0.0.1", ngx.var.port)) + local req = { + 'GET /foo HTTP/1.0\r\n', + 'Host: localhost\r\n', + 'Connection: close\r\n\r\n', + } + local ok, err = sock:send(req) + if not ok then + ngx.say("send request failed: ", err) + return + end + + -- skip http header + while true do + local data, err, _ = sock:receive('*l') + if err then + ngx.say('unexpected error occurs when receiving http head: ', err) + return + end + + if #data == 0 then -- read last line of head + break + end + end + + -- receive http body + while true do + local data, err = sock:receiveany(1024) + if err then + if err ~= 'closed' then + ngx.say('unexpected err: ', err) + end + break + end + ngx.say(data) + end + + sock:close() + } + } + + location = /foo { + content_by_lua_block { + local resp = { + '1', + '22', + 'hello world', + } + + local length = 0 + for _, v in ipairs(resp) do + length = length + #v + end + + -- flush http header + ngx.header['Content-Length'] = length + ngx.flush(true) + ngx.sleep(0.01) + + -- send http body + for _, v in ipairs(resp) do + ngx.print(v) + ngx.flush(true) + ngx.sleep(0.01) + end + } + } + +--- request +GET /t +--- response_body +1 +22 +hello world +--- no_error_log +[error] +--- error_log +lua tcp socket read any + + + +=== TEST 65: receiveany send data after read side closed +--- config + server_tokens off; + location = /t { + content_by_lua_block { + local sock = ngx.socket.tcp() + sock:settimeout(500) + assert(sock:connect("127.0.0.1", 7658)) + + while true do + local data, err = sock:receiveany(1024) + if err then + if err ~= 'closed' then + ngx.say('unexpected err: ', err) + break + end + + local data = "send data after read side closed" + local bytes, err = sock:send(data) + if not bytes then + ngx.say(err) + end + + break + end + ngx.say(data) + end + + sock:close() + } + } + +--- request +GET /t +--- tcp_listen: 7658 +--- tcp_shutdown: 1 +--- tcp_query eval: "send data after read side closed" +--- tcp_query_len: 32 +--- response_body +--- no_error_log +[error] + + + +=== TEST 66: receiveany with limited, max <= 0 +--- config + location = /t { + set $port $TEST_NGINX_SERVER_PORT; + content_by_lua_block { + local sock = ngx.socket.tcp() + sock:settimeout(500) + assert(sock:connect("127.0.0.1", ngx.var.port)) + + local function receiveany_say_err(...) + local ok, err = pcall(sock.receiveany, sock, ...) + if not ok then + ngx.say(err) + end + end + + + receiveany_say_err(0) + receiveany_say_err(-1) + receiveany_say_err() + receiveany_say_err(nil) + } + } + +--- response_body +bad argument #2 to '?' (bad max argument) +bad argument #2 to '?' (bad max argument) +expecting 2 arguments (including the object), but got 1 +bad argument #2 to '?' (bad max argument) +--- request +GET /t +--- no_error_log +[error] + + + +=== TEST 67: receiveany with limited, max is larger than data +--- config + server_tokens off; + location = /t { + set $port $TEST_NGINX_SERVER_PORT; + content_by_lua_block { + local sock = ngx.socket.tcp() + sock:settimeout(500) + assert(sock:connect("127.0.0.1", ngx.var.port)) + local req = { + 'GET /foo HTTP/1.0\r\n', + 'Host: localhost\r\n', + 'Connection: close\r\n\r\n', + } + local ok, err = sock:send(req) + if not ok then + ngx.say("send request failed: ", err) + return + end + + while true do + local data, err, _ = sock:receive('*l') + if err then + ngx.say('unexpected error occurs when receiving http head: ', err) + return + end + + if #data == 0 then -- read last line of head + break + end + end + + local data, err = sock:receiveany(128) + if err then + if err ~= 'closed' then + ngx.say('unexpected err: ', err) + end + else + ngx.say(data) + end + + sock:close() + } + } + + location = /foo { + content_by_lua_block { + local resp = 'hello world' + local length = #resp + + ngx.header['Content-Length'] = length + ngx.flush(true) + ngx.sleep(0.01) + + ngx.print(resp) + } + } + +--- request +GET /t +--- response_body +hello world +--- no_error_log +[error] +--- error_log +lua tcp socket calling receiveany() method to read at most 128 bytes + + + +=== TEST 68: receiveany with limited, max is smaller than data +--- config + server_tokens off; + location = /t { + set $port $TEST_NGINX_SERVER_PORT; + content_by_lua_block { + local sock = ngx.socket.tcp() + sock:settimeout(500) + assert(sock:connect("127.0.0.1", ngx.var.port)) + local req = { + 'GET /foo HTTP/1.0\r\n', + 'Host: localhost\r\n', + 'Connection: close\r\n\r\n', + } + local ok, err = sock:send(req) + if not ok then + ngx.say("send request failed: ", err) + return + end + + while true do + local data, err, _ = sock:receive('*l') + if err then + ngx.say('unexpected error occurs when receiving http head: ', err) + return + end + + if #data == 0 then -- read last line of head + break + end + end + + while true do + local data, err = sock:receiveany(7) + if err then + if err ~= 'closed' then + ngx.say('unexpected err: ', err) + end + break + + else + ngx.say(data) + end + end + + sock:close() + } + } + + location = /foo { + content_by_lua_block { + local resp = 'hello world' + local length = #resp + + ngx.header['Content-Length'] = length + ngx.flush(true) + ngx.sleep(0.01) + + ngx.print(resp) + } + } + +--- request +GET /t +--- response_body +hello w +orld +--- no_error_log +[error] +--- error_log +lua tcp socket calling receiveany() method to read at most 7 bytes diff --git a/debian/modules/http-lua/t/062-count.t b/debian/modules/http-lua/t/062-count.t index 2ad2f9f..9b0afe8 100644 --- a/debian/modules/http-lua/t/062-count.t +++ b/debian/modules/http-lua/t/062-count.t @@ -283,7 +283,7 @@ n = 5 --- request GET /test --- response_body -n = 18 +n = 22 --- no_error_log [error] @@ -444,7 +444,28 @@ worker: 4 -=== TEST 20: entries under the metatable of udp sockets +=== TEST 20: entries under the metatable of tcp sockets +--- config + location = /test { + content_by_lua_block { + local n = 0 + local sock = ngx.socket.tcp() + for k, v in pairs(getmetatable(sock)) do + n = n + 1 + end + ngx.say("n = ", n) + } + } +--- request +GET /test +--- response_body +n = 13 +--- no_error_log +[error] + + + +=== TEST 21: entries under the metatable of udp sockets --- config location = /test { content_by_lua ' @@ -465,7 +486,7 @@ n = 6 -=== TEST 21: entries under the metatable of req raw sockets +=== TEST 22: entries under the metatable of req raw sockets --- config location = /test { content_by_lua ' @@ -497,7 +518,7 @@ n = 6 -=== TEST 22: entries under the req raw sockets +=== TEST 23: entries under the req raw sockets --- config location = /test { content_by_lua_block { @@ -536,7 +557,7 @@ nrec = 3 -=== TEST 23: entries under the req sockets +=== TEST 24: entries under the req sockets --- config location = /test { content_by_lua_block { diff --git a/debian/modules/http-lua/t/063-abort.t b/debian/modules/http-lua/t/063-abort.t index 411a07e..7c90eaa 100644 --- a/debian/modules/http-lua/t/063-abort.t +++ b/debian/modules/http-lua/t/063-abort.t @@ -22,7 +22,7 @@ __DATA__ === TEST 1: ngx.exit(400) should abort print --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /memc_query { internal; @@ -68,7 +68,7 @@ GET /test?a === TEST 2: ngx.exit(400) should abort ngx.log --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /memc_query { internal; @@ -116,7 +116,7 @@ GET /test?a === TEST 3: ngx.exit(400) should abort ngx.location.capture --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /memc_query { internal; @@ -161,7 +161,7 @@ the "$memc_key" variable is not set === TEST 4: ngx.exit(400) should abort ngx.location.capture_multi --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /memc_query { internal; @@ -206,7 +206,7 @@ the "$memc_key" variable is not set === TEST 5: ngx.exit(400) should abort ngx.redirect --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /test { content_by_lua ' @@ -233,7 +233,7 @@ lua redirect to "/blah" with code 302 === TEST 6: ngx.exit(400) should abort ngx.exit --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /test { content_by_lua ' @@ -260,7 +260,7 @@ lua exit with code 503 === TEST 7: ngx.exit(400) should abort ngx.exec --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /test { content_by_lua ' @@ -287,7 +287,7 @@ lua exec "/blah?" === TEST 8: ngx.exit(400) should abort ngx.send_headers --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /test { content_by_lua ' @@ -314,7 +314,7 @@ lua send headers === TEST 9: ngx.exit(400) should abort ngx.print --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /test { content_by_lua ' @@ -341,7 +341,7 @@ lua print response === TEST 10: ngx.exit(400) should abort ngx.say --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /test { content_by_lua ' @@ -368,7 +368,7 @@ lua say response === TEST 11: ngx.exit(400) should abort ngx.flush --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /test { content_by_lua ' @@ -395,7 +395,7 @@ lua flush asynchronously === TEST 12: ngx.exit(400) should abort ngx.eof --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /test { content_by_lua ' @@ -422,7 +422,7 @@ lua send eof === TEST 13: ngx.exit(400) should abort ngx.re.match --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /test { content_by_lua ' @@ -449,7 +449,7 @@ lua compiling match regex "a" with options "jo" === TEST 14: ngx.exit(400) should abort ngx.re.gmatch --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /test { content_by_lua ' @@ -476,7 +476,7 @@ lua compiling gmatch regex "a" with options "jo" === TEST 15: ngx.exit(400) should abort ngx.re.sub --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /test { content_by_lua ' @@ -503,7 +503,7 @@ lua compiling sub regex "a" with options "jo" === TEST 16: ngx.exit(400) should abort ngx.re.gsub --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /test { content_by_lua ' @@ -530,7 +530,7 @@ lua compiling gsub regex "a" with options "jo" === TEST 17: ngx.exit(400) should abort ngx.shared.DICT (set) --- http_config eval - "lua_shared_dict dogs 1m; lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_shared_dict dogs 1m; lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /test { content_by_lua ' @@ -560,7 +560,7 @@ foo = 56 === TEST 18: ngx.exit(400) should abort ngx.shared.DICT (replace) --- http_config eval - "lua_shared_dict dogs 1m; lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_shared_dict dogs 1m; lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /test { content_by_lua ' @@ -590,7 +590,7 @@ foo = 56 === TEST 19: ngx.exit(400) should abort ngx.shared.DICT (incr) --- http_config eval - "lua_shared_dict dogs 1m; lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_shared_dict dogs 1m; lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /test { content_by_lua ' @@ -620,7 +620,7 @@ foo = 88 === TEST 20: ngx.exit(400) should abort ngx.shared.DICT (get) --- http_config eval - "lua_shared_dict dogs 1m; lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_shared_dict dogs 1m; lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /test { content_by_lua ' @@ -649,7 +649,7 @@ fetching key "foo" in shared dict "dogs" === TEST 21: ngx.exit(400) should skip os.execute --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /test { content_by_lua ' @@ -679,7 +679,7 @@ GET /test === TEST 22: ngx.exit(400) should break pcall and skip os.execute --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /test { content_by_lua ' @@ -709,7 +709,7 @@ fetching key "foo" in shared dict "dogs" === TEST 23: ngx.exit(400) should break pcall and skip os.execute (all in user module) --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /test { content_by_lua ' @@ -739,7 +739,7 @@ GET /test === TEST 24: ngx.redirect() should break pcall and skip os.execute (all in user module) --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /test { content_by_lua ' @@ -769,7 +769,7 @@ GET /test === TEST 25: ngx.redirect() should skip os.execute (all in user module) --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /test { content_by_lua ' @@ -799,7 +799,7 @@ GET /test === TEST 26: ngx.exec() should break pcall and skip os.execute (all in user module) --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /test { content_by_lua ' @@ -832,7 +832,7 @@ foo === TEST 27: ngx.exec() should skip os.execute (all in user module) --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /test { content_by_lua ' @@ -865,7 +865,7 @@ foo === TEST 28: ngx.set_uri(uri, true) should break pcall and skip os.execute (all in user module) --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /test { rewrite_by_lua ' @@ -921,7 +921,7 @@ hello world === TEST 30: ngx.exit(400) should break xpcall and skip os.execute (all in user module) --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /test { content_by_lua ' @@ -955,7 +955,7 @@ GET /test === TEST 31: ngx.exec() should skip os.execute (all in user module) --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /test { content_by_lua ' @@ -988,7 +988,7 @@ foo === TEST 32: ngx.exec() should break pcall and skip os.execute (all in user module) --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /test { content_by_lua ' diff --git a/debian/modules/http-lua/t/064-pcall.t b/debian/modules/http-lua/t/064-pcall.t index 3011f3e..9af2de7 100644 --- a/debian/modules/http-lua/t/064-pcall.t +++ b/debian/modules/http-lua/t/064-pcall.t @@ -22,11 +22,11 @@ __DATA__ === TEST 1: pcall works --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /test { content_by_lua ' - function f(a, b) + local function f(a, b) if a == 0 and b == 0 then error("zero error") end @@ -58,11 +58,11 @@ $/s === TEST 2: xpcall works --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /test { content_by_lua ' - function f(a, b) + local function f(a, b) if a == 0 and b == 0 then error("zero error") end @@ -70,15 +70,15 @@ $/s return 23, "hello", true end - function g() + local function g() return f(0, 0) end - function h() + local function h() return f(0) end - function err(...) + local function err(...) ngx.say("error handler called: ", ...) return "this is the new err" end diff --git a/debian/modules/http-lua/t/065-tcp-socket-timeout.t b/debian/modules/http-lua/t/065-tcp-socket-timeout.t index 78b8cff..092094a 100644 --- a/debian/modules/http-lua/t/065-tcp-socket-timeout.t +++ b/debian/modules/http-lua/t/065-tcp-socket-timeout.t @@ -51,7 +51,7 @@ __DATA__ location /t { content_by_lua ' local sock = ngx.socket.tcp() - local ok, err = sock:connect("agentzh.org", 12345) + local ok, err = sock:connect("127.0.0.2", 12345) if not ok then ngx.say("failed to connect: ", err) return @@ -66,7 +66,7 @@ GET /t failed to connect: timeout --- error_log lua tcp socket connect timeout: 100 -lua tcp socket connect timed out, when connecting to 172.105.207.225:12345 +lua tcp socket connect timed out, when connecting to 127.0.0.2:12345 --- timeout: 10 @@ -81,7 +81,7 @@ lua tcp socket connect timed out, when connecting to 172.105.207.225:12345 content_by_lua ' local sock = ngx.socket.tcp() sock:settimeout(150) - local ok, err = sock:connect("agentzh.org", 12345) + local ok, err = sock:connect("127.0.0.2", 12345) if not ok then ngx.say("failed to connect: ", err) return @@ -96,7 +96,7 @@ GET /t failed to connect: timeout --- error_log lua tcp socket connect timeout: 150 -lua tcp socket connect timed out, when connecting to 172.105.207.225:12345 +lua tcp socket connect timed out, when connecting to 127.0.0.2:12345 --- timeout: 10 @@ -110,7 +110,7 @@ lua tcp socket connect timed out, when connecting to 172.105.207.225:12345 content_by_lua ' local sock = ngx.socket.tcp() sock:settimeout(nil) - local ok, err = sock:connect("agentzh.org", 12345) + local ok, err = sock:connect("127.0.0.2", 12345) if not ok then ngx.say("failed to connect: ", err) return @@ -125,7 +125,7 @@ GET /t failed to connect: timeout --- error_log lua tcp socket connect timeout: 102 -lua tcp socket connect timed out, when connecting to 172.105.207.225:12345 +lua tcp socket connect timed out, when connecting to 127.0.0.2:12345 @@ -139,7 +139,7 @@ lua tcp socket connect timed out, when connecting to 172.105.207.225:12345 content_by_lua ' local sock = ngx.socket.tcp() sock:settimeout(0) - local ok, err = sock:connect("agentzh.org", 12345) + local ok, err = sock:connect("127.0.0.2", 12345) if not ok then ngx.say("failed to connect: ", err) return @@ -154,7 +154,7 @@ GET /t failed to connect: timeout --- error_log lua tcp socket connect timeout: 102 -lua tcp socket connect timed out, when connecting to 172.105.207.225:12345 +lua tcp socket connect timed out, when connecting to 127.0.0.2:12345 --- timeout: 10 @@ -168,7 +168,7 @@ lua tcp socket connect timed out, when connecting to 172.105.207.225:12345 content_by_lua ' local sock = ngx.socket.tcp() sock:settimeout(-1) - local ok, err = sock:connect("agentzh.org", 12345) + local ok, err = sock:connect("127.0.0.2", 12345) if not ok then ngx.say("failed to connect: ", err) return @@ -584,7 +584,7 @@ bad timeout value --- config location /lua { content_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -683,7 +683,7 @@ after location /t { content_by_lua ' local sock = ngx.socket.tcp() - local ok, err = sock:connect("agentzh.org", 12345) + local ok, err = sock:connect("127.0.0.2", 12345) if not ok then ngx.say("1: failed to connect: ", err) @@ -707,7 +707,7 @@ GET /t 2: connected: 1 --- error_log lua tcp socket connect timeout: 100 -lua tcp socket connect timed out, when connecting to 172.105.207.225:12345 +lua tcp socket connect timed out, when connecting to 127.0.0.2:12345 --- timeout: 10 diff --git a/debian/modules/http-lua/t/066-socket-receiveuntil.t b/debian/modules/http-lua/t/066-socket-receiveuntil.t index ffe74aa..89d2abf 100644 --- a/debian/modules/http-lua/t/066-socket-receiveuntil.t +++ b/debian/modules/http-lua/t/066-socket-receiveuntil.t @@ -245,7 +245,7 @@ close: 1 nil local reader = sock:receiveuntil("abcabd") for i = 1, 2 do - line, err, part = reader() + local line, err, part = reader() if line then ngx.say("read: ", line) @@ -316,7 +316,7 @@ close: 1 nil local reader = sock:receiveuntil("aa") for i = 1, 2 do - line, err, part = reader() + local line, err, part = reader() if line then ngx.say("read: ", line) @@ -387,7 +387,7 @@ close: 1 nil local reader = sock:receiveuntil("aaa") for i = 1, 2 do - line, err, part = reader() + local line, err, part = reader() if line then ngx.say("read: ", line) @@ -458,7 +458,7 @@ close: 1 nil local reader = sock:receiveuntil("aaaaad") for i = 1, 2 do - line, err, part = reader() + local line, err, part = reader() if line then ngx.say("read: ", line) @@ -530,7 +530,7 @@ close: 1 nil local reader = sock:receiveuntil("aaaaad") for i = 1, 2 do - line, err, part = reader() + local line, err, part = reader() if line then ngx.say("read: ", line) @@ -602,7 +602,7 @@ close: 1 nil local reader = sock:receiveuntil("aaaaad") for i = 1, 2 do - line, err, part = reader() + local line, err, part = reader() if line then ngx.say("read: ", line) @@ -673,7 +673,7 @@ close: 1 nil local reader = sock:receiveuntil("abcabdabcabe") for i = 1, 2 do - line, err, part = reader() + local line, err, part = reader() if line then ngx.say("read: ", line) @@ -744,7 +744,7 @@ close: 1 nil local reader = sock:receiveuntil("abcabdabcabe") for i = 1, 2 do - line, err, part = reader() + local line, err, part = reader() if line then ngx.say("read: ", line) @@ -815,7 +815,7 @@ close: 1 nil local reader = sock:receiveuntil("abcabdabcabe") for i = 1, 2 do - line, err, part = reader() + local line, err, part = reader() if line then ngx.say("read: ", line) @@ -886,7 +886,7 @@ close: 1 nil local reader = sock:receiveuntil("abcabdabcabe") for i = 1, 2 do - line, err, part = reader() + local line, err, part = reader() if line then ngx.say("read: ", line) @@ -957,7 +957,7 @@ close: 1 nil local reader = sock:receiveuntil("--abc") for i = 1, 2 do - line, err, part = reader() + local line, err, part = reader() if line then ngx.say("read: ", line) @@ -1028,7 +1028,7 @@ close: 1 nil local reader = sock:receiveuntil("--abc") for i = 1, 7 do - line, err, part = reader(4) + local line, err, part = reader(4) if line then ngx.say("read: ", line) @@ -1105,7 +1105,7 @@ close: 1 nil local reader = sock:receiveuntil("--abc") for i = 1, 7 do - line, err, part = reader(4) + local line, err, part = reader(4) if line then ngx.say("read: ", line) @@ -1182,7 +1182,7 @@ close: 1 nil local reader = sock:receiveuntil("--abc") for i = 1, 7 do - line, err, part = reader(4) + local line, err, part = reader(4) if line then ngx.say("read: ", line) @@ -1270,7 +1270,7 @@ close: 1 nil local reader = sock:receiveuntil("abcabd") for i = 1, 2 do - line, err, part = reader() + local line, err, part = reader() if line then ngx.say("read: ", line) diff --git a/debian/modules/http-lua/t/067-req-socket.t b/debian/modules/http-lua/t/067-req-socket.t index 229d5cc..6593360 100644 --- a/debian/modules/http-lua/t/067-req-socket.t +++ b/debian/modules/http-lua/t/067-req-socket.t @@ -320,7 +320,7 @@ found the end of the stream === TEST 4: attempt to use the req socket across request boundary --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location /t { content_by_lua ' @@ -369,7 +369,7 @@ hello world === TEST 5: receive until on request_body - receiveuntil(1) on the last byte of the body See https://groups.google.com/group/openresty/browse_thread/thread/43cf01da3c681aba for details --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location /t { content_by_lua ' @@ -431,7 +431,7 @@ done === TEST 6: pipelined POST requests --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location /t { content_by_lua ' diff --git a/debian/modules/http-lua/t/068-socket-keepalive.t b/debian/modules/http-lua/t/068-socket-keepalive.t index f052e9a..e4c6988 100644 --- a/debian/modules/http-lua/t/068-socket-keepalive.t +++ b/debian/modules/http-lua/t/068-socket-keepalive.t @@ -4,13 +4,14 @@ use Test::Nginx::Socket::Lua; #repeat_each(2); -plan tests => repeat_each() * (blocks() * 5 + 9); +plan tests => repeat_each() * (blocks() * 4 + 31); our $HtmlDir = html_dir; $ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211; $ENV{TEST_NGINX_HTML_DIR} = $HtmlDir; $ENV{TEST_NGINX_REDIS_PORT} ||= 6379; +$ENV{TEST_NGINX_RESOLVER} ||= '8.8.8.8'; $ENV{LUA_PATH} ||= '/usr/local/openresty-debug/lualib/?.lua;/usr/local/openresty/lualib/?.lua;;'; @@ -29,7 +30,7 @@ __DATA__ === TEST 1: sanity --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location /t { set $port $TEST_NGINX_MEMCACHED_PORT; @@ -97,7 +98,7 @@ lua tcp socket keepalive create connection pool for key "127.0.0.1:$ENV{TEST_NGI === TEST 2: free up the whole connection pool if no active connections --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location /t { set $port $TEST_NGINX_MEMCACHED_PORT; @@ -168,7 +169,7 @@ received: OK === TEST 3: upstream sockets close prematurely --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config server_tokens off; keepalive_timeout 100ms; @@ -243,7 +244,7 @@ done === TEST 4: http keepalive --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config server_tokens off; location /t { @@ -701,7 +702,35 @@ qr/lua tcp socket connection pool size: 25\b/] -=== TEST 10: sock:keepalive_timeout(0) means unlimited +=== TEST 10: setkeepalive() 'pool_size' should be greater than zero +--- config + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + content_by_lua_block { + local sock, err = ngx.socket.connect("127.0.0.1", ngx.var.port) + if not sock then + ngx.say(err) + return + end + + local ok, err = pcall(sock.setkeepalive, sock, 0, 0) + if not ok then + ngx.say(err) + return + end + ngx.say(ok) + } + } +--- request +GET /t +--- response_body +bad argument #3 to '?' (bad "pool_size" option value: 0) +--- no_error_log +[error] + + + +=== TEST 11: sock:keepalive_timeout(0) means unlimited --- config server_tokens off; location /t { @@ -776,10 +805,10 @@ qr/lua tcp socket connection pool size: 30\b/] -=== TEST 11: sanity (uds) +=== TEST 12: sanity (uds) --- http_config eval " - lua_package_path '$::HtmlDir/?.lua;./?.lua'; + lua_package_path '$::HtmlDir/?.lua;./?.lua;;'; server { listen unix:$::HtmlDir/nginx.sock; default_type 'text/plain'; @@ -858,7 +887,7 @@ received response of 119 bytes -=== TEST 12: github issue #108: ngx.locaiton.capture + redis.set_keepalive +=== TEST 13: github issue #108: ngx.locaiton.capture + redis.set_keepalive --- http_config eval qq{ lua_package_path "$::HtmlDir/?.lua;;"; @@ -905,9 +934,9 @@ lua tcp socket get keepalive peer: using connection -=== TEST 13: github issue #110: ngx.exit with HTTP_NOT_FOUND causes worker process to exit +=== TEST 14: github issue #110: ngx.exit with HTTP_NOT_FOUND causes worker process to exit --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config error_page 404 /404.html; location /t { @@ -964,9 +993,9 @@ Not found, dear... -=== TEST 14: custom pools (different pool for the same host:port) - tcp +=== TEST 15: custom pools (different pool for the same host:port) - tcp --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location /t { set $port $TEST_NGINX_MEMCACHED_PORT; @@ -1012,9 +1041,9 @@ lua tcp socket keepalive create connection pool for key "B" -=== TEST 15: custom pools (same pool for different host:port) - tcp +=== TEST 16: custom pools (same pool for different host:port) - tcp --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location /t { set $port $TEST_NGINX_MEMCACHED_PORT; @@ -1059,10 +1088,10 @@ lua tcp socket get keepalive peer: using connection -=== TEST 16: custom pools (different pool for the same host:port) - unix +=== TEST 17: custom pools (different pool for the same host:port) - unix --- http_config eval " - lua_package_path '$::HtmlDir/?.lua;./?.lua'; + lua_package_path '$::HtmlDir/?.lua;./?.lua;;'; server { listen unix:$::HtmlDir/nginx.sock; default_type 'text/plain'; @@ -1119,10 +1148,10 @@ lua tcp socket keepalive create connection pool for key "B" -=== TEST 17: custom pools (same pool for the same path) - unix +=== TEST 18: custom pools (same pool for the same path) - unix --- http_config eval " - lua_package_path '$::HtmlDir/?.lua;./?.lua'; + lua_package_path '$::HtmlDir/?.lua;./?.lua;;'; server { listen unix:$::HtmlDir/nginx.sock; default_type 'text/plain'; @@ -1174,9 +1203,9 @@ lua tcp socket get keepalive peer: using connection -=== TEST 18: numeric pool option value +=== TEST 19: numeric pool option value --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location /t { set $port $TEST_NGINX_MEMCACHED_PORT; @@ -1221,9 +1250,9 @@ lua tcp socket get keepalive peer: using connection -=== TEST 19: nil pool option value +=== TEST 20: nil pool option value --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location /t { set $port $TEST_NGINX_MEMCACHED_PORT; @@ -1264,9 +1293,9 @@ connected: 1, reused: 0 -=== TEST 20: (bad) table pool option value +=== TEST 21: (bad) table pool option value --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location /t { set $port $TEST_NGINX_MEMCACHED_PORT; @@ -1305,9 +1334,9 @@ bad argument #3 to 'connect' (bad "pool" option type: table) -=== TEST 21: (bad) boolean pool option value +=== TEST 22: (bad) boolean pool option value --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location /t { set $port $TEST_NGINX_MEMCACHED_PORT; @@ -1346,7 +1375,7 @@ bad argument #3 to 'connect' (bad "pool" option type: boolean) -=== TEST 22: clear the redis store +=== TEST 23: clear the redis store --- config location /t { redis2_query flushall; @@ -1363,9 +1392,9 @@ bad argument #3 to 'connect' (bad "pool" option type: boolean) -=== TEST 23: bug in send(): clear the chain writer ctx +=== TEST 24: bug in send(): clear the chain writer ctx --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location /t { set $port $TEST_NGINX_REDIS_PORT; @@ -1478,7 +1507,7 @@ done -=== TEST 24: setkeepalive() with explicit nil args +=== TEST 25: setkeepalive() with explicit nil args --- config server_tokens off; location /t { @@ -1551,3 +1580,1379 @@ done "lua tcp socket keepalive timeout: 100 ms", qr/lua tcp socket connection pool size: 30\b/] --- timeout: 4 + + + +=== TEST 26: conn queuing: connect() verifies the options for connection pool +--- config + location /t { + set $port $TEST_NGINX_SERVER_PORT; + + content_by_lua_block { + local sock = ngx.socket.tcp() + local function check_opts_for_connect(opts) + local ok, err = pcall(function() + sock:connect("127.0.0.1", ngx.var.port, opts) + end) + if not ok then + ngx.say(err) + else + ngx.say("ok") + end + end + + check_opts_for_connect({pool_size = 'a'}) + check_opts_for_connect({pool_size = 0}) + check_opts_for_connect({backlog = -1}) + check_opts_for_connect({backlog = 0}) + } + } +--- request +GET /t +--- response_body_like +.+ 'connect' \(bad "pool_size" option type: string\) +.+ 'connect' \(bad "pool_size" option value: 0\) +.+ 'connect' \(bad "backlog" option value: -1\) +ok +--- no_error_log +[error] + + + +=== TEST 27: conn queuing: connect() can specify 'pool_size' which overrides setkeepalive() +--- config + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + + content_by_lua_block { + local port = ngx.var.port + local function go() + local sock = ngx.socket.tcp() + local ok, err = sock:connect("127.0.0.1", port, {pool_size = 1}) + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok, ", reused: ", sock:getreusedtimes()) + + 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 + + local ok, err = sock:setkeepalive(0, 20) + if not ok then + ngx.say("failed to set reusable: ", err) + end + end + + -- reuse ok + go() + go() + + local sock1 = ngx.socket.connect("127.0.0.1", port) + local sock2 = ngx.socket.connect("127.0.0.1", port) + local ok, err = sock1:setkeepalive(0, 20) + if not ok then + ngx.say(err) + end + local ok, err = sock2:setkeepalive(0, 20) + if not ok then + ngx.say(err) + end + + -- the pool_size is 1 instead of 20 + sock1 = ngx.socket.connect("127.0.0.1", port) + sock2 = ngx.socket.connect("127.0.0.1", port) + ngx.say("reused: ", sock1:getreusedtimes()) + ngx.say("reused: ", sock2:getreusedtimes()) + sock1:setkeepalive(0, 20) + sock2:setkeepalive(0, 20) + } + } +--- request +GET /t +--- response_body +connected: 1, reused: 0 +request sent: 11 +received: OK +connected: 1, reused: 1 +request sent: 11 +received: OK +reused: 1 +reused: 0 +--- no_error_log eval +["[error]", +"lua tcp socket keepalive: free connection pool for ", +"lua tcp socket connection pool size: 20"] +--- error_log eval +[qq{lua tcp socket keepalive create connection pool for key "127.0.0.1:$ENV{TEST_NGINX_MEMCACHED_PORT}"}, +"lua tcp socket connection pool size: 1", +] + + + +=== TEST 28: conn queuing: connect() can specify 'pool_size' for unix domain socket +--- http_config eval +" + server { + listen unix:$::HtmlDir/nginx.sock; + } +" +--- config + location /t { + content_by_lua_block { + local path = "unix:" .. "$TEST_NGINX_HTML_DIR/nginx.sock"; + local function go() + local sock = ngx.socket.tcp() + local ok, err = sock:connect(path, {pool_size = 1}) + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok, ", reused: ", sock:getreusedtimes()) + + local ok, err = sock:setkeepalive(0, 20) + if not ok then + ngx.say("failed to set reusable: ", err) + end + end + + go() + go() + + local sock1 = ngx.socket.connect(path) + local sock2 = ngx.socket.connect(path) + local ok, err = sock1:setkeepalive(0, 20) + if not ok then + ngx.say(err) + end + local ok, err = sock2:setkeepalive(0, 20) + if not ok then + ngx.say(err) + end + + -- the pool_size is 1 instead of 20 + sock1 = ngx.socket.connect(path) + sock2 = ngx.socket.connect(path) + ngx.say("reused: ", sock1:getreusedtimes()) + ngx.say("reused: ", sock2:getreusedtimes()) + sock1:setkeepalive(0, 20) + sock2:setkeepalive(0, 20) + } + } +--- request +GET /t +--- response_body +connected: 1, reused: 0 +connected: 1, reused: 1 +reused: 1 +reused: 0 +--- no_error_log eval +["[error]", +"lua tcp socket keepalive: free connection pool for ", +"lua tcp socket connection pool size: 20"] +--- error_log eval +["lua tcp socket get keepalive peer: using connection", +'lua tcp socket keepalive create connection pool for key "unix:', +"lua tcp socket connection pool size: 1", +] + + + +=== TEST 29: conn queuing: connect() can specify 'pool_size' for custom pool +--- config + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + + content_by_lua_block { + local port = ngx.var.port + local function go(pool) + local sock = ngx.socket.tcp() + local ok, err = sock:connect("127.0.0.1", port, {pool = pool, pool_size = 1}) + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", pool, ", reused: ", sock:getreusedtimes()) + + local ok, err = sock:setkeepalive(0, 20) + if not ok then + ngx.say("failed to set reusable: ", err) + end + end + + go('A') + go('B') + go('A') + go('B') + + local sock1 = ngx.socket.connect("127.0.0.1", port, {pool = 'A'}) + local sock2 = ngx.socket.connect("127.0.0.1", port, {pool = 'A'}) + local ok, err = sock1:setkeepalive(0, 20) + if not ok then + ngx.say(err) + end + local ok, err = sock2:setkeepalive(0, 20) + if not ok then + ngx.say(err) + end + + -- the pool_size is 1 instead of 20 + sock1 = ngx.socket.connect("127.0.0.1", port, {pool = 'A'}) + sock2 = ngx.socket.connect("127.0.0.1", port, {pool = 'A'}) + ngx.say("reused: ", sock1:getreusedtimes()) + ngx.say("reused: ", sock2:getreusedtimes()) + sock1:setkeepalive(0, 20) + sock2:setkeepalive(0, 20) + } + } +--- request +GET /t +--- response_body +connected: A, reused: 0 +connected: B, reused: 0 +connected: A, reused: 1 +connected: B, reused: 1 +reused: 1 +reused: 0 +--- no_error_log eval +["[error]", +"lua tcp socket keepalive: free connection pool for ", +"lua tcp socket connection pool size: 20"] +--- error_log eval +[qq{lua tcp socket keepalive create connection pool for key "A"}, +qq{lua tcp socket keepalive create connection pool for key "B"}, +"lua tcp socket connection pool size: 1", +] + + + +=== TEST 30: conn queuing: connect() uses lua_socket_pool_size as default if 'backlog' is given +--- config + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + lua_socket_pool_size 1234; + + content_by_lua_block { + local port = ngx.var.port + local opts = {backlog = 0} + local sock, err = ngx.socket.connect("127.0.0.1", port, opts) + if not sock then + ngx.say(err) + else + ngx.say("ok") + end + } + } +--- request +GET /t +--- response_body +ok +--- error_log +lua tcp socket connection pool size: 1234 +--- no_error_log +[error] + + + +=== TEST 31: conn queuing: more connect operations than 'backlog' size +--- config + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + + content_by_lua_block { + local port = ngx.var.port + local opts = {pool_size = 2, backlog = 0} + local sock = ngx.socket.connect("127.0.0.1", port, opts) + local not_reused_socket, err = ngx.socket.connect("127.0.0.1", port, opts) + if not not_reused_socket then + ngx.say(err) + return + end + -- burst + local ok, err = ngx.socket.connect("127.0.0.1", port, opts) + if not ok then + ngx.say(err) + end + + local ok, err = sock:setkeepalive() + if not ok then + ngx.say(err) + return + end + + ok, err = sock:connect("127.0.0.1", port, opts) + if not ok then + ngx.say(err) + end + ngx.say("reused: ", sock:getreusedtimes()) + -- both queue and pool is full + ok, err = ngx.socket.connect("127.0.0.1", port, opts) + if not ok then + ngx.say(err) + end + } + } +--- request +GET /t +--- response_body +too many waiting connect operations +reused: 1 +too many waiting connect operations +--- no_error_log +[error] + + + +=== TEST 32: conn queuing: once 'pool_size' is reached and pool has 'backlog' +--- config + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + + content_by_lua_block { + local port = ngx.var.port + local opts = {pool_size = 2, backlog = 2} + local sock1 = ngx.socket.connect("127.0.0.1", port, opts) + + ngx.timer.at(0, function(premature) + local sock2, err = ngx.socket.connect("127.0.0.1", port, opts) + if not sock2 then + ngx.log(ngx.ERR, err) + return + end + + ngx.log(ngx.WARN, "start to handle timer") + ngx.sleep(0.1) + sock2:close() + -- resume connect operation + ngx.log(ngx.WARN, "continue to handle timer") + end) + + ngx.sleep(0.05) + ngx.log(ngx.WARN, "start to handle cosocket") + local sock3, err = ngx.socket.connect("127.0.0.1", port, opts) + if not sock3 then + ngx.say(err) + return + end + ngx.log(ngx.WARN, "continue to handle cosocket") + + local req = "flush_all\r\n" + local bytes, err = sock3:send(req) + if not bytes then + ngx.say("failed to send request: ", err) + return + end + ngx.say("request sent: ", bytes) + + local line, err, part = sock3:receive() + if line then + ngx.say("received: ", line) + else + ngx.say("failed to receive a line: ", err, " [", part, "]") + end + + local ok, err = sock3:setkeepalive() + if not ok then + ngx.say("failed to set reusable: ", err) + end + ngx.say("setkeepalive: OK") + } + } +--- request +GET /t +--- response_body +request sent: 11 +received: OK +setkeepalive: OK +--- no_error_log +[error] +--- error_log +lua tcp socket queue connect operation for connection pool "127.0.0.1 +--- grep_error_log eval: qr/(start|continue) to handle \w+/ +--- grep_error_log_out +start to handle timer +start to handle cosocket +continue to handle timer +continue to handle cosocket + + + +=== TEST 33: conn queuing: do not count failed connect operations +--- config + resolver $TEST_NGINX_RESOLVER ipv6=off; + resolver_timeout 3s; + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + + content_by_lua_block { + local port = ngx.var.port + local opts = {pool = "test", pool_size = 1, backlog = 0} + + local sock = ngx.socket.tcp() + sock:settimeouts(100, 3000, 3000) + local ok, err = sock:connect("127.0.0.2", 12345, opts) + if not ok then + ngx.say(err) + end + + local sock, err = ngx.socket.connect("127.0.0.1", port, opts) + if not sock then + ngx.say(err) + end + ngx.say("ok") + } + } +--- request +GET /t +--- error_log +lua tcp socket connect timed out, when connecting to +--- response_body +timeout +ok + + + +=== TEST 34: conn queuing: connect until backlog is reached +--- config + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + + content_by_lua_block { + local port = ngx.var.port + local opts = {pool_size = 1, backlog = 1} + local sock1 = ngx.socket.connect("127.0.0.1", port, opts) + + ngx.timer.at(0.01, function(premature) + ngx.log(ngx.WARN, "start to handle timer") + local sock2, err = ngx.socket.connect("127.0.0.1", port, opts) + if not sock2 then + ngx.log(ngx.ERR, err) + return + end + + ngx.sleep(0.02) + local ok, err = sock2:close() + if not ok then + ngx.log(ngx.ERR, err) + end + ngx.log(ngx.WARN, "continue to handle timer") + end) + + ngx.sleep(0.02) + local sock3, err = ngx.socket.connect("127.0.0.1", port, opts) + if not sock3 then + ngx.say(err) + end + local ok, err = sock1:setkeepalive() + if not ok then + ngx.say(err) + return + end + ngx.sleep(0.01) -- run sock2 + + ngx.log(ngx.WARN, "start to handle cosocket") + local sock3, err = ngx.socket.connect("127.0.0.1", port, opts) + if not sock3 then + ngx.say(err) + return + end + ngx.log(ngx.WARN, "continue to handle cosocket") + + local ok, err = sock3:setkeepalive() + if not ok then + ngx.say(err) + end + } + } +--- request +GET /t +--- response_body +too many waiting connect operations +--- no_error_log +[error] +--- error_log +lua tcp socket queue connect operation for connection pool "127.0.0.1 +--- grep_error_log eval: qr/queue connect operation for connection pool|(start|continue) to handle \w+/ +--- grep_error_log_out +start to handle timer +queue connect operation for connection pool +start to handle cosocket +queue connect operation for connection pool +continue to handle timer +continue to handle cosocket + + + +=== TEST 35: conn queuing: memory reuse for host in queueing connect operation ctx +--- config + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + + content_by_lua_block { + local port = ngx.var.port + local opts = {pool = "test", pool_size = 1, backlog = 3} + local sock = ngx.socket.connect("127.0.0.1", port, opts) + + ngx.timer.at(0.01, function(premature) + local sock, err = ngx.socket.connect("0.0.0.0", port, opts) + if not sock then + ngx.log(ngx.ERR, err) + return + end + + local ok, err = sock:close() + if not ok then + ngx.log(ngx.ERR, err) + end + end) + + ngx.timer.at(0.015, function(premature) + local sock, err = ngx.socket.connect("127.0.0.1", port, opts) + if not sock then + ngx.log(ngx.ERR, err) + return + end + + local ok, err = sock:close() + if not ok then + ngx.log(ngx.ERR, err) + end + end) + + ngx.timer.at(0.02, function(premature) + local sock, err = ngx.socket.connect("0.0.0.0", port, opts) + if not sock then + ngx.log(ngx.ERR, err) + return + end + + local ok, err = sock:close() + if not ok then + ngx.log(ngx.ERR, err) + end + end) + + ngx.sleep(0.03) + local ok, err = sock:setkeepalive() + if not ok then + ngx.say(err) + return + end + ngx.say("ok") + } + } +--- request +GET /t +--- response_body +ok +--- no_error_log +[error] +--- grep_error_log eval: qr/queue connect operation for connection pool/ +--- grep_error_log_out +queue connect operation for connection pool +queue connect operation for connection pool +queue connect operation for connection pool + + + +=== TEST 36: conn queuing: connect() returns error after connect operation resumed +--- config + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + + content_by_lua_block { + local port = ngx.var.port + local opts = {pool = "test", pool_size = 1, backlog = 1} + local sock = ngx.socket.connect("127.0.0.1", port, opts) + + ngx.timer.at(0, function(premature) + local sock, err = ngx.socket.connect("", port, opts) + if not sock then + ngx.log(ngx.WARN, err) + end + end) + + ngx.sleep(0.01) + -- use 'close' to force parsing host instead of reusing conn + local ok, err = sock:close() + if not ok then + ngx.say(err) + return + end + ngx.say("ok") + } + } +--- request +GET /t +--- response_body +ok +--- no_error_log +[error] +--- error_log +failed to parse host name +--- grep_error_log eval: qr/queue connect operation for connection pool/ +--- grep_error_log_out +queue connect operation for connection pool + + + +=== TEST 37: conn queuing: in uthread +--- config + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + + content_by_lua_block { + local port = ngx.var.port + local opts = {pool_size = 1, backlog = 2} + + local conn_sock = function() + local sock, err = ngx.socket.connect("127.0.0.1", port, opts) + if not sock then + ngx.say(err) + return + end + ngx.say("start to handle uthread") + + ngx.sleep(0.01) + sock:close() + ngx.say("continue to handle other uthread") + end + + local sock, err = ngx.socket.connect("127.0.0.1", port, opts) + if not sock then + ngx.log(ngx.ERR, err) + return + end + + local co1 = ngx.thread.spawn(conn_sock) + local co2 = ngx.thread.spawn(conn_sock) + local co3 = ngx.thread.spawn(conn_sock) + + local ok, err = sock:setkeepalive() + if not ok then + ngx.log(ngx.ERR, err) + end + + ngx.thread.wait(co1) + ngx.thread.wait(co2) + ngx.thread.wait(co3) + ngx.say("all uthreads ok") + } + } +--- request +GET /t +--- response_body +too many waiting connect operations +start to handle uthread +continue to handle other uthread +start to handle uthread +continue to handle other uthread +all uthreads ok +--- no_error_log +[error] +--- grep_error_log eval: qr/queue connect operation for connection pool/ +--- grep_error_log_out +queue connect operation for connection pool +queue connect operation for connection pool + + + +=== TEST 38: conn queuing: in access_by_lua +--- config + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + + access_by_lua_block { + local port = ngx.var.port + local opts = {pool_size = 1, backlog = 2} + + local conn_sock = function() + local sock, err = ngx.socket.connect("127.0.0.1", port, opts) + if not sock then + ngx.say(err) + return + end + ngx.say("start to handle uthread") + + ngx.sleep(0.01) + sock:close() + ngx.say("continue to handle other uthread") + end + + local sock, err = ngx.socket.connect("127.0.0.1", port, opts) + if not sock then + ngx.log(ngx.ERR, err) + return + end + + local co1 = ngx.thread.spawn(conn_sock) + local co2 = ngx.thread.spawn(conn_sock) + local co3 = ngx.thread.spawn(conn_sock) + + local ok, err = sock:setkeepalive() + if not ok then + ngx.log(ngx.ERR, err) + end + + ngx.thread.wait(co1) + ngx.thread.wait(co2) + ngx.thread.wait(co3) + ngx.say("all uthreads ok") + } + } +--- request +GET /t +--- response_body +too many waiting connect operations +start to handle uthread +continue to handle other uthread +start to handle uthread +continue to handle other uthread +all uthreads ok +--- no_error_log +[error] +--- grep_error_log eval: qr/queue connect operation for connection pool/ +--- grep_error_log_out +queue connect operation for connection pool +queue connect operation for connection pool + + + +=== TEST 39: conn queuing: in rewrite_by_lua +--- config + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + + rewrite_by_lua_block { + local port = ngx.var.port + local opts = {pool_size = 1, backlog = 2} + + local conn_sock = function() + local sock, err = ngx.socket.connect("127.0.0.1", port, opts) + if not sock then + ngx.say(err) + return + end + ngx.say("start to handle uthread") + + ngx.sleep(0.01) + sock:close() + ngx.say("continue to handle other uthread") + end + + local sock, err = ngx.socket.connect("127.0.0.1", port, opts) + if not sock then + ngx.log(ngx.ERR, err) + return + end + + local co1 = ngx.thread.spawn(conn_sock) + local co2 = ngx.thread.spawn(conn_sock) + local co3 = ngx.thread.spawn(conn_sock) + + local ok, err = sock:setkeepalive() + if not ok then + ngx.log(ngx.ERR, err) + end + + ngx.thread.wait(co1) + ngx.thread.wait(co2) + ngx.thread.wait(co3) + ngx.say("all uthreads ok") + } + } +--- request +GET /t +--- response_body +too many waiting connect operations +start to handle uthread +continue to handle other uthread +start to handle uthread +continue to handle other uthread +all uthreads ok +--- no_error_log +[error] +--- grep_error_log eval: qr/queue connect operation for connection pool/ +--- grep_error_log_out +queue connect operation for connection pool +queue connect operation for connection pool + + + +=== TEST 40: conn queuing: in subrequest +--- config + set $port $TEST_NGINX_MEMCACHED_PORT; + + location /t { + content_by_lua_block { + local port = ngx.var.port + ngx.timer.at(0, function() + local opts = {pool_size = 1, backlog = 2} + local sock, err = ngx.socket.connect("127.0.0.1", port, opts) + if not sock then + ngx.log(ngx.ERR, err) + return + end + + ngx.sleep(0.1) + local ok, err = sock:setkeepalive() + if not ok then + ngx.log(ngx.ERR, err) + end + end) + + ngx.sleep(0.01) + local res1, res2, res3 = ngx.location.capture_multi{ + {"/conn"}, {"/conn"}, {"/conn"} + } + ngx.say(res1.body) + ngx.say(res2.body) + ngx.say(res3.body) + } + } + + location /conn { + content_by_lua_block { + local port = ngx.var.port + local sock, err = ngx.socket.connect("127.0.0.1", port) + if not sock then + ngx.print(err) + return + end + local ok, err = sock:setkeepalive() + if not ok then + ngx.print(err) + else + ngx.print("ok") + end + } + } +--- request +GET /t +--- response_body +ok +ok +too many waiting connect operations +--- no_error_log +[error] +--- grep_error_log eval: qr/queue connect operation for connection pool/ +--- grep_error_log_out +queue connect operation for connection pool +queue connect operation for connection pool + + + +=== TEST 41: conn queuing: timeouts when 'connect_timeout' is reached +--- config + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + + content_by_lua_block { + local port = ngx.var.port + local opts = {pool_size = 1, backlog = 1} + local sock1 = ngx.socket.connect("127.0.0.1", port, opts) + + local sock2 = ngx.socket.tcp() + sock2:settimeouts(10, 3000, 3000) + local ok, err = sock2:connect("127.0.0.1", port, opts) + if not ok then + ngx.say(err) + end + } + } +--- request +GET /t +--- response_body +timeout +--- error_log eval +"lua tcp socket queued connect timed out, when trying to connect to 127.0.0.1:$ENV{TEST_NGINX_MEMCACHED_PORT}" + + + +=== TEST 42: conn queuing: set timeout via lua_socket_connect_timeout +--- config + lua_socket_connect_timeout 10ms; + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + + content_by_lua_block { + local port = ngx.var.port + local opts = {pool_size = 1, backlog = 1} + local sock1 = ngx.socket.connect("127.0.0.1", port, opts) + + local sock2 = ngx.socket.tcp() + local ok, err = sock2:connect("127.0.0.1", port, opts) + if not ok then + ngx.say(err) + end + } + } +--- request +GET /t +--- response_body +timeout +--- error_log eval +"lua tcp socket queued connect timed out, when trying to connect to 127.0.0.1:$ENV{TEST_NGINX_MEMCACHED_PORT}" + + + +=== TEST 43: conn queuing: client aborting while connect operation is queued +--- config + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + + content_by_lua_block { + local port = ngx.var.port + local opts = {pool_size = 1, backlog = 1} + local sock1 = ngx.socket.connect("127.0.0.1", port, opts) + + local sock2 = ngx.socket.tcp() + sock2:settimeouts(3000, 3000, 3000) + local ok, err = sock2:connect("127.0.0.1", port, opts) + if not ok then + ngx.say(err) + end + } + } +--- request +GET /t +--- ignore_response +--- timeout: 0.1 +--- abort +--- no_error_log +[error] + + + +=== TEST 44: conn queuing: resume next connect operation if resumed connect failed immediately +--- config + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + + content_by_lua_block { + local port = ngx.var.port + local opts = {pool = "test", pool_size = 1, backlog = 2} + + local conn_sock = function(should_timeout) + local sock = ngx.socket.tcp() + local ok, err + if should_timeout then + ok, err = sock:connect("", port, opts) + else + ok, err = sock:connect("127.0.0.1", port, opts) + end + if not ok then + ngx.say(err) + return + end + ngx.say("connected in uthread") + sock:close() + end + + local sock, err = ngx.socket.connect("127.0.0.1", port, opts) + if not sock then + ngx.log(ngx.ERR, err) + return + end + + local co1 = ngx.thread.spawn(conn_sock, true) + local co2 = ngx.thread.spawn(conn_sock) + + local ok, err = sock:close() + if not ok then + ngx.log(ngx.ERR, err) + end + + ngx.thread.wait(co1) + ngx.thread.wait(co2) + ngx.say("ok") + } + } +--- request +GET /t +--- response_body +failed to parse host name "": no host +connected in uthread +ok +--- no_error_log +[error] + + + +=== TEST 45: conn queuing: resume connect operation if resumed connect failed (timeout) +--- config + resolver $TEST_NGINX_RESOLVER ipv6=off; + resolver_timeout 3s; + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + + content_by_lua_block { + local port = ngx.var.port + local opts = {pool = "test", pool_size = 1, backlog = 1} + + local conn_sock = function(should_timeout) + local sock = ngx.socket.tcp() + local ok, err + if should_timeout then + sock:settimeouts(100, 3000, 3000) + ok, err = sock:connect("127.0.0.2", 12345, opts) + else + ok, err = sock:connect("127.0.0.1", port, opts) + end + if not ok then + ngx.say(err) + return + end + ngx.say("connected in uthread") + sock:close() + end + + local co1 = ngx.thread.spawn(conn_sock, true) + local co2 = ngx.thread.spawn(conn_sock) + + ngx.thread.wait(co1) + ngx.thread.wait(co2) + ngx.say("ok") + } + } +--- request +GET /t +--- response_body +timeout +connected in uthread +ok +--- error_log +queue connect operation for connection pool "test" +lua tcp socket connect timed out, when connecting to + + + +=== TEST 46: conn queuing: resume connect operation if resumed connect failed (could not be resolved) +--- config + resolver 127.0.0.2:12345 ipv6=off; + resolver_timeout 1s; + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + + content_by_lua_block { + local port = ngx.var.port + local opts = {pool = "test", pool_size = 1, backlog = 1} + + local conn_sock = function(should_timeout) + local sock = ngx.socket.tcp() + local ok, err + if should_timeout then + sock:settimeouts(1, 3000, 3000) + ok, err = sock:connect("agentzh.org", 80, opts) + else + ok, err = sock:connect("127.0.0.1", port, opts) + end + if not ok then + ngx.say(err) + return + end + ngx.say("connected in uthread") + sock:close() + end + + local co1 = ngx.thread.spawn(conn_sock, true) + local co2 = ngx.thread.spawn(conn_sock) + + ngx.thread.wait(co1) + ngx.thread.wait(co2) + ngx.say("ok") + } + } +--- request +GET /t +--- response_body +agentzh.org could not be resolved (110: Operation timed out) +connected in uthread +ok +--- error_log +queue connect operation for connection pool "test" + + + +=== TEST 47: conn queuing: resume connect operation if resumed connect failed (connection refused) +--- config + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + + content_by_lua_block { + local port = ngx.var.port + local opts = {pool = "test", pool_size = 1, backlog = 1} + + local conn_sock = function(should_timeout) + local sock = ngx.socket.tcp() + local ok, err + if should_timeout then + sock:settimeouts(100, 3000, 3000) + ok, err = sock:connect("127.0.0.1", 62345, opts) + else + ok, err = sock:connect("127.0.0.1", port, opts) + end + if not ok then + ngx.say(err) + return + end + ngx.say("connected in uthread") + sock:close() + end + + local co1 = ngx.thread.spawn(conn_sock, true) + local co2 = ngx.thread.spawn(conn_sock) + + ngx.thread.wait(co1) + ngx.thread.wait(co2) + ngx.say("ok") + } + } +--- request +GET /t +--- response_body +connection refused +connected in uthread +ok +--- error_log +queue connect operation for connection pool "test" + + + +=== TEST 48: conn queuing: resume connect operation if resumed connect failed (uthread aborted while resolving) +--- http_config + lua_package_path '../lua-resty-core/lib/?.lua;../lua-resty-lrucache/lib/?.lua;;'; +--- config + resolver 127.0.0.1 ipv6=off; + resolver_timeout 100s; + set $port $TEST_NGINX_MEMCACHED_PORT; + + location /sub { + content_by_lua_block { + local semaphore = require "ngx.semaphore" + local sem = semaphore.new() + + local function f() + sem:wait(0.1) + ngx.exit(0) + end + + local opts = {pool = "test", pool_size = 1, backlog = 1} + local port = ngx.var.port + ngx.timer.at(0, function() + sem:post() + local sock2, err = ngx.socket.connect("127.0.0.1", port, opts) + package.loaded.for_timer_to_resume:post() + if not sock2 then + ngx.log(ngx.ALERT, "resume connect failed: ", err) + return + end + + ngx.log(ngx.INFO, "resume success") + end) + + ngx.thread.spawn(f) + local sock1, err = ngx.socket.connect("openresty.org", 80, opts) + if not sock1 then + ngx.say(err) + return + end + } + } + + location /t { + content_by_lua_block { + local semaphore = require "ngx.semaphore" + local for_timer_to_resume = semaphore.new() + package.loaded.for_timer_to_resume = for_timer_to_resume + + ngx.location.capture("/sub") + for_timer_to_resume:wait(0.1) + } + } +--- request +GET /t +--- no_error_log +[alert] +--- error_log +resume success + + + +=== TEST 49: conn queuing: resume connect operation if resumed connect failed (uthread killed while resolving) +--- config + resolver 127.0.0.1 ipv6=off; + resolver_timeout 100s; + set $port $TEST_NGINX_MEMCACHED_PORT; + + location /t { + content_by_lua_block { + local opts = {pool = "test", pool_size = 1, backlog = 1} + local port = ngx.var.port + + local function resolve() + local sock1, err = ngx.socket.connect("openresty.org", 80, opts) + if not sock1 then + ngx.say(err) + return + end + end + + local th = ngx.thread.spawn(resolve) + local ok, err = ngx.thread.kill(th) + if not ok then + ngx.log(ngx.ALERT, "kill thread failed: ", err) + return + end + + local sock2, err = ngx.socket.connect("127.0.0.1", port, opts) + if not sock2 then + ngx.log(ngx.ALERT, "resume connect failed: ", err) + return + end + + ngx.log(ngx.INFO, "resume success") + } + } +--- request +GET /t +--- no_error_log +[alert] +--- error_log +resume success + + + +=== TEST 50: conn queuing: increase the counter for connections created before creating the pool with setkeepalive() +--- config + set $port $TEST_NGINX_MEMCACHED_PORT; + + location /t { + content_by_lua_block { + local function connect() + local sock, err = ngx.socket.connect("127.0.0.1", ngx.var.port) + if not sock then + error("connect failed: " .. err) + end + + return sock + end + + local sock1 = connect() + local sock2 = connect() + assert(sock1:setkeepalive()) + assert(sock2:setkeepalive()) + + local sock1 = connect() + local sock2 = connect() + assert(sock1:close()) + assert(sock2:close()) + + ngx.say("ok") + } + } +--- request +GET /t +--- no_error_log +[error] +--- response_body +ok + + + +=== TEST 51: conn queuing: only decrease the counter for connections which were counted by the pool +--- config + set $port $TEST_NGINX_MEMCACHED_PORT; + + location /t { + content_by_lua_block { + local function connect() + local sock, err = ngx.socket.connect("127.0.0.1", ngx.var.port) + if not sock then + error("connect failed: " .. err) + end + + return sock + end + + local sock1 = connect() + local sock2 = connect() + assert(sock1:setkeepalive(1000, 1)) + assert(sock2:setkeepalive(1000, 1)) + + local sock1 = connect() + local sock2 = connect() + assert(sock1:close()) + assert(sock2:close()) + + ngx.say("ok") + } + } +--- request +GET /t +--- no_error_log +[error] +--- response_body +ok + + + +=== TEST 52: conn queuing: clean up pending connect operations which are in queue +--- config + set $port $TEST_NGINX_MEMCACHED_PORT; + + location /sub { + content_by_lua_block { + local opts = {pool = "test", pool_size = 1, backlog = 1} + local sock, err = ngx.socket.connect("127.0.0.1", ngx.var.port, opts) + if not sock then + ngx.say("connect failed: " .. err) + return + end + + local function f() + assert(ngx.socket.connect("127.0.0.1", ngx.var.port, opts)) + end + + local th = ngx.thread.spawn(f) + local ok, err = ngx.thread.kill(th) + if not ok then + ngx.log(ngx.ERR, "kill thread failed: ", err) + return + end + + sock:close() + } + } + + location /t { + content_by_lua_block { + ngx.location.capture("/sub") + -- let pending connect operation resumes first + ngx.sleep(0) + ngx.say("ok") + } + } +--- request +GET /t +--- no_error_log +[error] +--- error_log +lua tcp socket abort queueing +--- response_body +ok diff --git a/debian/modules/http-lua/t/073-backtrace.t b/debian/modules/http-lua/t/073-backtrace.t index 6c54692..663c3af 100644 --- a/debian/modules/http-lua/t/073-backtrace.t +++ b/debian/modules/http-lua/t/073-backtrace.t @@ -21,10 +21,10 @@ __DATA__ --- config location /lua { content_by_lua - ' function bar() + ' local function bar() return lua_concat(3) end - function foo() + local function foo() bar() end foo() @@ -37,7 +37,7 @@ GET /lua attempt to call global 'lua_concat' : in function 'bar' :5: in function 'foo' -:7: in function +:7: in main chunk @@ -45,10 +45,10 @@ attempt to call global 'lua_concat' --- config location /lua { content_by_lua - ' function bar() + ' local function bar() error(nil) end - function foo() + local function foo() bar() end foo() @@ -64,7 +64,7 @@ GET /lua " in function 'error'", ": in function 'bar'", ":5: in function 'foo'", -qr/:7: in function /, +qr/:7: in main chunk/, ] @@ -125,7 +125,7 @@ probe process("$LIBLUA_PATH").function("lua_concat") { :63: in function 'func16' :67: in function 'func17' :71: in function 'func18' -:74: in function +:74: in main chunk diff --git a/debian/modules/http-lua/t/075-logby.t b/debian/modules/http-lua/t/075-logby.t index 520c62e..8eece69 100644 --- a/debian/modules/http-lua/t/075-logby.t +++ b/debian/modules/http-lua/t/075-logby.t @@ -220,7 +220,7 @@ failed to run log_by_lua*: unknown reason -=== TEST 11: globals get cleared for every single request +=== TEST 11: globals sharing --- config location /lua { echo ok; @@ -228,6 +228,7 @@ failed to run log_by_lua*: unknown reason if not foo then foo = 1 else + ngx.log(ngx.INFO, "old foo: ", foo) foo = foo + 1 end ngx.log(ngx.WARN, "foo = ", foo) @@ -237,8 +238,9 @@ failed to run log_by_lua*: unknown reason GET /lua --- response_body ok ---- error_log -foo = 1 +--- grep_error_log eval: qr/old foo: \d+/ +--- grep_error_log_out eval +["", "old foo: 1\n"] @@ -495,7 +497,8 @@ API disabled in the context of log_by_lua* location /t { echo ok; log_by_lua ' - function foo() + local bar + local function foo() bar() end diff --git a/debian/modules/http-lua/t/081-bytecode.t b/debian/modules/http-lua/t/081-bytecode.t index cb50e94..92383bc 100644 --- a/debian/modules/http-lua/t/081-bytecode.t +++ b/debian/modules/http-lua/t/081-bytecode.t @@ -24,7 +24,7 @@ __DATA__ content_by_lua ' ngx.req.read_body(); local b = ngx.req.get_body_data(); - f = io.open(ngx.var.realpath_root.."/test.lua", "w"); + local f = io.open(ngx.var.realpath_root.."/test.lua", "w"); -- luajit bytecode: sub(149,-1), lua bytecode: sub(1,147) if jit then if not string.find(jit.version, "LuaJIT 2.0") then @@ -35,7 +35,8 @@ __DATA__ else f:write(string.sub(b, 1, 147)); end - f:close(); res = ngx.location.capture("/call"); + f:close(); + local res = ngx.location.capture("/call"); ngx.print(res.body) '; } @@ -60,14 +61,15 @@ __DATA__ content_by_lua ' ngx.req.read_body(); local b = ngx.req.get_body_data(); - f = io.open(ngx.var.realpath_root.."/test.lua", "w"); + local f = io.open(ngx.var.realpath_root.."/test.lua", "w"); -- luajit bytecode: sub(149,-1), lua bytecode: sub(1,147) if not package.loaded["jit"] then f:write(string.sub(b, 149)); else f:write(string.sub(b, 1, 147)); end - f:close(); res = ngx.location.capture("/call"); + f:close(); + local res = ngx.location.capture("/call"); if res.status == 200 then ngx.print(res.body) else @@ -85,7 +87,7 @@ __DATA__ --- response_body error --- error_log eval -qr/failed to load external Lua file ".*?test\.lua": bad byte-code header/ +qr/failed to load external Lua file ".*?test\.lua": .* cannot load incompatible bytecode/ @@ -96,14 +98,15 @@ qr/failed to load external Lua file ".*?test\.lua": bad byte-code header/ content_by_lua ' ngx.req.read_body(); local b = ngx.req.get_body_data(); - f = io.open(ngx.var.realpath_root.."/test.lua", "w"); + local f = io.open(ngx.var.realpath_root.."/test.lua", "w"); -- luajit bytecode: sub(149,-1), lua bytecode: sub(1,147) if package.loaded["jit"] then f:write(string.sub(b, 149)); else f:write(string.sub(b, 1, 147)); end - f:close(); res = ngx.location.capture("/call"); + f:close(); + local res = ngx.location.capture("/call"); if res.status == 200 then ngx.print(res.body) else @@ -121,7 +124,7 @@ qr/failed to load external Lua file ".*?test\.lua": bad byte-code header/ --- response_body error --- error_log -bytecode format version unsupported +cannot load incompatible bytecode @@ -132,7 +135,7 @@ bytecode format version unsupported content_by_lua ' ngx.req.read_body(); local b = ngx.req.get_body_data(); - f = io.open(ngx.var.realpath_root.."/test.lua", "w"); + local f = io.open(ngx.var.realpath_root.."/test.lua", "w"); -- luajit bytecode: sub(149,-1), lua bytecode: sub(1,147) local do_jit if jit then @@ -176,7 +179,7 @@ bytecode format version unsupported content_by_lua ' ngx.req.read_body(); local b = ngx.req.get_body_data(); - f = io.open(ngx.var.realpath_root.."/test.lua", "w"); + local f = io.open(ngx.var.realpath_root.."/test.lua", "w"); -- luajit bytecode: sub(149,-1), lua bytecode: sub(1,147) local jit; if package.loaded["jit"] then @@ -220,7 +223,7 @@ error content_by_lua ' ngx.req.read_body(); local b = ngx.req.get_body_data(); - f = io.open(ngx.var.realpath_root.."/test.lua", "w"); + local f = io.open(ngx.var.realpath_root.."/test.lua", "w"); -- luajit bytecode: sub(149,-1), lua bytecode: sub(1,147) if jit then if not string.find(jit.version, "LuaJIT 2.0") then @@ -256,9 +259,9 @@ error content_by_lua ' local bcsave = require "jit.bcsave" if jit then - local prefix = ngx.config.prefix() - local infile = prefix .. "html/a.lua" - local outfile = prefix .. "html/a.luac" + local prefix = "$TEST_NGINX_SERVER_ROOT" + local infile = prefix .. "/html/a.lua" + local outfile = prefix .. "/html/a.luac" bcsave.start("-s", infile, outfile) return ngx.exec("/call") end @@ -289,9 +292,9 @@ ngx.status = 201 ngx.say("hello from Lua!") content_by_lua ' local bcsave = require "jit.bcsave" if jit then - local prefix = ngx.config.prefix() - local infile = prefix .. "html/a.lua" - local outfile = prefix .. "html/a.luac" + local prefix = "$TEST_NGINX_SERVER_ROOT" + local infile = prefix .. "/html/a.lua" + local outfile = prefix .. "/html/a.luac" bcsave.start("-g", infile, outfile) return ngx.exec("/call") end @@ -320,9 +323,9 @@ ngx.status = 201 ngx.say("hello from Lua!") --- config location = /t { content_by_lua_block { - local f = assert(loadstring("a = a and a + 1 or 1 ngx.say('a = ', a)", "=code")) + local f = assert(loadstring("local a = 1 ngx.say('a = ', a)", "=code")) local bc = string.dump(f) - local f = assert(io.open("t/servroot/html/a.luac", "w")) + local f = assert(io.open("$TEST_NGINX_SERVER_ROOT/html/a.luac", "w")) f:write(bc) f:close() } @@ -349,9 +352,9 @@ a = 1 --- config location = /t { content_by_lua_block { - local f = assert(loadstring("a = a and a + 1 or 1 ngx.say('a = ', a)", "=code")) + local f = assert(loadstring("local a = 1 ngx.say('a = ', a)", "=code")) local bc = string.dump(f, true) - local f = assert(io.open("t/servroot/html/a.luac", "w")) + local f = assert(io.open("$TEST_NGINX_SERVER_ROOT/html/a.luac", "w")) f:write(bc) f:close() } diff --git a/debian/modules/http-lua/t/082-body-filter.t b/debian/modules/http-lua/t/082-body-filter.t index 98efa84..5f765fa 100644 --- a/debian/modules/http-lua/t/082-body-filter.t +++ b/debian/modules/http-lua/t/082-body-filter.t @@ -460,7 +460,8 @@ GET /t --- config location /t { body_filter_by_lua ' - function foo() + local bar + local function foo() bar() end diff --git a/debian/modules/http-lua/t/084-inclusive-receiveuntil.t b/debian/modules/http-lua/t/084-inclusive-receiveuntil.t index f7d5d3d..66be893 100644 --- a/debian/modules/http-lua/t/084-inclusive-receiveuntil.t +++ b/debian/modules/http-lua/t/084-inclusive-receiveuntil.t @@ -56,7 +56,7 @@ __DATA__ local reader = sock:receiveuntil("abcabd", { inclusive = true }) for i = 1, 3 do - line, err, part = reader() + local line, err, part = reader() if line then ngx.say("read: ", line) @@ -128,7 +128,7 @@ close: 1 nil local reader = sock:receiveuntil("abcabdabcabe", { inclusive = true }) for i = 1, 2 do - line, err, part = reader() + local line, err, part = reader() if line then ngx.say("read: ", line) @@ -200,7 +200,7 @@ close: 1 nil local reader = sock:receiveuntil("abcabd", { inclusive = true }) for i = 1, 3 do - line, err, part = reader() + local line, err, part = reader() if line then ngx.say("read: ", line) @@ -272,7 +272,7 @@ close: 1 nil local reader = sock:receiveuntil("aa", { inclusive = nil }) for i = 1, 2 do - line, err, part = reader() + local line, err, part = reader() if line then ngx.say("read: ", line) @@ -343,7 +343,7 @@ close: 1 nil local reader = sock:receiveuntil("aa", { inclusive = false }) for i = 1, 2 do - line, err, part = reader() + local line, err, part = reader() if line then ngx.say("read: ", line) @@ -414,7 +414,7 @@ close: 1 nil local reader = sock:receiveuntil("aa", { inclusive = true }) for i = 1, 2 do - line, err, part = reader() + local line, err, part = reader() if line then ngx.say("read: ", line) @@ -485,7 +485,7 @@ close: 1 nil local reader = sock:receiveuntil("aa", { inclusive = "true" }) for i = 1, 2 do - line, err, part = reader() + local line, err, part = reader() if line then ngx.say("read: ", line) @@ -552,7 +552,7 @@ bad "inclusive" option value type: string local reader = sock:receiveuntil("aa", { inclusive = "true" }) for i = 1, 2 do - line, err, part = reader() + local line, err, part = reader() if line then ngx.say("read: ", line) @@ -620,7 +620,7 @@ bad "inclusive" option value type: string local reader = sock:receiveuntil("--abc", { inclusive = true }) for i = 1, 7 do - line, err, part = reader(4) + local line, err, part = reader(4) if line then ngx.say("read: ", line) @@ -697,7 +697,7 @@ close: 1 nil local reader = sock:receiveuntil("--abc", { inclusive = true }) for i = 1, 7 do - line, err, part = reader(4) + local line, err, part = reader(4) if line then ngx.say("read: ", line) diff --git a/debian/modules/http-lua/t/087-udp-socket.t b/debian/modules/http-lua/t/087-udp-socket.t index 8bedc32..dc6cad5 100644 --- a/debian/modules/http-lua/t/087-udp-socket.t +++ b/debian/modules/http-lua/t/087-udp-socket.t @@ -555,7 +555,7 @@ lua udp socket read timed out local udp = socket.udp() - udp:settimeout(2000) -- 2 sec + udp:settimeout(5000) -- 5 sec local ok, err = udp:setpeername("$TEST_NGINX_RESOLVER", 53) if not ok then @@ -824,7 +824,7 @@ probe syscall.socket.return, syscall.connect.return { === TEST 15: bad request tries to setpeer --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config server_tokens off; location = /main { @@ -881,7 +881,7 @@ qr/runtime error: content_by_lua\(nginx\.conf:\d+\):14: bad request/ === TEST 16: bad request tries to send --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config server_tokens off; location = /main { @@ -938,7 +938,7 @@ qr/runtime error: content_by_lua\(nginx\.conf:\d+\):14: bad request/ === TEST 17: bad request tries to receive --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config server_tokens off; location = /main { @@ -995,7 +995,7 @@ qr/runtime error: content_by_lua\(nginx\.conf:\d+\):14: bad request/ === TEST 18: bad request tries to close --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config server_tokens off; location = /main { @@ -1052,7 +1052,7 @@ qr/runtime error: content_by_lua\(nginx\.conf:\d+\):14: bad request/ === TEST 19: bad request tries to receive --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config server_tokens off; location = /main { diff --git a/debian/modules/http-lua/t/090-log-socket-errors.t b/debian/modules/http-lua/t/090-log-socket-errors.t index 16576b6..f5a9f80 100644 --- a/debian/modules/http-lua/t/090-log-socket-errors.t +++ b/debian/modules/http-lua/t/090-log-socket-errors.t @@ -28,7 +28,7 @@ __DATA__ lua_socket_log_errors off; content_by_lua ' local sock = ngx.socket.tcp() - local ok, err = sock:connect("agentzh.org", 12345) + local ok, err = sock:connect("127.0.0.2", 12345) ngx.say(err) '; } @@ -50,7 +50,7 @@ timeout lua_socket_log_errors on; content_by_lua ' local sock = ngx.socket.tcp() - local ok, err = sock:connect("agentzh.org", 12345) + local ok, err = sock:connect("127.0.0.2", 12345) ngx.say(err) '; } @@ -59,7 +59,7 @@ GET /t --- response_body timeout --- error_log -lua tcp socket connect timed out, when connecting to 172.105.207.225:12345 +lua tcp socket connect timed out, when connecting to 127.0.0.2:12345 @@ -72,7 +72,7 @@ lua tcp socket connect timed out, when connecting to 172.105.207.225:12345 lua_socket_read_timeout 1ms; content_by_lua ' local sock = ngx.socket.udp() - local ok, err = sock:setpeername("agentzh.org", 12345) + local ok, err = sock:setpeername("127.0.0.2", 12345) ok, err = sock:receive() ngx.say(err) '; @@ -95,7 +95,7 @@ lua udp socket read timed out lua_socket_read_timeout 1ms; content_by_lua ' local sock = ngx.socket.udp() - local ok, err = sock:setpeername("agentzh.org", 12345) + local ok, err = sock:setpeername("127.0.0.2", 12345) ok, err = sock:receive() ngx.say(err) '; diff --git a/debian/modules/http-lua/t/091-coroutine.t b/debian/modules/http-lua/t/091-coroutine.t index bceb512..7cf60f9 100644 --- a/debian/modules/http-lua/t/091-coroutine.t +++ b/debian/modules/http-lua/t/091-coroutine.t @@ -85,7 +85,7 @@ __DATA__ content_by_lua ' local cc, cr, cy = coroutine.create, coroutine.resume, coroutine.yield - function f() + local function f() local cnt = 0 for i = 1, 20 do ngx.say("Hello, ", cnt) @@ -120,7 +120,7 @@ Hello, 2 --- config location /lua { content_by_lua ' - function f(fid) + local function f(fid) local cnt = 0 while true do ngx.say("cc", fid, ": ", cnt) @@ -163,7 +163,7 @@ cc3: 2 resolver $TEST_NGINX_RESOLVER ipv6=off; location /lua { content_by_lua ' - function worker(url) + local function worker(url) local sock = ngx.socket.tcp() local ok, err = sock:connect(url, 80) coroutine.yield() @@ -178,7 +178,7 @@ cc3: 2 local urls = { "agentzh.org", - "iscribblet.org", + "openresty.com", "openresty.org" } @@ -204,7 +204,7 @@ cc3: 2 GET /lua --- response_body successfully connected to: agentzh.org -successfully connected to: iscribblet.org +successfully connected to: openresty.com successfully connected to: openresty.org *** All Done *** --- no_error_log @@ -218,14 +218,14 @@ successfully connected to: openresty.org location /lua { content_by_lua ' -- generate all the numbers from 2 to n - function gen (n) + local function gen (n) return coroutine.wrap(function () for i=2,n do coroutine.yield(i) end end) end -- filter the numbers generated by g, removing multiples of p - function filter (p, g) + local function filter (p, g) return coroutine.wrap(function () while 1 do local n = g() @@ -235,8 +235,8 @@ successfully connected to: openresty.org end) end - N = 10 - x = gen(N) -- generate primes up to N + local N = 10 + local x = gen(N) -- generate primes up to N while 1 do local n = x() -- pick a number until done if n == nil then break end @@ -264,14 +264,14 @@ GET /lua coroutine.create = nil coroutine.resume = nil -- generate all the numbers from 2 to n - function gen (n) + local function gen (n) return coroutine.wrap(function () for i=2,n do coroutine.yield(i) end end) end -- filter the numbers generated by g, removing multiples of p - function filter (p, g) + local function filter (p, g) return coroutine.wrap(function () while 1 do local n = g() @@ -281,8 +281,8 @@ GET /lua end) end - N = 10 - x = gen(N) -- generate primes up to N + local N = 10 + local x = gen(N) -- generate primes up to N while 1 do local n = x() -- pick a number until done if n == nil then break end @@ -307,7 +307,7 @@ GET /lua --- config location /lua { content_by_lua ' - function generatefib (n) + local function generatefib (n) return coroutine.wrap(function () local a,b = 1, 1 while a <= n do @@ -362,7 +362,7 @@ GET /lua resolver $TEST_NGINX_RESOLVER ipv6=off; location /lua { content_by_lua ' - function worker(url) + local function worker(url) local sock = ngx.socket.tcp() local ok, err = sock:connect(url, 80) coroutine.yield() @@ -377,7 +377,7 @@ GET /lua local urls = { "agentzh.org", - "iscribblet.org", + "openresty.com", "openresty.org" } @@ -398,7 +398,7 @@ GET /lua GET /lua --- response_body successfully connected to: agentzh.org -successfully connected to: iscribblet.org +successfully connected to: openresty.com successfully connected to: openresty.org *** All Done *** --- no_error_log @@ -414,7 +414,7 @@ successfully connected to: openresty.org local cc, cr, cy = coroutine.create, coroutine.resume, coroutine.yield local st, rn = coroutine.status, coroutine.running - function f(self) + local function f(self) local cnt = 0 if rn() ~= self then ngx.say("error"); return end ngx.say("running: ", st(self)) --running @@ -509,7 +509,7 @@ GET /lua --- config location /lua { content_by_lua ' - function print(...) + local function print(...) local args = {...} local is_first = true for i,v in ipairs(args) do @@ -523,12 +523,12 @@ GET /lua ngx.print("\\\n") end - function foo (a) + local function foo (a) print("foo", a) return coroutine.yield(2*a) end - co = coroutine.create(function (a,b) + local co = coroutine.create(function (a,b) print("co-body", a, b) local r = foo(a+1) print("co-body", r) @@ -566,7 +566,8 @@ main false cannot resume dead coroutine local create = coroutine.create local resume = coroutine.resume local yield = coroutine.yield - function f() + local g + local function f() ngx.say("f begin") yield() local c2 = create(g) @@ -627,8 +628,9 @@ main done local yield = coroutine.yield local code = 400 + local g - function f() + local function f() local c2 = create(g) yield() code = code + 1 @@ -683,8 +685,9 @@ exit local yield = coroutine.yield local code = 0 + local g - function f() + local function f() local c2 = create(g) yield() code = code + 1 @@ -740,7 +743,7 @@ num: 3 location /lua { echo hello; header_filter_by_lua ' - function f() + local function f() yield() end @@ -764,13 +767,13 @@ API disabled in the context of header_filter_by_lua* local c1, c2 - function f() + local function f() print("f 1") print(coroutine.resume(c2)) print("f 2") end - function g() + local function g() print("g 1") -- print(coroutine.resume(c1)) print("g 2") @@ -803,13 +806,13 @@ f 2 local c1, c2 - function f() + local function f() print("f 1") print(coroutine.resume(c2)) print("f 2") end - function g() + local function g() print("g 1") print(coroutine.resume(c1)) print("g 2") @@ -859,7 +862,7 @@ falsecannot resume running coroutine location /t { content_by_lua ' local co - function f() + local function f() ngx.say("f: ", coroutine.status(co)) ngx.say("f: ", coroutine.resume(co)) end @@ -885,7 +888,7 @@ chunk: true location /t { content_by_lua ' local co - function f() + local function f() error("bad") end co = coroutine.create(f) @@ -990,7 +993,7 @@ test10 resolver $TEST_NGINX_RESOLVER ipv6=off; location /lua { content_by_lua ' - function worker(url) + local function worker(url) local sock = ngx.socket.tcp() local ok, err = sock:connect(url, 80) coroutine.yield() @@ -1044,7 +1047,7 @@ successfully connected to: agentzh.org resolver $TEST_NGINX_RESOLVER ipv6=off; location /lua { content_by_lua ' - function worker(url) + local function worker(url) local sock = ngx.socket.tcp() local ok, err = sock:connect(url, 80) coroutine.yield() @@ -1104,7 +1107,7 @@ successfully connected to: agentzh.org --- config location /cotest { content_by_lua ' - function generator() + local function generator() return co_wrap(function() co_yield("data") end) @@ -1133,7 +1136,7 @@ data --- config location /cotest { content_by_lua ' - function generator() + local function generator() return co_wrap(function() co_yield("data") end) @@ -1166,7 +1169,7 @@ data content_by_lua ' local cc, cr, cy = coroutine.create, coroutine.resume, coroutine.yield - function f() + local function f() return 3 end @@ -1199,7 +1202,7 @@ ok local coroutine = require "coroutine" local cc, cr, cy = coroutine.create, coroutine.resume, coroutine.yield - function f() + local function f() local cnt = 0 for i = 1, 20 do ngx.say("Hello, ", cnt) @@ -1238,7 +1241,7 @@ Hello, 2 header_filter_by_lua ' local cc, cr, cy = coroutine.create, coroutine.resume, coroutine.yield - function f() + local function f() local cnt = 0 for i = 1, 20 do print("co yield: ", cnt) @@ -1278,7 +1281,7 @@ co yield: 2 body_filter_by_lua ' local cc, cr, cy = coroutine.create, coroutine.resume, coroutine.yield - function f() + local function f() local cnt = 0 for i = 1, 20 do print("co yield: ", cnt) diff --git a/debian/modules/http-lua/t/093-uthread-spawn.t b/debian/modules/http-lua/t/093-uthread-spawn.t index b622d30..ab6db2f 100644 --- a/debian/modules/http-lua/t/093-uthread-spawn.t +++ b/debian/modules/http-lua/t/093-uthread-spawn.t @@ -24,7 +24,7 @@ __DATA__ --- config location /lua { content_by_lua ' - function f() + local function f() ngx.say("hello in thread") end @@ -58,11 +58,11 @@ after --- config location /lua { content_by_lua ' - function f() + local function f() ngx.say("in thread 1") end - function g() + local function g() ngx.say("in thread 2") end @@ -107,7 +107,7 @@ after 2 --- config location /lua { content_by_lua ' - function f() + local function f() ngx.say("before sleep") ngx.sleep(0.1) ngx.say("after sleep") @@ -144,13 +144,13 @@ after sleep --- config location /lua { content_by_lua ' - function f() + local function f() ngx.say("1: before sleep") ngx.sleep(0.2) ngx.say("1: after sleep") end - function g() + local function g() ngx.say("2: before sleep") ngx.sleep(0.1) ngx.say("2: after sleep") @@ -200,7 +200,7 @@ delete thread 2 --- config location /lua { content_by_lua ' - function f() + local function f() ngx.blah() end @@ -231,9 +231,9 @@ qr/lua user thread aborted: runtime error: content_by_lua\(nginx\.conf:\d+\):3: --- config location /lua { content_by_lua ' - function f() + local function f() ngx.say("before capture") - res = ngx.location.capture("/proxy") + local res = ngx.location.capture("/proxy") ngx.say("after capture: ", res.body) end @@ -277,7 +277,7 @@ after capture: hello world --- config location /lua { content_by_lua ' - function f() + local function f() ngx.say("before capture") local res = ngx.location.capture("/proxy?foo") ngx.say("after capture: ", res.body) @@ -330,7 +330,7 @@ after capture: hello foo --- config location /lua { content_by_lua ' - function f() + local function f() ngx.say("before capture") local res = ngx.location.capture("/proxy?foo") ngx.say("after capture: ", res.body) @@ -384,13 +384,13 @@ capture: hello bar --- config location /lua { content_by_lua ' - function f() + local function f() ngx.say("f: before capture") local res = ngx.location.capture("/proxy?foo") ngx.say("f: after capture: ", res.body) end - function g() + local function g() ngx.say("g: before capture") local res = ngx.location.capture("/proxy?bah") ngx.say("g: after capture: ", res.body) @@ -462,7 +462,8 @@ g: after capture: hello bah --- config location /lua { content_by_lua ' - function f() + local g + local function f() ngx.say("before g") ngx.thread.spawn(g) ngx.say("after g") @@ -508,7 +509,8 @@ after g --- config location /lua { content_by_lua ' - function f() + local g + local function f() ngx.say("before g") ngx.thread.spawn(g) ngx.say("after g") @@ -556,7 +558,7 @@ hello in g() location /lua { content_by_lua ' local co - function f() + local function f() co = coroutine.running() ngx.sleep(0.1) end @@ -589,7 +591,7 @@ status: running location /lua { content_by_lua ' local co - function f() + local function f() co = coroutine.running() end @@ -621,7 +623,8 @@ status: zombie location /lua { content_by_lua ' local co - function f() + local g + local function f() co = coroutine.running() local co2 = coroutine.create(g) coroutine.resume(co2) @@ -660,7 +663,8 @@ status: normal --- config location /lua { content_by_lua ' - function f() + local g + local function f() ngx.say("before g") ngx.thread.spawn(g) ngx.say("after g") @@ -707,7 +711,7 @@ after f content_by_lua ' local yield = coroutine.yield - function f() + local function f() local self = coroutine.running() ngx.say("f 1") yield(self) @@ -760,7 +764,7 @@ f 3 content_by_lua ' local yield = coroutine.yield - function f() + local function f() local self = coroutine.running() ngx.say("f 1") yield(self) @@ -769,7 +773,7 @@ f 3 ngx.say("f 3") end - function g() + local function g() local self = coroutine.running() ngx.say("g 1") yield(self) @@ -816,7 +820,7 @@ g 3 --- config location /lua { content_by_lua ' - function f() + local function f() ngx.say("hello in thread") coroutine.yield(coroutine.running) ngx.flush(true) @@ -853,12 +857,12 @@ after --- config location /lua { content_by_lua ' - function f() + local function f() ngx.say("hello from f") ngx.flush(true) end - function g() + local function g() ngx.say("hello from g") ngx.flush(true) end @@ -904,7 +908,7 @@ hello from g --- config location /lua { content_by_lua ' - function f() + local function f() local sock = ngx.socket.tcp() local ok, err = sock:connect("127.0.0.1", $TEST_NGINX_MEMCACHED_PORT) if not ok then @@ -956,7 +960,7 @@ received: OK --- config location /lua { content_by_lua ' - function f() + local function f() local sock = ngx.socket.udp() local ok, err = sock:setpeername("127.0.0.1", 12345) local bytes, err = sock:send("blah") @@ -1018,7 +1022,7 @@ after)$ --- config location /lua { content_by_lua ' - function f() + local function f() ngx.req.read_body() local body = ngx.req.get_body_data() ngx.say("body: ", body) @@ -1063,7 +1067,7 @@ body: hello world)$ --- config location /lua { content_by_lua ' - function f() + local function f() local sock = ngx.req.socket() local body, err = sock:receive(11) if not body then @@ -1113,7 +1117,7 @@ body: hello world)$ --- config location /lua { content_by_lua ' - function f(a, b) + local function f(a, b) ngx.say("hello ", a, " and ", b) end @@ -1647,7 +1651,7 @@ ok --- config location /lua { content_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.say("f") end diff --git a/debian/modules/http-lua/t/094-uthread-exit.t b/debian/modules/http-lua/t/094-uthread-exit.t index 2f7d9ba..58d8d0b 100644 --- a/debian/modules/http-lua/t/094-uthread-exit.t +++ b/debian/modules/http-lua/t/094-uthread-exit.t @@ -24,7 +24,7 @@ __DATA__ --- config location /lua { content_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.exit(0) end @@ -87,7 +87,7 @@ hello in thread --- config location /lua { content_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -171,13 +171,13 @@ after --- config location /lua { content_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.say("f") ngx.exit(0) end - function g() + local function g() ngx.sleep(1) ngx.say("g") end @@ -261,7 +261,7 @@ f --- config location /lua { content_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.say("exiting the user thread") ngx.exit(0) @@ -297,10 +297,10 @@ exiting the user thread === TEST 5: exit in user thread (entry thread is still pending on the DNS resolver for ngx.socket.tcp) --- config location /lua { - resolver agentzh.org; + resolver 127.0.0.2:12345; resolver_timeout 12s; content_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.sleep(0.001) ngx.exit(0) @@ -393,10 +393,10 @@ after === TEST 6: exit in user thread (entry thread is still pending on the DNS resolver for ngx.socket.udp) --- config location /lua { - resolver agentzh.org; + resolver 127.0.0.2:12345; resolver_timeout 12s; content_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.sleep(0.001) ngx.exit(0) @@ -490,7 +490,7 @@ after --- config location /lua { content_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -501,7 +501,7 @@ after ngx.say("after") local sock = ngx.socket.tcp() sock:settimeout(12000) - local ok, err = sock:connect("172.105.207.225", 12345) + local ok, err = sock:connect("127.0.0.2", 12345) if not ok then ngx.say("failed to connect: ", err) return @@ -580,7 +580,7 @@ after --- config location /lua { content_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -680,7 +680,7 @@ after --- config location /lua { content_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -786,7 +786,7 @@ after --- config location /lua { content_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -881,7 +881,7 @@ after --- config location /lua { content_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -974,7 +974,7 @@ after location /lua { client_body_timeout 12000ms; content_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -1059,7 +1059,7 @@ after location /lua { client_body_timeout 12000ms; content_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -1142,7 +1142,7 @@ attempt to abort with pending subrequests location /lua { client_body_timeout 12000ms; content_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.exit(0) end @@ -1225,7 +1225,7 @@ attempt to abort with pending subrequests location /lua { client_body_timeout 12000ms; content_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.exit(0) end @@ -1315,7 +1315,7 @@ attempt to abort with pending subrequests location /lua { client_body_timeout 12000ms; content_by_lua ' - function f() + local function f() ngx.location.capture_multi{ {"/echo"}, {"/sleep"} @@ -1407,7 +1407,7 @@ attempt to abort with pending subrequests location /lua { client_body_timeout 12000ms; content_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(444) @@ -1490,7 +1490,7 @@ free request location /lua { client_body_timeout 12000ms; content_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(408) @@ -1573,7 +1573,7 @@ free request location /lua { client_body_timeout 12000ms; content_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(499) diff --git a/debian/modules/http-lua/t/095-uthread-exec.t b/debian/modules/http-lua/t/095-uthread-exec.t index 56156c4..7bf37c0 100644 --- a/debian/modules/http-lua/t/095-uthread-exec.t +++ b/debian/modules/http-lua/t/095-uthread-exec.t @@ -23,7 +23,7 @@ __DATA__ --- config location /lua { content_by_lua ' - function f() + local function f() ngx.exec("/foo") end @@ -58,7 +58,7 @@ i am foo --- config location /lua { content_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.exec("/foo") end @@ -93,7 +93,7 @@ i am foo --- config location /lua { content_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.exec("/foo") end @@ -175,12 +175,12 @@ hello foo --- config location /lua { content_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.exec("/foo") end - function g() + local function g() ngx.sleep(1) end @@ -267,7 +267,7 @@ hello foo location /lua { client_body_timeout 12000ms; content_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.exec("/foo") end @@ -348,7 +348,7 @@ attempt to abort with pending subrequests location /lua { client_body_timeout 12000ms; content_by_lua ' - function f() + local function f() ngx.location.capture("/sleep") ngx.say("end") end diff --git a/debian/modules/http-lua/t/096-uthread-redirect.t b/debian/modules/http-lua/t/096-uthread-redirect.t index 003c642..95bff01 100644 --- a/debian/modules/http-lua/t/096-uthread-redirect.t +++ b/debian/modules/http-lua/t/096-uthread-redirect.t @@ -25,7 +25,7 @@ __DATA__ location /lua { client_body_timeout 12000ms; content_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.redirect(301) end @@ -114,7 +114,7 @@ attempt to abort with pending subrequests --- config location /lua { content_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.redirect(301) end @@ -194,7 +194,7 @@ free request location /lua { client_body_timeout 12000ms; content_by_lua ' - function f() + local function f() ngx.location.capture_multi{ {"/echo"}, {"/sleep"} diff --git a/debian/modules/http-lua/t/097-uthread-rewrite.t b/debian/modules/http-lua/t/097-uthread-rewrite.t index 2f0c06f..998e256 100644 --- a/debian/modules/http-lua/t/097-uthread-rewrite.t +++ b/debian/modules/http-lua/t/097-uthread-rewrite.t @@ -23,7 +23,7 @@ __DATA__ --- config location /lua { rewrite_by_lua ' - function f() + local function f() ngx.req.set_uri("/foo", true) end @@ -58,7 +58,7 @@ i am foo --- config location /lua { rewrite_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.req.set_uri("/foo", true) end @@ -93,7 +93,7 @@ i am foo --- config location /lua { rewrite_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.req.set_uri("/foo", true) end @@ -175,12 +175,12 @@ hello foo --- config location /lua { rewrite_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.req.set_uri("/foo", true) end - function g() + local function g() ngx.sleep(1) end @@ -267,7 +267,7 @@ hello foo location /lua { client_body_timeout 12000ms; rewrite_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.req.set_uri("/foo", true) end diff --git a/debian/modules/http-lua/t/098-uthread-wait.t b/debian/modules/http-lua/t/098-uthread-wait.t index 4948596..c2819ae 100644 --- a/debian/modules/http-lua/t/098-uthread-wait.t +++ b/debian/modules/http-lua/t/098-uthread-wait.t @@ -23,7 +23,7 @@ __DATA__ --- config location /lua { content_by_lua ' - function f() + local function f() ngx.say("hello in thread") return "done" end @@ -72,7 +72,7 @@ done --- config location /lua { content_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.say("hello in thread") return "done" @@ -120,13 +120,13 @@ done --- config location /lua { content_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.say("f: hello") return "done" end - function g() + local function g() ngx.sleep(0.2) ngx.say("g: hello") return "done" @@ -200,13 +200,13 @@ f: done --- config location /lua { content_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.say("f: hello") return "done" end - function g() + local function g() ngx.sleep(0.2) ngx.say("g: hello") return "done" @@ -228,7 +228,7 @@ f: done ngx.say("g thread created: ", coroutine.status(tg)) - ok, res = ngx.thread.wait(tf) + local ok, res = ngx.thread.wait(tf) if not ok then ngx.say("failed to wait f: ", res) return @@ -281,7 +281,7 @@ g: done --- config location /lua { content_by_lua ' - function f() + local function f() ngx.say("hello in thread") return "done", 3.14 end @@ -330,7 +330,7 @@ res: done 3.14 --- config location /lua { content_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.say("hello in thread") return "done", 3.14 @@ -378,7 +378,7 @@ res: done 3.14 --- config location /lua { content_by_lua ' - function f() + local function f() ngx.say("hello in thread") error("bad bad!") end @@ -427,7 +427,7 @@ qr/lua user thread aborted: runtime error: content_by_lua\(nginx\.conf:\d+\):4: --- config location /lua { content_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.say("hello in thread") error("bad bad!") @@ -477,12 +477,12 @@ qr/lua user thread aborted: runtime error: content_by_lua\(nginx\.conf:\d+\):5: --- config location /lua { content_by_lua ' - function g() + local function g() ngx.say("hello in thread") return "done" end - function f() + local function f() local t, err = ngx.thread.spawn(g) if not t then ngx.say("failed to spawn thread: ", err) @@ -533,13 +533,13 @@ done --- config location /lua { content_by_lua ' - function g() + local function g() ngx.sleep(0.1) ngx.say("hello in thread") return "done" end - function f() + local function f() local t, err = ngx.thread.spawn(g) if not t then ngx.say("failed to spawn thread: ", err) @@ -593,12 +593,12 @@ done -- local out = function (...) ngx.log(ngx.ERR, ...) end local out = ngx.say - function f() + local function f() out("f: hello") return "f done" end - function g() + local function g() out("g: hello") return "g done" end @@ -668,13 +668,13 @@ g status: zombie -- local out = function (...) ngx.log(ngx.ERR, ...) end local out = ngx.say - function f() + local function f() ngx.sleep(0.1) out("f: hello") return "f done" end - function g() + local function g() ngx.sleep(0.2) out("g: hello") return "g done" @@ -745,13 +745,13 @@ g: hello -- local out = function (...) ngx.log(ngx.ERR, ...) end local out = ngx.say - function f() + local function f() ngx.sleep(0.2) out("f: hello") return "f done" end - function g() + local function g() ngx.sleep(0.1) out("g: hello") return "g done" @@ -822,12 +822,12 @@ f: hello -- local out = function (...) ngx.log(ngx.ERR, ...) end local out = ngx.say - function f() + local function f() out("f: hello") error("f done") end - function g() + local function g() out("g: hello") error("g done") end @@ -896,13 +896,13 @@ qr/lua user thread aborted: runtime error: content_by_lua\(nginx\.conf:\d+\):7: -- local out = function (...) ngx.log(ngx.ERR, ...) end local out = ngx.say - function f() + local function f() ngx.sleep(0.1) out("f: hello") error("f done") end - function g() + local function g() ngx.sleep(0.2) out("g: hello") error("g done") @@ -969,13 +969,13 @@ qr/lua user thread aborted: runtime error: content_by_lua\(nginx\.conf:\d+\):8: --- config location /lua { content_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.say("f: hello") return "done" end - function g() + local function g() ngx.sleep(0.2) ngx.say("g: hello") return "done" @@ -997,7 +997,7 @@ qr/lua user thread aborted: runtime error: content_by_lua\(nginx\.conf:\d+\):8: ngx.say("g thread created: ", coroutine.status(tg)) - ok, res = ngx.thread.wait(tf, tg) + local ok, res = ngx.thread.wait(tf, tg) if not ok then ngx.say("failed to wait: ", res) return @@ -1038,13 +1038,13 @@ res: done --- config location /lua { content_by_lua ' - function f() + local function f() ngx.sleep(0.2) ngx.say("f: hello") return "f done" end - function g() + local function g() ngx.sleep(0.1) ngx.say("g: hello") return "g done" @@ -1066,7 +1066,7 @@ res: done ngx.say("g thread created: ", coroutine.status(tg)) - ok, res = ngx.thread.wait(tf, tg) + local ok, res = ngx.thread.wait(tf, tg) if not ok then ngx.say("failed to wait: ", res) return @@ -1109,12 +1109,12 @@ res: g done content_by_lua ' local t - function f() + local function f() ngx.sleep(0.1) return "done" end - function g() + local function g() t = ngx.thread.spawn(f) end @@ -1154,7 +1154,7 @@ only the parent coroutine can wait on the thread --- config location /lua { content_by_lua ' - function f() + local function f() ngx.sleep(0.1) coroutine.yield() return "done" @@ -1192,7 +1192,7 @@ qr/lua entry thread aborted: runtime error: content_by_lua\(nginx\.conf:\d+\):11 --- config location /lua { content_by_lua ' - function f() + local function f() ngx.sleep(0.1) collectgarbage() error("f done") @@ -1228,7 +1228,7 @@ qr/lua user thread aborted: runtime error: content_by_lua\(nginx\.conf:\d+\):5: --- config location /lua { content_by_lua ' - function f() + local function f() ngx.say("hello in thread") return "done" end @@ -1283,7 +1283,7 @@ failed to run thread: already waited or killed --- config location /lua { content_by_lua ' - function f() + local function f() -- ngx.say("hello in thread") return "done" end diff --git a/debian/modules/http-lua/t/099-c-api.t b/debian/modules/http-lua/t/099-c-api.t index a0b375c..5033462 100644 --- a/debian/modules/http-lua/t/099-c-api.t +++ b/debian/modules/http-lua/t/099-c-api.t @@ -86,7 +86,7 @@ dogs zone: defined local buf = ffi.new("char[?]", 4) ffi.copy(buf, "dogs", 4) - zone = ffi.C.ngx_http_lua_find_zone(buf, 4) + local zone = ffi.C.ngx_http_lua_find_zone(buf, 4) local val = ffi.new("ngx_http_lua_value_t[?]", 1) @@ -149,7 +149,7 @@ bar: rc=0, type=3, val=3.14159 local buf = ffi.new("char[?]", 4) ffi.copy(buf, "dogs", 4) - zone = ffi.C.ngx_http_lua_find_zone(buf, 4) + local zone = ffi.C.ngx_http_lua_find_zone(buf, 4) local val = ffi.new("ngx_http_lua_value_t[?]", 1) @@ -212,7 +212,7 @@ bar: rc=0, type=1, val=0 local buf = ffi.new("char[?]", 4) ffi.copy(buf, "dogs", 4) - zone = ffi.C.ngx_http_lua_find_zone(buf, 4) + local zone = ffi.C.ngx_http_lua_find_zone(buf, 4) local val = ffi.new("ngx_http_lua_value_t[?]", 1) @@ -272,7 +272,7 @@ bar: rc=-5 local buf = ffi.new("char[?]", 4) ffi.copy(buf, "dogs", 4) - zone = ffi.C.ngx_http_lua_find_zone(buf, 4) + local zone = ffi.C.ngx_http_lua_find_zone(buf, 4) local s = ffi.new("char[?]", 20) @@ -344,7 +344,7 @@ bar: rc=0, type=4, val=, len=0 local buf = ffi.new("char[?]", 4) ffi.copy(buf, "dogs", 4) - zone = ffi.C.ngx_http_lua_find_zone(buf, 4) + local zone = ffi.C.ngx_http_lua_find_zone(buf, 4) local val = ffi.new("ngx_http_lua_value_t[?]", 1) diff --git a/debian/modules/http-lua/t/100-client-abort.t b/debian/modules/http-lua/t/100-client-abort.t index 89c1f6a..f571387 100644 --- a/debian/modules/http-lua/t/100-client-abort.t +++ b/debian/modules/http-lua/t/100-client-abort.t @@ -195,7 +195,7 @@ bad things happen location = /sub { proxy_ignore_client_abort on; - proxy_pass http://agentzh.org:12345/; + proxy_pass http://127.0.0.2:12345/; } location = /sleep { @@ -236,7 +236,7 @@ client prematurely closed connection location = /sub { proxy_ignore_client_abort off; - proxy_pass http://agentzh.org:12345/; + proxy_pass http://127.0.0.2:12345/; } --- request GET /t @@ -540,7 +540,7 @@ client prematurely closed connection return end - ok, err = sock:connect("127.0.0.1", $TEST_NGINX_REDIS_PORT) + local ok, err = sock:connect("127.0.0.1", $TEST_NGINX_REDIS_PORT) if not ok then ngx.log(ngx.ERR, "failed to connect: ", err) return diff --git a/debian/modules/http-lua/t/106-timer.t b/debian/modules/http-lua/t/106-timer.t index 3e4741e..7b7c85e 100644 --- a/debian/modules/http-lua/t/106-timer.t +++ b/debian/modules/http-lua/t/106-timer.t @@ -76,7 +76,7 @@ qr/\[lua\] content_by_lua\(nginx\.conf:\d+\):\d+: elapsed: 0\.0(?:4[4-9]|5[0-6]) -=== TEST 2: separated global env +=== TEST 2: globals are shared --- config location /t { content_by_lua ' @@ -104,7 +104,7 @@ F(ngx_http_lua_timer_handler) { --- response_body registered timer -foo = nil +foo = 3 --- wait: 0.1 --- no_error_log @@ -320,7 +320,7 @@ qr/received: Server: \S+/, === TEST 6: tcp cosocket in timer handler (keep-alive connections) --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /t { @@ -596,7 +596,7 @@ qr/\[lua\] log_by_lua\(nginx\.conf:\d+\):\d+: elapsed: 0\.0(?:6[4-9]|7[0-6])/, === TEST 10: tcp cosocket in timer handler (keep-alive connections) - log_by_lua --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /t { @@ -693,7 +693,7 @@ qr/go\(\): connected: 1, reused: \d+/, === TEST 11: tcp cosocket in timer handler (keep-alive connections) - header_filter_by_lua --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /t { @@ -799,7 +799,7 @@ qr/go\(\): connected: 1, reused: \d+/, === TEST 12: tcp cosocket in timer handler (keep-alive connections) - body_filter_by_lua --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /t { @@ -912,7 +912,7 @@ qr/go\(\): connected: 1, reused: \d+/, === TEST 13: tcp cosocket in timer handler (keep-alive connections) - set_by_lua --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /t { @@ -1023,7 +1023,7 @@ qr/go\(\): connected: 1, reused: \d+/, content_by_lua ' local cc, cr, cy = coroutine.create, coroutine.resume, coroutine.yield local function f() - function f() + local function f() local cnt = 0 for i = 1, 20 do print("cnt = ", cnt) @@ -1090,7 +1090,7 @@ registered timer ngx.log(ngx.ERR, ...) end local function handle() - function f() + local function f() print("hello in thread") return "done" end diff --git a/debian/modules/http-lua/t/108-timer-safe.t b/debian/modules/http-lua/t/108-timer-safe.t index 2795998..758d01a 100644 --- a/debian/modules/http-lua/t/108-timer-safe.t +++ b/debian/modules/http-lua/t/108-timer-safe.t @@ -229,7 +229,7 @@ qr/received: Server: \S+/, === TEST 4: tcp cosocket in timer handler (keep-alive connections) --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /t { @@ -489,7 +489,7 @@ delete thread 2 --- response_body hello world ---- wait: 0.1 +--- wait: 0.15 --- no_error_log [error] [alert] @@ -499,7 +499,7 @@ hello world [ "registered timer", qr/\[lua\] .*? my lua timer handler/, -qr/\[lua\] log_by_lua\(nginx\.conf:\d+\):\d+: elapsed: 0\.0(?:6[4-9]|7[0-6])/, +qr/\[lua\] log_by_lua\(nginx\.conf:\d+\):\d+: elapsed: 0\.0(?:6[4-9]|7[0-9]|8[0-6])/, "lua ngx.timer expired", "http lua close fake http connection" ] @@ -508,7 +508,7 @@ qr/\[lua\] log_by_lua\(nginx\.conf:\d+\):\d+: elapsed: 0\.0(?:6[4-9]|7[0-6])/, === TEST 8: tcp cosocket in timer handler (keep-alive connections) - log_by_lua --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /t { @@ -606,7 +606,7 @@ qr/go\(\): connected: 1, reused: \d+/, === TEST 9: tcp cosocket in timer handler (keep-alive connections) - header_filter_by_lua --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /t { @@ -713,7 +713,7 @@ qr/go\(\): connected: 1, reused: \d+/, === TEST 10: tcp cosocket in timer handler (keep-alive connections) - body_filter_by_lua --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /t { @@ -827,7 +827,7 @@ qr/go\(\): connected: 1, reused: \d+/, === TEST 11: tcp cosocket in timer handler (keep-alive connections) - set_by_lua --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /t { @@ -1007,7 +1007,7 @@ registered timer ngx.log(ngx.ERR, ...) end local function handle() - function f() + local function f() print("hello in thread") return "done" end diff --git a/debian/modules/http-lua/t/109-timer-hup.t b/debian/modules/http-lua/t/109-timer-hup.t index 0864046..2c197c2 100644 --- a/debian/modules/http-lua/t/109-timer-hup.t +++ b/debian/modules/http-lua/t/109-timer-hup.t @@ -46,7 +46,7 @@ __DATA__ --- config location /t { content_by_lua ' - local f, err = io.open("t/servroot/logs/nginx.pid", "r") + local f, err = io.open("$TEST_NGINX_SERVER_ROOT/logs/nginx.pid", "r") if not f then ngx.say("failed to open nginx.pid: ", err) return @@ -99,7 +99,7 @@ timer prematurely expired: true --- config location /t { content_by_lua ' - local f, err = io.open("t/servroot/logs/nginx.pid", "r") + local f, err = io.open("$TEST_NGINX_SERVER_ROOT/logs/nginx.pid", "r") if not f then ngx.say("failed to open nginx.pid: ", err) return @@ -163,7 +163,7 @@ timer prematurely expired: true --- config location /t { content_by_lua ' - local f, err = io.open("t/servroot/logs/nginx.pid", "r") + local f, err = io.open("$TEST_NGINX_SERVER_ROOT/logs/nginx.pid", "r") if not f then ngx.say("failed to open nginx.pid: ", err) return @@ -219,7 +219,7 @@ failed to register a new timer after reload: process exiting, context: ngx.timer --- config location /t { content_by_lua ' - local f, err = io.open("t/servroot/logs/nginx.pid", "r") + local f, err = io.open("$TEST_NGINX_SERVER_ROOT/logs/nginx.pid", "r") if not f then ngx.say("failed to open nginx.pid: ", err) return @@ -284,7 +284,7 @@ g: exiting=true --- config location /t { content_by_lua ' - local f, err = io.open("t/servroot/logs/nginx.pid", "r") + local f, err = io.open("$TEST_NGINX_SERVER_ROOT/logs/nginx.pid", "r") if not f then ngx.say("failed to open nginx.pid: ", err) return @@ -363,7 +363,7 @@ lua found 100 pending timers local line, err = sock:receive("*l") until not line or string.find(line, "^%s*$") - function foo() + local function foo() repeat -- Get and read chunk local line, err = sock:receive("*l") @@ -379,7 +379,7 @@ lua found 100 pending timers until len == 0 end - co = coroutine.create(foo) + local co = coroutine.create(foo) repeat local chunk = select(2,coroutine.resume(co)) until chunk == nil @@ -399,7 +399,7 @@ lua found 100 pending timers end local ok, err = ngx.timer.at(1, background_thread) - local f, err = io.open("t/servroot/logs/nginx.pid", "r") + local f, err = io.open("$TEST_NGINX_SERVER_ROOT/logs/nginx.pid", "r") if not f then ngx.say("failed to open nginx.pid: ", err) return @@ -453,7 +453,7 @@ lua found 1 pending timers end if kill then - local f, err = io.open("t/servroot/logs/nginx.pid", "r") + local f, err = io.open("$TEST_NGINX_SERVER_ROOT/logs/nginx.pid", "r") if not f then ngx.log(ngx.ERR, "failed to open nginx.pid: ", err) return diff --git a/debian/modules/http-lua/t/120-re-find.t b/debian/modules/http-lua/t/120-re-find.t index 73e6134..f80ca4f 100644 --- a/debian/modules/http-lua/t/120-re-find.t +++ b/debian/modules/http-lua/t/120-re-find.t @@ -622,7 +622,7 @@ matched: 你 >>> a.lua local re = [==[(?i:([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:=|<=>|r?like|sounds\s+like|regexp)([\s'\"`´’‘\(\)]*)?\2|([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:!=|<=|>=|<>|<|>|\^|is\s+not|not\s+like|not\s+regexp)([\s'\"`´’‘\(\)]*)?(?!\6)([\d\w]+))]==] -s = string.rep([[ABCDEFG]], 10) +local s = string.rep([[ABCDEFG]], 10) local start = ngx.now() @@ -664,7 +664,7 @@ error: pcre_exec() failed: -8 >>> a.lua local re = [==[(?i:([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:=|<=>|r?like|sounds\s+like|regexp)([\s'\"`´’‘\(\)]*)?\2|([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:!=|<=|>=|<>|<|>|\^|is\s+not|not\s+like|not\s+regexp)([\s'\"`´’‘\(\)]*)?(?!\6)([\d\w]+))]==] -s = string.rep([[ABCDEFG]], 10) +local s = string.rep([[ABCDEFG]], 10) local start = ngx.now() diff --git a/debian/modules/http-lua/t/123-lua-path.t b/debian/modules/http-lua/t/123-lua-path.t index 23681a9..e30132f 100644 --- a/debian/modules/http-lua/t/123-lua-path.t +++ b/debian/modules/http-lua/t/123-lua-path.t @@ -11,7 +11,7 @@ repeat_each(2); plan tests => repeat_each() * (blocks() * 3 + 1); -$ENV{LUA_PATH} = "/foo/bar/baz"; +$ENV{LUA_PATH} = "../lua-resty-core/lib/?.lua;../lua-resty-lrucache/lib/?.lua;/foo/bar/baz"; $ENV{LUA_CPATH} = "/baz/bar/foo"; #no_diff(); #no_long_string(); @@ -36,8 +36,8 @@ env LUA_CPATH; } --- request GET /lua ---- response_body -/foo/bar/baz +--- response_body_like +(?:\.\.\/lua-resty-core\/lib\/\?\.lua;\.\.\/lua-resty-lrucache\/lib\/\?\.lua;){1,2}\/foo\/bar\/baz /baz/bar/foo --- no_error_log @@ -60,8 +60,8 @@ env LUA_CPATH; } --- request GET /lua ---- response_body -/foo/bar/baz +--- response_body_like +(?:\.\.\/lua-resty-core\/lib\/\?\.lua;\.\.\/lua-resty-lrucache\/lib\/\?\.lua;){1,2}\/foo\/bar\/baz /baz/bar/foo --- no_error_log diff --git a/debian/modules/http-lua/t/124-init-worker.t b/debian/modules/http-lua/t/124-init-worker.t index 9b2a91f..b648d55 100644 --- a/debian/modules/http-lua/t/124-init-worker.t +++ b/debian/modules/http-lua/t/124-init-worker.t @@ -521,12 +521,11 @@ warn(): Thu, 01 Jan 1970 01:34:38 GMT } --- request GET /t ---- response_body -timer created +--- response_body_like connected: 1 request sent: 56 -first line received: HTTP/1.1 200 OK -second line received: Server: openresty +first line received: HTTP\/1\.1 200 OK +second line received: (?:Date|Server): .*? --- no_error_log [error] --- timeout: 10 @@ -550,6 +549,7 @@ second line received: Server: openresty else say("connect: ", ok, " ", err) end + done = true end local ok, err = ngx.timer.at(0, handler) @@ -600,6 +600,7 @@ qr/connect\(\) failed \(\d+: Connection refused\), context: ngx\.timer$/ else say("connect: ", ok, " ", err) end + done = true end local ok, err = ngx.timer.at(0, handler) @@ -650,6 +651,7 @@ qr/connect\(\) failed \(\d+: Connection refused\)/ else say("connect: ", ok, " ", err) end + done = true end local ok, err = ngx.timer.at(0, handler) diff --git a/debian/modules/http-lua/t/126-shdict-frag.t b/debian/modules/http-lua/t/126-shdict-frag.t index 5a2aff8..33646d1 100644 --- a/debian/modules/http-lua/t/126-shdict-frag.t +++ b/debian/modules/http-lua/t/126-shdict-frag.t @@ -1240,8 +1240,8 @@ failed to safe set baz: no memory local key = "mylittlekey" .. rand(maxkeyidx) local ok, err = dogs:get(key) if not ok or rand() > 0.6 then - sz = rand(maxsz) - val = rep("a", sz) + local sz = rand(maxsz) + local val = rep("a", sz) local ok, err, forcible = dogs:set(key, val) if err then ngx.log(ngx.ERR, "failed to set key: ", err) diff --git a/debian/modules/http-lua/t/127-uthread-kill.t b/debian/modules/http-lua/t/127-uthread-kill.t index cc43c62..5542153 100644 --- a/debian/modules/http-lua/t/127-uthread-kill.t +++ b/debian/modules/http-lua/t/127-uthread-kill.t @@ -23,7 +23,7 @@ __DATA__ --- config location /lua { content_by_lua ' - function f() + local function f() ngx.say("hello from f()") ngx.sleep(1) end @@ -81,7 +81,7 @@ lua clean up the timer for pending ngx.sleep --- config location /lua { content_by_lua ' - function f() + local function f() ngx.say("hello from f()") ngx.sleep(0.001) return 32 @@ -138,12 +138,12 @@ lua clean up the timer for pending ngx.sleep === TEST 3: kill pending resolver --- config - resolver agentzh.org:12345; + resolver 127.0.0.2:12345; location /lua { content_by_lua ' - function f() + local function f() local sock = ngx.socket.tcp() - sock:connect("some.agentzh.org", 12345) + sock:connect("some.127.0.0.2", 12345) end local t, err = ngx.thread.spawn(f) @@ -194,13 +194,13 @@ resolve name done: -2 location /lua { content_by_lua ' local ready = false - function f() + local function f() local sock = ngx.socket.tcp() sock:connect("agentzh.org", 80) sock:close() ready = true sock:settimeout(10000) - sock:connect("agentzh.org", 12345) + sock:connect("127.0.0.2", 12345) end local t, err = ngx.thread.spawn(f) @@ -262,7 +262,7 @@ lua finalize socket location = /t { content_by_lua ' - function f() + local function f() ngx.location.capture("/sub") end @@ -309,11 +309,11 @@ lua tcp socket abort resolver location = /t { content_by_lua ' - function f() + local function f() ngx.location.capture("/sub") end - function g() + local function g() ngx.sleep(0.3) end @@ -376,7 +376,7 @@ lua tcp socket abort resolver location = /t { content_by_lua ' local ready = false - function f() + local function f() ngx.location.capture("/sub") ready = true ngx.sleep(0.5) @@ -424,7 +424,7 @@ lua tcp socket abort resolver --- config location = /t { content_by_lua ' - function f() + local function f() return end @@ -473,7 +473,7 @@ lua tcp socket abort resolver ngx.say("killed main thread.") end - function f() + local function f() local ok, err = ngx.thread.kill(coroutine.running()) if not ok then ngx.say("failed to kill user thread: ", err) diff --git a/debian/modules/http-lua/t/128-duplex-tcp-socket.t b/debian/modules/http-lua/t/128-duplex-tcp-socket.t index aed560c..22b9f03 100644 --- a/debian/modules/http-lua/t/128-duplex-tcp-socket.t +++ b/debian/modules/http-lua/t/128-duplex-tcp-socket.t @@ -396,7 +396,7 @@ F(ngx_http_lua_socket_tcp_finalize_write_part) { end sock:settimeout(300) - local ok, err = sock:connect("172.105.207.225", 12345) + local ok, err = sock:connect("127.0.0.2", 12345) ngx.say("connect: ", ok, " ", err) local ok, err = sock:close() @@ -425,7 +425,7 @@ close: nil closed --- config server_tokens off; lua_socket_log_errors off; - resolver agentzh.org:12345; + resolver 127.0.0.2:12345; resolver_timeout 300ms; location /t { content_by_lua ' @@ -459,7 +459,7 @@ close: nil closed end sock:settimeout(300) - local ok, err = sock:connect("some2.agentzh.org", 12345) + local ok, err = sock:connect("some2.agentzh.org", 80) ngx.say("connect: ", ok, " ", err) local ok, err = sock:close() diff --git a/debian/modules/http-lua/t/129-ssl-socket.t b/debian/modules/http-lua/t/129-ssl-socket.t index 3f05640..f2fa26b 100644 --- a/debian/modules/http-lua/t/129-ssl-socket.t +++ b/debian/modules/http-lua/t/129-ssl-socket.t @@ -301,7 +301,7 @@ SSL reused session content_by_lua ' local sock = ngx.socket.tcp() - sock:settimeout(2000) + sock:settimeout(7000) do @@ -380,7 +380,7 @@ lua ssl free session --- no_error_log [error] [alert] ---- timeout: 5 +--- timeout: 10 @@ -573,7 +573,7 @@ SSL reused session ngx.say("ssl handshake: ", type(session)) - local req = "GET / HTTP/1.1\\r\\nHost: agentzh.org\\r\\nConnection: close\\r\\n\\r\\n" + local req = "GET /en/linux-packages.html HTTP/1.1\\r\\nHost: openresty.com\\r\\nConnection: close\\r\\n\\r\\n" local bytes, err = sock:send(req) if not bytes then ngx.say("failed to send http request: ", err) @@ -602,7 +602,7 @@ GET /t --- response_body connected: 1 ssl handshake: userdata -sent http request: 56 bytes. +sent http request: 80 bytes. received: HTTP/1.1 404 Not Found close: 1 nil @@ -1333,13 +1333,13 @@ failed to send http request: closed --- grep_error_log_out --- error_log eval [ -qr/\[crit\] .*?SSL_do_handshake\(\) failed .*?(unsupported protocol|no protocols available)/, +qr/\[(crit|error)\] .*?SSL_do_handshake\(\) failed .*?(unsupported protocol|no protocols available)/, 'lua ssl server name: "openresty.org"', ] --- no_error_log SSL reused session -[error] [alert] +[emerg] --- timeout: 5 @@ -2508,7 +2508,7 @@ SSL reused session content_by_lua_block { local sock = ngx.socket.tcp() - sock:settimeout(2000) + sock:settimeout(7000) local ok, err = sock:connect("openresty.org", 443) if not ok then @@ -2529,4 +2529,4 @@ GET /t qr/\[error\] .* ngx.socket sslhandshake: expecting 1 ~ 5 arguments \(including the object\), but seen 0/ --- no_error_log [alert] ---- timeout: 5 +--- timeout: 10 diff --git a/debian/modules/http-lua/t/130-internal-api.t b/debian/modules/http-lua/t/130-internal-api.t index eba0980..2158e87 100644 --- a/debian/modules/http-lua/t/130-internal-api.t +++ b/debian/modules/http-lua/t/130-internal-api.t @@ -8,7 +8,7 @@ use Test::Nginx::Socket::Lua; repeat_each(2); -plan tests => repeat_each() * 3; +plan tests => repeat_each() * blocks() * 3; #no_diff(); no_long_string(); @@ -19,12 +19,7 @@ run_tests(); __DATA__ -=== TEST 1: __ngx_req and __ngx_cycle ---- http_config - init_by_lua ' - my_cycle = __ngx_cycle - '; - +=== TEST 1: req --- config location = /t { content_by_lua ' @@ -32,18 +27,14 @@ __DATA__ local function tonum(ud) return tonumber(ffi.cast("uintptr_t", ud)) end - ngx.say(string.format("init: cycle=%#x", tonum(my_cycle))) - ngx.say(string.format("content cycle=%#x", tonum(__ngx_cycle))) - ngx.say(string.format("content req=%#x", tonum(__ngx_req))) + ngx.say(string.format("content req=%#x", tonum(exdata()))) '; } --- request GET /t --- response_body_like chop -^init: cycle=(0x[a-f0-9]{4,}) -content cycle=\1 -content req=0x[a-f0-9]{4,} +^content req=0x[a-f0-9]{4,} $ --- no_error_log [error] diff --git a/debian/modules/http-lua/t/134-worker-count-5.t b/debian/modules/http-lua/t/134-worker-count-5.t index b257c12..ec6d0e7 100644 --- a/debian/modules/http-lua/t/134-worker-count-5.t +++ b/debian/modules/http-lua/t/134-worker-count-5.t @@ -3,7 +3,7 @@ use Test::Nginx::Socket::Lua; #worker_connections(1014); -#master_on(); +master_on(); workers(5); #log_level('warn'); @@ -55,7 +55,7 @@ workers: 5 === TEST 3: init_by_lua + module (github #681) --- http_config - lua_package_path "t/servroot/html/?.lua;;"; + lua_package_path "$TEST_NGINX_SERVER_ROOT/html/?.lua;;"; init_by_lua_block { local blah = require "file" diff --git a/debian/modules/http-lua/t/138-balancer.t b/debian/modules/http-lua/t/138-balancer.t index 0aba66d..151db7b 100644 --- a/debian/modules/http-lua/t/138-balancer.t +++ b/debian/modules/http-lua/t/138-balancer.t @@ -362,8 +362,6 @@ me: 101 === TEST 13: lua subrequests --- http_config - lua_package_path "t/servroot/html/?.lua;;"; - lua_code_cache off; upstream backend { diff --git a/debian/modules/http-lua/t/139-ssl-cert-by.t b/debian/modules/http-lua/t/139-ssl-cert-by.t index a65d703..bebbdb2 100644 --- a/debian/modules/http-lua/t/139-ssl-cert-by.t +++ b/debian/modules/http-lua/t/139-ssl-cert-by.t @@ -1278,7 +1278,7 @@ lua ssl server name: "test.com" listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; ssl_certificate_by_lua_block { - function f() + local function f() ngx.sleep(0.01) print("uthread: hello in thread") return "done" diff --git a/debian/modules/http-lua/t/140-ssl-c-api.t b/debian/modules/http-lua/t/140-ssl-c-api.t index 8734d14..a77f5d4 100644 --- a/debian/modules/http-lua/t/140-ssl-c-api.t +++ b/debian/modules/http-lua/t/140-ssl-c-api.t @@ -10,6 +10,7 @@ my $openssl_version = eval { `$NginxBinary -V 2>&1` }; if ($openssl_version =~ m/built with OpenSSL (0|1\.0\.(?:0|1[^\d]|2[a-d]).*)/) { plan(skip_all => "too old OpenSSL, need 1.0.2e, was $1"); + } else { plan tests => repeat_each() * (blocks() * 5 + 1); } @@ -68,7 +69,7 @@ _EOC_ my $http_config = $block->http_config || ''; $http_config .= <<'_EOC_'; -lua_package_path "$prefix/html/?.lua;;"; +lua_package_path "$prefix/html/?.lua;../lua-resty-core/lib/?.lua;;"; _EOC_ $block->set_value("http_config", $http_config); }); @@ -91,8 +92,8 @@ __DATA__ local errmsg = ffi.new("char *[1]") - local r = getfenv(0).__ngx_req - if not r then + local r = require "resty.core.base" .get_request() + if r == nil then ngx.log(ngx.ERR, "no request found") return end @@ -245,8 +246,8 @@ lua ssl server name: "test.com" local errmsg = ffi.new("char *[1]") - local r = getfenv(0).__ngx_req - if not r then + local r = require "resty.core.base" .get_request() + if r == nil then ngx.log(ngx.ERR, "no request found") return end @@ -399,8 +400,8 @@ lua ssl server name: "test.com" local errmsg = ffi.new("char *[1]") - local r = getfenv(0).__ngx_req - if not r then + local r = require "resty.core.base" .get_request() + if r == nil then ngx.log(ngx.ERR, "no request found") return end @@ -528,8 +529,8 @@ failed to parse PEM priv key: PEM_read_bio_PrivateKey() failed local errmsg = ffi.new("char *[1]") - local r = getfenv(0).__ngx_req - if not r then + local r = require "resty.core.base" .get_request() + if r == nil then ngx.log(ngx.ERR, "no request found") return end @@ -678,8 +679,8 @@ lua ssl server name: "test.com" local errmsg = ffi.new("char *[1]") - local r = getfenv(0).__ngx_req - if not r then + local r = require "resty.core.base" .get_request() + if r == nil then ngx.log(ngx.ERR, "no request found") return end diff --git a/debian/modules/http-lua/t/143-ssl-session-fetch.t b/debian/modules/http-lua/t/143-ssl-session-fetch.t index 4dc992d..78a66cf 100644 --- a/debian/modules/http-lua/t/143-ssl-session-fetch.t +++ b/debian/modules/http-lua/t/143-ssl-session-fetch.t @@ -1114,3 +1114,108 @@ qr/ssl_session_fetch_by_lua_block:1: ssl fetch sess by lua is running!/s [error] [alert] [emerg] + + + +=== TEST 14: keep global variable in ssl_session_(store|fetch)_by_lua when OpenResty LuaJIT is used +--- http_config + ssl_session_store_by_lua_block { + ngx.log(ngx.WARN, "new foo: ", foo) + if not foo then + foo = 1 + else + ngx.log(ngx.WARN, "old foo: ", foo) + foo = foo + 1 + end + } + ssl_session_fetch_by_lua_block { + ngx.log(ngx.WARN, "new bar: ", foo) + if not bar then + bar = 1 + else + ngx.log(ngx.WARN, "old bar: ", bar) + bar = bar + 1 + end + } + + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + server_name test.com; + ssl_certificate ../../cert/test.crt; + ssl_certificate_key ../../cert/test.key; + ssl_session_tickets off; + + server_tokens off; + location /foo { + content_by_lua_block { + ngx.say("foo: ", foo) + ngx.say("bar: ", bar) + } + } + } +--- config + server_tokens off; + lua_ssl_trusted_certificate ../../cert/test.crt; + + location /t { + content_by_lua_block { + do + local sock = ngx.socket.tcp() + + sock:settimeout(2000) + + local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") + if not ok then + ngx.say("failed to connect: ", err) + return + end + + local sess, err = sock:sslhandshake(package.loaded.session, "test.com", true) + if not sess then + ngx.say("failed to do SSL handshake: ", err) + return + end + + package.loaded.session = sess + + local req = "GET /foo HTTP/1.0\r\nHost: test.com\r\nConnection: close\r\n\r\n" + local bytes, err = sock:send(req) + if not bytes then + ngx.say("failed to send http request: ", err) + return + end + + while true do + local line, err = sock:receive() + if not line then + -- ngx.say("failed to receive response status line: ", err) + break + end + + local m, err = ngx.re.match(line, "^foo: (.*)$", "jo") + if err then + ngx.say("failed to match line: ", err) + end + + if m and m[1] then + ngx.print(m[1]) + end + end + + local ok, err = sock:close() + ngx.say("done") + end -- do + } + } + +--- request +GET /t +--- response_body_like chomp +\A[123]done\n\z +--- grep_error_log eval: qr/old (foo|bar): \d+/ +--- grep_error_log_out eval +["", "old foo: 1\n", "old bar: 1\nold foo: 2\n"] +--- no_error_log +[error] +[alert] +[emerg] diff --git a/debian/modules/http-lua/t/147-tcp-socket-timeouts.t b/debian/modules/http-lua/t/147-tcp-socket-timeouts.t index 4ebc8f3..8566c0b 100644 --- a/debian/modules/http-lua/t/147-tcp-socket-timeouts.t +++ b/debian/modules/http-lua/t/147-tcp-socket-timeouts.t @@ -323,7 +323,7 @@ lua tcp socket write timed out sock:settimeouts(100, 100, 100) - local ok, err = sock:connect("agentzh.org", 12345) + local ok, err = sock:connect("127.0.0.2", 12345) ngx.say("connect: ", ok, " ", err) local bytes @@ -346,7 +346,7 @@ send: nil closed receive: nil closed close: nil closed --- error_log -lua tcp socket connect timed out, when connecting to 172.105.207.225:12345 +lua tcp socket connect timed out, when connecting to 127.0.0.2:12345 --- timeout: 10 @@ -411,7 +411,7 @@ lua tcp socket connect timed out, when connecting to 172.105.207.225:12345 local chunk = 4 - function read() + local function read() sock:settimeout(200) -- read: 200 ms local data, err = sock:receive(content_length) @@ -506,7 +506,7 @@ failed to receive data: timeout local chunk = 4 - function read() + local function read() local data, err = sock:receive(content_length) if not data then ngx.log(ngx.ERR, "failed to receive data: ", err) diff --git a/debian/modules/http-lua/t/152-timer-every.t b/debian/modules/http-lua/t/152-timer-every.t index c8d62e7..7b42d2d 100644 --- a/debian/modules/http-lua/t/152-timer-every.t +++ b/debian/modules/http-lua/t/152-timer-every.t @@ -63,7 +63,7 @@ qr/\[lua\] content_by_lua\(nginx\.conf:\d+\):\d+: elapsed: 0\.(?:09|10)\d*, cont -=== TEST 2: separated global env +=== TEST 2: shared global env --- config location /t { content_by_lua_block { @@ -84,7 +84,7 @@ qr/\[lua\] content_by_lua\(nginx\.conf:\d+\):\d+: elapsed: 0\.(?:09|10)\d*, cont --- request GET /t --- response_body -foo = nil +foo = 3 --- wait: 0.12 --- no_error_log [error] diff --git a/debian/modules/http-lua/t/153-semaphore-hup.t b/debian/modules/http-lua/t/153-semaphore-hup.t index c85a21d..5c271a4 100644 --- a/debian/modules/http-lua/t/153-semaphore-hup.t +++ b/debian/modules/http-lua/t/153-semaphore-hup.t @@ -67,7 +67,7 @@ add_block_preprocessor(sub { return end - shdict = ngx.shared.shdict + local shdict = ngx.shared.shdict local success = shdict:add("reloaded", 1) if not success then return diff --git a/debian/modules/http-lua/t/156-slow-network.t b/debian/modules/http-lua/t/156-slow-network.t new file mode 100644 index 0000000..2d80506 --- /dev/null +++ b/debian/modules/http-lua/t/156-slow-network.t @@ -0,0 +1,138 @@ +BEGIN { + if (!defined $ENV{LD_PRELOAD}) { + $ENV{LD_PRELOAD} = ''; + } + + if ($ENV{LD_PRELOAD} !~ /\bmockeagain\.so\b/) { + $ENV{LD_PRELOAD} = "mockeagain.so $ENV{LD_PRELOAD}"; + } + + if ($ENV{MOCKEAGAIN} eq 'r') { + $ENV{MOCKEAGAIN} = 'rw'; + + } else { + $ENV{MOCKEAGAIN} = 'w'; + } + + $ENV{TEST_NGINX_EVENT_TYPE} = 'poll'; +} + +use Test::Nginx::Socket::Lua; + +repeat_each(2); + +plan tests => repeat_each() * (blocks() * 4); + +add_block_preprocessor(sub { + my $block = shift; + + if (!defined $block->error_log) { + $block->set_value("no_error_log", "[error]"); + } + + if (!defined $block->request) { + $block->set_value("request", "GET /t"); + } + +}); + + +log_level("debug"); +no_long_string(); +#no_diff(); +run_tests(); + +__DATA__ + +=== TEST 1: receiveany returns anything once socket receives +--- config + server_tokens off; + location = /t { + set $port $TEST_NGINX_SERVER_PORT; + content_by_lua_block { + local sock = ngx.socket.tcp() + sock:settimeout(500) + assert(sock:connect("127.0.0.1", ngx.var.port)) + local req = { + 'GET /foo HTTP/1.0\r\n', + 'Host: localhost\r\n', + 'Connection: close\r\n\r\n', + } + local ok, err = sock:send(req) + if not ok then + ngx.say("send request failed: ", err) + return + end + + + -- skip http header + while true do + local data, err, _ = sock:receive('*l') + if err then + ngx.say('unexpected error occurs when receiving http head: ' .. err) + return + end + if #data == 0 then -- read last line of head + break + end + end + + -- receive http body + while true do + local data, err = sock:receiveany(1024) + if err then + if err ~= 'closed' then + ngx.say('unexpected err: ', err) + end + break + end + ngx.say(data) + end + + sock:close() + } + } + + location = /foo { + content_by_lua_block { + local resp = { + '1', + 'hello', + } + + local length = 0 + for _, v in ipairs(resp) do + length = length + #v + end + + -- flush http header + ngx.header['Content-Length'] = length + ngx.flush(true) + ngx.sleep(0.01) + + -- send http body bytes by bytes + for _, v in ipairs(resp) do + ngx.print(v) + ngx.flush(true) + ngx.sleep(0.01) + end + } + } + +--- response_body +1 +h +e +l +l +o +--- grep_error_log eval +qr/lua tcp socket read any/ +--- grep_error_log_out +lua tcp socket read any +lua tcp socket read any +lua tcp socket read any +lua tcp socket read any +lua tcp socket read any +lua tcp socket read any +lua tcp socket read any diff --git a/debian/modules/http-lua/t/157-socket-keepalive-hup.t b/debian/modules/http-lua/t/157-socket-keepalive-hup.t new file mode 100644 index 0000000..357bb59 --- /dev/null +++ b/debian/modules/http-lua/t/157-socket-keepalive-hup.t @@ -0,0 +1,91 @@ +# 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 $SkipReason ? (skip_all => $SkipReason) : (); + +repeat_each(2); + +plan tests => repeat_each() * (blocks() * 8); + +#no_diff(); +no_long_string(); + +worker_connections(1024); +run_tests(); + +__DATA__ + +=== TEST 1: exiting +--- config + location /t { + set $port $TEST_NGINX_SERVER_PORT; + + content_by_lua_block { + local f, err = io.open("$TEST_NGINX_SERVER_ROOT/logs/nginx.pid", "r") + if not f then + ngx.say("failed to open nginx.pid: ", err) + return + end + + local pid = f:read() + -- ngx.say("master pid: [", pid, "]") + + f:close() + + local i = 0 + local port = ngx.var.port + + local function f(premature) + print("timer prematurely expired: ", premature) + + local sock = ngx.socket.tcp() + + local ok, err = sock:connect("127.0.0.1", port) + if not ok then + print("failed to connect: ", err) + return + end + + local ok, err = sock:setkeepalive() + if not ok then + print("failed to setkeepalive: ", err) + return + end + + print("setkeepalive successfully") + end + local ok, err = ngx.timer.at(3, f) + if not ok then + ngx.say("failed to set timer: ", err) + return + end + ngx.say("registered timer") + os.execute("kill -HUP " .. pid) + } + } +--- request +GET /t + +--- response_body +registered timer + +--- wait: 0.3 +--- no_error_log +[error] +[alert] +[crit] +--- error_log +timer prematurely expired: true +setkeepalive successfully +lua tcp socket set keepalive while process exiting, closing connection diff --git a/debian/modules/http-lua/t/158-global-var.t b/debian/modules/http-lua/t/158-global-var.t new file mode 100644 index 0000000..414a43a --- /dev/null +++ b/debian/modules/http-lua/t/158-global-var.t @@ -0,0 +1,508 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use Test::Nginx::Socket::Lua; + +log_level('debug'); + +repeat_each(2); + +plan tests => repeat_each() * (blocks() * 3 + 14); + +our $HtmlDir = html_dir; + +$ENV{TEST_NGINX_HTML_DIR} ||= html_dir(); + +no_long_string(); + +sub read_file { + my $infile = shift; + open my $in, $infile + or die "cannot open $infile for reading: $!"; + my $cert = do { local $/; <$in> }; + close $in; + $cert; +} + +our $TestCertificate = read_file("t/cert/test.crt"); +our $TestCertificateKey = read_file("t/cert/test.key"); + +add_block_preprocessor(sub { + my $block = shift; + + if (!defined $block->error_log) { + $block->set_value("no_error_log", "[error]"); + } + + if (!defined $block->request) { + $block->set_value("request", "GET /t"); + } + +}); + +run_tests(); + +__DATA__ + +=== TEST 1: set_by_lua +--- config + location /t { + set_by_lua_block $res { + if not foo then + foo = 1 + else + ngx.log(ngx.WARN, "old foo: ", foo) + foo = foo + 1 + end + return foo + } + echo $res; + } +--- response_body_like chomp +\A[12]\n\z +--- grep_error_log eval +qr/(old foo: \d+|\[\w+\].*?writing a global lua variable \('[^'\s]+'\)|set_by_lua:\d+: in main chunk, )/ +--- grep_error_log_out eval +[qr/\A\[warn\] .*?writing a global lua variable \('foo'\) +set_by_lua:3: in main chunk, \n\z/, "old foo: 1\n"] + + + +=== TEST 2: rewrite_by_lua +--- config + location /t { + rewrite_by_lua_block { + if not foo then + foo = 1 + else + ngx.log(ngx.WARN, "old foo: ", foo) + foo = foo + 1 + end + ngx.say(foo) + } + } +--- response_body_like chomp +\A[12]\n\z +--- grep_error_log eval +qr/(old foo: \d+|\[\w+\].*?writing a global lua variable \('[^'\s]+'\)|\w+_by_lua\(.*?\):\d+: in main chunk, )/ +--- grep_error_log_out eval +[qr/\A\[warn\] .*?writing a global lua variable \('foo'\) +rewrite_by_lua\(nginx\.conf:48\):3: in main chunk, \n\z/, "old foo: 1\n"] + + + +=== TEST 3: access_by_lua +--- config + location /t { + access_by_lua_block { + if not foo then + foo = 1 + else + ngx.log(ngx.WARN, "old foo: ", foo) + foo = foo + 1 + end + ngx.say(foo) + } + } +--- response_body_like chomp +\A[12]\n\z +--- grep_error_log eval +qr/(old foo: \d+|\[\w+\].*?writing a global lua variable \('[^'\s]+'\)|\w+_by_lua\(.*?\):\d+: in main chunk, )/ +--- grep_error_log_out eval +[qr/\A\[warn\] .*?writing a global lua variable \('foo'\) +access_by_lua\(nginx\.conf:48\):3: in main chunk, \n\z/, "old foo: 1\n"] + + + +=== TEST 4: content_by_lua +--- config + location /t { + content_by_lua_block { + if not foo then + foo = 1 + else + ngx.log(ngx.WARN, "old foo: ", foo) + foo = foo + 1 + end + ngx.say(foo) + } + } +--- response_body_like chomp +\A[12]\n\z +--- grep_error_log eval +qr/(old foo: \d+|\[\w+\].*?writing a global lua variable \('[^'\s]+'\)|\w+_by_lua\(.*?\):\d+: in main chunk, )/ +--- grep_error_log_out eval +[qr/\A\[warn\] .*?writing a global lua variable \('foo'\) +content_by_lua\(nginx\.conf:48\):3: in main chunk, \n\z/, "old foo: 1\n"] + + + +=== TEST 5: header_filter_by_lua +--- config + location /t { + content_by_lua_block { + ngx.say(foo) + } + header_filter_by_lua_block { + if not foo then + foo = 1 + else + ngx.log(ngx.WARN, "old foo: ", foo) + foo = foo + 1 + end + } + } +--- response_body_like chomp +\A(?:nil|1)\n\z +--- grep_error_log eval +qr/(old foo: \d+|\[\w+\].*?writing a global lua variable \('[^'\s]+'\)|\w+_by_lua:\d+: in main chunk, )/ +--- grep_error_log_out eval +[qr/\A\[warn\] .*?writing a global lua variable \('foo'\) +header_filter_by_lua:3: in main chunk, \n\z/, "old foo: 1\n"] + + + +=== TEST 6: body_filter_by_lua +--- config + location /t { + content_by_lua_block { + ngx.say(foo) + } + body_filter_by_lua_block { + if not foo then + foo = 1 + else + ngx.log(ngx.WARN, "old foo: ", foo) + foo = foo + 1 + end + } + } +--- response_body_like chomp +\A(?:nil|2)\n\z +--- grep_error_log eval +qr/(old foo: \d+|\[\w+\].*?writing a global lua variable \('[^'\s]+'\)|\w+_by_lua:\d+: in main chunk, )/ +--- grep_error_log_out eval +[qr/\[warn\] .*?writing a global lua variable \('foo'\) +body_filter_by_lua:3: in main chunk, +old foo: 1\n\z/, "old foo: 2\nold foo: 3\n"] + + + +=== TEST 7: log_by_lua +--- config + location /t { + content_by_lua_block { + ngx.say(foo) + } + log_by_lua_block { + if not foo then + foo = 1 + else + ngx.log(ngx.WARN, "old foo: ", foo) + foo = foo + 1 + end + } + } +--- response_body_like chomp +\A(?:nil|1)\n\z +--- grep_error_log eval +qr/(old foo: \d+|\[\w+\].*?writing a global lua variable \('[^'\s]+'\)|\w+_by_lua\(.*?\):\d+: in main chunk)/ +--- grep_error_log_out eval +[qr/\A\[warn\] .*?writing a global lua variable \('foo'\) +log_by_lua\(nginx\.conf:50\):3: in main chunk\n\z/, "old foo: 1\n"] + + + +=== TEST 8: ssl_certificate_by_lua +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + server_name test.com; + ssl_certificate_by_lua_block { + if not foo then + foo = 1 + else + ngx.log(ngx.WARN, "old foo: ", foo) + foo = foo + 1 + end + } + ssl_certificate ../../cert/test.crt; + ssl_certificate_key ../../cert/test.key; + + server_tokens off; + location /foo { + content_by_lua_block { + ngx.say("foo: ", foo) + } + } + } +--- config + server_tokens off; + lua_ssl_trusted_certificate ../../cert/test.crt; + + location /t { + content_by_lua_block { + do + local sock = ngx.socket.tcp() + + sock:settimeout(2000) + + local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") + if not ok then + ngx.say("failed to connect: ", err) + return + end + + -- ngx.say("connected: ", ok) + + local sess, err = sock:sslhandshake(nil, "test.com", true) + if not sess then + ngx.say("failed to do SSL handshake: ", err) + return + end + + -- ngx.say("ssl handshake: ", type(sess)) + + local req = "GET /foo HTTP/1.0\r\nHost: test.com\r\nConnection: close\r\n\r\n" + local bytes, err = sock:send(req) + if not bytes then + ngx.say("failed to send http request: ", err) + return + end + + -- ngx.say("sent http request: ", bytes, " bytes.") + + while true do + local line, err = sock:receive() + if not line then + -- ngx.say("failed to receive response status line: ", err) + break + end + + local m, err = ngx.re.match(line, "^foo: (.*)$", "jo") + if err then + ngx.say("failed to match line: ", err) + end + + if m and m[1] then + ngx.print(m[1]) + end + end + + local ok, err = sock:close() + ngx.say("done") + end -- do + } + } + +--- response_body_like chomp +\A[12]done\n\z +--- grep_error_log eval +qr/(old foo: \d+|\[\w+\].*?writing a global lua variable \('[^'\s]+'\)|\w+_by_lua:\d+: in main chunk)/ +--- grep_error_log_out eval +[qr/\A\[warn\] .*?writing a global lua variable \('foo'\) +ssl_certificate_by_lua:3: in main chunk\n\z/, "old foo: 1\n"] + + + +=== TEST 9: timer +--- config + location /t { + content_by_lua_block { + local function f() + if not foo then + foo = 1 + else + ngx.log(ngx.WARN, "old foo: ", foo) + foo = foo + 1 + end + end + local ok, err = ngx.timer.at(0, f) + if not ok then + ngx.say("failed to set timer: ", err) + return + end + ngx.sleep(0.01) + ngx.say(foo) + } + } +--- response_body_like chomp +\A[12]\n\z +--- grep_error_log eval +qr/(old foo: \d+|\[\w+\].*?writing a global lua variable \('[^'\s]+'\)|\w+_by_lua\(.*?\):\d+: in\b)/ +--- grep_error_log_out eval +[qr/\A\[warn\] .*?writing a global lua variable \('foo'\) +content_by_lua\(nginx\.conf:56\):4: in\n\z/, "old foo: 1\n"] + + + +=== TEST 10: init_by_lua +--- http_config + init_by_lua_block { + foo = 1 + } +--- config + location /t { + content_by_lua_block { + if not foo then + foo = 1 + else + ngx.log(ngx.WARN, "old foo: ", foo) + foo = foo + 1 + end + ngx.say(foo) + } + } +--- response_body_like chomp +\A[23]\n\z +--- grep_error_log eval: qr/old foo: \d+/ +--- grep_error_log_out eval +["old foo: 1\n", "old foo: 2\n"] + + + +=== TEST 11: init_worker_by_lua +--- http_config + init_worker_by_lua_block { + if not foo then + foo = 1 + else + ngx.log(ngx.WARN, "old foo: ", foo) + foo = foo + 1 + end + } +--- config + location /t { + content_by_lua_block { + if not foo then + foo = 1 + else + ngx.log(ngx.WARN, "old foo: ", foo) + foo = foo + 1 + end + ngx.say(foo) + } + } +--- response_body_like chomp +\A[23]\n\z +--- grep_error_log eval: qr/old foo: \d+/ +--- grep_error_log_out eval +["old foo: 1\n", "old foo: 2\n"] + + + +=== TEST 12: init_by_lua + init_worker_by_lua +--- http_config + init_by_lua_block { + if not foo then + foo = 1 + else + ngx.log(ngx.WARN, "old foo: ", foo) + foo = foo + 1 + end + } + init_worker_by_lua_block { + if not foo then + foo = 1 + else + ngx.log(ngx.WARN, "old foo: ", foo) + foo = foo + 1 + end + } +--- config + location /t { + content_by_lua_block { + if not foo then + foo = 1 + else + ngx.log(ngx.WARN, "old foo: ", foo) + foo = foo + 1 + end + ngx.say(foo) + } + } +--- response_body_like chomp +\A[34]\n\z +--- grep_error_log eval: qr/old foo: \d+/ +--- grep_error_log_out eval +["old foo: 1\nold foo: 2\n", "old foo: 3\n"] + + + +=== TEST 13: don't show warn messages in init/init_worker +--- http_config + init_by_lua_block { + foo = 1 + } + + init_worker_by_lua_block { + bar = 2 + } +--- config + location /t { + content_by_lua_block { + ngx.say(foo) + ngx.say(bar) + } + } +--- response_body +1 +2 +--- no_error_log +setting global variable + + + +=== TEST 14: uthread +--- config + location /t { + content_by_lua_block { + local function f() + if not foo then + foo = 1 + else + ngx.log(ngx.WARN, "old foo: ", foo) + foo = foo + 1 + end + end + local ok, err = ngx.thread.spawn(f) + if not ok then + ngx.say("failed to set timer: ", err) + return + end + ngx.sleep(0.01) + ngx.say(foo) + } + } +--- response_body_like chomp +\A[12]\n\z +--- grep_error_log eval +qr/(old foo: \d+|writing a global lua variable \('\w+'\))/ +--- grep_error_log_out eval +["writing a global lua variable \('foo'\)\n", "old foo: 1\n"] + + + +=== TEST 15: balancer_by_lua +--- http_config + upstream backend { + server 0.0.0.1; + balancer_by_lua_block { + if not foo then + foo = 1 + else + ngx.log(ngx.WARN, "old foo: ", foo) + foo = foo + 1 + end + } + } +--- config + location = /t { + proxy_pass http://backend; + } +--- response_body_like: 502 Bad Gateway +--- error_code: 502 +--- error_log eval +qr/\[crit\].*?\Qconnect() to 0.0.0.1:80 failed\E/ +--- grep_error_log eval: qr/(old foo: \d+|writing a global lua variable \('\w+'\))/ +--- grep_error_log_out eval +["writing a global lua variable \('foo'\)\n", "old foo: 1\n"] diff --git a/debian/modules/http-lua/t/159-sa-restart.t b/debian/modules/http-lua/t/159-sa-restart.t new file mode 100644 index 0000000..a0f0c0e --- /dev/null +++ b/debian/modules/http-lua/t/159-sa-restart.t @@ -0,0 +1,180 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use Test::Nginx::Socket::Lua; + +add_block_preprocessor(sub { + my $block = shift; + + my $http_config = $block->http_config || ''; + + $http_config .= <<_EOC_; + init_by_lua_block { + function test_sa_restart() + local signals = { + --"HUP", + --"INFO", + --"XCPU", + --"USR1", + --"USR2", + "ALRM", + --"INT", + "IO", + "CHLD", + --"WINCH", + } + + for _, signame in ipairs(signals) do + local cmd = string.format("kill -s %s %d && sleep 0.01", + signame, ngx.worker.pid()) + local err = select(2, io.popen(cmd):read("*a")) + if err then + error("SIG" .. signame .. " caused: " .. err) + end + end + end + } +_EOC_ + + $block->set_value("http_config", $http_config); + + if (!defined $block->config) { + my $config = <<_EOC_; + location /t { + echo ok; + } +_EOC_ + + $block->set_value("config", $config); + } + + if (!defined $block->request) { + $block->set_value("request", "GET /t"); + } + + if (!defined $block->response_body) { + $block->set_value("ignore_response_body"); + } + + if (!defined $block->no_error_log) { + $block->set_value("no_error_log", "[error]"); + } +}); + +plan tests => repeat_each() * (blocks() * 2 + 1); + +no_long_string(); +run_tests(); + +__DATA__ + +=== TEST 1: lua_sa_restart default - sets SA_RESTART in init_worker_by_lua* +--- http_config + init_worker_by_lua_block { + test_sa_restart() + } + + + +=== TEST 2: lua_sa_restart off - does not set SA_RESTART +--- http_config + lua_sa_restart off; + + init_worker_by_lua_block { + test_sa_restart() + } +--- no_error_log +[crit] +--- error_log +Interrupted system call + + + +=== TEST 3: lua_sa_restart on (default) - sets SA_RESTART if no init_worker_by_lua* phase is defined +--- config + location /t { + content_by_lua_block { + test_sa_restart() + } + } + + + +=== TEST 4: lua_sa_restart on (default) - SA_RESTART is effective in rewrite_by_lua* +--- config + location /t { + rewrite_by_lua_block { + test_sa_restart() + } + + echo ok; + } + + + +=== TEST 5: lua_sa_restart on (default) - SA_RESTART is effective in access_by_lua* +--- config + location /t { + access_by_lua_block { + test_sa_restart() + } + + echo ok; + } + + + +=== TEST 6: lua_sa_restart on (default) - SA_RESTART is effective in content_by_lua* +--- config + location /t { + content_by_lua_block { + test_sa_restart() + } + } + + + +=== TEST 7: lua_sa_restart on (default) - SA_RESTART is effective in header_filter_by_lua* +--- config + location /t { + echo ok; + + header_filter_by_lua_block { + test_sa_restart() + } + } + + + +=== TEST 8: lua_sa_restart on (default) - SA_RESTART is effective in body_filter_by_lua* +--- config + location /t { + echo ok; + + body_filter_by_lua_block { + test_sa_restart() + } + } + + + +=== TEST 9: lua_sa_restart on (default) - SA_RESTART is effective in log_by_lua* +--- config + location /t { + echo ok; + + log_by_lua_block { + test_sa_restart() + } + } + + + +=== TEST 10: lua_sa_restart on (default) - SA_RESTART is effective in timer phase +--- config + location /t { + echo ok; + + log_by_lua_block { + ngx.timer.at(0, test_sa_restart) + } + } diff --git a/debian/modules/http-lua/t/160-disable-init-by-lua.t b/debian/modules/http-lua/t/160-disable-init-by-lua.t new file mode 100644 index 0000000..541771e --- /dev/null +++ b/debian/modules/http-lua/t/160-disable-init-by-lua.t @@ -0,0 +1,194 @@ +use Test::Nginx::Socket::Lua; + +repeat_each(2); + +plan tests => repeat_each() * (blocks() * 3); + +$ENV{TEST_NGINX_HTML_DIR} ||= html_dir(); + +my $html_dir = $ENV{TEST_NGINX_HTML_DIR}; +my $http_config = <<_EOC_; + init_by_lua_block { + function set_up_ngx_tmp_conf(conf) + if conf == nil then + conf = [[ + events { + worker_connections 64; + } + http { + init_by_lua_block { + ngx.log(ngx.ERR, "run init_by_lua") + } + } + ]] + end + + assert(os.execute("mkdir -p $html_dir/logs")) + + local conf_file = "$html_dir/nginx.conf" + local f, err = io.open(conf_file, "w") + if not f then + ngx.log(ngx.ERR, err) + return + end + + assert(f:write(conf)) + + return conf_file + end + + function get_ngx_bin_path() + local ffi = require "ffi" + ffi.cdef[[char **ngx_argv;]] + return ffi.string(ffi.C.ngx_argv[0]) + end + } +_EOC_ + +add_block_preprocessor(sub { + my $block = shift; + + if (!defined $block->http_config) { + $block->set_value("http_config", $http_config); + } + + if (!defined $block->request) { + $block->set_value("request", "GET /t"); + } +}); + +env_to_nginx("PATH"); +log_level("warn"); +no_long_string(); +run_tests(); + +__DATA__ + +=== TEST 1: ensure init_by_lua* is not run in signaller process +--- config + location = /t { + content_by_lua_block { + local conf_file = set_up_ngx_tmp_conf() + local nginx = get_ngx_bin_path() + + local cmd = nginx .. " -p $TEST_NGINX_HTML_DIR -c " .. conf_file .. " -s reopen" + local p, err = io.popen(cmd) + if not p then + ngx.log(ngx.ERR, err) + return + end + + local out, err = p:read("*a") + if not out then + ngx.log(ngx.ERR, err) + + else + ngx.log(ngx.WARN, out) + end + } + } +--- error_log +failed (2: No such file or directory) +--- no_error_log eval +qr/\[error\] .*? init_by_lua:\d+: run init_by_lua/ + + + +=== TEST 2: init_by_lua* does not run when testing Nginx configuration +--- config + location = /t { + content_by_lua_block { + local conf_file = set_up_ngx_tmp_conf() + local nginx = get_ngx_bin_path() + + local cmd = nginx .. " -p $TEST_NGINX_HTML_DIR -c " .. conf_file .. " -t" + local p, err = io.popen(cmd) + if not p then + ngx.log(ngx.ERR, err) + return + end + + local out, err = p:read("*a") + if not out then + ngx.log(ngx.ERR, err) + + else + ngx.log(ngx.WARN, out) + end + + local cmd = nginx .. " -p $TEST_NGINX_HTML_DIR -c " .. conf_file .. " -T" + local p, err = io.popen(cmd) + if not p then + ngx.log(ngx.ERR, err) + return + end + + local out, err = p:read("*a") + if not out then + ngx.log(ngx.ERR, err) + + else + ngx.log(ngx.WARN, out) + end + } + } +--- error_log +test is successful +--- no_error_log eval +qr/\[error\] .*? init_by_lua:\d+: run init_by_lua/ + + + +=== TEST 3: init_by_lua* does not run when testing Nginx configuration which contains 'lua_shared_dict' (GitHub #1462) +--- config + location = /t { + content_by_lua_block { + local conf = [[ + events { + worker_connections 64; + } + http { + lua_shared_dict test 64k; + init_by_lua_block { + ngx.log(ngx.ERR, "run init_by_lua with lua_shared_dict") + } + } + ]] + local conf_file = set_up_ngx_tmp_conf(conf) + local nginx = get_ngx_bin_path() + + local cmd = nginx .. " -p $TEST_NGINX_HTML_DIR -c " .. conf_file .. " -t" + local p, err = io.popen(cmd) + if not p then + ngx.log(ngx.ERR, err) + return + end + + local out, err = p:read("*a") + if not out then + ngx.log(ngx.ERR, err) + + else + ngx.log(ngx.WARN, out) + end + + local cmd = nginx .. " -p $TEST_NGINX_HTML_DIR -c " .. conf_file .. " -T" + local p, err = io.popen(cmd) + if not p then + ngx.log(ngx.ERR, err) + return + end + + local out, err = p:read("*a") + if not out then + ngx.log(ngx.ERR, err) + + else + ngx.log(ngx.WARN, out) + end + } + } +--- error_log +test is successful +--- no_error_log eval +qr/\[error\] .*? init_by_lua:\d+: run init_by_lua with lua_shared_dict/ diff --git a/debian/modules/http-lua/t/161-load-resty-core.t b/debian/modules/http-lua/t/161-load-resty-core.t new file mode 100644 index 0000000..41b18f0 --- /dev/null +++ b/debian/modules/http-lua/t/161-load-resty-core.t @@ -0,0 +1,68 @@ +use Test::Nginx::Socket::Lua; + +repeat_each(2); + +plan tests => repeat_each() * (blocks() * 3); + +add_block_preprocessor(sub { + my $block = shift; + + if (!defined $block->request) { + $block->set_value("request", "GET /t"); + } + + if (!defined $block->no_error_log) { + $block->set_value("no_error_log", "[error]"); + } +}); + +no_long_string(); +run_tests(); + +__DATA__ + +=== TEST 1: lua_load_resty_core is enabled by default +--- config + location = /t { + content_by_lua_block { + local loaded_resty_core = package.loaded["resty.core"] + local resty_core = require "resty.core" + + ngx.say("resty.core loaded: ", loaded_resty_core == resty_core) + } + } +--- response_body +resty.core loaded: true + + + +=== TEST 2: lua_load_resty_core can be disabled +--- http_config + lua_load_resty_core off; +--- config + location = /t { + content_by_lua_block { + local loaded_resty_core = package.loaded["resty.core"] + + ngx.say("resty.core loaded: ", loaded_resty_core ~= nil) + } + } +--- response_body +resty.core loaded: false + + + +=== TEST 3: lua_load_resty_core is effective when using lua_shared_dict +--- http_config + lua_shared_dict dogs 128k; +--- config + location = /t { + content_by_lua_block { + local loaded_resty_core = package.loaded["resty.core"] + local resty_core = require "resty.core" + + ngx.say("resty.core loaded: ", loaded_resty_core == resty_core) + } + } +--- response_body +resty.core loaded: true diff --git a/debian/modules/http-lua/t/data/fake-shm-module/ngx_http_lua_fake_shm_module.c b/debian/modules/http-lua/t/data/fake-shm-module/ngx_http_lua_fake_shm_module.c index 0286853..ffc32f5 100644 --- a/debian/modules/http-lua/t/data/fake-shm-module/ngx_http_lua_fake_shm_module.c +++ b/debian/modules/http-lua/t/data/fake-shm-module/ngx_http_lua_fake_shm_module.c @@ -213,10 +213,9 @@ ngx_http_lua_fake_shm_preload(lua_State *L) ngx_uint_t i; ngx_shm_zone_t **zone; + ngx_shm_zone_t **zone_udata; - lua_getglobal(L, "__ngx_cycle"); - cycle = lua_touserdata(L, -1); - lua_pop(L, 1); + cycle = (ngx_cycle_t *) ngx_cycle; hmcf_ctx = (ngx_http_conf_ctx_t *) cycle->conf_ctx[ngx_http_module.index]; lfsmcf = hmcf_ctx->main_conf[ngx_http_lua_fake_shm_module.ctx_index]; @@ -242,7 +241,9 @@ ngx_http_lua_fake_shm_preload(lua_State *L) lua_createtable(L, 1 /* narr */, 0 /* nrec */); /* table of zone[i] */ - lua_pushlightuserdata(L, zone[i]); /* shared mt key ud */ + zone_udata = lua_newuserdata(L, sizeof(ngx_shm_zone_t *)); + /* shared mt key ud */ + *zone_udata = zone[i]; lua_rawseti(L, -2, 1); /* {zone[i]} */ lua_pushvalue(L, -3); /* shared mt key ud mt */ lua_setmetatable(L, -2); /* shared mt key ud */ @@ -262,9 +263,10 @@ ngx_http_lua_fake_shm_preload(lua_State *L) static int ngx_http_lua_fake_shm_get_info(lua_State *L) { - ngx_int_t n; - ngx_shm_zone_t *zone; - ngx_http_lua_fake_shm_ctx_t *ctx; + ngx_int_t n; + ngx_shm_zone_t *zone; + ngx_shm_zone_t **zone_udata; + ngx_http_lua_fake_shm_ctx_t *ctx; n = lua_gettop(L); @@ -276,13 +278,15 @@ ngx_http_lua_fake_shm_get_info(lua_State *L) luaL_checktype(L, 1, LUA_TTABLE); lua_rawgeti(L, 1, 1); - zone = lua_touserdata(L, -1); + zone_udata = lua_touserdata(L, -1); lua_pop(L, 1); - if (zone == NULL) { + if (zone_udata == NULL) { return luaL_error(L, "bad \"zone\" argument"); } + zone = *zone_udata; + ctx = (ngx_http_lua_fake_shm_ctx_t *) zone->data; lua_pushlstring(L, (char *) zone->shm.name.data, zone->shm.name.len); diff --git a/debian/modules/http-lua/util/build.sh b/debian/modules/http-lua/util/build.sh index 164bf9f..14e9fd4 100755 --- a/debian/modules/http-lua/util/build.sh +++ b/debian/modules/http-lua/util/build.sh @@ -22,6 +22,8 @@ force=$2 #--without-http_referer_module \ #--with-http_spdy_module \ +add_fake_shm_module="--add-module=$root/t/data/fake-shm-module" + time ngx-build $force $version \ --with-pcre-jit \ --with-ipv6 \ @@ -55,7 +57,7 @@ time ngx-build $force $version \ --add-module=$root/../redis2-nginx-module \ --add-module=$root/../stream-lua-nginx-module \ --add-module=$root/t/data/fake-module \ - --add-module=$root/t/data/fake-shm-module \ + $add_fake_shm_module \ --add-module=$root/t/data/fake-delayed-load-module \ --with-http_gunzip_module \ --with-http_dav_module \