Squashed 'src/deps/src/lua-nginx-module/' changes from 0e769b7643..f44c188590

f44c188590 bumped version of lua-nginx-module to 10027.
0cc05a6090 tests: t/188-*.t: use random port instead of 8090 port.
2d8fcbe643 tests: skip t/163-signal.t in check leak mode.
f1cbe4ae94 tests: t/020-subrequest.t: replace the random port with an unused five-digit port.
0ea5e94a80 tests: added curl_error for http/3.
b3c6aebcc7 travis: bumped the NGINX core to 1.27.0.
bf4bdcd5b2 bugfix: fixed keepalive error in cosocket.
5777a36a93 bugfix: failed to build on the old nginx version.
0b5507a255 bugfix: added initialization.
d535753f54 bugfix: nginx crashed when binding local address failed from lua.
29fe7a504f dev: util/build.sh: fixed command line argument validation and environment variable usage.
6768721255 doc: update lua-cjson ref link.
ed8cb8fe30 bugfix: treat shdict entries with ttl equal to 0 as expired.
6f311f82c3 tests: update ngixn to 1.25.3.
8670e53ea7 bugfix: let `balancer.recreate_request` API work for body data changed case.
45c63cda41 feature: add ssl trusted certificate.
94f55f7a4d bugfix: respect max retry after using balancer pool.
0a1c704c2e feature: support ngx.location.capture and ngx.location.capture_multi with `headers` option.
39d165ca41 bugfix: undefined symbol SSL_client_hello_get0_ext when linking against libressl.
6477a7b46d bugfix: fixed compilation errors when building without SSL.
6738c3a3b0 change: should match the local address when get connection from the keepalive pool.
7b6fa21abc feature: implemented keepalive pooling in 'balancer_by_lua*'.
4f8b943759 bugfix:main thread access free fake request.
892b7ee5e8 bugfix: lua-nginx-module context was clear when ngx.send_header() trigger filter_finalize case.
b5d1688ae7 bugfix: fix config test for signalfd with gcc 11.
5bf876104c doc: update doc for 'ngx.req.http_version'.
c1d309284d bugfix: worker thread Lua VM may take lots of memory.
6c00bd4765 bugfix: the connection won't be closed normally when set arg[1] = "" before arg[2] = true.
e2067ddd2b bugfix: wrong arguments of setkeepalive() result in the compromise of data integrity.
f725c60ea0 bugfix: Fixing compatibility issues with BoringSSL.
76e3d67a04 feature: validate and expose nextUpdate field in OCSP response.
0189eb14f6 feature: add suport for deriving key from tls master secret.
ca942b6984 feature: add udp cosocket bind api.
e5248aa820 bugfix: fixed HTTP HEAD request smuggling issue.
6394debe28 optimize: allow to reenable the tls for the upstream.
1654cc6a4d feature: add FFI function for balancer.disable_ssl.
6df2b6f01c bugfix: correct offset vector memory allocation size for PCRE2.
9e59105fd9 tests: fixed typo.
54e5cb09d3 feature: add ngx_http_lua_ffi_ssl_client_random.
1c77f025fa bugfix: fix memory corruption in consecutive regex calls.
8dec675832 docs: docs about ngx.read_body() API limitations in stream HTTP2 and HTTP3 processing case
6e29c1a96e Revert "bugfix: disable http2 in body read due to http2 stream processing bug."
e0d19f787e Revert "changes: modify read body api limitation for HTTP/2 or HTTP/3 requests."
7598ff389e feature: add ngx_http_lua_ffi_parse_der_cert and ngx_http_lua_ffi_parse_der_key functions.

git-subtree-dir: src/deps/src/lua-nginx-module
git-subtree-split: f44c18859050be5af314bae8f05660478af5e31d
This commit is contained in:
Théophile Diot 2024-08-08 18:57:55 +01:00
parent 65e43ea606
commit 4d0b4160e6
50 changed files with 2949 additions and 438 deletions

View file

@ -43,7 +43,7 @@ env:
- LUAJIT_INC=$LUAJIT_PREFIX/include/luajit-2.1
- LUA_INCLUDE_DIR=$LUAJIT_INC
- PCRE_VER=8.45
- PCRE2_VER=10.37
- PCRE2_VER=10.42
- PCRE_PREFIX=/opt/pcre
- PCRE2_PREFIX=/opt/pcre2
- PCRE_LIB=$PCRE_PREFIX/lib
@ -64,8 +64,8 @@ env:
#- NGINX_VERSION=1.21.4 OPENSSL_VER=1.1.0l OPENSSL_PATCH_VER=1.1.0d
#- NGINX_VERSION=1.25.1 OPENSSL_VER=1.1.0l OPENSSL_PATCH_VER=1.1.0d
- NGINX_VERSION=1.21.4 OPENSSL_VER=1.1.1w OPENSSL_PATCH_VER=1.1.1f
- NGINX_VERSION=1.25.1 OPENSSL_VER=1.1.1w OPENSSL_PATCH_VER=1.1.1f USE_PCRE2=Y
- NGINX_VERSION=1.25.1 BORINGSSL=1 TEST_NGINX_USE_HTTP3=1 USE_PCRE2=Y
- NGINX_VERSION=1.27.0 OPENSSL_VER=1.1.1w OPENSSL_PATCH_VER=1.1.1f USE_PCRE2=Y TEST_NGINX_TIMEOUT=5
- NGINX_VERSION=1.27.0 BORINGSSL=1 TEST_NGINX_USE_HTTP3=1 USE_PCRE2=Y TEST_NGINX_QUIC_IDLE_TIMEOUT=3
#- NGINX_VERSION=1.25.1 OPENSSL_VER=1.1.1w TEST_NGINX_USE_HTTP2=1
services:
@ -81,7 +81,7 @@ before_install:
install:
- if [ ! -f download-cache/drizzle7-$DRIZZLE_VER.tar.gz ]; then wget -P download-cache https://github.com/openresty/openresty-deps-prebuild/releases/download/v20230902/drizzle7-$DRIZZLE_VER.tar.gz; fi
- if [ "$USE_PCRE2" != "Y" ] && [ ! -f download-cache/pcre-$PCRE_VER.tar.gz ]; then wget -P download-cache https://downloads.sourceforge.net/project/pcre/pcre/${PCRE_VER}/pcre-${PCRE_VER}.tar.gz; fi
- if [ "$USE_PCRE2" = "Y" ] && [ ! -f download-cache/pcre2-$PCRE2_VER.tar.gz ]; then wget -P download-cache https://downloads.sourceforge.net/project/pcre/pcre2/${PCRE2_VER}/pcre2-${PCRE2_VER}.tar.gz; fi
- if [ "$USE_PCRE2" = "Y" ] && [ ! -f download-cache/pcre2-$PCRE2_VER.tar.gz ]; then wget -P download-cache https://github.com/PCRE2Project/pcre2/releases/download/pcre2-${PCRE2_VER}/pcre2-${PCRE2_VER}.tar.gz; fi
- if [ -n "$OPENSSL_VER" ] && [ ! -f download-cache/openssl-$OPENSSL_VER.tar.gz ]; then wget -P download-cache https://www.openssl.org/source/openssl-$OPENSSL_VER.tar.gz || wget -P download-cache https://www.openssl.org/source/old/${OPENSSL_VER//[a-z]/}/openssl-$OPENSSL_VER.tar.gz; fi
- if [ -n "$OPENSSL_VER" ] && [ ! -f download-cache/openssl-$OPENSSL_VER.tar.gz ]; then wget -P download-cache https://www.openssl.org/source/openssl-$OPENSSL_VER.tar.gz || wget -P download-cache https://www.openssl.org/source/old/${OPENSSL_VER//[a-z]/}/openssl-$OPENSSL_VER.tar.gz; fi
- wget https://github.com/openresty/openresty-deps-prebuild/releases/download/v20230902/boringssl-20230902-x64-focal.tar.gz

View file

@ -966,7 +966,6 @@ TODO
* cosocket: add support in the context of [init_by_lua*](#init_by_lua).
* cosocket: review and merge aviramc's [patch](https://github.com/openresty/lua-nginx-module/pull/290) for adding the `bsdrecv` method.
* cosocket: add configure options for different strategies of handling the cosocket connection exceeding in the pools.
* review and apply vadim-pavlov's patch for [ngx.location.capture](#ngxlocationcapture)'s `extra_headers` option
* use `ngx_hash_t` to optimize the built-in header look-up process for [ngx.req.set_header](#ngxreqset_header), and etc.
* add `ignore_resp_headers`, `ignore_resp_body`, and `ignore_resp` options to [ngx.location.capture](#ngxlocationcapture) and [ngx.location.capture_multi](#ngxlocationcapture_multi) methods, to allow micro performance tuning on the user side.
* add automatic Lua code time slicing support by yielding and resuming the Lua VM actively via Lua's debug hooks.
@ -1012,7 +1011,7 @@ The order in which these modules are added during configuration is important bec
filtering chain determines the final output, for example. The correct adding order is shown above.
* 3rd-party Lua libraries:
* [lua-cjson](http://www.kyne.com.au/~mark/software/lua-cjson.php)
* [lua-cjson](https://www.kyne.au/~mark/software/lua-cjson.php)
* Applications:
* mysql: create database 'ngx_test', grant all privileges to user 'ngx_test', password is 'ngx_test'
@ -1144,6 +1143,7 @@ Directives
* [log_by_lua_file](#log_by_lua_file)
* [balancer_by_lua_block](#balancer_by_lua_block)
* [balancer_by_lua_file](#balancer_by_lua_file)
* [balancer_keepalive](#balancer_keepalive)
* [lua_need_request_body](#lua_need_request_body)
* [ssl_client_hello_by_lua_block](#ssl_client_hello_by_lua_block)
* [ssl_client_hello_by_lua_file](#ssl_client_hello_by_lua_file)
@ -2711,6 +2711,29 @@ This directive was first introduced in the `v0.10.0` release.
[Back to TOC](#directives)
balancer_keepalive
------------------
**syntax:** *balancer_keepalive <total-connections>*
**context:** *upstream*
**phase:** *loading-config*
The `total-connections` parameter sets the maximum number of idle
keepalive connections to upstream servers that are preserved in the cache of
each worker process. When this number is exceeded, the least recently used
connections are closed.
It should be particularly noted that the keepalive directive does not limit the
total number of connections to upstream servers that an nginx worker process
can open. The connections parameter should be set to a number small enough to
let upstream servers process new incoming connections as well.
This directive was first introduced in the `v0.10.21` release.
[Back to TOC](#directives)
lua_need_request_body
---------------------
@ -2722,8 +2745,6 @@ lua_need_request_body
**phase:** *depends on usage*
Due to the stream processing feature of HTTP/2 or HTTP/3, this configuration could potentially block the entire request. Therefore, this configuration is effective only when HTTP/2 or HTTP/3 requests send content-length header. For requests with versions lower than HTTP/2, this configuration can still be used without any problems.
Determines whether to force the request body data to be read before running rewrite/access/content_by_lua* or not. The Nginx core does not read the client request body by default and if request body data is required, then this directive should be turned `on` or the [ngx.req.read_body](#ngxreqread_body) function should be called within the Lua code.
To read the request body data within the [$request_body](http://nginx.org/en/docs/http/ngx_http_core_module.html#var_request_body) variable,
@ -3601,7 +3622,7 @@ lua_worker_thread_vm_pool_size
**syntax:** *lua_worker_thread_vm_pool_size <size>*
**default:** *lua_worker_thread_vm_pool_size 100*
**default:** *lua_worker_thread_vm_pool_size 10*
**context:** *http*
@ -3613,6 +3634,8 @@ The Lua VM in the VM pool is used to execute Lua code in separate thread.
The pool is global at Nginx worker level. And it is used to reuse Lua VMs between requests.
**Warning:** Each worker thread uses a separate Lua VM and caches the Lua VM for reuse in subsequent operations. Configuring too many worker threads can result in consuming a lot of memory.
[Back to TOC](#directives)
Nginx API for Lua
@ -3717,6 +3740,7 @@ Nginx API for Lua
* [ngx.shared.DICT.capacity](#ngxshareddictcapacity)
* [ngx.shared.DICT.free_space](#ngxshareddictfree_space)
* [ngx.socket.udp](#ngxsocketudp)
* [udpsock:bind](#udpsockbind)
* [udpsock:setpeername](#udpsocksetpeername)
* [udpsock:send](#udpsocksend)
* [udpsock:receive](#udpsockreceive)
@ -4280,6 +4304,8 @@ argument, which supports the options:
specify the subrequest's request body (string value only).
* `args`
specify the subrequest's URI query arguments (both string value and Lua tables are accepted)
* `headers`
specify the subrequest's request headers (Lua table only). this headers will override the original headers of the subrequest.
* `ctx`
specify a Lua table to be the [ngx.ctx](#ngxctx) table for the subrequest. It can be the current request's [ngx.ctx](#ngxctx) table, which effectively makes the parent and its subrequest to share exactly the same context table. This option was first introduced in the `v0.3.1rc25` release.
* `vars`
@ -4431,6 +4457,33 @@ Accessing `/lua` will yield the output
dog = hello
cat = 32
The `headers` option can be used to specify the request headers for the subrequest. The value of this option should be a Lua table where the keys are the header names and the values are the header values. For example,
```lua
location /foo {
content_by_lua_block {
ngx.print(ngx.var.http_x_test)
}
}
location /lua {
content_by_lua_block {
local res = ngx.location.capture("/foo", {
headers = {
["X-Test"] = "aa",
}
})
ngx.print(res.body)
}
}
```
Accessing `/lua` will yield the output
aa
The `ctx` option can be used to specify a custom Lua table to serve as the [ngx.ctx](#ngxctx) table for the subrequest.
@ -4788,7 +4841,7 @@ ngx.req.http_version
Returns the HTTP version number for the current request as a Lua number.
Current possible values are 2.0, 1.0, 1.1, and 0.9. Returns `nil` for unrecognized values.
Current possible values are 3.0, 2.0, 1.0, 1.1, and 0.9. Returns `nil` for unrecognized values.
This method was first introduced in the `v0.7.17` release.
@ -5426,8 +5479,6 @@ Reads the client request body synchronously without blocking the Nginx event loo
local args = ngx.req.get_post_args()
```
Due to the stream processing feature of HTTP/2 or HTTP/3, this api could potentially block the entire request. Therefore, this api is effective only when HTTP/2 or HTTP/3 requests send content-length header. For requests with versions lower than HTTP/2, this api can still be used without any problems.
If the request body is already read previously by turning on [lua_need_request_body](#lua_need_request_body) or by using other modules, then this function does not run and returns immediately.
If the request body has already been explicitly discarded, either by the [ngx.req.discard_body](#ngxreqdiscard_body) function or other modules, this function does not run and returns immediately.
@ -5512,6 +5563,8 @@ If the request body has been read into memory, try calling the [ngx.req.get_body
To force in-file request bodies, try turning on [client_body_in_file_only](http://nginx.org/en/docs/http/ngx_http_core_module.html#client_body_in_file_only).
Note that this function is also work for balancer phase but it needs to call [balancer.recreate_request](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/balancer.md#recreate_request) to make the change take effect after set the request body data or headers.
This function was first introduced in the `v0.3.1rc17` release.
See also [ngx.req.get_body_data](#ngxreqget_body_data).
@ -5523,7 +5576,7 @@ ngx.req.set_body_data
**syntax:** *ngx.req.set_body_data(data)*
**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua**
**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, balancer_by_lua*,*
Set the current request's request body using the in-memory data specified by the `data` argument.
@ -5531,6 +5584,8 @@ If the request body has not been read yet, call [ngx.req.read_body](#ngxreqread_
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.
Note that this function is also work for balancer phase but it needs to call [balancer.recreate_request](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/balancer.md#recreate_request) to make the change take effect after set the request body data or headers.
This function was first introduced in the `v0.3.1rc18` release.
See also [ngx.req.set_body_file](#ngxreqset_body_file).
@ -5542,7 +5597,7 @@ ngx.req.set_body_file
**syntax:** *ngx.req.set_body_file(file_name, auto_clean?)*
**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua**
**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, balancer_by_lua*,*
Set the current request's request body using the in-file data specified by the `file_name` argument.
@ -5643,7 +5698,7 @@ Returns a read-only cosocket object that wraps the downstream connection. Only [
In case of error, `nil` will be returned as well as a string describing the error.
Due to the streaming nature of HTTP2 and HTTP3, this API cannot be used when the downstream connection is HTTP2 and HTTP3.
**Note:** This method will block while waiting for client request body to be fully received. Block time depends on the [client_body_timeout](http://nginx.org/en/docs/http/ngx_http_core_module.html#client_body_timeout) directive and maximum body size specified by the [client_max_body_size](http://nginx.org/en/docs/http/ngx_http_core_module.html#client_max_body_size) directive. If read timeout occurs or client body size exceeds the defined limit, this function will not return and `408 Request Time-out` or `413 Request Entity Too Large` response will be returned to the client instead.
The socket object returned by this method is usually used to read the current request's body in a streaming fashion. Do not turn on the [lua_need_request_body](#lua_need_request_body) directive, and do not mix this call with [ngx.req.read_body](#ngxreqread_body) and [ngx.req.discard_body](#ngxreqdiscard_body).
@ -7526,6 +7581,7 @@ ngx.socket.udp
Creates and returns a UDP or datagram-oriented unix domain socket object (also known as one type of the "cosocket" objects). The following methods are supported on this object:
* [bind](#udpsockbind)
* [setpeername](#udpsocksetpeername)
* [send](#udpsocksend)
* [receive](#udpsockreceive)
@ -7540,6 +7596,36 @@ See also [ngx.socket.tcp](#ngxsockettcp).
[Back to TOC](#nginx-api-for-lua)
udpsock:bind
------------
**syntax:** *ok, err = udpsock:bind(address)*
**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*,ssl_session_fetch_by_lua*,ssl_client_hello_by_lua**
Just like the standard [proxy_bind](http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_bind) directive, this api makes the outgoing connection to a upstream server originate from the specified local IP address.
Only IP addresses can be specified as the `address` argument.
Here is an example for connecting to a TCP server from the specified local IP address:
```nginx
location /test {
content_by_lua_block {
local sock = ngx.socket.udp()
-- assume "192.168.1.10" is the local ip address
local ok, err = sock:bind("192.168.1.10")
if not ok then
ngx.say("failed to bind: ", err)
return
end
sock:close()
}
}
```
[Back to TOC](#nginx-api-for-lua)
udpsock:setpeername
-------------------
@ -7916,11 +8002,11 @@ Set client certificate chain and corresponding private key to the TCP socket obj
The certificate chain and private key provided will be used later by the [tcpsock:sslhandshake](#tcpsocksslhandshake) method.
* `cert` specify a client certificate chain cdata object that will be used while handshaking with
remote server. These objects can be created using [ngx.ssl.parse\_pem\_cert](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/ssl.md#parse_pem_cert)
remote server. These objects can be created using [ngx.ssl.parse\_pem\_cert](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/ssl.md#parse_pem_cert) or [ngx.ssl.parse\_der\_cert](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/ssl.md#parse_der_cert)
function provided by lua-resty-core. Note that specifying the `cert` option requires
corresponding `pkey` be provided too. See below.
* `pkey` specify a private key corresponds to the `cert` option above.
These objects can be created using [ngx.ssl.parse\_pem\_priv\_key](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/ssl.md#parse_pem_priv_key)
These objects can be created using [ngx.ssl.parse\_pem\_priv\_key](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/ssl.md#parse_pem_priv_key) or [ngx.ssl.parse\_der\_priv\_key](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/ssl.md#parse_der_priv_key)
function provided by lua-resty-core.
If both of `cert` and `pkey` are `nil`, this method will clear any existing client certificate and private key

5
config
View file

@ -289,6 +289,7 @@ HTTP_LUA_SRCS=" \
$ngx_addon_dir/src/ngx_http_lua_worker.c \
$ngx_addon_dir/src/ngx_http_lua_ssl_client_helloby.c \
$ngx_addon_dir/src/ngx_http_lua_ssl_certby.c \
$ngx_addon_dir/src/ngx_http_lua_ssl_export_keying_material.c \
$ngx_addon_dir/src/ngx_http_lua_ssl_ocsp.c \
$ngx_addon_dir/src/ngx_http_lua_lex.c \
$ngx_addon_dir/src/ngx_http_lua_balancer.c \
@ -354,6 +355,7 @@ HTTP_LUA_DEPS=" \
$ngx_addon_dir/src/ngx_http_lua_ssl_certby.h \
$ngx_addon_dir/src/ngx_http_lua_lex.h \
$ngx_addon_dir/src/ngx_http_lua_balancer.h \
$ngx_addon_dir/src/ngx_http_lua_ssl_export_keying_material.h \
$ngx_addon_dir/src/ngx_http_lua_ssl_session_storeby.h \
$ngx_addon_dir/src/ngx_http_lua_ssl_session_fetchby.h \
$ngx_addon_dir/src/ngx_http_lua_ssl.h \
@ -460,7 +462,8 @@ ngx_feature_libs=
ngx_feature_name="NGX_HTTP_LUA_HAVE_SIGNALFD"
ngx_feature_run=no
ngx_feature_incs="#include <sys/signalfd.h>"
ngx_feature_test="sigset_t set; signalfd(-1, &set, SFD_NONBLOCK|SFD_CLOEXEC);"
ngx_feature_test="sigset_t set = { 0 };
signalfd(-1, &set, SFD_NONBLOCK|SFD_CLOEXEC);"
SAVED_CC_TEST_FLAGS="$CC_TEST_FLAGS"
CC_TEST_FLAGS="-Werror -Wall $CC_TEST_FLAGS"

View file

@ -2288,6 +2288,26 @@ When a relative path like <code>foo/bar.lua</code> is given, they will be turned
This directive was first introduced in the <code>v0.10.0</code> release.
== balancer_keepalive ==
'''syntax:''' ''balancer_keepalive <total-connections>''
'''context:''' ''upstream''
'''phase:''' ''loading-config''
The <code>total-connections</code> parameter sets the maximum number of idle
keepalive connections to upstream servers that are preserved in the cache of
each worker process. When this number is exceeded, the least recently used
connections are closed.
It should be particularly noted that the keepalive directive does not limit the
total number of connections to upstream servers that an nginx worker process
can open. The connections parameter should be set to a number small enough to
let upstream servers process new incoming connections as well.
This directive was first introduced in the <code>v0.10.21</code> release.
== lua_need_request_body ==
'''syntax:''' ''lua_need_request_body <on|off>''
@ -4637,7 +4657,7 @@ See also [[#ngx.req.get_body_data|ngx.req.get_body_data]].
'''syntax:''' ''ngx.req.set_body_data(data)''
'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*''
'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, balancer_by_lua*''
Set the current request's request body using the in-memory data specified by the <code>data</code> argument.
@ -4645,6 +4665,8 @@ If the request body has not been read yet, call [[#ngx.req.read_body|ngx.req.rea
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.
Note that this function is also work for balancer phase but it needs to call [https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/balancer.md#recreate_request balancer.recreate_request] to make the change take effect after set the request body data or headers.
This function was first introduced in the <code>v0.3.1rc18</code> release.
See also [[#ngx.req.set_body_file|ngx.req.set_body_file]].
@ -4653,7 +4675,7 @@ See also [[#ngx.req.set_body_file|ngx.req.set_body_file]].
'''syntax:''' ''ngx.req.set_body_file(file_name, auto_clean?)''
'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*''
'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, balancer_by_lua*''
Set the current request's request body using the in-file data specified by the <code>file_name</code> argument.
@ -4665,6 +4687,8 @@ Please ensure that the file specified by the <code>file_name</code> argument exi
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.
Note that this function is also work for balancer phase but it needs to call [https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/balancer.md#recreate_request balancer.recreate_request] to make the change take effect after set the request body data or headers.
This function was first introduced in the <code>v0.3.1rc18</code> release.
See also [[#ngx.req.set_body_data|ngx.req.set_body_data]].
@ -4741,8 +4765,7 @@ Returns a read-only cosocket object that wraps the downstream connection. Only [
In case of error, <code>nil</code> will be returned as well as a string describing the error.
Due to the streaming nature of HTTP2 and HTTP3, this API cannot be used when the downstream connection is HTTP2 and HTTP3.
'''Note:''' This method will block while waiting for client request body to be fully received. Block time depends on the [http://nginx.org/en/docs/http/ngx_http_core_module.html#client_body_timeout client_body_timeout] directive and maximum body size specified by the [http://nginx.org/en/docs/http/ngx_http_core_module.html#client_max_body_size client_max_body_size] directive. If read timeout occurs or client body size exceeds the defined limit, this function will not return and <code>408 Request Time-out</code> or <code>413 Request Entity Too Large</code> response will be returned to the client instead.
The socket object returned by this method is usually used to read the current request's body in a streaming fashion. Do not turn on the [[#lua_need_request_body|lua_need_request_body]] directive, and do not mix this call with [[#ngx.req.read_body|ngx.req.read_body]] and [[#ngx.req.discard_body|ngx.req.discard_body]].
If any request body data has been pre-read into the Nginx core request header buffer, the resulting cosocket object will take care of this to avoid potential data loss resulting from such pre-reading.

View file

@ -19,7 +19,7 @@
/* Public API for other Nginx modules */
#define ngx_http_lua_version 10026
#define ngx_http_lua_version 10027
typedef struct ngx_http_lua_co_ctx_s ngx_http_lua_co_ctx_t;

View file

@ -137,26 +137,6 @@ ngx_http_lua_access_handler(ngx_http_request_t *r)
}
if (llcf->force_read_body && !ctx->read_body_done) {
#if (NGX_HTTP_V2)
if (r->main->stream && r->headers_in.content_length_n < 0) {
ngx_log_error(NGX_LOG_WARN, r->connection->log, 0,
"disable lua_need_request_body, since "
"http2 read_body may break http2 stream process");
goto done;
}
#endif
#if (NGX_HTTP_V3)
if (r->http_version == NGX_HTTP_VERSION_30
&& r->headers_in.content_length_n < 0)
{
ngx_log_error(NGX_LOG_WARN, r->connection->log, 0,
"disable lua_need_request_body, since "
"http2 read_body may break http2 stream process");
goto done;
}
#endif
r->request_body_in_single_buf = 1;
r->request_body_in_persistent_file = 1;
r->request_body_in_clean_file = 1;
@ -174,12 +154,6 @@ ngx_http_lua_access_handler(ngx_http_request_t *r)
}
}
#if defined(NGX_HTTP_V3) || defined(NGX_HTTP_V2)
done:
#endif
dd("calling access handler");
return llcf->access_handler(r);
}

File diff suppressed because it is too large Load diff

View file

@ -23,5 +23,7 @@ char *ngx_http_lua_balancer_by_lua(ngx_conf_t *cf, ngx_command_t *cmd,
char *ngx_http_lua_balancer_by_lua_block(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
char *ngx_http_lua_balancer_keepalive(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
#endif /* _NGX_HTTP_LUA_BALANCER_H_INCLUDED_ */

View file

@ -532,9 +532,23 @@ ngx_http_lua_body_filter_param_set(lua_State *L, ngx_http_request_t *r,
if (last) {
ctx->seen_last_in_filter = 1;
/* the "in" chain cannot be NULL and we set the "last_buf" or
* "last_in_chain" flag in the last buf of "in" */
/* the "in" chain cannot be NULL except that we set arg[1] = ""
* before arg[2] = true
*/
if (in == NULL) {
in = ngx_http_lua_chain_get_free_buf(r->connection->log,
r->pool,
&ctx->free_bufs, 0);
if (in == NULL) {
return luaL_error(L, "no memory");
}
in->buf->tag = (ngx_buf_tag_t) &ngx_http_lua_body_filter;
lmcf->body_filter_chain = in;
}
/* we set the "last_buf" or "last_in_chain" flag
* in the last buf of "in" */
for (cl = in; cl; cl = cl->next) {
if (cl->next == NULL) {
if (r == r->main) {

View file

@ -167,7 +167,7 @@ typedef struct ngx_http_lua_co_ctx_s ngx_http_lua_co_ctx_t;
typedef struct ngx_http_lua_sema_mm_s ngx_http_lua_sema_mm_t;
typedef union ngx_http_lua_srv_conf_u ngx_http_lua_srv_conf_t;
typedef struct ngx_http_lua_srv_conf_s ngx_http_lua_srv_conf_t;
typedef struct ngx_http_lua_main_conf_s ngx_http_lua_main_conf_t;
@ -258,13 +258,6 @@ struct ngx_http_lua_main_conf_s {
ngx_str_t exit_worker_src;
u_char *exit_worker_chunkname;
ngx_http_lua_balancer_peer_data_t *balancer_peer_data;
/* 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
@ -323,7 +316,7 @@ struct ngx_http_lua_main_conf_s {
};
union ngx_http_lua_srv_conf_u {
struct ngx_http_lua_srv_conf_s {
struct {
#if (NGX_HTTP_SSL)
ngx_http_lua_srv_conf_handler_pt ssl_cert_handler;
@ -359,6 +352,14 @@ union ngx_http_lua_srv_conf_u {
} srv;
struct {
ngx_uint_t max_cached;
ngx_queue_t cache;
ngx_queue_t free;
ngx_queue_t *buckets;
ngx_uint_t bucket_cnt;
ngx_http_upstream_init_pt original_init_upstream;
ngx_http_upstream_init_peer_pt original_init_peer;
ngx_http_lua_srv_conf_handler_pt handler;
ngx_str_t src;
u_char *src_key;

View file

@ -196,26 +196,6 @@ ngx_http_lua_content_handler(ngx_http_request_t *r)
}
if (llcf->force_read_body && !ctx->read_body_done) {
#if (NGX_HTTP_V2)
if (r->main->stream && r->headers_in.content_length_n < 0) {
ngx_log_error(NGX_LOG_WARN, r->connection->log, 0,
"disable lua_need_request_body, since "
"http2 read_body may break http2 stream process");
goto done;
}
#endif
#if (NGX_HTTP_V3)
if (r->http_version == NGX_HTTP_VERSION_30
&& r->headers_in.content_length_n < 0)
{
ngx_log_error(NGX_LOG_WARN, r->connection->log, 0,
"disable lua_need_request_body, since "
"http2 read_body may break http2 stream process");
goto done;
}
#endif
r->request_body_in_single_buf = 1;
r->request_body_in_persistent_file = 1;
r->request_body_in_clean_file = 1;
@ -234,12 +214,6 @@ ngx_http_lua_content_handler(ngx_http_request_t *r)
}
}
#if defined(NGX_HTTP_V3) || defined(NGX_HTTP_V2)
done:
#endif
dd("setting entered");
ctx->entered_content_phase = 1;

View file

@ -297,6 +297,8 @@ ngx_http_lua_init_worker(ngx_cycle_t *cycle)
(void) lmcf->init_worker_handler(cycle->log, lmcf, lmcf->lua);
ngx_http_lua_set_req(lmcf->lua, NULL);
ngx_destroy_pool(c->pool);
return NGX_OK;

View file

@ -33,7 +33,9 @@
#include "ngx_http_lua_ssl_session_fetchby.h"
#include "ngx_http_lua_headers.h"
#include "ngx_http_lua_headers_out.h"
#if !(NGX_WIN32)
#include "ngx_http_lua_pipe.h"
#endif
static void *ngx_http_lua_create_main_conf(ngx_conf_t *cf);
@ -494,6 +496,13 @@ static ngx_command_t ngx_http_lua_cmds[] = {
0,
(void *) ngx_http_lua_balancer_handler_file },
{ ngx_string("balancer_keepalive"),
NGX_HTTP_UPS_CONF|NGX_CONF_TAKE1,
ngx_http_lua_balancer_keepalive,
NGX_HTTP_SRV_CONF_OFFSET,
offsetof(ngx_http_lua_srv_conf_t, balancer.max_cached),
NULL },
{ ngx_string("lua_socket_keepalive_timeout"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF
|NGX_HTTP_LIF_CONF|NGX_CONF_TAKE1,
@ -1141,7 +1150,7 @@ ngx_http_lua_init_main_conf(ngx_conf_t *cf, void *conf)
#endif
if (lmcf->worker_thread_vm_pool_size == NGX_CONF_UNSET_UINT) {
lmcf->worker_thread_vm_pool_size = 100;
lmcf->worker_thread_vm_pool_size = 10;
}
if (ngx_http_lua_init_builtin_headers_out(cf, lmcf) != NGX_OK) {
@ -1188,6 +1197,8 @@ ngx_http_lua_create_srv_conf(ngx_conf_t *cf)
* lscf->srv.ssl_sess_fetch_chunkname = NULL;
* lscf->srv.ssl_sess_fetch_src_key = NULL;
*
* lscf->balancer.original_init_upstream = NULL;
* lscf->balancer.original_init_peer = NULL;
* lscf->balancer.handler = NULL;
* lscf->balancer.src = { 0, NULL };
* lscf->balancer.chunkname = NULL;
@ -1202,7 +1213,7 @@ ngx_http_lua_create_srv_conf(ngx_conf_t *cf)
#endif
lscf->balancer.src_ref = LUA_REFNIL;
lscf->balancer.max_cached = NGX_CONF_UNSET_UINT;
return lscf;
}
@ -1503,7 +1514,11 @@ ngx_http_lua_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
ngx_conf_merge_bitmask_value(conf->ssl_protocols, prev->ssl_protocols,
(NGX_CONF_BITMASK_SET
|NGX_SSL_TLSv1|NGX_SSL_TLSv1_1
|NGX_SSL_TLSv1_2|NGX_SSL_TLSv1_3));
|NGX_SSL_TLSv1_2
#ifdef NGX_SSL_TLSv1_3
|NGX_SSL_TLSv1_3
#endif
));
ngx_conf_merge_str_value(conf->ssl_ciphers, prev->ssl_ciphers,
"DEFAULT");

View file

@ -591,7 +591,11 @@ ngx_http_lua_ffi_compile_regex(const unsigned char *pat, size_t pat_len,
re_comp.captures = 0;
} else {
#if (NGX_PCRE2)
ovecsize = (re_comp.captures + 1) * 2;
#else
ovecsize = (re_comp.captures + 1) * 3;
#endif
}
dd("allocating cap with size: %d", (int) ovecsize);
@ -684,21 +688,21 @@ ngx_http_lua_ffi_exec_regex(ngx_http_lua_regex_t *re, int flags,
{
int rc, exec_opts = 0;
size_t *ov;
ngx_uint_t ovecsize, n, i;
ngx_uint_t ovecpair, n, i;
ngx_pool_t *old_pool;
if (flags & NGX_LUA_RE_MODE_DFA) {
ovecsize = 2;
ovecpair = 1;
re->ncaptures = 0;
} else {
ovecsize = (re->ncaptures + 1) * 3;
ovecpair = re->ncaptures + 1;
}
old_pool = ngx_http_lua_pcre_malloc_init(NULL);
if (ngx_regex_match_data == NULL
|| ovecsize > ngx_regex_match_data_size)
|| ovecpair > ngx_regex_match_data_size)
{
/*
* Allocate a match data if not yet allocated or smaller than
@ -709,8 +713,8 @@ ngx_http_lua_ffi_exec_regex(ngx_http_lua_regex_t *re, int flags,
pcre2_match_data_free(ngx_regex_match_data);
}
ngx_regex_match_data_size = ovecsize;
ngx_regex_match_data = pcre2_match_data_create(ovecsize / 3, NULL);
ngx_regex_match_data_size = ovecpair;
ngx_regex_match_data = pcre2_match_data_create(ovecpair, NULL);
if (ngx_regex_match_data == NULL) {
rc = PCRE2_ERROR_NOMEMORY;
@ -741,7 +745,7 @@ ngx_http_lua_ffi_exec_regex(ngx_http_lua_regex_t *re, int flags,
#if (NGX_DEBUG)
ngx_log_debug4(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
"pcre2_match failed: flags 0x%05Xd, options 0x%08Xd, "
"rc %d, ovecsize %ui", flags, exec_opts, rc, ovecsize);
"rc %d, ovecpair %ui", flags, exec_opts, rc, ovecpair);
#endif
goto failed;
@ -753,11 +757,11 @@ ngx_http_lua_ffi_exec_regex(ngx_http_lua_regex_t *re, int flags,
#if (NGX_DEBUG)
ngx_log_debug5(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
"pcre2_match: flags 0x%05Xd, options 0x%08Xd, rc %d, "
"n %ui, ovecsize %ui", flags, exec_opts, rc, n, ovecsize);
"n %ui, ovecpair %ui", flags, exec_opts, rc, n, ovecpair);
#endif
if (!(flags & NGX_LUA_RE_MODE_DFA) && n > ovecsize / 3) {
n = ovecsize / 3;
if (n > ovecpair) {
n = ovecpair;
}
for (i = 0; i < n; i++) {

View file

@ -85,23 +85,6 @@ ngx_http_lua_ngx_req_read_body(lua_State *L)
return luaL_error(L, "request object not found");
}
/* http2 read body may break http2 stream process */
#if (NGX_HTTP_V2)
if (r->main->stream && r->headers_in.content_length_n < 0) {
return luaL_error(L, "http2 requests are not supported"
" without content-length header");
}
#endif
#if (NGX_HTTP_V3)
if (r->http_version == NGX_HTTP_VERSION_30
&& r->headers_in.content_length_n < 0)
{
return luaL_error(L, "http3 requests are not supported"
" without content-length header");
}
#endif
r->request_body_in_single_buf = 1;
r->request_body_in_persistent_file = 1;
r->request_body_in_clean_file = 1;
@ -349,23 +332,6 @@ ngx_http_lua_ngx_req_get_body_file(lua_State *L)
return luaL_error(L, "request object not found");
}
/* http2 read body may break http2 stream process */
#if (NGX_HTTP_V2)
if (r->main->stream && r->headers_in.content_length_n < 0) {
return luaL_error(L, "http2 requests are not supported"
" without content-length header");
}
#endif
#if (NGX_HTTP_V3)
if (r->http_version == NGX_HTTP_VERSION_30
&& r->headers_in.content_length_n < 0)
{
return luaL_error(L, "http3 requests are not supported"
" without content-length header");
}
#endif
ngx_http_lua_check_fake_request(L, r);
if (r->request_body == NULL || r->request_body->temp_file == NULL) {

View file

@ -140,12 +140,7 @@ ngx_http_lua_rewrite_handler(ngx_http_request_t *r)
return NGX_DONE;
}
/* http2 read body may break http2 stream process */
#if (NGX_HTTP_V2)
if (llcf->force_read_body && !ctx->read_body_done && !r->main->stream) {
#else
if (llcf->force_read_body && !ctx->read_body_done) {
#endif
r->request_body_in_single_buf = 1;
r->request_body_in_persistent_file = 1;
r->request_body_in_clean_file = 1;

View file

@ -102,13 +102,8 @@ ngx_http_lua_server_rewrite_handler(ngx_http_request_t *r)
return NGX_DONE;
}
/* TODO: lscf do not have force_read_body
* http2 read body may break http2 stream process */
#if (NGX_HTTP_V2)
if (llcf->force_read_body && !ctx->read_body_done && !r->main->stream) {
#else
/* TODO: lscf do not have force_read_body */
if (llcf->force_read_body && !ctx->read_body_done) {
#endif
r->request_body_in_single_buf = 1;
r->request_body_in_persistent_file = 1;
r->request_body_in_clean_file = 1;

View file

@ -210,7 +210,7 @@ ngx_http_lua_shdict_lookup(ngx_shm_zone_t *shm_zone, ngx_uint_t hash,
dd("time to live: %lld", (long long) ms);
if (ms < 0) {
if (ms <= 0) {
dd("node already expired");
return NGX_DONE;
}

View file

@ -861,13 +861,7 @@ ngx_http_lua_socket_tcp_bind(lua_State *L)
return luaL_error(L, "no ctx found");
}
ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_REWRITE
| NGX_HTTP_LUA_CONTEXT_ACCESS
| NGX_HTTP_LUA_CONTEXT_CONTENT
| NGX_HTTP_LUA_CONTEXT_TIMER
| NGX_HTTP_LUA_CONTEXT_SSL_CERT
| NGX_HTTP_LUA_CONTEXT_SSL_SESS_FETCH
| NGX_HTTP_LUA_CONTEXT_SSL_CLIENT_HELLO);
ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_YIELDABLE);
luaL_checktype(L, 1, LUA_TTABLE);
@ -5385,6 +5379,34 @@ ngx_http_lua_socket_tcp_setkeepalive(lua_State *L)
luaL_checktype(L, 1, LUA_TTABLE);
r = ngx_http_lua_get_req(L);
if (r == NULL) {
return luaL_error(L, "no request found");
}
llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module);
/* luaL_checkinteger will throw error if the argument is not a number.
* e.g.: bad argument \#2 to '?' (number expected, got string)
*
* We should check the argument in advance; otherwise,
* throwing an exception in the middle can compromise data integrity.
* e.g.: set pc->connection to NULL without following cleanup.
*/
if (n >= 2 && !lua_isnil(L, 2)) {
timeout = (ngx_msec_t) luaL_checkinteger(L, 2);
} else {
timeout = llcf->keepalive_timeout;
}
if (n >= 3 && !lua_isnil(L, 3)) {
pool_size = luaL_checkinteger(L, 3);
} else {
pool_size = llcf->pool_size;
}
lua_rawgeti(L, 1, SOCKET_CTX_INDEX);
u = lua_touserdata(L, -1);
lua_pop(L, 1);
@ -5411,11 +5433,6 @@ ngx_http_lua_socket_tcp_setkeepalive(lua_State *L)
return 2;
}
r = ngx_http_lua_get_req(L);
if (r == NULL) {
return luaL_error(L, "no request found");
}
if (u->request != r) {
return luaL_error(L, "bad request");
}
@ -5486,18 +5503,8 @@ ngx_http_lua_socket_tcp_setkeepalive(lua_State *L)
/* stack: obj timeout? size? pools cache_key */
llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module);
if (spool == NULL) {
/* create a new socket pool for the current peer key */
if (n >= 3 && !lua_isnil(L, 3)) {
pool_size = luaL_checkinteger(L, 3);
} else {
pool_size = llcf->pool_size;
}
if (pool_size <= 0) {
msg = lua_pushfstring(L, "bad \"pool_size\" option value: %d",
pool_size);
@ -5561,13 +5568,6 @@ ngx_http_lua_socket_tcp_setkeepalive(lua_State *L)
ngx_del_timer(c->write);
}
if (n >= 2 && !lua_isnil(L, 2)) {
timeout = (ngx_msec_t) luaL_checkinteger(L, 2);
} else {
timeout = llcf->keepalive_timeout;
}
#if (NGX_DEBUG)
if (timeout == 0) {
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
@ -5747,6 +5747,16 @@ ngx_http_lua_socket_keepalive_close_handler(ngx_event_t *ev)
"lua tcp socket keepalive close handler check stale events");
n = recv(c->fd, buf, 1, MSG_PEEK);
#if (NGX_HTTP_SSL)
/* ignore ssl protocol data like change cipher spec */
if (n == 1 && c->ssl != NULL) {
n = c->recv(c, (unsigned char *) buf, 1);
if (n == NGX_AGAIN) {
n = -1;
ngx_socket_errno = NGX_EAGAIN;
}
}
#endif
if (n == -1 && ngx_socket_errno == NGX_EAGAIN) {
/* stale event */

View file

@ -54,16 +54,19 @@ static void ngx_http_lua_socket_udp_read_handler(ngx_http_request_t *r,
ngx_http_lua_socket_udp_upstream_t *u);
static void ngx_http_lua_socket_udp_handle_success(ngx_http_request_t *r,
ngx_http_lua_socket_udp_upstream_t *u);
static ngx_int_t ngx_http_lua_udp_connect(ngx_http_lua_udp_connection_t *uc);
static ngx_int_t ngx_http_lua_udp_connect(ngx_http_lua_udp_connection_t *uc,
ngx_addr_t *local);
static int ngx_http_lua_socket_udp_close(lua_State *L);
static ngx_int_t ngx_http_lua_socket_udp_resume(ngx_http_request_t *r);
static void ngx_http_lua_udp_resolve_cleanup(void *data);
static void ngx_http_lua_udp_socket_cleanup(void *data);
static int ngx_http_lua_socket_udp_bind(lua_State *L);
enum {
SOCKET_CTX_INDEX = 1,
SOCKET_TIMEOUT_INDEX = 2,
SOCKET_BIND_INDEX = 3,
};
@ -100,6 +103,9 @@ ngx_http_lua_inject_socket_udp_api(ngx_log_t *log, lua_State *L)
lua_pushcfunction(L, ngx_http_lua_socket_udp_close);
lua_setfield(L, -2, "close"); /* ngx socket mt */
lua_pushcfunction(L, ngx_http_lua_socket_udp_bind);
lua_setfield(L, -2, "bind");
lua_pushvalue(L, -1);
lua_setfield(L, -2, "__index");
lua_rawset(L, LUA_REGISTRYINDEX);
@ -159,6 +165,7 @@ ngx_http_lua_socket_udp_setpeername(lua_State *L)
ngx_http_request_t *r;
ngx_http_lua_ctx_t *ctx;
ngx_str_t host;
ngx_addr_t *local;
int port;
ngx_resolver_ctx_t *rctx, temp;
ngx_http_core_loc_conf_t *clcf;
@ -291,6 +298,13 @@ ngx_http_lua_socket_udp_setpeername(lua_State *L)
u->read_timeout = u->conf->read_timeout;
}
lua_rawgeti(L, 1, SOCKET_BIND_INDEX);
local = lua_touserdata(L, -1);
lua_pop(L, 1);
if (local != NULL) {
u->local = local;
}
ngx_memzero(&url, sizeof(ngx_url_t));
url.url.len = host.len;
@ -618,7 +632,7 @@ ngx_http_lua_socket_resolve_retval_handler(ngx_http_request_t *r,
return 2;
}
rc = ngx_http_lua_udp_connect(uc);
rc = ngx_http_lua_udp_connect(uc, u->local);
if (rc != NGX_OK) {
u->socket_errno = ngx_socket_errno;
@ -721,6 +735,56 @@ ngx_http_lua_socket_error_retval_handler(ngx_http_request_t *r,
}
static int
ngx_http_lua_socket_udp_bind(lua_State *L)
{
ngx_http_request_t *r;
ngx_http_lua_ctx_t *ctx;
int n;
u_char *text;
size_t len;
ngx_addr_t *local;
n = lua_gettop(L);
if (n != 2) {
return luaL_error(L, "expecting 2 arguments, but got %d",
lua_gettop(L));
}
r = ngx_http_lua_get_req(L);
if (r == NULL) {
return luaL_error(L, "no request found");
}
ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
if (ctx == NULL) {
return luaL_error(L, "no ctx found");
}
ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_YIELDABLE);
luaL_checktype(L, 1, LUA_TTABLE);
text = (u_char *) luaL_checklstring(L, 2, &len);
local = ngx_http_lua_parse_addr(L, text, len);
if (local == NULL) {
lua_pushnil(L);
lua_pushfstring(L, "bad address");
return 2;
}
lua_rawseti(L, 1, SOCKET_BIND_INDEX);
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"lua udp socket bind ip: %V", &local->name);
lua_pushinteger(L, 1);
return 1;
}
static int
ngx_http_lua_socket_udp_send(lua_State *L)
{
@ -1340,7 +1404,7 @@ ngx_http_lua_socket_udp_handle_success(ngx_http_request_t *r,
static ngx_int_t
ngx_http_lua_udp_connect(ngx_http_lua_udp_connection_t *uc)
ngx_http_lua_udp_connect(ngx_http_lua_udp_connection_t *uc, ngx_addr_t *local)
{
int rc;
ngx_int_t event;
@ -1413,8 +1477,19 @@ ngx_http_lua_udp_connect(ngx_http_lua_udp_connection_t *uc)
return NGX_ERROR;
}
}
#endif
if (local != NULL) {
fprintf(stderr, "=== have local address\n");
if (bind(s, local->sockaddr, local->socklen) == -1) {
ngx_log_error(NGX_LOG_CRIT, &uc->log, ngx_socket_errno,
"bind(%V) failed", &local->name);
return NGX_ERROR;
}
}
ngx_log_debug3(NGX_LOG_DEBUG_EVENT, &uc->log, 0,
"connect to %V, fd:%d #%d", &uc->server, s, c->number);

View file

@ -42,6 +42,8 @@ struct ngx_http_lua_socket_udp_upstream_s {
ngx_http_request_t *request;
ngx_http_lua_udp_connection_t udp_connection;
ngx_addr_t *local;
ngx_msec_t read_timeout;
ngx_http_upstream_resolved_t *resolved;
@ -53,7 +55,7 @@ struct ngx_http_lua_socket_udp_upstream_s {
ngx_http_lua_co_ctx_t *co_ctx;
unsigned waiting; /* :1 */
unsigned waiting:1; /* :1 */
};

View file

@ -1172,6 +1172,81 @@ ngx_http_lua_ffi_parse_pem_cert(const u_char *pem, size_t pem_len,
}
void *
ngx_http_lua_ffi_parse_der_cert(const char *data, size_t len,
char **err)
{
BIO *bio;
X509 *x509;
STACK_OF(X509) *chain;
if (data == NULL || len == 0) {
*err = "invalid argument";
ERR_clear_error();
return NULL;
}
bio = BIO_new_mem_buf((char *) data, len);
if (bio == NULL) {
*err = "BIO_new_mem_buf() failed";
ERR_clear_error();
return NULL;
}
x509 = d2i_X509_bio(bio, NULL);
if (x509 == NULL) {
*err = "d2i_X509_bio() failed";
BIO_free(bio);
ERR_clear_error();
return NULL;
}
chain = sk_X509_new_null();
if (chain == NULL) {
*err = "sk_X509_new_null() failed";
X509_free(x509);
BIO_free(bio);
ERR_clear_error();
return NULL;
}
if (sk_X509_push(chain, x509) == 0) {
*err = "sk_X509_push() failed";
sk_X509_free(chain);
X509_free(x509);
BIO_free(bio);
ERR_clear_error();
return NULL;
}
/* read rest of the chain */
while (!BIO_eof(bio)) {
x509 = d2i_X509_bio(bio, NULL);
if (x509 == NULL) {
*err = "d2i_X509_bio() failed in rest of chain";
sk_X509_pop_free(chain, X509_free);
BIO_free(bio);
ERR_clear_error();
return NULL;
}
if (sk_X509_push(chain, x509) == 0) {
*err = "sk_X509_push() failed in rest of chain";
sk_X509_pop_free(chain, X509_free);
X509_free(x509);
BIO_free(bio);
ERR_clear_error();
return NULL;
}
}
BIO_free(bio);
return chain;
}
void
ngx_http_lua_ffi_free_cert(void *cdata)
{
@ -1209,6 +1284,40 @@ ngx_http_lua_ffi_parse_pem_priv_key(const u_char *pem, size_t pem_len,
}
void *
ngx_http_lua_ffi_parse_der_priv_key(const char *data, size_t len,
char **err)
{
BIO *bio = NULL;
EVP_PKEY *pkey = NULL;
if (data == NULL || len == 0) {
*err = "invalid argument";
ERR_clear_error();
return NULL;
}
bio = BIO_new_mem_buf((char *) data, len);
if (bio == NULL) {
*err = "BIO_new_mem_buf() failed";
ERR_clear_error();
return NULL;
}
pkey = d2i_PrivateKey_bio(bio, NULL);
if (pkey == NULL) {
*err = "d2i_PrivateKey_bio() failed";
BIO_free(bio);
ERR_clear_error();
return NULL;
}
BIO_free(bio);
return pkey;
}
void
ngx_http_lua_ffi_free_priv_key(void *cdata)
{
@ -1359,8 +1468,8 @@ ngx_http_lua_ssl_verify_callback(int ok, X509_STORE_CTX *x509_store)
int
ngx_http_lua_ffi_ssl_verify_client(ngx_http_request_t *r, void *ca_certs,
int depth, char **err)
ngx_http_lua_ffi_ssl_verify_client(ngx_http_request_t *r, void *client_certs,
void *trusted_certs, int depth, char **err)
{
#ifdef LIBRESSL_VERSION_NUMBER
@ -1372,7 +1481,8 @@ ngx_http_lua_ffi_ssl_verify_client(ngx_http_request_t *r, void *ca_certs,
ngx_http_lua_ctx_t *ctx;
ngx_ssl_conn_t *ssl_conn;
ngx_http_ssl_srv_conf_t *sscf;
STACK_OF(X509) *chain = ca_certs;
STACK_OF(X509) *client_chain = client_certs;
STACK_OF(X509) *trusted_chain = trusted_certs;
STACK_OF(X509_NAME) *name_chain = NULL;
X509 *x509 = NULL;
X509_NAME *subject = NULL;
@ -1426,54 +1536,75 @@ ngx_http_lua_ffi_ssl_verify_client(ngx_http_request_t *r, void *ca_certs,
/* set CA chain */
if (chain != NULL) {
if (client_chain != NULL || trusted_chain != NULL) {
ca_store = X509_STORE_new();
if (ca_store == NULL) {
*err = "X509_STORE_new() failed";
return NGX_ERROR;
}
/* construct name chain */
if (client_chain != NULL) {
name_chain = sk_X509_NAME_new_null();
if (name_chain == NULL) {
*err = "sk_X509_NAME_new_null() failed";
goto failed;
/* construct name chain */
name_chain = sk_X509_NAME_new_null();
if (name_chain == NULL) {
*err = "sk_X509_NAME_new_null() failed";
goto failed;
}
for (i = 0; i < sk_X509_num(client_chain); i++) {
x509 = sk_X509_value(client_chain, i);
if (x509 == NULL) {
*err = "sk_X509_value() failed";
goto failed;
}
/* add subject to name chain, which will be sent to client */
subject = X509_NAME_dup(X509_get_subject_name(x509));
if (subject == NULL) {
*err = "X509_get_subject_name() failed";
goto failed;
}
if (!sk_X509_NAME_push(name_chain, subject)) {
*err = "sk_X509_NAME_push() failed";
X509_NAME_free(subject);
goto failed;
}
/* add to trusted CA store */
if (X509_STORE_add_cert(ca_store, x509) == 0) {
*err = "X509_STORE_add_cert() failed";
goto failed;
}
}
/* clean subject name list, and set it for send to client */
SSL_set_client_CA_list(ssl_conn, name_chain);
}
for (i = 0; i < sk_X509_num(chain); i++) {
x509 = sk_X509_value(chain, i);
if (x509 == NULL) {
*err = "sk_X509_value() failed";
goto failed;
}
if (trusted_chain != NULL) {
for (i = 0; i < sk_X509_num(trusted_chain); i++) {
x509 = sk_X509_value(trusted_chain, i);
if (x509 == NULL) {
*err = "sk_X509_value() failed";
goto failed;
}
/* add subject to name chain, which will be sent to client */
subject = X509_NAME_dup(X509_get_subject_name(x509));
if (subject == NULL) {
*err = "X509_get_subject_name() failed";
goto failed;
}
if (!sk_X509_NAME_push(name_chain, subject)) {
*err = "sk_X509_NAME_push() failed";
X509_NAME_free(subject);
goto failed;
}
/* add to trusted CA store */
if (X509_STORE_add_cert(ca_store, x509) == 0) {
*err = "X509_STORE_add_cert() failed";
goto failed;
/* add to trusted CA store */
if (X509_STORE_add_cert(ca_store, x509) == 0) {
*err = "X509_STORE_add_cert() failed";
goto failed;
}
}
}
/* clean ca_store, and store new ca_store */
if (SSL_set0_verify_cert_store(ssl_conn, ca_store) == 0) {
*err = "SSL_set0_verify_cert_store() failed";
goto failed;
}
SSL_set_client_CA_list(ssl_conn, name_chain);
}
return NGX_OK;
@ -1500,4 +1631,27 @@ ngx_http_lua_ffi_get_req_ssl_pointer(ngx_http_request_t *r)
}
int
ngx_http_lua_ffi_ssl_client_random(ngx_http_request_t *r,
unsigned char *out, size_t *outlen, char **err)
{
ngx_ssl_conn_t *ssl_conn;
if (r->connection == NULL || r->connection->ssl == NULL) {
*err = "bad request";
return NGX_ERROR;
}
ssl_conn = r->connection->ssl->connection;
if (ssl_conn == NULL) {
*err = "bad ssl conn";
return NGX_ERROR;
}
*outlen = SSL_get_client_random(ssl_conn, out, *outlen);
return NGX_OK;
}
#endif /* NGX_HTTP_SSL */

View file

@ -541,6 +541,10 @@ int
ngx_http_lua_ffi_ssl_get_client_hello_server_name(ngx_http_request_t *r,
const char **name, size_t *namelen, char **err)
{
#ifdef LIBRESSL_VERSION_NUMBER
*err = "LibreSSL does not support by ssl_client_hello_by_lua*";
return NGX_ERROR;
#else
ngx_ssl_conn_t *ssl_conn;
#ifdef SSL_ERROR_WANT_CLIENT_HELLO_CB
const unsigned char *p;
@ -619,6 +623,7 @@ ngx_http_lua_ffi_ssl_get_client_hello_server_name(ngx_http_request_t *r,
*err = "no TLS extension support";
return NGX_ERROR;
#endif
#endif /* LIBRESSL_VERSION_NUMBER */
}
@ -626,6 +631,10 @@ int
ngx_http_lua_ffi_ssl_get_client_hello_ext(ngx_http_request_t *r,
unsigned int type, const unsigned char **out, size_t *outlen, char **err)
{
#ifdef LIBRESSL_VERSION_NUMBER
*err = "LibreSSL does not support by ssl_client_hello_by_lua*";
return NGX_ERROR;
#else
ngx_ssl_conn_t *ssl_conn;
if (r->connection == NULL || r->connection->ssl == NULL) {
@ -649,7 +658,7 @@ ngx_http_lua_ffi_ssl_get_client_hello_ext(ngx_http_request_t *r,
*err = "OpenSSL too old to support this function";
return NGX_ERROR;
#endif
#endif /* LIBRESSL_VERSION_NUMBER */
}
@ -703,7 +712,7 @@ ngx_http_lua_ffi_ssl_set_protocols(ngx_http_request_t *r,
}
#endif
#ifdef SSL_OP_NO_TLSv1_3
#if defined(NGX_SSL_TLSv1_3) && defined( SSL_OP_NO_TLSv1_3)
SSL_clear_options(ssl_conn, SSL_OP_NO_TLSv1_3);
if (!(protocols & NGX_SSL_TLSv1_3)) {
SSL_set_options(ssl_conn, SSL_OP_NO_TLSv1_3);

View file

@ -0,0 +1,125 @@
/*
* Copyright (C) Yichun Zhang (agentzh)
*/
#ifndef DDEBUG
#define DDEBUG 0
#endif
#include "ddebug.h"
#if (NGX_HTTP_SSL)
#include <openssl/ssl.h>
#include "ngx_http_lua_cache.h"
#include "ngx_http_lua_initworkerby.h"
#include "ngx_http_lua_util.h"
#include "ngx_http_ssl_module.h"
#include "ngx_http_lua_contentby.h"
#include "ngx_http_lua_ssl_session_fetchby.h"
#include "ngx_http_lua_ssl.h"
#include "ngx_http_lua_directive.h"
#include "ngx_http_lua_ssl_export_keying_material.h"
ngx_int_t
ngx_http_lua_ffi_ssl_export_keying_material(ngx_http_request_t *r,
u_char *out, size_t out_size, const char *label, size_t llen,
const u_char *context, size_t ctxlen, int use_ctx, char **err)
{
#if defined(OPENSSL_IS_BORINGSSL) || OPENSSL_VERSION_NUMBER < 0x10101000L
*err = "BoringSSL does not support SSL_export_keying_material";
return NGX_ERROR;
#elif defined(LIBRESSL_VERSION_NUMBER)
*err = "LibreSSL does not support SSL_export_keying_material";
return NGX_ERROR;
#elif OPENSSL_VERSION_NUMBER < 0x10101000L
*err = "OpenSSL too old";
return NGX_ERROR;
#else
ngx_connection_t *c;
ngx_ssl_conn_t *ssl_conn;
int rc;
c = r->connection;
if (c == NULL || c->ssl == NULL) {
*err = "bad request";
return NGX_ERROR;
}
ssl_conn = c->ssl->connection;
if (ssl_conn == NULL) {
*err = "bad ssl connection";
return NGX_ERROR;
}
rc = SSL_export_keying_material(ssl_conn, out, out_size, label, llen,
context, ctxlen, use_ctx);
if (rc == 1) {
return NGX_OK;
}
ngx_ssl_error(NGX_LOG_INFO, c->log, 0,
"SSL_export_keying_material rc: %d, error: %s",
rc, ERR_error_string(ERR_get_error(), NULL));
*err = "SSL_export_keying_material() failed";
return NGX_ERROR;
#endif
}
ngx_int_t
ngx_http_lua_ffi_ssl_export_keying_material_early(ngx_http_request_t *r,
u_char *out, size_t out_size, const char *label, size_t llen,
const u_char *context, size_t ctxlen, char **err)
{
#if defined(OPENSSL_IS_BORINGSSL) || OPENSSL_VERSION_NUMBER < 0x10101000L
*err = "BoringSSL does not support SSL_export_keying_material";
return NGX_ERROR;
#elif defined(LIBRESSL_VERSION_NUMBER)
*err = "LibreSSL does not support SSL_export_keying_material";
return NGX_ERROR;
#elif OPENSSL_VERSION_NUMBER < 0x10101000L
*err = "OpenSSL too old";
return NGX_ERROR;
#else
int rc;
ngx_ssl_conn_t *ssl_conn;
ngx_connection_t *c;
c = r->connection;
if (c == NULL || c->ssl == NULL) {
*err = "bad request";
return NGX_ERROR;
}
ssl_conn = c->ssl->connection;
if (ssl_conn == NULL) {
*err = "bad ssl connection";
return NGX_ERROR;
}
rc = SSL_export_keying_material_early(ssl_conn, out, out_size,
label, llen, context, ctxlen);
if (rc == 1) {
return NGX_OK;
}
ngx_ssl_error(NGX_LOG_INFO, c->log, 0,
"SSL_export_keying_material_early rc: %d, error: %s",
rc, ERR_error_string(ERR_get_error(), NULL));
*err = "SSL_export_keying_material_early() failed";
return NGX_ERROR;
#endif
}
#endif /* NGX_HTTP_SSL */

View file

@ -0,0 +1,24 @@
/*
* Copyright (C) Yichun Zhang (agentzh)
*/
#ifndef _NGX_HTTP_LUA_SSL_EXPORT_KEYING_MATERIAL_H_INCLUDED_
#define _NGX_HTTP_LUA_SSL_EXPORT_KEYING_MATERIAL_H_INCLUDED_
#include "ngx_http_lua_common.h"
#if (NGX_HTTP_SSL)
ngx_int_t ngx_http_lua_ffi_ssl_export_keying_material(ngx_http_request_t *r,
u_char *out, size_t out_size, const char *label, size_t llen,
const u_char *ctx, size_t ctxlen, int use_ctx, char **err);
ngx_int_t ngx_http_lua_ffi_ssl_export_keying_material_early(
ngx_http_request_t *r, u_char *out, size_t out_size, const char *label,
size_t llen, const u_char *ctx, size_t ctxlen, char **err);
#endif
#endif /* _NGX_HTTP_LUA_SSL_EXPORT_KEYING_MATERIAL_H_INCLUDED_ */
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */

View file

@ -19,8 +19,9 @@
#ifdef NGX_HTTP_LUA_USE_OCSP
static int ngx_http_lua_ssl_empty_status_callback(ngx_ssl_conn_t *ssl_conn,
void *data);
#endif
static long ngx_http_lua_ssl_stapling_time(ASN1_GENERALIZEDTIME *asn1time);
#endif
int
ngx_http_lua_ffi_ssl_get_ocsp_responder_from_der_chain(
@ -262,7 +263,7 @@ failed:
int
ngx_http_lua_ffi_ssl_validate_ocsp_response(const u_char *resp,
size_t resp_len, const char *chain_data, size_t chain_len,
u_char *errbuf, size_t *errbuf_size)
u_char *errbuf, size_t *errbuf_size, long *valid)
{
#ifndef NGX_HTTP_LUA_USE_OCSP
@ -279,7 +280,7 @@ ngx_http_lua_ffi_ssl_validate_ocsp_response(const u_char *resp,
OCSP_RESPONSE *ocsp = NULL;
OCSP_BASICRESP *basic = NULL;
STACK_OF(X509) *chain = NULL;
ASN1_GENERALIZEDTIME *thisupdate, *nextupdate;
ASN1_GENERALIZEDTIME *thisupdate = NULL, *nextupdate = NULL;
ocsp = d2i_OCSP_RESPONSE(NULL, &resp, resp_len);
if (ocsp == NULL) {
@ -383,6 +384,16 @@ ngx_http_lua_ffi_ssl_validate_ocsp_response(const u_char *resp,
goto error;
}
if (nextupdate) {
*valid = ngx_http_lua_ssl_stapling_time(nextupdate);
if (*valid == NGX_ERROR) {
*errbuf_size = ngx_snprintf(errbuf, *errbuf_size,
"invalid nextUpdate time "
"in certificate status") - errbuf;
goto error;
}
}
sk_X509_free(chain);
X509_free(cert);
X509_free(issuer);
@ -437,6 +448,40 @@ ngx_http_lua_ssl_empty_status_callback(ngx_ssl_conn_t *ssl_conn, void *data)
{
return SSL_TLSEXT_ERR_OK;
}
static long
ngx_http_lua_ssl_stapling_time(ASN1_GENERALIZEDTIME *asn1time)
{
BIO *bio;
char *value;
size_t len;
time_t time;
/*
* OpenSSL doesn't provide a way to convert ASN1_GENERALIZEDTIME
* into long. To do this, we use ASN1_GENERALIZEDTIME_print(),
* which uses the "MMM DD HH:MM:SS YYYY [GMT]" format (e.g.,
* "Feb 3 00:55:52 2015 GMT"), and parse the result.
*/
bio = BIO_new(BIO_s_mem());
if (bio == NULL) {
return NGX_ERROR;
}
/* fake weekday prepended to match C asctime() format */
BIO_write(bio, "Tue ", sizeof("Tue ") - 1);
ASN1_GENERALIZEDTIME_print(bio, asn1time);
len = BIO_get_mem_data(bio, &value);
time = ngx_parse_http_time((u_char *) value, len);
BIO_free(bio);
return time;
}
#endif

View file

@ -62,10 +62,10 @@ static ngx_str_t ngx_http_lua_content_length_header_key =
static ngx_int_t ngx_http_lua_adjust_subrequest(ngx_http_request_t *sr,
ngx_uint_t method, int forward_body,
ngx_http_request_body_t *body, unsigned vars_action,
ngx_array_t *extra_vars);
ngx_array_t *extra_vars, ngx_array_t *extra_headers);
static int ngx_http_lua_ngx_location_capture(lua_State *L);
static int ngx_http_lua_ngx_location_capture_multi(lua_State *L);
static void ngx_http_lua_process_vars_option(ngx_http_request_t *r,
static void ngx_http_lua_process_keyval_option(ngx_http_request_t *r,
lua_State *L, int table, ngx_array_t **varsp);
static ngx_int_t ngx_http_lua_subrequest_add_extra_vars(ngx_http_request_t *r,
ngx_array_t *extra_vars);
@ -79,7 +79,7 @@ static void ngx_http_lua_cancel_subreq(ngx_http_request_t *r);
static ngx_int_t ngx_http_post_request_to_head(ngx_http_request_t *r);
static ngx_int_t ngx_http_lua_copy_in_file_request_body(ngx_http_request_t *r);
static ngx_int_t ngx_http_lua_copy_request_headers(ngx_http_request_t *sr,
ngx_http_request_t *pr, int pr_not_chunked);
ngx_http_request_t *pr, int pr_not_chunked, ngx_array_t *extra_headers);
enum {
@ -127,6 +127,7 @@ ngx_http_lua_ngx_location_capture_multi(lua_State *L)
ngx_http_lua_ctx_t *sr_ctx;
ngx_http_lua_ctx_t *ctx;
ngx_array_t *extra_vars;
ngx_array_t *extra_headers;
ngx_str_t uri;
ngx_str_t args;
ngx_str_t extra_args;
@ -224,6 +225,7 @@ ngx_http_lua_ngx_location_capture_multi(lua_State *L)
coctx->pending_subreqs = 0;
extra_vars = NULL;
extra_headers = NULL;
for (index = 0; index < nsubreqs; index++) {
coctx->pending_subreqs++;
@ -263,6 +265,11 @@ ngx_http_lua_ngx_location_capture_multi(lua_State *L)
extra_vars->nelts = 0;
}
if (extra_headers != NULL) {
/* flush out existing elements in the array */
extra_headers->nelts = 0;
}
vars_action = 0;
custom_ctx = 0;
@ -318,7 +325,7 @@ ngx_http_lua_ngx_location_capture_multi(lua_State *L)
switch (lua_type(L, -1)) {
case LUA_TTABLE:
ngx_http_lua_process_vars_option(r, L, -1, &extra_vars);
ngx_http_lua_process_keyval_option(r, L, -1, &extra_vars);
dd("post process vars top: %d", lua_gettop(L));
break;
@ -335,6 +342,29 @@ ngx_http_lua_ngx_location_capture_multi(lua_State *L)
dd("queries query uri opts: %d", lua_gettop(L));
/* check the headers option */
lua_getfield(L, 4, "headers");
switch (lua_type(L, -1)) {
case LUA_TTABLE:
ngx_http_lua_process_keyval_option(r, L, -1, &extra_headers);
dd("post process vars top: %d", lua_gettop(L));
break;
case LUA_TNIL:
/* do nothing */
break;
default:
return luaL_error(L, "Bad headers option value");
}
lua_pop(L, 1); /* pop the headers */
dd("queries query uri opts: %d", lua_gettop(L));
/* check the share_all_vars option */
lua_getfield(L, 4, "share_all_vars");
@ -595,7 +625,8 @@ ngx_http_lua_ngx_location_capture_multi(lua_State *L)
ngx_http_set_ctx(sr, sr_ctx, ngx_http_lua_module);
rc = ngx_http_lua_adjust_subrequest(sr, method, always_forward_body,
body, vars_action, extra_vars);
body, vars_action, extra_vars,
extra_headers);
if (rc != NGX_OK) {
ngx_http_lua_cancel_subreq(sr);
@ -631,7 +662,7 @@ ngx_http_lua_ngx_location_capture_multi(lua_State *L)
static ngx_int_t
ngx_http_lua_adjust_subrequest(ngx_http_request_t *sr, ngx_uint_t method,
int always_forward_body, ngx_http_request_body_t *body,
unsigned vars_action, ngx_array_t *extra_vars)
unsigned vars_action, ngx_array_t *extra_vars, ngx_array_t *extra_headers)
{
ngx_http_request_t *r;
ngx_http_core_main_conf_t *cmcf;
@ -667,7 +698,9 @@ ngx_http_lua_adjust_subrequest(ngx_http_request_t *sr, ngx_uint_t method,
}
}
if (ngx_http_lua_copy_request_headers(sr, r, pr_not_chunked) != NGX_OK) {
if (ngx_http_lua_copy_request_headers(sr, r, pr_not_chunked, extra_headers)
!= NGX_OK)
{
return NGX_ERROR;
}
@ -882,7 +915,7 @@ ngx_http_lua_subrequest_add_extra_vars(ngx_http_request_t *sr,
static void
ngx_http_lua_process_vars_option(ngx_http_request_t *r, lua_State *L,
ngx_http_lua_process_keyval_option(ngx_http_request_t *r, lua_State *L,
int table, ngx_array_t **varsp)
{
ngx_array_t *vars;
@ -1635,10 +1668,11 @@ ngx_http_lua_copy_in_file_request_body(ngx_http_request_t *r)
static ngx_int_t
ngx_http_lua_copy_request_headers(ngx_http_request_t *sr,
ngx_http_request_t *pr, int pr_not_chunked)
ngx_http_request_t *pr, int pr_not_chunked, ngx_array_t *extra_headers)
{
ngx_table_elt_t *clh, *header;
ngx_list_part_t *part;
ngx_keyval_t *header_keyval;
ngx_chain_t *in;
ngx_uint_t i;
u_char *p;
@ -1742,6 +1776,20 @@ ngx_http_lua_copy_request_headers(ngx_http_request_t *sr,
}
}
if (extra_headers && extra_headers->nelts > 0) {
header_keyval = extra_headers->elts;
for (i = 0; i < extra_headers->nelts; i++, header_keyval++) {
if (ngx_http_lua_set_input_header(sr, header_keyval->key,
header_keyval->value, 1) == NGX_ERROR)
{
return NGX_ERROR;
}
}
}
dd("after: parent req headers count: %d",
(int) pr->headers_in.headers.part.nelts);

View file

@ -549,6 +549,10 @@ ngx_http_lua_send_header_if_needed(ngx_http_request_t *r,
if (!ctx->buffering) {
dd("sending headers");
rc = ngx_http_send_header(r);
if (r->filter_finalize) {
ngx_http_set_ctx(r, ctx, ngx_http_lua_module);
}
ctx->header_sent = 1;
return rc;
}
@ -599,6 +603,12 @@ ngx_http_lua_send_chain_link(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx,
if (r->header_only) {
ctx->eof = 1;
if (!r->request_body && r == r->main) {
if (ngx_http_discard_request_body(r) != NGX_OK) {
return NGX_ERROR;
}
}
if (ctx->buffering) {
return ngx_http_lua_send_http10_headers(r, ctx);
}

View file

@ -194,11 +194,21 @@ ngx_http_lua_get_task_ctx(lua_State *L, ngx_http_request_t *r)
static void
ngx_http_lua_free_task_ctx(ngx_http_lua_task_ctx_t *ctx)
{
lua_State *vm;
ctx->next = ctxpool->next;
ctxpool->next = ctx;
/* clean Lua stack */
lua_settop(ctx->vm, 0);
vm = ctx->vm;
/* call collectgarbage("collect") */
lua_settop(vm, 0);
lua_getglobal(vm, "collectgarbage");
lua_pushstring(vm, "collect");
lua_pcall(vm, 1, 1, 0);
lua_settop(vm, 0);
}

View file

@ -1098,3 +1098,25 @@ failed to load inlined Lua code: content_by_lua(...45678901234567890123456789012
GET /lua
--- response_body_like: 503 Service Temporarily Unavailable
--- error_code: 503
=== TEST 52: send_header trigger filter finalize does not clear the ctx
--- config
location /lua {
content_by_lua_block {
ngx.header["Last-Modified"] = ngx.http_time(ngx.time())
ngx.send_headers()
local phase = ngx.get_phase()
}
header_filter_by_lua_block {
ngx.header["X-Hello-World"] = "Hello World"
}
}
--- request
GET /lua
--- more_headers
If-Unmodified-Since: Wed, 01 Jan 2020 07:28:00 GMT
--- error_code: 412
--- no_error_log
unknown phase: 0

View file

@ -828,7 +828,7 @@ qr/curl: \(28\) Operation timed out after \d+ milliseconds with 0 bytes received
rewrite ^/myproxy/(.*) /$1 break;
resolver_timeout 3s;
#resolver 172.16.0.23; # AWS DNS resolver address is the same in all regions - 172.16.0.23
resolver 8.8.8.8;
resolver $TEST_NGINX_RESOLVER;
proxy_read_timeout 1s;
proxy_send_timeout 1s;
proxy_connect_timeout 1s;

View file

@ -1,6 +1,7 @@
# vim:set ft= ts=4 sw=4 et fdm=marker:
use Test::Nginx::Socket::Lua;
use Test::Nginx::Util 'is_tcp_port_used';
#master_on();
#workers(1);
@ -16,6 +17,16 @@ plan tests => repeat_each() * (blocks() * 3 + 23);
$ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211;
$ENV{TEST_NGINX_HTML_DIR} ||= html_dir();
# NB: tcp_listen_port needs to be greater than 10000,
# because the test cases expect it to be a 5-digit number
my $tcp_listen_port = 19113;
while (++$tcp_listen_port < 65535) {
if (!is_tcp_port_used $tcp_listen_port) {
last;
}
}
$ENV{TEST_NGINX_TCP_LISTEN_PORT} = $tcp_listen_port;
#no_diff();
no_long_string();
#no_shuffle();
@ -1383,7 +1394,7 @@ upstream timed out
#proxy_read_timeout 100ms;
proxy_buffering on;
proxy_pass http://127.0.0.1:$TEST_NGINX_RAND_PORT_2;
proxy_pass http://127.0.0.1:$TEST_NGINX_TCP_LISTEN_PORT;
}
location /main {
@ -1396,7 +1407,7 @@ upstream timed out
}
--- request
GET /main
--- tcp_listen: $TEST_NGINX_RAND_PORT_2
--- tcp_listen: $TEST_NGINX_TCP_LISTEN_PORT
--- tcp_query_len: 65
--- tcp_reply eval
"HTTP/1.0 200 OK\r\nContent-Length: 1024\r\n\r\nhello world"
@ -1443,7 +1454,7 @@ upstream prematurely closed connection
proxy_read_timeout 100ms;
proxy_buffering on;
proxy_pass http://127.0.0.1:$TEST_NGINX_RAND_PORT_2;
proxy_pass http://127.0.0.1:$TEST_NGINX_TCP_LISTEN_PORT;
}
location /main {
@ -1456,7 +1467,7 @@ upstream prematurely closed connection
}
--- request
GET /main
--- tcp_listen: $TEST_NGINX_RAND_PORT_2
--- tcp_listen: $TEST_NGINX_TCP_LISTEN_PORT
--- tcp_no_close
--- tcp_reply eval
"HTTP/1.0 200 OK\r\nContent-Length: 1024\r\n\r\nhello world"
@ -1505,7 +1516,7 @@ upstream timed out
#proxy_read_timeout 100ms;
proxy_buffering on;
proxy_pass http://127.0.0.1:$TEST_NGINX_RAND_PORT_2;
proxy_pass http://127.0.0.1:$TEST_NGINX_TCP_LISTEN_PORT;
}
location /main {
@ -1518,7 +1529,7 @@ upstream timed out
}
--- request
GET /main
--- tcp_listen: $TEST_NGINX_RAND_PORT_2
--- tcp_listen: $TEST_NGINX_TCP_LISTEN_PORT
--- tcp_query_len: 65
--- tcp_reply eval
"HTTP/1.0 200 OK\r\n\r\nhello world"
@ -1565,7 +1576,7 @@ truncated: false
proxy_read_timeout 100ms;
proxy_buffering on;
proxy_pass http://127.0.0.1:$TEST_NGINX_RAND_PORT_2;
proxy_pass http://127.0.0.1:$TEST_NGINX_TCP_LISTEN_PORT;
}
location /main {
@ -1578,7 +1589,7 @@ truncated: false
}
--- request
GET /main
--- tcp_listen: $TEST_NGINX_RAND_PORT_2
--- tcp_listen: $TEST_NGINX_TCP_LISTEN_PORT
--- tcp_no_close
--- tcp_reply eval
"HTTP/1.0 200 OK\r\n\r\nhello world"
@ -1628,7 +1639,7 @@ upstream timed out
#proxy_read_timeout 100ms;
proxy_buffering off;
proxy_pass http://127.0.0.1:$TEST_NGINX_RAND_PORT_2;
proxy_pass http://127.0.0.1:$TEST_NGINX_TCP_LISTEN_PORT;
}
location /main {
@ -1641,7 +1652,7 @@ upstream timed out
}
--- request
GET /main
--- tcp_listen: $TEST_NGINX_RAND_PORT_2
--- tcp_listen: $TEST_NGINX_TCP_LISTEN_PORT
--- tcp_query_len: 65
--- tcp_reply eval
"HTTP/1.0 200 OK\r\n\r\nhello world"
@ -1688,7 +1699,7 @@ truncated: false
proxy_read_timeout 500ms;
proxy_buffering off;
proxy_pass http://127.0.0.1:$TEST_NGINX_RAND_PORT_2;
proxy_pass http://127.0.0.1:$TEST_NGINX_TCP_LISTEN_PORT;
}
location /main {
@ -1701,7 +1712,7 @@ truncated: false
}
--- request
GET /main
--- tcp_listen: $TEST_NGINX_RAND_PORT_2
--- tcp_listen: $TEST_NGINX_TCP_LISTEN_PORT
--- tcp_no_close
--- tcp_reply eval
"HTTP/1.0 200 OK\r\n\r\nhello world"
@ -1914,7 +1925,7 @@ a client request body is buffered to a temporary file
#proxy_read_timeout 100ms;
proxy_http_version 1.1;
proxy_buffering on;
proxy_pass http://127.0.0.1:$TEST_NGINX_RAND_PORT_2;
proxy_pass http://127.0.0.1:$TEST_NGINX_TCP_LISTEN_PORT;
}
location /main {
@ -1927,7 +1938,7 @@ a client request body is buffered to a temporary file
}
--- request
GET /main
--- tcp_listen: $TEST_NGINX_RAND_PORT_2
--- tcp_listen: $TEST_NGINX_TCP_LISTEN_PORT
--- tcp_query_len: 65
--- tcp_reply eval
"HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\nb\r\nhello world\r"
@ -1977,7 +1988,7 @@ upstream prematurely closed connection
#proxy_read_timeout 100ms;
proxy_http_version 1.1;
proxy_buffering off;
proxy_pass http://127.0.0.1:$TEST_NGINX_RAND_PORT_2;
proxy_pass http://127.0.0.1:$TEST_NGINX_TCP_LISTEN_PORT;
}
location /main {
@ -1990,7 +2001,7 @@ upstream prematurely closed connection
}
--- request
GET /main
--- tcp_listen: $TEST_NGINX_RAND_PORT_2
--- tcp_listen: $TEST_NGINX_TCP_LISTEN_PORT
--- tcp_query_len: 65
--- tcp_reply eval
"HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\nb\r\nhello world\r"
@ -2038,7 +2049,7 @@ upstream prematurely closed connection
proxy_read_timeout 100ms;
proxy_buffering on;
proxy_http_version 1.1;
proxy_pass http://127.0.0.1:$TEST_NGINX_RAND_PORT_2;
proxy_pass http://127.0.0.1:$TEST_NGINX_TCP_LISTEN_PORT;
}
location /main {
@ -2051,7 +2062,7 @@ upstream prematurely closed connection
}
--- request
GET /main
--- tcp_listen: $TEST_NGINX_RAND_PORT_2
--- tcp_listen: $TEST_NGINX_TCP_LISTEN_PORT
--- tcp_no_close
--- tcp_reply eval
"HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\nb\r\nhello world\r"
@ -2100,7 +2111,7 @@ upstream timed out
#proxy_read_timeout 100ms;
proxy_buffering on;
proxy_http_version 1.1;
proxy_pass http://127.0.0.1:$TEST_NGINX_RAND_PORT_2;
proxy_pass http://127.0.0.1:$TEST_NGINX_TCP_LISTEN_PORT;
}
location /main {
@ -2113,7 +2124,7 @@ upstream timed out
}
--- request
GET /main
--- tcp_listen: $TEST_NGINX_RAND_PORT_2
--- tcp_listen: $TEST_NGINX_TCP_LISTEN_PORT
--- tcp_no_close
--- tcp_reply eval
"HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n5\r\nhello\r\n0\r\n\r\n"
@ -2158,7 +2169,7 @@ truncated: false
#proxy_read_timeout 100ms;
proxy_buffering off;
proxy_http_version 1.1;
proxy_pass http://127.0.0.1:$TEST_NGINX_RAND_PORT_2;
proxy_pass http://127.0.0.1:$TEST_NGINX_TCP_LISTEN_PORT;
}
location /main {
@ -2171,7 +2182,7 @@ truncated: false
}
--- request
GET /main
--- tcp_listen: $TEST_NGINX_RAND_PORT_2
--- tcp_listen: $TEST_NGINX_TCP_LISTEN_PORT
--- tcp_no_close
--- tcp_reply eval
"HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n5\r\nhello\r\n0\r\n\r\n"
@ -2217,7 +2228,7 @@ truncated: false
#proxy_read_timeout 100ms;
proxy_buffering off;
proxy_pass http://127.0.0.1:$TEST_NGINX_RAND_PORT_2;
proxy_pass http://127.0.0.1:$TEST_NGINX_TCP_LISTEN_PORT;
}
location /main {
@ -2230,7 +2241,7 @@ truncated: false
}
--- request
GET /main
--- tcp_listen: $TEST_NGINX_RAND_PORT_2
--- tcp_listen: $TEST_NGINX_TCP_LISTEN_PORT
--- tcp_query_len: 65
--- tcp_reply eval
"HTTP/1.0 200 OK\r\nContent-Length: 1024\r\n\r\nhello world"
@ -3527,3 +3538,83 @@ HTTP/1.1 400 Bad Request
[error]
--- skip_nginx
3: < 1.21.1
=== TEST 83: avoid request smuggling of HEAD req
--- config
location /capture {
server_tokens off;
more_clear_headers Date;
content_by_lua_block {
ngx.say("Hello")
}
}
location /t {
content_by_lua_block {
local req = [[
HEAD /capture HTTP/1.1
Host: test.com
Content-Length: 63
GET /capture HTTP/1.1
Host: test.com
X: GET /bar HTTP/1.0
]]
local sock = ngx.socket.tcp()
sock:settimeout(1000)
local ok, err = sock:connect("127.0.0.1", $TEST_NGINX_SERVER_PORT)
if not ok then
ngx.say("failed to connect: ", err)
return
end
local bytes, err = sock:send(req)
if not bytes then
ngx.say("failed to send req: ", err)
return
end
ngx.say("req bytes: ", bytes)
local n_resp = 0
local reader = sock:receiveuntil("\r\n")
while true do
local line, err = reader()
if line then
ngx.say(line)
if line == "0" then
n_resp = n_resp + 1
end
if n_resp >= 2 then
break
end
else
ngx.say("err: ", err)
break
end
end
sock:close()
}
}
--- request
GET /t
--- response_body
req bytes: 117
HTTP/1.1 200 OK
Server: nginx
Content-Type: text/plain
Connection: keep-alive
err: timeout
--- error_log
lua tcp socket read timed out

View file

@ -170,26 +170,3 @@ Expect: 100-Continue
http finalize request: 500, "/echo_body?" a:1, c:2
http finalize request: 500, "/echo_body?" a:1, c:0
--- log_level: debug
--- skip_eval: 4:$ENV{TEST_NGINX_USE_HTTP3}
=== TEST 9: test HTTP2 reading request body was disabled
--- config
location /echo_body {
lua_need_request_body on;
rewrite_by_lua_block {
ngx.print(ngx.var.request_body or "nil")
}
content_by_lua 'ngx.exit(ngx.OK)';
}
--- http2
--- request eval
"POST /echo_body
hello\x00\x01\x02
world\x03\x04\xff"
--- more_headers
Content-Length:
--- response_body eval
"nil"
--- no_error_log

View file

@ -170,26 +170,3 @@ Expect: 100-Continue
http finalize request: 500, "/echo_body?" a:1, c:2
http finalize request: 500, "/echo_body?" a:1, c:0
--- log_level: debug
--- skip_eval: 4:$ENV{TEST_NGINX_USE_HTTP3}
=== TEST 9: test HTTP2 reading request body was disabled
--- config
location /echo_body {
lua_need_request_body on;
access_by_lua_block {
ngx.print(ngx.var.request_body or "nil")
}
content_by_lua 'ngx.exit(ngx.OK)';
}
--- http2
--- request eval
"POST /echo_body
hello\x00\x01\x02
world\x03\x04\xff"
--- more_headers
Content-Length:
--- response_body eval
"nil"
--- no_error_log

View file

@ -752,3 +752,75 @@ proxy_cache_path conf/cache levels=1:2 keys_zone=STATIC:10m inactive=10m max_siz
GET /foo
--- response_body
ok
=== TEST 14: capture multi with headers
--- config
location /foo {
content_by_lua_block {
local res1, res2, res3 = ngx.location.capture_multi{
{"/test", { headers = { ["X-Test-Header"] = "aa"} } },
{"/test", { headers = { ["X-Test-Header"] = "bb"} } },
{"/test"},
}
ngx.say("res1.status = " .. res1.status)
ngx.say("res1.body = " .. res1.body)
ngx.say("res2.status = " .. res2.status)
ngx.say("res2.body = " .. res2.body)
ngx.say("res3.status = " .. res3.status)
ngx.say("res3.body = " .. res3.body)
}
}
location = /test {
content_by_lua_block {
ngx.print(ngx.var.http_x_test_header)
}
}
--- request
GET /foo
--- response_body
res1.status = 200
res1.body = aa
res2.status = 200
res2.body = bb
res3.status = 200
res3.body = nil
=== TEST 15: capture multi with headers override
--- config
location /foo {
content_by_lua_block {
local res1, res2, res3 = ngx.location.capture_multi{
{"/test", { headers = { ["X-Test-Header"] = "aa"} } },
{"/test", { headers = { ["X-Test-Header"] = "bb"} } },
{"/test"},
}
ngx.say("res1.status = " .. res1.status)
ngx.say("res1.body = " .. res1.body)
ngx.say("res2.status = " .. res2.status)
ngx.say("res2.body = " .. res2.body)
ngx.say("res3.status = " .. res3.status)
ngx.say("res3.body = " .. res3.body)
}
}
location = /test {
content_by_lua_block {
ngx.print(ngx.var.http_x_test_header)
}
}
--- request
GET /foo
--- more_headers
X-Test-Header: cc
--- response_body
res1.status = 200
res1.body = aa
res2.status = 200
res2.body = bb
res3.status = 200
res3.body = cc

View file

@ -7,7 +7,7 @@ log_level('warn');
repeat_each(2);
plan tests => repeat_each() * (blocks() * 4 + 56);
plan tests => repeat_each() * (blocks() * 4 + 58);
#no_diff();
no_long_string();
@ -1774,23 +1774,3 @@ content length: 5
--- no_error_log
[error]
[alert]
--- skip_eval: 4:$ENV{TEST_NGINX_USE_HTTP3}
=== TEST 53: HTTP2 read buffered body was discarded
--- config
location = /test {
content_by_lua_block {
local err = pcall(ngx.req.read_body())
ngx.say(err)
}
}
--- http2
--- request
POST /test
hello, world
--- more_headers
Content-Length:
--- error_code: 500
--- error_log: http2 requests are not supported without content-length header

View file

@ -207,3 +207,41 @@ exec opts: 0
--- no_error_log
[error]
=== TEST 9: matched with do
--- config
location /re {
content_by_lua '
local m = ngx.re.match("hello", "(h)(e)(l)", "jo")
if m then
ngx.say(m[0])
ngx.say(m[1])
ngx.say(m[2])
ngx.say(m[3])
else
ngx.say("not matched!")
end
local m = ngx.re.match("horld", "(h)(e)?(l)?", "jo")
if m then
ngx.say(m[0])
ngx.say(m[1])
ngx.say(m[2])
ngx.say(m[3])
else
ngx.say("not matched!")
end
';
}
--- request
GET /re
--- response_body
hel
h
e
l
h
h
false
false

View file

@ -481,7 +481,7 @@ n = 16
--- request
GET /test
--- response_body
n = 6
n = 7
--- no_error_log
[error]

View file

@ -3029,3 +3029,167 @@ connected: 1, reused: 0
--- error_log
lua tcp socket keepalive create connection pool for key "A"
lua tcp socket keepalive create connection pool for key "B"
=== TEST 54: wrong first argument for setkeepalive
--- quic_max_idle_timeout: 1.2
--- http_config eval
"lua_package_path '$::HtmlDir/?.lua;./?.lua;;';"
--- config
server_tokens off;
location /t {
keepalive_timeout 60s;
set $port $TEST_NGINX_SERVER_PORT;
content_by_lua_block {
local port = ngx.var.port
local sock = ngx.socket.tcp()
local ok, err = sock:connect("127.0.0.1", port)
if not ok then
ngx.say("failed to connect: ", err)
return
end
ngx.say("connected: ", ok)
local req = "GET /foo HTTP/1.1\r\nHost: localhost\r\nConnection: keepalive\r\n\r\n"
local bytes, err = sock:send(req)
if not bytes then
ngx.say("failed to send request: ", err)
return
end
ngx.say("request sent: ", bytes)
local reader = sock:receiveuntil("\r\n0\r\n\r\n")
local data, err = reader()
if not data then
ngx.say("failed to receive response body: ", err)
return
end
ngx.say("received response of ", #data, " bytes")
ok, err = sock:setkeepalive()
if not ok then
ngx.say("failed to set reusable: ", err)
end
ok, err = sock:connect("127.0.0.1", port)
if not ok then
ngx.say("failed to connect: ", err)
return
end
ok, err = sock:setkeepalive("not a number", "not a number")
if not ok then
ngx.say("failed to set reusable: ", err)
end
}
}
location /foo {
echo foo;
}
location /sleep {
echo_sleep 1;
}
--- request
GET /t
--- error_code:
--- response_body
--- error_log eval
qr/\Qbad argument #1 to 'setkeepalive' (number expected, got string)\E/
--- no_error_log
[crit]
--- timeout: 4
--- curl_error eval
qr{HTTP/3 stream 0 reset by server}
=== TEST 55: wrong second argument for setkeepalive
--- quic_max_idle_timeout: 1.2
--- http_config eval
"lua_package_path '$::HtmlDir/?.lua;./?.lua;;';"
--- config
server_tokens off;
location /t {
keepalive_timeout 60s;
set $port $TEST_NGINX_SERVER_PORT;
content_by_lua_block {
local port = ngx.var.port
local sock = ngx.socket.tcp()
local ok, err = sock:connect("127.0.0.1", port)
if not ok then
ngx.say("failed to connect: ", err)
return
end
ngx.say("connected: ", ok)
local req = "GET /foo HTTP/1.1\r\nHost: localhost\r\nConnection: keepalive\r\n\r\n"
local bytes, err = sock:send(req)
if not bytes then
ngx.say("failed to send request: ", err)
return
end
ngx.say("request sent: ", bytes)
local reader = sock:receiveuntil("\r\n0\r\n\r\n")
local data, err = reader()
if not data then
ngx.say("failed to receive response body: ", err)
return
end
ngx.say("received response of ", #data, " bytes")
ok, err = sock:setkeepalive()
if not ok then
ngx.say("failed to set reusable: ", err)
end
ok, err = sock:connect("127.0.0.1", port)
if not ok then
ngx.say("failed to connect: ", err)
return
end
ok, err = sock:setkeepalive(10, "not a number")
if not ok then
ngx.say("failed to set reusable: ", err)
end
}
}
location /foo {
echo foo;
}
location /sleep {
echo_sleep 1;
}
--- request
GET /t
--- error_code:
--- response_body
--- error_log eval
qr/\Qbad argument #2 to 'setkeepalive' (number expected, got string)\E/
--- no_error_log
[crit]
--- timeout: 4
--- curl_error eval
qr{HTTP/3 stream 0 reset by server}

View file

@ -225,3 +225,47 @@ GET /t
[error]
[alert]
[crit]
=== TEST 4: set resp body nil with ngx.arg[1] first
--- config
location /t {
content_by_lua_block {
ngx.say("Hello World!")
}
body_filter_by_lua_block {
ngx.arg[1] = ""
ngx.arg[2] = true
}
}
--- request
GET /t
--- response_body
--- no_error_log
[error]
[alert]
[crit]
=== TEST 5: set resp body nil with ngx.arg[2] first
--- config
location /t {
content_by_lua_block {
ngx.say("Hello World!")
}
body_filter_by_lua_block {
ngx.arg[2] = true
ngx.arg[1] = ""
}
}
--- request
GET /t
--- response_body
--- no_error_log
[error]
[alert]
[crit]

View file

@ -4,7 +4,7 @@ use Test::Nginx::Socket::Lua;
repeat_each(2);
plan tests => repeat_each() * (3 * blocks() + 15);
plan tests => repeat_each() * (3 * blocks() + 16);
our $HtmlDir = html_dir;
@ -1222,3 +1222,113 @@ qr/send: fd:\d+ 22 of 22
send: fd:\d+ 16 of 16
send: fd:\d+ 22 of 22/
--- log_level: debug
=== TEST 23: udp bind
--- config
server_tokens off;
location /t {
#set $port 5000;
set $port $TEST_NGINX_MEMCACHED_PORT;
#set $port 1234;
content_by_lua_block {
local socket = ngx.socket
local udp = socket.udp()
local port = ngx.var.port
udp:settimeout(1000) -- 1 sec
local ok, err = udp:bind("127.0.0.10")
if not ok then
ngx.say("failed to bind: ", err)
return
end
local ok, err = udp:setpeername("127.0.0.1", port)
if not ok then
ngx.say("failed to connect: ", err)
return
end
ngx.say("connected")
local req = "\0\1\0\0\0\1\0\0flush_all\r\n"
local ok, err = udp:send(req)
if not ok then
ngx.say("failed to send: ", err)
return
end
local data, err = udp:receive()
if not data then
ngx.say("failed to receive data: ", err)
return
end
ngx.print("received ", #data, " bytes: ", data)
}
}
--- request
GET /t
--- response_body eval
"connected\nreceived 12 bytes: \x{00}\x{01}\x{00}\x{00}\x{00}\x{01}\x{00}\x{00}OK\x{0d}\x{0a}"
--- no_error_log
[error]
--- log_level: debug
--- error_log
lua udp socket receive buffer size: 65536
=== TEST 24: udp bind failed
--- config
server_tokens off;
location /t {
#set $port 5000;
set $port $TEST_NGINX_MEMCACHED_PORT;
#set $port 1234;
content_by_lua_block {
local socket = ngx.socket
local udp = socket.udp()
local port = ngx.var.port
udp:settimeout(1000) -- 1 sec
local ok, err = udp:bind("127.0.0.1000")
if not ok then
ngx.say("failed to bind: ", err)
return
end
local ok, err = udp:setpeername("127.0.0.1", port)
if not ok then
ngx.say("failed to connect: ", err)
return
end
ngx.say("connected")
local req = "\0\1\0\0\0\1\0\0flush_all\r\n"
local ok, err = udp:send(req)
if not ok then
ngx.say("failed to send: ", err)
return
end
local data, err = udp:receive()
if not data then
ngx.say("failed to receive data: ", err)
return
end
ngx.print("received ", #data, " bytes: ", data)
}
}
--- request
GET /t
--- response_body
failed to bind: bad address
--- no_error_log
[error]
--- log_level: debug

View file

@ -1484,6 +1484,72 @@ SSL reused session
=== TEST 18: openresty.org: passing SSL verify: keepalive (no reusing the ssl session)
The session returned by SSL_get1_session maybe different.
After function tls_process_new_session_ticket, the session saved in SSL->session
will be replace by a new one.
ngx_ssl_session_t *
ngx_ssl_get_session(ngx_connection_t *c)
{
#ifdef TLS1_3_VERSION
if (c->ssl->session) {
SSL_SESSION_up_ref(c->ssl->session);
return c->ssl->session;
}
#endif
return SSL_get1_session(c->ssl->connection);
}
SSL_SESSION *SSL_get1_session(SSL *ssl)
/* variant of SSL_get_session: caller really gets something */
{
SSL_SESSION *sess;
/*
* Need to lock this all up rather than just use CRYPTO_add so that
* somebody doesn't free ssl->session between when we check it's non-null
* and when we up the reference count.
*/
CRYPTO_THREAD_read_lock(ssl->lock);
sess = ssl->session;
if (sess)
SSL_SESSION_up_ref(sess);
CRYPTO_THREAD_unlock(ssl->lock);
return sess;
}
#0 tls_process_new_session_ticket (s=0x7e6ea0, pkt=0x7fffffffc820) at ssl/statem/statem_clnt.c:2650
#1 0x00007ffff7af50fd in read_state_machine (s=0x7e6ea0) at ssl/statem/statem.c:636
#2 state_machine (s=0x7e6ea0, server=0) at ssl/statem/statem.c:434
#3 0x00007ffff7aca6b3 in ssl3_read_bytes (s=<optimized out>, type=23, recvd_type=0x0, buf=0x7fffffffc9d7 "\027\320\355t", len=1,
peek=0, readbytes=0x7fffffffc978) at ssl/record/rec_layer_s3.c:1677
#4 0x00007ffff7ad2250 in ssl3_read_internal (readbytes=0x7fffffffc978, peek=0, len=1, buf=0x7fffffffc9d7, s=0x7e6ea0)
at ssl/s3_lib.c:4477
#5 ssl3_read (s=0x7e6ea0, buf=0x7fffffffc9d7, len=1, readbytes=0x7fffffffc978) at ssl/s3_lib.c:4500
#6 0x00007ffff7ade695 in SSL_read (s=<optimized out>, buf=buf@entry=0x7fffffffc9d7, num=num@entry=1) at ssl/ssl_lib.c:1799
#7 0x000000000045a965 in ngx_ssl_recv (c=0x72c3b0, buf=0x7fffffffc9d7 "\027\320\355t", size=1)
at src/event/ngx_event_openssl.c:2337
#8 0x0000000000533b17 in ngx_http_lua_socket_keepalive_close_handler (ev=0x7e2f20)
at /var/code/openresty/lua-nginx-module/src/ngx_http_lua_socket_tcp.c:5753
#9 0x000000000052cf40 in ngx_http_lua_socket_tcp_setkeepalive (L=0x74edd0)
at /var/code/openresty/lua-nginx-module/src/ngx_http_lua_socket_tcp.c:5602
#10 0x00007ffff7f0fabe in lj_BC_FUNCC ()
from /tmp/undodb.72729.1722915526.2470007.80d50d088e818fd4/debuggee-1-zwqz8svp/symbol-files/opt/luajit-sysm/lib/libluajit-5.1.so.2
#11 0x000000000051f2b2 in ngx_http_lua_run_thread (L=L@entry=0x767670, r=r@entry=0x7edf80, ctx=ctx@entry=0x750e40, nrets=0)
at /var/code/openresty/lua-nginx-module/src/ngx_http_lua_util.c:1194
#12 0x0000000000524347 in ngx_http_lua_content_by_chunk (L=0x767670, r=0x7edf80)
at /var/code/openresty/lua-nginx-module/src/ngx_http_lua_contentby.c:124
#13 0x000000000047c663 in ngx_http_core_content_phase (r=0x7edf80, ph=0x7b4470) at src/http/ngx_http_core_module.c:1271
#14 0x000000000047b80d in ngx_http_core_run_phases (r=0x7edf80) at src/http/ngx_http_core_module.c:885
#15 ngx_http_handler (r=r@entry=0x7edf80) at src/http/ngx_http_core_module.c:868
#16 0x00000000004854ad in ngx_http_process_request (r=r@entry=0x7edf80) at src/http/ngx_http_request.c:2140
#17 0x00000000004868e8 in ngx_http_process_request_headers (rev=rev@entry=0x7e2f80) at src/http/ngx_http_request.c:1529
#18 0x0000000000486468 in ngx_http_process_request_line (rev=0x7e2f80) at src/http/ngx_http_request.c:1196
#19 0x000000000044b338 in ngx_event_process_posted (cycle=cycle@entry=0x721690, posted=0x62f250 <ngx_posted_events>)
at src/event/ngx_event_posted.c:35
#20 0x000000000044a522 in ngx_process_events_and_timers (cycle=cycle@entry=0x721690) at src/event/ngx_event.c:273
#21 0x0000000000453819 in ngx_single_process_cycle (cycle=cycle@entry=0x721690) at src/os/unix/ngx_process_cycle.c:323
#22 0x0000000000429dee in main (argc=argc@entry=5, argv=argv@entry=0x7fffffffd1a8) at src/core/nginx.c:384
--- config
server_tokens off;
resolver $TEST_NGINX_RESOLVER ipv6=off;
@ -1548,11 +1614,11 @@ set keepalive: 1 nil
--- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+/
--- grep_error_log_out eval
qr/^lua ssl save session: ([0-9A-F]+)
lua ssl save session: \1
lua ssl save session: \1
lua ssl free session: \1
lua ssl free session: \1
lua ssl free session: \1
lua ssl save session: ([0-9A-F]+)
lua ssl save session: ([0-9A-F]+)
lua ssl free session: ([0-9A-F]+)
lua ssl free session: ([0-9A-F]+)
lua ssl free session: ([0-9A-F]+)
$/
--- error_log

View file

@ -12,7 +12,7 @@ use Test::Nginx::Socket::Lua;
repeat_each(2);
plan tests => repeat_each() * (blocks() * 4 + 9);
plan tests => repeat_each() * (blocks() * 4 + 7);
#no_diff();
no_long_string();
@ -571,7 +571,7 @@ upstream sent more data than specified in "Content-Length" header while reading
=== TEST 18: error in balancer_by_llua_block
=== TEST 18: error in balancer_by_lua_block
--- http_config
upstream backend {
server 0.0.0.1;
@ -591,3 +591,90 @@ upstream sent more data than specified in "Content-Length" header while reading
"failed to load inlined Lua code: balancer_by_lua(nginx.conf:27):3: ')' expected (to close '(' at line 2) near '<eof>'",
--- no_error_log
[warn]
=== TEST 19: disable ssl
--- http_config
lua_package_path "$TEST_NGINX_SERVER_ROOT/html/?.lua;;";
upstream backend {
server 127.0.0.1:$TEST_NGINX_SERVER_PORT;
balancer_by_lua_block {
local ffi = require "ffi"
local C = ffi.C
ffi.cdef[[
int
ngx_http_lua_ffi_balancer_set_upstream_tls(ngx_http_request_t *r, int on, char **err);
]]
local errmsg = ffi.new("char *[1]")
local r = require "resty.core.base" .get_request()
if r == nil then
ngx.log(ngx.ERR, "no request found")
return
end
local rc = C.ngx_http_lua_ffi_balancer_set_upstream_tls(r, 0, errmsg)
if rc < 0 then
ngx.log(ngx.ERR, "failed to disable ssl: ", ffi.string(errmsg[0]))
return
end
}
}
--- config
location = /t {
proxy_pass https://backend/back;
}
location = /back {
echo ok;
}
--- request
GET /t
--- response_body
ok
--- no_error_log
[error]
[cirt]
=== TEST 20: recreate_request refresh body buffer when ngx.req.set_body_data is used in balancer phase
--- http_config
lua_package_path "../lua-resty-core/lib/?.lua;;";
server {
listen 127.0.0.1:$TEST_NGINX_RAND_PORT_1;
location / {
content_by_lua_block {
ngx.req.read_body()
local body = ngx.req.get_body_data()
ngx.log(ngx.ERR, "body: ", body)
ngx.say(body)
}
}
}
upstream foo {
server 127.0.0.1:$TEST_NGINX_RAND_PORT_1 max_fails=0;
balancer_by_lua_block {
local bal = require "ngx.balancer"
ngx.req.set_body_data("hello world")
assert(bal.recreate_request())
}
}
--- config
location = /t {
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_pass http://foo;
}
--- request
GET /t
--- error_code: 200
--- response_body
hello world

View file

@ -12,7 +12,7 @@ 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);
plan tests => repeat_each() * (blocks() * 5 - 1);
}
$ENV{TEST_NGINX_HTML_DIR} ||= html_dir();
@ -53,6 +53,12 @@ ffi.cdef[[
void *ngx_http_lua_ffi_parse_pem_priv_key(const unsigned char *pem,
size_t pem_len, char **err);
void *ngx_http_lua_ffi_parse_der_cert(const char *data, size_t len,
char **err);
void *ngx_http_lua_ffi_parse_der_priv_key(const char *data, size_t len,
char **err);
int ngx_http_lua_ffi_set_cert(void *r,
void *cdata, char **err);
@ -66,7 +72,10 @@ ffi.cdef[[
void ngx_http_lua_ffi_free_priv_key(void *cdata);
int ngx_http_lua_ffi_ssl_verify_client(void *r, void *cdata,
int depth, char **err);
void *cdata, int depth, char **err);
int ngx_http_lua_ffi_ssl_client_random(ngx_http_request_t *r,
unsigned char *out, size_t *outlen, char **err);
]]
_EOC_
@ -844,21 +853,21 @@ lua ssl server name: "test.com"
local cert_data = f:read("*all")
f:close()
local cert = ffi.C.ngx_http_lua_ffi_parse_pem_cert(cert_data, #cert_data, errmsg)
if not cert then
ngx.log(ngx.ERR, "failed to parse PEM cert: ",
local client_cert = ffi.C.ngx_http_lua_ffi_parse_pem_cert(cert_data, #cert_data, errmsg)
if not client_cert then
ngx.log(ngx.ERR, "failed to parse PEM client cert: ",
ffi.string(errmsg[0]))
return
end
local rc = ffi.C.ngx_http_lua_ffi_ssl_verify_client(r, cert, 1, errmsg)
local rc = ffi.C.ngx_http_lua_ffi_ssl_verify_client(r, client_cert, nil, 1, errmsg)
if rc ~= 0 then
ngx.log(ngx.ERR, "failed to verify client: ",
ffi.string(errmsg[0]))
return
end
ffi.C.ngx_http_lua_ffi_free_cert(cert)
ffi.C.ngx_http_lua_ffi_free_cert(client_cert)
}
ssl_certificate ../../cert/test2.crt;
@ -915,7 +924,7 @@ client certificate subject: emailAddress=agentzh@gmail.com,CN=test.com
return
end
local rc = ffi.C.ngx_http_lua_ffi_ssl_verify_client(r, nil, -1, errmsg)
local rc = ffi.C.ngx_http_lua_ffi_ssl_verify_client(r, nil, nil, -1, errmsg)
if rc ~= 0 then
ngx.log(ngx.ERR, "failed to verify client: ",
ffi.string(errmsg[0]))
@ -981,21 +990,21 @@ client certificate subject: emailAddress=agentzh@gmail.com,CN=test.com
local cert_data = f:read("*all")
f:close()
local cert = ffi.C.ngx_http_lua_ffi_parse_pem_cert(cert_data, #cert_data, errmsg)
if not cert then
ngx.log(ngx.ERR, "failed to parse PEM cert: ",
local client_cert = ffi.C.ngx_http_lua_ffi_parse_pem_cert(cert_data, #cert_data, errmsg)
if not client_cert then
ngx.log(ngx.ERR, "failed to parse PEM client cert: ",
ffi.string(errmsg[0]))
return
end
local rc = ffi.C.ngx_http_lua_ffi_ssl_verify_client(r, cert, 1, errmsg)
local rc = ffi.C.ngx_http_lua_ffi_ssl_verify_client(r, client_cert, nil, 1, errmsg)
if rc ~= 0 then
ngx.log(ngx.ERR, "failed to verify client: ",
ffi.string(errmsg[0]))
return
end
ffi.C.ngx_http_lua_ffi_free_cert(cert)
ffi.C.ngx_http_lua_ffi_free_cert(client_cert)
}
ssl_certificate ../../cert/test2.crt;
@ -1323,3 +1332,448 @@ SNI is test.com
--- no_error_log
[error]
[alert]
=== TEST 11: DER cert + private key cdata
--- http_config
server {
listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl;
server_name test.com;
ssl_certificate_by_lua_block {
collectgarbage()
local ffi = require "ffi"
require "defines"
local errmsg = ffi.new("char *[1]")
local r = require "resty.core.base" .get_request()
if r == nil then
ngx.log(ngx.ERR, "no request found")
return
end
ffi.C.ngx_http_lua_ffi_ssl_clear_certs(r, errmsg)
local f = assert(io.open("t/cert/test_der.crt", "rb"))
local cert_data = f:read("*all")
f:close()
local cert = ffi.C.ngx_http_lua_ffi_parse_der_cert(cert_data, #cert_data, errmsg)
if not cert then
ngx.log(ngx.ERR, "failed to parse DER cert: ",
ffi.string(errmsg[0]))
return
end
local rc = ffi.C.ngx_http_lua_ffi_set_cert(r, cert, errmsg)
if rc ~= 0 then
ngx.log(ngx.ERR, "failed to set cdata cert: ",
ffi.string(errmsg[0]))
return
end
ffi.C.ngx_http_lua_ffi_free_cert(cert)
f = assert(io.open("t/cert/test_der.key", "rb"))
local pkey_data = f:read("*all")
f:close()
local pkey = ffi.C.ngx_http_lua_ffi_parse_der_priv_key(pkey_data, #pkey_data, errmsg)
if pkey == nil then
ngx.log(ngx.ERR, "failed to parse DER priv key: ",
ffi.string(errmsg[0]))
return
end
local rc = ffi.C.ngx_http_lua_ffi_set_priv_key(r, pkey, errmsg)
if rc ~= 0 then
ngx.log(ngx.ERR, "failed to set cdata priv key: ",
ffi.string(errmsg[0]))
return
end
ffi.C.ngx_http_lua_ffi_free_priv_key(pkey)
}
ssl_certificate ../../cert/test2.crt;
ssl_certificate_key ../../cert/test2.key;
server_tokens off;
location /foo {
default_type 'text/plain';
content_by_lua_block { ngx.status = 201 ngx.say("foo") ngx.exit(201) }
more_clear_headers Date;
}
}
--- config
server_tokens off;
lua_ssl_trusted_certificate ../../cert/test.crt;
location /t {
content_by_lua_block {
do
local sock = ngx.socket.tcp()
sock:settimeout(2000)
local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock")
if not ok then
ngx.say("failed to connect: ", err)
return
end
ngx.say("connected: ", ok)
local sess, err = sock:sslhandshake(nil, "test.com", true)
if not sess then
ngx.say("failed to do SSL handshake: ", err)
return
end
ngx.say("ssl handshake: ", type(sess))
local req = "GET /foo HTTP/1.0\r\nHost: test.com\r\nConnection: close\r\n\r\n"
local bytes, err = sock:send(req)
if not bytes then
ngx.say("failed to send http request: ", err)
return
end
ngx.say("sent http request: ", bytes, " bytes.")
while true do
local line, err = sock:receive()
if not line then
-- ngx.say("failed to receive response status line: ", err)
break
end
ngx.say("received: ", line)
end
local ok, err = sock:close()
ngx.say("close: ", ok, " ", err)
end -- do
-- collectgarbage()
}
}
--- request
GET /t
--- response_body
connected: 1
ssl handshake: cdata
sent http request: 56 bytes.
received: HTTP/1.1 201 Created
received: Server: nginx
received: Content-Type: text/plain
received: Content-Length: 4
received: Connection: close
received:
received: foo
close: 1 nil
--- error_log
lua ssl server name: "test.com"
--- no_error_log
[error]
[alert]
=== TEST 12: client random
--- http_config
server {
listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl;
server_name test.com;
ssl_certificate_by_lua_block {
collectgarbage()
local ffi = require "ffi"
require "defines"
local errmsg = ffi.new("char *[1]")
local r = require "resty.core.base" .get_request()
if r == nil then
ngx.log(ngx.ERR, "no request found")
return
end
-- test client random length
local out = ffi.new("unsigned char[?]", 0)
local sizep = ffi.new("size_t[1]", 0)
local rc = ffi.C.ngx_http_lua_ffi_ssl_client_random(r, out, sizep, errmsg)
if rc ~= 0 then
ngx.log(ngx.ERR, "failed to get client random length: ",
ffi.string(errmsg[0]))
return
end
if tonumber(sizep[0]) ~= 32 then
ngx.log(ngx.ERR, "client random length does not equal 32")
return
end
-- test client random value
out = ffi.new("unsigned char[?]", 50)
sizep = ffi.new("size_t[1]", 50)
rc = ffi.C.ngx_http_lua_ffi_ssl_client_random(r, out, sizep, errmsg)
if rc ~= 0 then
ngx.log(ngx.ERR, "failed to get client random: ",
ffi.string(errmsg[0]))
return
end
local init_v = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
if ffi.string(out, sizep[0]) == init_v then
ngx.log(ngx.ERR, "maybe the client random value is incorrect")
return
end
}
ssl_certificate ../../cert/test.crt;
ssl_certificate_key ../../cert/test.key;
server_tokens off;
location /foo {
default_type 'text/plain';
content_by_lua_block { ngx.status = 201 ngx.say("foo") ngx.exit(201) }
more_clear_headers Date;
}
}
--- config
server_tokens off;
lua_ssl_trusted_certificate ../../cert/test.crt;
location /t {
content_by_lua_block {
do
local sock = ngx.socket.tcp()
sock:settimeout(2000)
local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock")
if not ok then
ngx.say("failed to connect: ", err)
return
end
ngx.say("connected: ", ok)
local sess, err = sock:sslhandshake(nil, "test.com", true)
if not sess then
ngx.say("failed to do SSL handshake: ", err)
return
end
ngx.say("ssl handshake: ", type(sess))
local req = "GET /foo HTTP/1.0\r\nHost: test.com\r\nConnection: close\r\n\r\n"
local bytes, err = sock:send(req)
if not bytes then
ngx.say("failed to send http request: ", err)
return
end
ngx.say("sent http request: ", bytes, " bytes.")
while true do
local line, err = sock:receive()
if not line then
-- ngx.say("failed to receive response status line: ", err)
break
end
ngx.say("received: ", line)
end
local ok, err = sock:close()
ngx.say("close: ", ok, " ", err)
end -- do
-- collectgarbage()
}
}
--- request
GET /t
--- response_body
connected: 1
ssl handshake: cdata
sent http request: 56 bytes.
received: HTTP/1.1 201 Created
received: Server: nginx
received: Content-Type: text/plain
received: Content-Length: 4
received: Connection: close
received:
received: foo
close: 1 nil
--- error_log
lua ssl server name: "test.com"
--- no_error_log
[error]
[alert]
=== TEST 13: verify client, but server don't trust root ca
--- http_config
server {
listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl;
server_name example.com;
ssl_certificate_by_lua_block {
collectgarbage()
require "defines"
local ffi = require "ffi"
local errmsg = ffi.new("char *[1]")
local r = require "resty.core.base" .get_request()
if r == nil then
ngx.log(ngx.ERR, "no request found")
return
end
local f = assert(io.open("t/cert/mtls_server.crt", "rb"))
local cert_data = f:read("*all")
f:close()
local client_cert = ffi.C.ngx_http_lua_ffi_parse_pem_cert(cert_data, #cert_data, errmsg)
if not client_cert then
ngx.log(ngx.ERR, "failed to parse PEM client cert: ",
ffi.string(errmsg[0]))
return
end
local rc = ffi.C.ngx_http_lua_ffi_ssl_verify_client(r, client_cert, nil, 2, errmsg)
if rc ~= 0 then
ngx.log(ngx.ERR, "failed to verify client: ",
ffi.string(errmsg[0]))
return
end
ffi.C.ngx_http_lua_ffi_free_cert(client_cert)
}
ssl_certificate ../../cert/mtls_server.crt;
ssl_certificate_key ../../cert/mtls_server.key;
location / {
default_type 'text/plain';
content_by_lua_block {
ngx.say(ngx.var.ssl_client_verify)
}
more_clear_headers Date;
}
}
--- config
location /t {
proxy_pass https://unix:$TEST_NGINX_HTML_DIR/nginx.sock;
proxy_ssl_certificate ../../cert/mtls_client.crt;
proxy_ssl_certificate_key ../../cert/mtls_client.key;
proxy_ssl_session_reuse off;
}
--- request
GET /t
--- response_body
FAILED:unable to verify the first certificate
--- no_error_log
[error]
[alert]
=== TEST 14: verify client and server trust root ca
--- http_config
server {
listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl;
server_name example.com;
ssl_certificate_by_lua_block {
collectgarbage()
require "defines"
local ffi = require "ffi"
local errmsg = ffi.new("char *[1]")
local r = require "resty.core.base" .get_request()
if r == nil then
ngx.log(ngx.ERR, "no request found")
return
end
local f = assert(io.open("t/cert/mtls_server.crt", "rb"))
local cert_data = f:read("*all")
f:close()
local client_cert = ffi.C.ngx_http_lua_ffi_parse_pem_cert(cert_data, #cert_data, errmsg)
if not client_cert then
ngx.log(ngx.ERR, "failed to parse PEM client cert: ",
ffi.string(errmsg[0]))
return
end
local f = assert(io.open("t/cert/mtls_ca.crt", "rb"))
local cert_data = f:read("*all")
f:close()
local trusted_cert = ffi.C.ngx_http_lua_ffi_parse_pem_cert(cert_data, #cert_data, errmsg)
if not trusted_cert then
ngx.log(ngx.ERR, "failed to parse PEM trusted cert: ",
ffi.string(errmsg[0]))
return
end
local rc = ffi.C.ngx_http_lua_ffi_ssl_verify_client(r, cert, trusted_cert, 2, errmsg)
if rc ~= 0 then
ngx.log(ngx.ERR, "failed to verify client: ",
ffi.string(errmsg[0]))
return
end
ffi.C.ngx_http_lua_ffi_free_cert(client_cert)
ffi.C.ngx_http_lua_ffi_free_cert(trusted_cert)
}
ssl_certificate ../../cert/mtls_server.crt;
ssl_certificate_key ../../cert/mtls_server.key;
location / {
default_type 'text/plain';
content_by_lua_block {
ngx.say(ngx.var.ssl_client_verify)
}
more_clear_headers Date;
}
}
--- config
location /t {
proxy_pass https://unix:$TEST_NGINX_HTML_DIR/nginx.sock;
proxy_ssl_certificate ../../cert/mtls_client.crt;
proxy_ssl_certificate_key ../../cert/mtls_client.key;
proxy_ssl_session_reuse off;
}
--- request
GET /t
--- response_body
SUCCESS
--- no_error_log
[error]
[alert]

View file

@ -5,6 +5,9 @@ our $SkipReason;
BEGIN {
if ($ENV{TEST_NGINX_USE_HUP}) {
$SkipReason = "unavailable under hup test mode";
} elsif ($ENV{TEST_NGINX_CHECK_LEAK}) {
$SkipReason = "unavailable under check leak test mode";
}
}

View file

@ -1602,3 +1602,74 @@ return {hello=hello}
GET /hello
--- response_body
false , suspicious circular references, table depth exceed max depth: 100 in the argument
=== TEST 50: call run_worker_thread twice
--- main_config
thread_pool testpool threads=1;
--- http_config eval
"lua_package_path '$::HtmlDir/?.lua;./?.lua;;';"
--- config
location /hello {
default_type 'text/plain';
content_by_lua_block {
local ok, hello_or_err = ngx.run_worker_thread("testpool", "hello", "hello")
ngx.say(ok, " : ", hello_or_err)
ok, hello_or_err = ngx.run_worker_thread("testpool", "hello", "hello")
ngx.say(ok, " : ", hello_or_err)
}
}
--- user_files
>>> hello.lua
local function hello()
return "hello"
end
return {hello=hello}
--- request
GET /hello
--- response_body
true : hello
true : hello
=== TEST 51: big object
--- main_config
thread_pool testpool threads=1;
--- http_config eval
"lua_package_path '$::HtmlDir/?.lua;./?.lua;;';"
--- config
location /hello {
default_type 'text/plain';
content_by_lua_block {
local ok, hello_or_err = ngx.run_worker_thread("testpool", "hello", "hello")
ngx.say(ok, " : ", #hello_or_err)
local ok, gcsize_or_err = ngx.run_worker_thread("testpool", "hello", "gcsize")
ngx.say(ok, " : ", gcsize_or_err)
}
}
--- user_files
>>> hello.lua
local function hello()
return string.rep("helloworld", 1000000)
end
local function gcsize()
return collectgarbage("count")
end
return {
hello = hello,
gcsize = gcsize
}
--- request
GET /hello
--- response_body eval
qr/\Atrue : 10000000
true : \d{3,4}\.\d+
\z/ms

View file

@ -0,0 +1,89 @@
# vim:set ft= ts=4 sw=4 et:
use Test::Nginx::Socket::Lua;
use Cwd qw(cwd);
log_level('info');
repeat_each(1);
plan tests => repeat_each() * (blocks() * 6);
my $pwd = cwd();
no_long_string();
check_accum_error_log();
run_tests();
__DATA__
=== TEST 1: sanity
--- http_config
lua_shared_dict request_counter 1m;
upstream my_upstream {
server 127.0.0.1;
balancer_by_lua_block {
local balancer = require "ngx.balancer"
if not ngx.ctx.tries then
ngx.ctx.tries = 0
end
ngx.ctx.tries = ngx.ctx.tries + 1
ngx.log(ngx.INFO, "tries ", ngx.ctx.tries)
if ngx.ctx.tries == 1 then
balancer.set_more_tries(5)
end
local host = "127.0.0.1"
local port = $TEST_NGINX_RAND_PORT_1;
local ok, err = balancer.set_current_peer(host, port)
if not ok then
ngx.log(ngx.ERR, "failed to set the current peer: ", err)
return ngx.exit(500)
end
balancer.set_timeouts(60000, 60000, 60000)
local ok, err = balancer.enable_keepalive(60, 100)
if not ok then
ngx.log(ngx.ERR, "failed to enable keepalive: ", err)
return ngx.exit(500)
end
}
}
server {
listen 127.0.0.1:$TEST_NGINX_RAND_PORT_1;
location /hello {
content_by_lua_block{
local request_counter = ngx.shared.request_counter
local first_request = request_counter:get("first_request")
if first_request == nil then
request_counter:set("first_request", "yes")
ngx.print("hello")
else
ngx.exit(ngx.HTTP_CLOSE)
end
}
}
}
--- config
location = /t {
proxy_pass http://my_upstream;
proxy_set_header Connection "keep-alive";
rewrite_by_lua_block {
ngx.req.set_uri("/hello")
}
}
--- pipelined_requests eval
["GET /t HTTP/1.1" , "GET /t HTTP/1.1"]
--- response_body eval
["hello", qr/502/]
--- error_code eval
[200, 502]
--- no_error_log eval
qr/tries 7/

BIN
t/cert/test_der.crt Normal file

Binary file not shown.

BIN
t/cert/test_der.key Normal file

Binary file not shown.

View file

@ -25,13 +25,13 @@ force=$2
add_fake_shm_module="--add-module=$root/t/data/fake-shm-module"
add_http3_module=--with-http_v3_module
answer=`$root/util/ver-ge "$NGINX_VERSION" 1.25.1`
answer=`$root/util/ver-ge "$version" 1.25.1`
if [ "$OPENSSL_VER" = "1.1.0l" ] || [ "$answer" = "N" ]; then
add_http3_module=""
fi
disable_pcre2=--without-pcre2
answer=`$root/util/ver-ge "$NGINX_VERSION" 1.25.1`
answer=`$root/util/ver-ge "$version" 1.25.1`
if [ "$answer" = "N" ] || [ "$USE_PCRE2" = "Y" ]; then
disable_pcre2=""
fi