diff --git a/.gitignore b/.gitignore index e5cbc8e7ac..eff337246b 100644 --- a/.gitignore +++ b/.gitignore @@ -154,6 +154,9 @@ src/timer.[ch] src/config.[ch] src/worker.[ch] src/certby.[ch] +src/storeby.[ch] +src/fetchby.[ch] +src/ssl.[ch] src/ocsp.c src/lex.[ch] src/balancer.[ch] diff --git a/.travis.yml b/.travis.yml index 4370d74cc5..9717ccb4d4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -107,6 +107,8 @@ script: - cd .. - tar zxf download-cache/openssl-$OPENSSL_VER.tar.gz - cd openssl-$OPENSSL_VER/ + - wget https://raw.githubusercontent.com/openresty/openresty/master/patches/openssl-$OPENSSL_VER-sess_set_get_cb_yield.patch + - patch -p1 < openssl-$OPENSSL_VER-sess_set_get_cb_yield.patch - ./config shared --prefix=$OPENSSL_PREFIX -DPURIFY > build.log 2>&1 || (cat build.log && exit 1) - make -j$JOBS > build.log 2>&1 || (cat build.log && exit 1) - sudo make PATH=$PATH install_sw > build.log 2>&1 || (cat build.log && exit 1) diff --git a/README.markdown b/README.markdown index b040e712b1..e100f0adf1 100644 --- a/README.markdown +++ b/README.markdown @@ -1037,6 +1037,10 @@ Directives * [lua_need_request_body](#lua_need_request_body) * [ssl_certificate_by_lua_block](#ssl_certificate_by_lua_block) * [ssl_certificate_by_lua_file](#ssl_certificate_by_lua_file) +* [ssl_session_fetch_by_lua_block](#ssl_session_fetch_by_lua_block) +* [ssl_session_fetch_by_lua_file](#ssl_session_fetch_by_lua_file) +* [ssl_session_store_by_lua_block](#ssl_session_store_by_lua_block) +* [ssl_session_store_by_lua_file](#ssl_session_store_by_lua_file) * [lua_shared_dict](#lua_shared_dict) * [lua_socket_connect_timeout](#lua_socket_connect_timeout) * [lua_socket_send_timeout](#lua_socket_send_timeout) @@ -2320,7 +2324,7 @@ lua_need_request_body Determines whether to force the request body data to be read before running rewrite/access/access_by_lua* or not. The Nginx core does not read the client request body by default and if request body data is required, then this directive should be turned `on` or the [ngx.req.read_body](#ngxreqread_body) function should be called within the Lua code. -To read the request body data within the [$request_body](http://nginx.org/en/docs/http/ngx_http_core_module.html#var_request_body) variable, +To read the request body data within the [$request_body](http://nginx.org/en/docs/http/ngx_http_core_module.html#var_request_body) variable, [client_body_buffer_size](http://nginx.org/en/docs/http/ngx_http_core_module.html#client_body_buffer_size) must have the same value as [client_max_body_size](http://nginx.org/en/docs/http/ngx_http_core_module.html#client_max_body_size). Because when the content length exceeds [client_body_buffer_size](http://nginx.org/en/docs/http/ngx_http_core_module.html#client_body_buffer_size) but less than [client_max_body_size](http://nginx.org/en/docs/http/ngx_http_core_module.html#client_max_body_size), Nginx will buffer the data into a temporary file on the disk, which will lead to empty value in the [$request_body](http://nginx.org/en/docs/http/ngx_http_core_module.html#var_request_body) variable. If the current location includes [rewrite_by_lua](#rewrite_by_lua) or [rewrite_by_lua_file](#rewrite_by_lua_file) directives, @@ -2441,6 +2445,123 @@ This directive was first introduced in the `v0.10.0` release. [Back to TOC](#directives) +ssl_session_fetch_by_lua_block +------------------------------ + +**syntax:** *ssl_session_fetch_by_lua_block { lua-script }* + +**context:** *server* + +**phase:** *right-before-SSL-handshake* + +This directive runs Lua code to look up and load the SSL session (if any) according to the session ID +provided by the current SSL handshake request for the downstream. + +The Lua API for obtaining the current session ID and loading a cached SSL session data +is provided in the [ngx.ssl.session](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/ssl/session.md) +Lua module shipped with the [lua-resty-core](https://github.com/openresty/lua-resty-core#readme) +library. + +Lua APIs that may yield, like [ngx.sleep](#ngxsleep) and [cosockets](#ngxsockettcp), +are enabled in this context. + +This hook, together with the [ssl_session_store_by_lua*](#ssl_session_store_by_lua_block) hook, +can be used to implement distributed caching mechanisms in pure Lua (based +on the [cosocket](#ngxsockettcp) API, for example). If a cached SSL session is found +and loaded into the current SSL connection context, +SSL session resumption can then get immediately initiated and bypass the full SSL handshake process which is very expensive in terms of CPU time. + +Please note that TLS session tickets are very different and it is the clients' responsibility +to cache the SSL session state when session tickets are used. SSL session resumptions based on +TLS session tickets would happen automatically without going through this hook (nor the +[ssl_session_store_by_lua_block](#ssl_session_store_by_lua) hook). This hook is mainly +for older or less capable SSL clients that can only do SSL sessions by session IDs. + +When [ssl_certificate_by_lua*](#ssl_certificate_by_lua_block) is specified at the same time, +this hook usually runs before [ssl_certificate_by_lua*](#ssl_certificate_by_lua_block). +When the SSL session is found and successfully loaded for the current SSL connection, +SSL session resumption will happen and thus bypass the [ssl_certificate_by_lua*](#ssl_certificate_by_lua_block) +hook completely. In this case, NGINX also bypasses the [ssl_session_store_by_lua_block](#ssl_session_store_by_lua) +hook, for obvious reasons. + +If you are using the [official pre-built packages](http://openresty.org/en/linux-packages.html) for [OpenResty](https://openresty.org/) +1.11.2.1 or later, then everything should work out of the box. + +If you are using OpenSSL libraries not provided by [OpenResty](https://openresty.org), +then you need to apply the following patch for OpenSSL 1.0.2h or later: + + + +If you are not using the NGINX core shipped with [OpenResty](https://openresty.org) 1.11.2.1 or later, then you need to +apply the following patch to the standard NGINX core 1.11.2 or later: + + + +This directive was first introduced in the `v0.10.6` release. + +[Back to TOC](#directives) + +ssl_session_fetch_by_lua_file +----------------------------- + +**syntax:** *ssl_session_fetch_by_lua_file <path-to-lua-script-file>* + +**context:** *server* + +**phase:** *right-before-SSL-handshake* + +Equivalent to [ssl_session_fetch_by_lua_block](#ssl_session_fetch_by_lua_block), except that the file specified by `` contains the Lua code, or rather, the [Lua/LuaJIT bytecode](#lualuajit-bytecode-support) to be executed. + +When a relative path like `foo/bar.lua` is given, they will be turned into the absolute path relative to the `server prefix` path determined by the `-p PATH` command-line option while starting the Nginx server. + +This directive was first introduced in the `v0.10.6` release. + +[Back to TOC](#directives) + +ssl_session_store_by_lua_block +------------------------------ + +**syntax:** *ssl_session_store_by_lua_block { lua-script }* + +**context:** *server* + +**phase:** *right-after-SSL-handshake* + +This directive runs Lua code to fetch and save the SSL session (if any) according to the session ID +provided by the current SSL handshake request for the downstream. The saved or cached SSL +session data can be used for future SSL connections to resume SSL sessions without going +through the full SSL handshake process (which is very expensive in terms of CPU time). + +Lua APIs that may yield, like [ngx.sleep](#ngxsleep) and [cosockets](#ngxsockettcp), +are *disabled* in this context. You can still, however, use the [ngx.timer.at](#ngxtimerat) API +to create 0-delay timers to save the SSL session data asynchronously to external services (like `redis` or `memcached`). + +The Lua API for obtaining the current session ID and the associated session state data +is provided in the [ngx.ssl.session](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/ssl/session.md#readme) +Lua module shipped with the [lua-resty-core](https://github.com/openresty/lua-resty-core#readme) +library. + +This directive was first introduced in the `v0.10.6` release. + +[Back to TOC](#directives) + +ssl_session_store_by_lua_file +----------------------------- + +**syntax:** *ssl_session_store_by_lua_file <path-to-lua-script-file>* + +**context:** *server* + +**phase:** *right-before-SSL-handshake* + +Equivalent to [ssl_session_store_by_lua_block](#ssl_session_store_by_lua_block), except that the file specified by `` contains the Lua code, or rather, the [Lua/LuaJIT bytecode](#lualuajit-bytecode-support) to be executed. + +When a relative path like `foo/bar.lua` is given, they will be turned into the absolute path relative to the `server prefix` path determined by the `-p PATH` command-line option while starting the Nginx server. + +This directive was first introduced in the `v0.10.6` release. + +[Back to TOC](#directives) + lua_shared_dict --------------- @@ -3110,7 +3231,7 @@ This API requires a relatively expensive metamethod call and it is recommended t Core constants -------------- -**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, *log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** +**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, *log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** ```lua @@ -3136,7 +3257,7 @@ The `ngx.DECLINED` constant was first introduced in the `v0.5.0rc19` release. HTTP method constants --------------------- -**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** +**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** ngx.HTTP_GET @@ -3162,7 +3283,7 @@ These constants are usually used in [ngx.location.capture](#ngxlocationcapture) HTTP status constants --------------------- -**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** +**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** ```nginx @@ -3206,7 +3327,7 @@ HTTP status constants Nginx log level constants ------------------------- -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** ```lua @@ -3229,7 +3350,7 @@ print ----- **syntax:** *print(...)* -**context:** *init_by_lua*, init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, log_by_lua*, ngx.timer.*, balancer_by_lua*, certificate_by_lua** +**context:** *init_by_lua*, init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** Writes argument values into the nginx `error.log` file with the `ngx.NOTICE` log level. @@ -4963,7 +5084,7 @@ ngx.log ------- **syntax:** *ngx.log(log_level, ...)* -**context:** *init_by_lua*, init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** +**context:** *init_by_lua*, init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** Log arguments concatenated to error.log with the given logging level. @@ -4981,9 +5102,9 @@ ngx.flush **context:** *rewrite_by_lua*, access_by_lua*, content_by_lua** -Flushes response output to the client. +Flushes response output to the client. -`ngx.flush` accepts an optional boolean `wait` argument (Default: `false`) first introduced in the `v0.3.1rc34` release. When called with the default argument, it issues an asynchronous call (Returns immediately without waiting for output data to be written into the system send buffer). Calling the function with the `wait` argument set to `true` switches to synchronous mode. +`ngx.flush` accepts an optional boolean `wait` argument (Default: `false`) first introduced in the `v0.3.1rc34` release. When called with the default argument, it issues an asynchronous call (Returns immediately without waiting for output data to be written into the system send buffer). Calling the function with the `wait` argument set to `true` switches to synchronous mode. In synchronous mode, the function will not return until all output data has been written into the system send buffer or until the [send_timeout](http://nginx.org/en/docs/http/ngx_http_core_module.html#send_timeout) setting has expired. Note that using the Lua coroutine mechanism means that this function does not block the Nginx event loop even in the synchronous mode. @@ -4999,7 +5120,7 @@ ngx.exit -------- **syntax:** *ngx.exit(status)* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** When `status >= 200` (i.e., `ngx.HTTP_OK` and above), it will interrupt the execution of the current request and return status code to nginx. @@ -5044,7 +5165,9 @@ Note that while this method accepts all [HTTP status constants](#http-status-con Also note that this method call terminates the processing of the current request and that it is recommended that a coding style that combines this method call with the `return` statement, i.e., `return ngx.exit(...)` be used to reinforce the fact that the request processing is being terminated. -When being used in the context of [header_filter_by_lua](#header_filter_by_lua), `ngx.exit()` is an asynchronous operation and will return immediately. This behavior may change in future and it is recommended that users always use `return` in combination as suggested above. +When being used in the contexts of [header_filter_by_lua](#header_filter_by_lua) and +[ssl_session_store_by_lua*](#ssl_session_store_by_lua_block), `ngx.exit()` is +an asynchronous operation and will return immediately. This behavior may change in future and it is recommended that users always use `return` in combination as suggested above. [Back to TOC](#nginx-api-for-lua) @@ -5087,7 +5210,7 @@ ngx.sleep --------- **syntax:** *ngx.sleep(seconds)* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua** Sleeps for the specified seconds without blocking. One can specify time resolution up to 0.001 seconds (i.e., one milliseconds). @@ -5103,7 +5226,7 @@ ngx.escape_uri -------------- **syntax:** *newstr = ngx.escape_uri(str)* -**context:** *init_by_lua*, init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** +**context:** *init_by_lua*, init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** Escape `str` as a URI component. @@ -5193,7 +5316,7 @@ ngx.decode_args --------------- **syntax:** *table = ngx.decode_args(str, max_args?)* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** Decodes a URI encoded query-string into a Lua table. This is the inverse function of [ngx.encode_args](#ngxencode_args). @@ -5216,7 +5339,7 @@ ngx.encode_base64 ----------------- **syntax:** *newstr = ngx.encode_base64(str, no_padding?)* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** Encodes `str` to a base64 digest. @@ -5228,7 +5351,7 @@ ngx.decode_base64 ----------------- **syntax:** *newstr = ngx.decode_base64(str)* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** Decodes the `str` argument as a base64 digest to the raw form. Returns `nil` if `str` is not well formed. @@ -5238,7 +5361,7 @@ ngx.crc32_short --------------- **syntax:** *intval = ngx.crc32_short(str)* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** Calculates the CRC-32 (Cyclic Redundancy Code) digest for the `str` argument. @@ -5254,7 +5377,7 @@ ngx.crc32_long -------------- **syntax:** *intval = ngx.crc32_long(str)* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** Calculates the CRC-32 (Cyclic Redundancy Code) digest for the `str` argument. @@ -5270,7 +5393,7 @@ ngx.hmac_sha1 ------------- **syntax:** *digest = ngx.hmac_sha1(secret_key, str)* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** Computes the [HMAC-SHA1](http://en.wikipedia.org/wiki/HMAC) digest of the argument `str` and turns the result using the secret key ``. @@ -5302,7 +5425,7 @@ ngx.md5 ------- **syntax:** *digest = ngx.md5(str)* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** Returns the hexadecimal representation of the MD5 digest of the `str` argument. @@ -5329,7 +5452,7 @@ ngx.md5_bin ----------- **syntax:** *digest = ngx.md5_bin(str)* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** Returns the binary form of the MD5 digest of the `str` argument. @@ -5341,7 +5464,7 @@ ngx.sha1_bin ------------ **syntax:** *digest = ngx.sha1_bin(str)* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** Returns the binary form of the SHA-1 digest of the `str` argument. @@ -5355,7 +5478,7 @@ ngx.quote_sql_str ----------------- **syntax:** *quoted_value = ngx.quote_sql_str(raw_value)* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** Returns a quoted SQL string literal according to the MySQL quoting rules. @@ -5365,7 +5488,7 @@ ngx.today --------- **syntax:** *str = ngx.today()* -**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** +**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** Returns current date (in the format `yyyy-mm-dd`) from the nginx cached time (no syscall involved unlike Lua's date library). @@ -5377,7 +5500,7 @@ ngx.time -------- **syntax:** *secs = ngx.time()* -**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** +**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** Returns the elapsed seconds from the epoch for the current time stamp from the nginx cached time (no syscall involved unlike Lua's date library). @@ -5389,7 +5512,7 @@ ngx.now ------- **syntax:** *secs = ngx.now()* -**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** +**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** Returns a floating-point number for the elapsed time in seconds (including milliseconds as the decimal part) from the epoch for the current time stamp from the nginx cached time (no syscall involved unlike Lua's date library). @@ -5403,7 +5526,7 @@ ngx.update_time --------------- **syntax:** *ngx.update_time()* -**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** +**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** Forcibly updates the Nginx current time cache. This call involves a syscall and thus has some overhead, so do not abuse it. @@ -5415,7 +5538,7 @@ ngx.localtime ------------- **syntax:** *str = ngx.localtime()* -**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** +**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** Returns the current time stamp (in the format `yyyy-mm-dd hh:mm:ss`) of the nginx cached time (no syscall involved unlike Lua's [os.date](http://www.lua.org/manual/5.1/manual.html#pdf-os.date) function). @@ -5427,7 +5550,7 @@ ngx.utctime ----------- **syntax:** *str = ngx.utctime()* -**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** +**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** Returns the current time stamp (in the format `yyyy-mm-dd hh:mm:ss`) of the nginx cached time (no syscall involved unlike Lua's [os.date](http://www.lua.org/manual/5.1/manual.html#pdf-os.date) function). @@ -5439,7 +5562,7 @@ ngx.cookie_time --------------- **syntax:** *str = ngx.cookie_time(sec)* -**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** +**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** Returns a formatted string can be used as the cookie expiration time. The parameter `sec` is the time stamp in seconds (like those returned from [ngx.time](#ngxtime)). @@ -5455,7 +5578,7 @@ ngx.http_time ------------- **syntax:** *str = ngx.http_time(sec)* -**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** +**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** Returns a formated string can be used as the http header time (for example, being used in `Last-Modified` header). The parameter `sec` is the time stamp in seconds (like those returned from [ngx.time](#ngxtime)). @@ -5471,7 +5594,7 @@ ngx.parse_http_time ------------------- **syntax:** *sec = ngx.parse_http_time(str)* -**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** +**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** Parse the http time string (as returned by [ngx.http_time](#ngxhttp_time)) into seconds. Returns the seconds or `nil` if the input string is in bad forms. @@ -5499,7 +5622,7 @@ ngx.re.match ------------ **syntax:** *captures, err = ngx.re.match(subject, regex, options?, ctx?, res_table?)* -**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** +**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** Matches the `subject` string using the Perl compatible regular expression `regex` with the optional `options`. @@ -5657,7 +5780,7 @@ ngx.re.find ----------- **syntax:** *from, to, err = ngx.re.find(subject, regex, options?, ctx?, nth?)* -**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** +**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** Similar to [ngx.re.match](#ngxrematch) but only returns the beginning index (`from`) and end index (`to`) of the matched substring. The returned indexes are 1-based and can be fed directly into the [string.sub](http://www.lua.org/manual/5.1/manual.html#pdf-string.sub) API function to obtain the matched substring. @@ -5711,7 +5834,7 @@ ngx.re.gmatch ------------- **syntax:** *iterator, err = ngx.re.gmatch(subject, regex, options?)* -**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** +**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** Similar to [ngx.re.match](#ngxrematch), but returns a Lua iterator instead, so as to let the user programmer iterate all the matches over the `` string argument with the PCRE `regex`. @@ -5789,7 +5912,7 @@ ngx.re.sub ---------- **syntax:** *newstr, n, err = ngx.re.sub(subject, regex, replace, options?)* -**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** +**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** Substitutes the first match of the Perl compatible regular expression `regex` on the `subject` argument string with the string or function argument `replace`. The optional `options` argument has exactly the same meaning as in [ngx.re.match](#ngxrematch). @@ -5855,7 +5978,7 @@ ngx.re.gsub ----------- **syntax:** *newstr, n, err = ngx.re.gsub(subject, regex, replace, options?)* -**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** +**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** Just like [ngx.re.sub](#ngxresub), but does global substitution. @@ -5895,7 +6018,7 @@ ngx.shared.DICT **syntax:** *dict = ngx.shared\[name_var\]* -**context:** *init_by_lua*, init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** +**context:** *init_by_lua*, init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** Fetching the shm-based Lua dictionary object for the shared memory zone named `DICT` defined by the [lua_shared_dict](#lua_shared_dict) directive. @@ -5968,7 +6091,7 @@ ngx.shared.DICT.get ------------------- **syntax:** *value, flags = ngx.shared.DICT:get(key)* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** Retrieving the value in the dictionary [ngx.shared.DICT](#ngxshareddict) for the key `key`. If the key does not exist or has been expired, then `nil` will be returned. @@ -6006,7 +6129,7 @@ ngx.shared.DICT.get_stale ------------------------- **syntax:** *value, flags, stale = ngx.shared.DICT:get_stale(key)* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** Similar to the [get](#ngxshareddictget) method but returns the value even if the key has already expired. @@ -6024,7 +6147,7 @@ ngx.shared.DICT.set ------------------- **syntax:** *success, err, forcible = ngx.shared.DICT:set(key, value, exptime?, flags?)* -**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** +**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** Unconditionally sets a key-value pair into the shm-based dictionary [ngx.shared.DICT](#ngxshareddict). Returns three values: @@ -6072,7 +6195,7 @@ ngx.shared.DICT.safe_set ------------------------ **syntax:** *ok, err = ngx.shared.DICT:safe_set(key, value, exptime?, flags?)* -**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** +**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** Similar to the [set](#ngxshareddictset) method, but never overrides the (least recently used) unexpired items in the store when running out of storage in the shared memory zone. In this case, it will immediately return `nil` and the string "no memory". @@ -6086,7 +6209,7 @@ ngx.shared.DICT.add ------------------- **syntax:** *success, err, forcible = ngx.shared.DICT:add(key, value, exptime?, flags?)* -**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** +**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** Just like the [set](#ngxshareddictset) method, but only stores the key-value pair into the dictionary [ngx.shared.DICT](#ngxshareddict) if the key does *not* exist. @@ -6102,7 +6225,7 @@ ngx.shared.DICT.safe_add ------------------------ **syntax:** *ok, err = ngx.shared.DICT:safe_add(key, value, exptime?, flags?)* -**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** +**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** Similar to the [add](#ngxshareddictadd) method, but never overrides the (least recently used) unexpired items in the store when running out of storage in the shared memory zone. In this case, it will immediately return `nil` and the string "no memory". @@ -6116,7 +6239,7 @@ ngx.shared.DICT.replace ----------------------- **syntax:** *success, err, forcible = ngx.shared.DICT:replace(key, value, exptime?, flags?)* -**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** +**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** Just like the [set](#ngxshareddictset) method, but only stores the key-value pair into the dictionary [ngx.shared.DICT](#ngxshareddict) if the key *does* exist. @@ -6132,7 +6255,7 @@ ngx.shared.DICT.delete ---------------------- **syntax:** *ngx.shared.DICT:delete(key)* -**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** +**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** Unconditionally removes the key-value pair from the shm-based dictionary [ngx.shared.DICT](#ngxshareddict). @@ -6148,7 +6271,7 @@ ngx.shared.DICT.incr -------------------- **syntax:** *newval, err = ngx.shared.DICT:incr(key, value)* -**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** +**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** Increments the (numerical) value for `key` in the shm-based dictionary [ngx.shared.DICT](#ngxshareddict) by the step value `value`. Returns the new resulting number if the operation is successfully completed or `nil` and an error message otherwise. @@ -6168,7 +6291,7 @@ ngx.shared.DICT.flush_all ------------------------- **syntax:** *ngx.shared.DICT:flush_all()* -**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** +**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** Flushes out all the items in the dictionary. This method does not actuall free up all the memory blocks in the dictionary but just marks all the existing items as expired. @@ -6182,7 +6305,7 @@ ngx.shared.DICT.flush_expired ----------------------------- **syntax:** *flushed = ngx.shared.DICT:flush_expired(max_count?)* -**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** +**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** Flushes out the expired items in the dictionary, up to the maximal number specified by the optional `max_count` argument. When the `max_count` argument is given `0` or not given at all, then it means unlimited. Returns the number of items that have actually been flushed. @@ -6198,7 +6321,7 @@ ngx.shared.DICT.get_keys ------------------------ **syntax:** *keys = ngx.shared.DICT:get_keys(max_count?)* -**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** +**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** Fetch a list of the keys from the dictionary, up to ``. @@ -6214,7 +6337,7 @@ ngx.socket.udp -------------- **syntax:** *udpsock = ngx.socket.udp()* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua** Creates and returns a UDP or datagram-oriented unix domain socket object (also known as one type of the "cosocket" objects). The following methods are supported on this object: @@ -6238,7 +6361,7 @@ udpsock:setpeername **syntax:** *ok, err = udpsock:setpeername("unix:/path/to/unix-domain.socket")* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua** Attempts to connect a UDP socket object to a remote server or to a datagram unix domain socket file. Because the datagram protocol is actually connection-less, this method does not really establish a "connection", but only just set the name of the remote peer for subsequent read/write operations. @@ -6297,7 +6420,7 @@ udpsock:send ------------ **syntax:** *ok, err = udpsock:send(data)* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua** Sends data on the current UDP or datagram unix domain socket object. @@ -6313,7 +6436,7 @@ udpsock:receive --------------- **syntax:** *data, err = udpsock:receive(size?)* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua** Receives data from the UDP or datagram unix domain socket object with an optional receive buffer size argument, `size`. @@ -6348,7 +6471,7 @@ udpsock:close ------------- **syntax:** *ok, err = udpsock:close()* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua** Closes the current UDP or datagram unix domain socket. It returns the `1` in case of success and returns `nil` with a string describing the error otherwise. @@ -6362,7 +6485,7 @@ udpsock:settimeout ------------------ **syntax:** *udpsock:settimeout(time)* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua** Set the timeout value in milliseconds for subsequent socket operations (like [receive](#udpsockreceive)). @@ -6386,7 +6509,7 @@ ngx.socket.tcp -------------- **syntax:** *tcpsock = ngx.socket.tcp()* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua** Creates and returns a TCP or stream-oriented unix domain socket object (also known as one type of the "cosocket" objects). The following methods are supported on this object: @@ -6432,7 +6555,7 @@ tcpsock:connect **syntax:** *ok, err = tcpsock:connect("unix:/path/to/unix-domain.socket", options_table?)* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua** Attempts to connect a TCP socket object to a remote server or to a stream unix domain socket file without blocking. @@ -6511,7 +6634,7 @@ tcpsock:sslhandshake -------------------- **syntax:** *session, err = tcpsock:sslhandshake(reused_session?, server_name?, ssl_verify?, send_status_req?)* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua** Does SSL/TLS handshake on the currently established connection. @@ -6556,7 +6679,7 @@ tcpsock:send ------------ **syntax:** *bytes, err = tcpsock:send(data)* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua** Sends data without blocking on the current TCP or Unix Domain Socket connection. @@ -6588,7 +6711,7 @@ tcpsock:receive **syntax:** *data, err, partial = tcpsock:receive(pattern?)* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua** Receives data from the connected socket according to the reading pattern or size. @@ -6630,7 +6753,7 @@ tcpsock:receiveuntil -------------------- **syntax:** *iterator = tcpsock:receiveuntil(pattern, options?)* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua** This method returns an iterator Lua function that can be called to read the data stream until it sees the specified pattern or an error occurs. @@ -6729,7 +6852,7 @@ tcpsock:close ------------- **syntax:** *ok, err = tcpsock:close()* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua** Closes the current TCP or stream unix domain socket. It returns the `1` in case of success and returns `nil` with a string describing the error otherwise. @@ -6745,7 +6868,7 @@ tcpsock:settimeout ------------------ **syntax:** *tcpsock:settimeout(time)* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua** Set the timeout value in milliseconds for subsequent socket operations ([connect](#tcpsockconnect), [receive](#tcpsockreceive), and iterators returned from [receiveuntil](#tcpsockreceiveuntil)). @@ -6761,7 +6884,7 @@ tcpsock:setoption ----------------- **syntax:** *tcpsock:setoption(option, value?)* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua** This function is added for [LuaSocket](http://w3.impa.br/~diego/software/luasocket/tcp.html) API compatibility and does nothing for now. Its functionality will be implemented in future. @@ -6773,7 +6896,7 @@ tcpsock:setkeepalive -------------------- **syntax:** *ok, err = tcpsock:setkeepalive(timeout?, size?)* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua** Puts the current socket's connection immediately into the cosocket built-in connection pool and keep it alive until other [connect](#tcpsockconnect) method calls request it or the associated maximal idle timeout is expired. @@ -6801,7 +6924,7 @@ tcpsock:getreusedtimes ---------------------- **syntax:** *count, err = tcpsock:getreusedtimes()* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua** This method returns the (successfully) reused times for the current connection. In case of error, it returns `nil` and a string describing the error. @@ -6841,7 +6964,7 @@ ngx.get_phase ------------- **syntax:** *str = ngx.get_phase()* -**context:** *init_by_lua*, init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** +**context:** *init_by_lua*, init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** Retrieves the current running phase name. Possible return values are @@ -6851,6 +6974,10 @@ Retrieves the current running phase name. Possible return values are for the context of [init_worker_by_lua](#init_worker_by_lua) or [init_worker_by_lua_file](#init_worker_by_lua_file). * `ssl_cert` for the context of [ssl_certificate_by_lua_block](#ssl_certificate_by_lua_block) or [ssl_certificate_by_lua_file](#ssl_certificate_by_lua_file). +* `ssl_session_fetch` + for the context of [ssl_session_fetch_by_lua*](#ssl_session_fetch_by_lua_block). +* `ssl_session_store` + for the context of [ssl_session_store_by_lua*](#ssl_session_store_by_lua_block). * `set` for the context of [set_by_lua](#set_by_lua) or [set_by_lua_file](#set_by_lua_file). * `rewrite` @@ -6878,7 +7005,7 @@ ngx.thread.spawn ---------------- **syntax:** *co = ngx.thread.spawn(func, arg1, arg2, ...)* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua** Spawns a new user "light thread" with the Lua function `func` as well as those optional arguments `arg1`, `arg2`, and etc. Returns a Lua thread (or Lua coroutine) object represents this "light thread". @@ -7016,7 +7143,7 @@ ngx.thread.wait --------------- **syntax:** *ok, res1, res2, ... = ngx.thread.wait(thread1, thread2, ...)* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua** Waits on one or more child "light threads" and returns the results of the first "light thread" that terminates (either successfully or with an error). @@ -7173,7 +7300,7 @@ ngx.timer.at ------------ **syntax:** *ok, err = ngx.timer.at(delay, callback, user_arg1, user_arg2, ...)* -**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** +**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** Creates an Nginx timer with a user callback function as well as optional user arguments. @@ -7299,7 +7426,7 @@ ngx.timer.running_count ----------------------- **syntax:** *count = ngx.timer.running_count()* -**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** +**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** Returns the number of timers currently running. @@ -7311,7 +7438,7 @@ ngx.timer.pending_count ----------------------- **syntax:** *count = ngx.timer.pending_count()* -**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** +**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** Returns the number of pending timers. @@ -7542,7 +7669,7 @@ ndk.set_var.DIRECTIVE --------------------- **syntax:** *res = ndk.set_var.DIRECTIVE_NAME* -**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** +**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** This mechanism allows calling other nginx C modules' directives that are implemented by [Nginx Devel Kit](https://github.com/simpl/ngx_devel_kit) (NDK)'s set_var submodule's `ndk_set_var_value`. @@ -7583,7 +7710,7 @@ coroutine.create ---------------- **syntax:** *co = coroutine.create(f)* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, init_by_lua*, ngx.timer.*, header_filter_by_lua*, body_filter_by_lua*, ssl_certificate_by_lua** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, init_by_lua*, ngx.timer.*, header_filter_by_lua*, body_filter_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** Creates a user Lua coroutines with a Lua function, and returns a coroutine object. @@ -7599,7 +7726,7 @@ coroutine.resume ---------------- **syntax:** *ok, ... = coroutine.resume(co, ...)* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, init_by_lua*, ngx.timer.*, header_filter_by_lua*, body_filter_by_lua*, ssl_certificate_by_lua** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, init_by_lua*, ngx.timer.*, header_filter_by_lua*, body_filter_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** Resumes the executation of a user Lua coroutine object previously yielded or just created. @@ -7615,7 +7742,7 @@ coroutine.yield --------------- **syntax:** *... = coroutine.yield(...)* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, init_by_lua*, ngx.timer.*, header_filter_by_lua*, body_filter_by_lua*, ssl_certificate_by_lua** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, init_by_lua*, ngx.timer.*, header_filter_by_lua*, body_filter_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** Yields the execution of the current user Lua coroutine. @@ -7631,7 +7758,7 @@ coroutine.wrap -------------- **syntax:** *co = coroutine.wrap(f)* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, init_by_lua*, ngx.timer.*, header_filter_by_lua*, body_filter_by_lua*, ssl_certificate_by_lua** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, init_by_lua*, ngx.timer.*, header_filter_by_lua*, body_filter_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** Similar to the standard Lua [coroutine.wrap](http://www.lua.org/manual/5.1/manual.html#pdf-coroutine.wrap) API, but works in the context of the Lua coroutines created by ngx_lua. @@ -7645,7 +7772,7 @@ coroutine.running ----------------- **syntax:** *co = coroutine.running()* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, init_by_lua*, ngx.timer.*, header_filter_by_lua*, body_filter_by_lua*, ssl_certificate_by_lua** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, init_by_lua*, ngx.timer.*, header_filter_by_lua*, body_filter_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** Identical to the standard Lua [coroutine.running](http://www.lua.org/manual/5.1/manual.html#pdf-coroutine.running) API. @@ -7659,7 +7786,7 @@ coroutine.status ---------------- **syntax:** *status = coroutine.status(co)* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, init_by_lua*, ngx.timer.*, header_filter_by_lua*, body_filter_by_lua*, ssl_certificate_by_lua** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, init_by_lua*, ngx.timer.*, header_filter_by_lua*, body_filter_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** Identical to the standard Lua [coroutine.status](http://www.lua.org/manual/5.1/manual.html#pdf-coroutine.status) API. diff --git a/config b/config index c91a07e3cd..0f2749d32f 100644 --- a/config +++ b/config @@ -357,6 +357,9 @@ HTTP_LUA_SRCS=" \ $ngx_addon_dir/src/ngx_http_lua_ssl_ocsp.c \ $ngx_addon_dir/src/ngx_http_lua_lex.c \ $ngx_addon_dir/src/ngx_http_lua_balancer.c \ + $ngx_addon_dir/src/ngx_http_lua_ssl_session_storeby.c \ + $ngx_addon_dir/src/ngx_http_lua_ssl_session_fetchby.c \ + $ngx_addon_dir/src/ngx_http_lua_ssl.c \ " HTTP_LUA_DEPS=" \ @@ -414,6 +417,9 @@ HTTP_LUA_DEPS=" \ $ngx_addon_dir/src/ngx_http_lua_ssl_certby.h \ $ngx_addon_dir/src/ngx_http_lua_lex.h \ $ngx_addon_dir/src/ngx_http_lua_balancer.h \ + $ngx_addon_dir/src/ngx_http_lua_ssl_session_storeby.h \ + $ngx_addon_dir/src/ngx_http_lua_ssl_session_fetchby.h \ + $ngx_addon_dir/src/ngx_http_lua_ssl.h \ " CFLAGS="$CFLAGS -DNDK_SET_VAR" diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index 1cb86b5dcb..2590244df6 100644 --- a/doc/HttpLuaModule.wiki +++ b/doc/HttpLuaModule.wiki @@ -1941,7 +1941,7 @@ This directive was first introduced in the v0.10.0 release. Determines whether to force the request body data to be read before running rewrite/access/access_by_lua* or not. The Nginx core does not read the client request body by default and if request body data is required, then this directive should be turned on or the [[#ngx.req.read_body|ngx.req.read_body]] function should be called within the Lua code. -To read the request body data within the [[HttpCoreModule#$request_body|$request_body]] variable, +To read the request body data within the [[HttpCoreModule#$request_body|$request_body]] variable, [[HttpCoreModule#client_body_buffer_size|client_body_buffer_size]] must have the same value as [[HttpCoreModule#client_max_body_size|client_max_body_size]]. Because when the content length exceeds [[HttpCoreModule#client_body_buffer_size|client_body_buffer_size]] but less than [[HttpCoreModule#client_max_body_size|client_max_body_size]], Nginx will buffer the data into a temporary file on the disk, which will lead to empty value in the [[HttpCoreModule#$request_body|$request_body]] variable. If the current location includes [[#rewrite_by_lua|rewrite_by_lua]] or [[#rewrite_by_lua_file|rewrite_by_lua_file]] directives, @@ -2053,6 +2053,111 @@ When a relative path like foo/bar.lua is given, they will be turned This directive was first introduced in the v0.10.0 release. +== ssl_session_fetch_by_lua_block == + +'''syntax:''' ''ssl_session_fetch_by_lua_block { lua-script }'' + +'''context:''' ''server'' + +'''phase:''' ''right-before-SSL-handshake'' + +This directive runs Lua code to look up and load the SSL session (if any) according to the session ID +provided by the current SSL handshake request for the downstream. + +The Lua API for obtaining the current session ID and loading a cached SSL session data +is provided in the [ngx.ssl.session](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/ssl/session.md) +Lua module shipped with the [lua-resty-core](https://github.com/openresty/lua-resty-core#readme) +library. + +Lua APIs that may yield, like [[#ngx.sleep|ngx.sleep]] and [[#ngx.socket.tcp|cosockets]], +are enabled in this context. + +This hook, together with the [[#ssl_session_store_by_lua_block|ssl_session_store_by_lua*]] hook, +can be used to implement distributed caching mechanisms in pure Lua (based +on the [[#ngx.socket.tcp|cosocket]] API, for example). If a cached SSL session is found +and loaded into the current SSL connection context, +SSL session resumption can then get immediately initiated and bypass the full SSL handshake process which is very expensive in terms of CPU time. + +Please note that TLS session tickets are very different and it is the clients' responsibility +to cache the SSL session state when session tickets are used. SSL session resumptions based on +TLS session tickets would happen automatically without going through this hook (nor the +[[#ssl_session_store_by_lua*|ssl_session_store_by_lua_block]] hook). This hook is mainly +for older or less capable SSL clients that can only do SSL sessions by session IDs. + +When [[#ssl_certificate_by_lua_block|ssl_certificate_by_lua*]] is specified at the same time, +this hook usually runs before [[#ssl_certificate_by_lua_block|ssl_certificate_by_lua*]]. +When the SSL session is found and successfully loaded for the current SSL connection, +SSL session resumption will happen and thus bypass the [[#ssl_certificate_by_lua_block|ssl_certificate_by_lua*]] +hook completely. In this case, NGINX also bypasses the [[#ssl_session_store_by_lua*|ssl_session_store_by_lua_block]] +hook, for obvious reasons. + +If you are using the [official pre-built packages](http://openresty.org/en/linux-packages.html) for [OpenResty](https://openresty.org/) +1.11.2.1 or later, then everything should work out of the box. + +If you are using OpenSSL libraries not provided by [OpenResty](https://openresty.org), +then you need to apply the following patch for OpenSSL 1.0.2h or later: + +https://github.com/openresty/openresty/blob/master/patches/openssl-1.0.2h-sess_set_get_cb_yield.patch + +If you are not using the NGINX core shipped with [OpenResty](https://openresty.org) 1.11.2.1 or later, then you need to +apply the following patch to the standard NGINX core 1.11.2 or later: + +http://openresty.org/download/nginx-1.11.2-nonblocking_ssl_handshake_hooks.patch + +This directive was first introduced in the v0.10.6 release. + +== ssl_session_fetch_by_lua_file == + +'''syntax:''' ''ssl_session_fetch_by_lua_file '' + +'''context:''' ''server'' + +'''phase:''' ''right-before-SSL-handshake'' + +Equivalent to [[#ssl_session_fetch_by_lua_block|ssl_session_fetch_by_lua_block]], except that the file specified by contains the Lua code, or rather, the [[#Lua/LuaJIT bytecode support|Lua/LuaJIT bytecode]] to be executed. + +When a relative path like foo/bar.lua is given, they will be turned into the absolute path relative to the server prefix path determined by the -p PATH command-line option while starting the Nginx server. + +This directive was first introduced in the v0.10.6 release. + +== ssl_session_store_by_lua_block == + +'''syntax:''' ''ssl_session_store_by_lua_block { lua-script }'' + +'''context:''' ''server'' + +'''phase:''' ''right-after-SSL-handshake'' + +This directive runs Lua code to fetch and save the SSL session (if any) according to the session ID +provided by the current SSL handshake request for the downstream. The saved or cached SSL +session data can be used for future SSL connections to resume SSL sessions without going +through the full SSL handshake process (which is very expensive in terms of CPU time). + +Lua APIs that may yield, like [[#ngx.sleep|ngx.sleep]] and [[#ngx.socket.tcp|cosockets]], +are *disabled* in this context. You can still, however, use the [[#ngx.timer.at|ngx.timer.at]] API +to create 0-delay timers to save the SSL session data asynchronously to external services (like redis or memcached). + +The Lua API for obtaining the current session ID and the associated session state data +is provided in the [ngx.ssl.session](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/ssl/session.md#readme) +Lua module shipped with the [lua-resty-core](https://github.com/openresty/lua-resty-core#readme) +library. + +This directive was first introduced in the v0.10.6 release. + +== ssl_session_store_by_lua_file == + +'''syntax:''' ''ssl_session_store_by_lua_file '' + +'''context:''' ''server'' + +'''phase:''' ''right-before-SSL-handshake'' + +Equivalent to [[#ssl_session_store_by_lua_block|ssl_session_store_by_lua_block]], except that the file specified by contains the Lua code, or rather, the [[#Lua/LuaJIT bytecode support|Lua/LuaJIT bytecode]] to be executed. + +When a relative path like foo/bar.lua is given, they will be turned into the absolute path relative to the server prefix path determined by the -p PATH command-line option while starting the Nginx server. + +This directive was first introduced in the v0.10.6 release. + == lua_shared_dict == '''syntax:''' ''lua_shared_dict '' @@ -2499,7 +2604,7 @@ Undefined NGINX variables are evaluated to `nil` while uninitialized (but define This API requires a relatively expensive metamethod call and it is recommended to avoid using it on hot code paths. == Core constants == -'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, *log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, *log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' ngx.OK (0) @@ -2520,7 +2625,7 @@ The ngx.null constant is a NULL light userdata usually The ngx.DECLINED constant was first introduced in the v0.5.0rc19 release. == HTTP method constants == -'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' ngx.HTTP_GET @@ -2543,7 +2648,7 @@ The ngx.DECLINED constant was first introduced in the v0.5.0r These constants are usually used in [[#ngx.location.capture|ngx.location.capture]] and [[#ngx.location.capture_multi|ngx.location.capture_multi]] method calls. == HTTP status constants == -'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' value = ngx.HTTP_CONTINUE (100) (first added in the v0.9.20 release) @@ -2583,7 +2688,7 @@ These constants are usually used in [[#ngx.location.capture|ngx.location.capture == Nginx log level constants == -'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' ngx.STDERR @@ -2602,7 +2707,7 @@ These constants are usually used by the [[#ngx.log|ngx.log]] method. == print == '''syntax:''' ''print(...)'' -'''context:''' ''init_by_lua*, init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, log_by_lua*, ngx.timer.*, balancer_by_lua*, certificate_by_lua*'' +'''context:''' ''init_by_lua*, init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' Writes argument values into the nginx error.log file with the ngx.NOTICE log level. @@ -4129,7 +4234,7 @@ Just as [[#ngx.print|ngx.print]] but also emit a trailing newline. == ngx.log == '''syntax:''' ''ngx.log(log_level, ...)'' -'''context:''' ''init_by_lua*, init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''init_by_lua*, init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' Log arguments concatenated to error.log with the given logging level. @@ -4144,9 +4249,9 @@ There is a hard coded 2048 byte limitation on error message lengths '''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*'' -Flushes response output to the client. +Flushes response output to the client. -ngx.flush accepts an optional boolean wait argument (Default: false) first introduced in the v0.3.1rc34 release. When called with the default argument, it issues an asynchronous call (Returns immediately without waiting for output data to be written into the system send buffer). Calling the function with the wait argument set to true switches to synchronous mode. +ngx.flush accepts an optional boolean wait argument (Default: false) first introduced in the v0.3.1rc34 release. When called with the default argument, it issues an asynchronous call (Returns immediately without waiting for output data to be written into the system send buffer). Calling the function with the wait argument set to true switches to synchronous mode. In synchronous mode, the function will not return until all output data has been written into the system send buffer or until the [[HttpCoreModule#send_timeout|send_timeout]] setting has expired. Note that using the Lua coroutine mechanism means that this function does not block the Nginx event loop even in the synchronous mode. @@ -4159,7 +4264,7 @@ Since v0.8.3 this function returns 1 on success, or re == ngx.exit == '''syntax:''' ''ngx.exit(status)'' -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' When status >= 200 (i.e., ngx.HTTP_OK and above), it will interrupt the execution of the current request and return status code to nginx. @@ -4201,7 +4306,9 @@ Note that while this method accepts all [[#HTTP status constants|HTTP status con Also note that this method call terminates the processing of the current request and that it is recommended that a coding style that combines this method call with the return statement, i.e., return ngx.exit(...) be used to reinforce the fact that the request processing is being terminated. -When being used in the context of [[#header_filter_by_lua|header_filter_by_lua]], ngx.exit() is an asynchronous operation and will return immediately. This behavior may change in future and it is recommended that users always use return in combination as suggested above. +When being used in the contexts of [[#header_filter_by_lua|header_filter_by_lua]] and +[[#ssl_session_store_by_lua_block|ssl_session_store_by_lua*]], ngx.exit() is +an asynchronous operation and will return immediately. This behavior may change in future and it is recommended that users always use return in combination as suggested above. == ngx.eof == '''syntax:''' ''ok, err = ngx.eof()'' @@ -4236,7 +4343,7 @@ Since v0.8.3 this function returns 1 on success, or re == ngx.sleep == '''syntax:''' ''ngx.sleep(seconds)'' -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*'' +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*'' Sleeps for the specified seconds without blocking. One can specify time resolution up to 0.001 seconds (i.e., one milliseconds). @@ -4249,7 +4356,7 @@ This method was introduced in the 0.5.0rc30 release. == ngx.escape_uri == '''syntax:''' ''newstr = ngx.escape_uri(str)'' -'''context:''' ''init_by_lua*, init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''init_by_lua*, init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' Escape str as a URI component. @@ -4326,7 +4433,7 @@ This method was first introduced in the v0.3.1rc27 release. == ngx.decode_args == '''syntax:''' ''table = ngx.decode_args(str, max_args?)'' -'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' Decodes a URI encoded query-string into a Lua table. This is the inverse function of [[#ngx.encode_args|ngx.encode_args]]. @@ -4345,7 +4452,7 @@ This method was introduced in the v0.5.0rc29. == ngx.encode_base64 == '''syntax:''' ''newstr = ngx.encode_base64(str, no_padding?)'' -'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' Encodes str to a base64 digest. @@ -4354,14 +4461,14 @@ Since the 0.9.16 release, an optional boolean-typed no_paddin == ngx.decode_base64 == '''syntax:''' ''newstr = ngx.decode_base64(str)'' -'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' Decodes the str argument as a base64 digest to the raw form. Returns nil if str is not well formed. == ngx.crc32_short == '''syntax:''' ''intval = ngx.crc32_short(str)'' -'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' Calculates the CRC-32 (Cyclic Redundancy Code) digest for the str argument. @@ -4374,7 +4481,7 @@ This API was first introduced in the v0.3.1rc8 release. == ngx.crc32_long == '''syntax:''' ''intval = ngx.crc32_long(str)'' -'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' Calculates the CRC-32 (Cyclic Redundancy Code) digest for the str argument. @@ -4387,7 +4494,7 @@ This API was first introduced in the v0.3.1rc8 release. == ngx.hmac_sha1 == '''syntax:''' ''digest = ngx.hmac_sha1(secret_key, str)'' -'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' Computes the [http://en.wikipedia.org/wiki/HMAC HMAC-SHA1] digest of the argument str and turns the result using the secret key . @@ -4415,7 +4522,7 @@ This function was first introduced in the v0.3.1rc29 release. == ngx.md5 == '''syntax:''' ''digest = ngx.md5(str)'' -'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' Returns the hexadecimal representation of the MD5 digest of the str argument. @@ -4438,7 +4545,7 @@ See [[#ngx.md5_bin|ngx.md5_bin]] if the raw binary MD5 digest is required. == ngx.md5_bin == '''syntax:''' ''digest = ngx.md5_bin(str)'' -'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' Returns the binary form of the MD5 digest of the str argument. @@ -4447,7 +4554,7 @@ See [[#ngx.md5|ngx.md5]] if the hexadecimal form of the MD5 digest is required. == ngx.sha1_bin == '''syntax:''' ''digest = ngx.sha1_bin(str)'' -'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' Returns the binary form of the SHA-1 digest of the str argument. @@ -4458,14 +4565,14 @@ This function was first introduced in the v0.5.0rc6. == ngx.quote_sql_str == '''syntax:''' ''quoted_value = ngx.quote_sql_str(raw_value)'' -'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' Returns a quoted SQL string literal according to the MySQL quoting rules. == ngx.today == '''syntax:''' ''str = ngx.today()'' -'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' Returns current date (in the format yyyy-mm-dd) from the nginx cached time (no syscall involved unlike Lua's date library). @@ -4474,7 +4581,7 @@ This is the local time. == ngx.time == '''syntax:''' ''secs = ngx.time()'' -'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' Returns the elapsed seconds from the epoch for the current time stamp from the nginx cached time (no syscall involved unlike Lua's date library). @@ -4483,7 +4590,7 @@ Updates of the Nginx time cache an be forced by calling [[#ngx.update_time|ngx.u == ngx.now == '''syntax:''' ''secs = ngx.now()'' -'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' Returns a floating-point number for the elapsed time in seconds (including milliseconds as the decimal part) from the epoch for the current time stamp from the nginx cached time (no syscall involved unlike Lua's date library). @@ -4494,7 +4601,7 @@ This API was first introduced in v0.3.1rc32. == ngx.update_time == '''syntax:''' ''ngx.update_time()'' -'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' Forcibly updates the Nginx current time cache. This call involves a syscall and thus has some overhead, so do not abuse it. @@ -4503,7 +4610,7 @@ This API was first introduced in v0.3.1rc32. == ngx.localtime == '''syntax:''' ''str = ngx.localtime()'' -'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' Returns the current time stamp (in the format yyyy-mm-dd hh:mm:ss) of the nginx cached time (no syscall involved unlike Lua's [http://www.lua.org/manual/5.1/manual.html#pdf-os.date os.date] function). @@ -4512,7 +4619,7 @@ This is the local time. == ngx.utctime == '''syntax:''' ''str = ngx.utctime()'' -'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' Returns the current time stamp (in the format yyyy-mm-dd hh:mm:ss) of the nginx cached time (no syscall involved unlike Lua's [http://www.lua.org/manual/5.1/manual.html#pdf-os.date os.date] function). @@ -4521,7 +4628,7 @@ This is the UTC time. == ngx.cookie_time == '''syntax:''' ''str = ngx.cookie_time(sec)'' -'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' Returns a formatted string can be used as the cookie expiration time. The parameter sec is the time stamp in seconds (like those returned from [[#ngx.time|ngx.time]]). @@ -4533,7 +4640,7 @@ Returns a formatted string can be used as the cookie expiration time. The parame == ngx.http_time == '''syntax:''' ''str = ngx.http_time(sec)'' -'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' Returns a formated string can be used as the http header time (for example, being used in Last-Modified header). The parameter sec is the time stamp in seconds (like those returned from [[#ngx.time|ngx.time]]). @@ -4545,7 +4652,7 @@ Returns a formated string can be used as the http header time (for example, bein == ngx.parse_http_time == '''syntax:''' ''sec = ngx.parse_http_time(str)'' -'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' Parse the http time string (as returned by [[#ngx.http_time|ngx.http_time]]) into seconds. Returns the seconds or nil if the input string is in bad forms. @@ -4566,7 +4673,7 @@ Returns true if the current request is an nginx subrequest, or subject string using the Perl compatible regular expression regex with the optional options. @@ -4713,7 +4820,7 @@ This feature was introduced in the v0.2.1rc11 release. == ngx.re.find == '''syntax:''' ''from, to, err = ngx.re.find(subject, regex, options?, ctx?, nth?)'' -'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' Similar to [[#ngx.re.match|ngx.re.match]] but only returns the beginning index (from) and end index (to) of the matched substring. The returned indexes are 1-based and can be fed directly into the [http://www.lua.org/manual/5.1/manual.html#pdf-string.sub string.sub] API function to obtain the matched substring. @@ -4762,7 +4869,7 @@ This API function was first introduced in the v0.9.2 release. == ngx.re.gmatch == '''syntax:''' ''iterator, err = ngx.re.gmatch(subject, regex, options?)'' -'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' Similar to [[#ngx.re.match|ngx.re.match]], but returns a Lua iterator instead, so as to let the user programmer iterate all the matches over the string argument with the PCRE regex. @@ -4835,7 +4942,7 @@ This feature was first introduced in the v0.2.1rc12 release. == ngx.re.sub == '''syntax:''' ''newstr, n, err = ngx.re.sub(subject, regex, replace, options?)'' -'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' Substitutes the first match of the Perl compatible regular expression regex on the subject argument string with the string or function argument replace. The optional options argument has exactly the same meaning as in [[#ngx.re.match|ngx.re.match]]. @@ -4894,7 +5001,7 @@ This feature was first introduced in the v0.2.1rc13 release. == ngx.re.gsub == '''syntax:''' ''newstr, n, err = ngx.re.gsub(subject, regex, replace, options?)'' -'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' Just like [[#ngx.re.sub|ngx.re.sub]], but does global substitution. @@ -4929,7 +5036,7 @@ This feature was first introduced in the v0.2.1rc15 release. '''syntax:''' ''dict = ngx.shared[name_var]'' -'''context:''' ''init_by_lua*, init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''init_by_lua*, init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' Fetching the shm-based Lua dictionary object for the shared memory zone named DICT defined by the [[#lua_shared_dict|lua_shared_dict]] directive. @@ -4997,7 +5104,7 @@ This feature was first introduced in the v0.3.1rc22 release. == ngx.shared.DICT.get == '''syntax:''' ''value, flags = ngx.shared.DICT:get(key)'' -'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' Retrieving the value in the dictionary [[#ngx.shared.DICT|ngx.shared.DICT]] for the key key. If the key does not exist or has been expired, then nil will be returned. @@ -5030,7 +5137,7 @@ See also [[#ngx.shared.DICT|ngx.shared.DICT]]. == ngx.shared.DICT.get_stale == '''syntax:''' ''value, flags, stale = ngx.shared.DICT:get_stale(key)'' -'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' Similar to the [[#ngx.shared.DICT.get|get]] method but returns the value even if the key has already expired. @@ -5045,7 +5152,7 @@ See also [[#ngx.shared.DICT|ngx.shared.DICT]]. == ngx.shared.DICT.set == '''syntax:''' ''success, err, forcible = ngx.shared.DICT:set(key, value, exptime?, flags?)'' -'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' Unconditionally sets a key-value pair into the shm-based dictionary [[#ngx.shared.DICT|ngx.shared.DICT]]. Returns three values: @@ -5088,7 +5195,7 @@ See also [[#ngx.shared.DICT|ngx.shared.DICT]]. == ngx.shared.DICT.safe_set == '''syntax:''' ''ok, err = ngx.shared.DICT:safe_set(key, value, exptime?, flags?)'' -'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' Similar to the [[#ngx.shared.DICT.set|set]] method, but never overrides the (least recently used) unexpired items in the store when running out of storage in the shared memory zone. In this case, it will immediately return nil and the string "no memory". @@ -5099,7 +5206,7 @@ See also [[#ngx.shared.DICT|ngx.shared.DICT]]. == ngx.shared.DICT.add == '''syntax:''' ''success, err, forcible = ngx.shared.DICT:add(key, value, exptime?, flags?)'' -'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' Just like the [[#ngx.shared.DICT.set|set]] method, but only stores the key-value pair into the dictionary [[#ngx.shared.DICT|ngx.shared.DICT]] if the key does ''not'' exist. @@ -5112,7 +5219,7 @@ See also [[#ngx.shared.DICT|ngx.shared.DICT]]. == ngx.shared.DICT.safe_add == '''syntax:''' ''ok, err = ngx.shared.DICT:safe_add(key, value, exptime?, flags?)'' -'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' Similar to the [[#ngx.shared.DICT.add|add]] method, but never overrides the (least recently used) unexpired items in the store when running out of storage in the shared memory zone. In this case, it will immediately return nil and the string "no memory". @@ -5123,7 +5230,7 @@ See also [[#ngx.shared.DICT|ngx.shared.DICT]]. == ngx.shared.DICT.replace == '''syntax:''' ''success, err, forcible = ngx.shared.DICT:replace(key, value, exptime?, flags?)'' -'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' Just like the [[#ngx.shared.DICT.set|set]] method, but only stores the key-value pair into the dictionary [[#ngx.shared.DICT|ngx.shared.DICT]] if the key ''does'' exist. @@ -5136,7 +5243,7 @@ See also [[#ngx.shared.DICT|ngx.shared.DICT]]. == ngx.shared.DICT.delete == '''syntax:''' ''ngx.shared.DICT:delete(key)'' -'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' Unconditionally removes the key-value pair from the shm-based dictionary [[#ngx.shared.DICT|ngx.shared.DICT]]. @@ -5149,7 +5256,7 @@ See also [[#ngx.shared.DICT|ngx.shared.DICT]]. == ngx.shared.DICT.incr == '''syntax:''' ''newval, err = ngx.shared.DICT:incr(key, value)'' -'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' Increments the (numerical) value for key in the shm-based dictionary [[#ngx.shared.DICT|ngx.shared.DICT]] by the step value value. Returns the new resulting number if the operation is successfully completed or nil and an error message otherwise. @@ -5166,7 +5273,7 @@ See also [[#ngx.shared.DICT|ngx.shared.DICT]]. == ngx.shared.DICT.flush_all == '''syntax:''' ''ngx.shared.DICT:flush_all()'' -'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' Flushes out all the items in the dictionary. This method does not actuall free up all the memory blocks in the dictionary but just marks all the existing items as expired. @@ -5177,7 +5284,7 @@ See also [[#ngx.shared.DICT.flush_expired|ngx.shared.DICT.flush_expired]] and [[ == ngx.shared.DICT.flush_expired == '''syntax:''' ''flushed = ngx.shared.DICT:flush_expired(max_count?)'' -'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' Flushes out the expired items in the dictionary, up to the maximal number specified by the optional max_count argument. When the max_count argument is given 0 or not given at all, then it means unlimited. Returns the number of items that have actually been flushed. @@ -5190,7 +5297,7 @@ See also [[#ngx.shared.DICT.flush_all|ngx.shared.DICT.flush_all]] and [[#ngx.sha == ngx.shared.DICT.get_keys == '''syntax:''' ''keys = ngx.shared.DICT:get_keys(max_count?)'' -'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' Fetch a list of the keys from the dictionary, up to . @@ -5203,7 +5310,7 @@ This feature was first introduced in the v0.7.3 release. == ngx.socket.udp == '''syntax:''' ''udpsock = ngx.socket.udp()'' -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*'' +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*'' Creates and returns a UDP or datagram-oriented unix domain socket object (also known as one type of the "cosocket" objects). The following methods are supported on this object: @@ -5224,7 +5331,7 @@ See also [[#ngx.socket.tcp|ngx.socket.tcp]]. '''syntax:''' ''ok, err = udpsock:setpeername("unix:/path/to/unix-domain.socket")'' -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*'' +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*'' Attempts to connect a UDP socket object to a remote server or to a datagram unix domain socket file. Because the datagram protocol is actually connection-less, this method does not really establish a "connection", but only just set the name of the remote peer for subsequent read/write operations. @@ -5277,7 +5384,7 @@ This method was first introduced in the v0.5.7 release. == udpsock:send == '''syntax:''' ''ok, err = udpsock:send(data)'' -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*'' +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*'' Sends data on the current UDP or datagram unix domain socket object. @@ -5290,7 +5397,7 @@ This feature was first introduced in the v0.5.7 release. == udpsock:receive == '''syntax:''' ''data, err = udpsock:receive(size?)'' -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*'' +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*'' Receives data from the UDP or datagram unix domain socket object with an optional receive buffer size argument, size. @@ -5321,7 +5428,7 @@ This feature was first introduced in the v0.5.7 release. == udpsock:close == '''syntax:''' ''ok, err = udpsock:close()'' -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*'' +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*'' Closes the current UDP or datagram unix domain socket. It returns the 1 in case of success and returns nil with a string describing the error otherwise. @@ -5332,7 +5439,7 @@ This feature was first introduced in the v0.5.7 release. == udpsock:settimeout == '''syntax:''' ''udpsock:settimeout(time)'' -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*'' +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*'' Set the timeout value in milliseconds for subsequent socket operations (like [[#udpsock:receive|receive]]). @@ -5350,7 +5457,7 @@ This API function was first added to the v0.10.1 release. == ngx.socket.tcp == '''syntax:''' ''tcpsock = ngx.socket.tcp()'' -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*'' +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*'' Creates and returns a TCP or stream-oriented unix domain socket object (also known as one type of the "cosocket" objects). The following methods are supported on this object: @@ -5393,7 +5500,7 @@ See also [[#ngx.socket.udp|ngx.socket.udp]]. '''syntax:''' ''ok, err = tcpsock:connect("unix:/path/to/unix-domain.socket", options_table?)'' -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*'' +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*'' Attempts to connect a TCP socket object to a remote server or to a stream unix domain socket file without blocking. @@ -5465,7 +5572,7 @@ This method was first introduced in the v0.5.0rc1 release. == tcpsock:sslhandshake == '''syntax:''' ''session, err = tcpsock:sslhandshake(reused_session?, server_name?, ssl_verify?, send_status_req?)'' -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*'' +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*'' Does SSL/TLS handshake on the currently established connection. @@ -5507,7 +5614,7 @@ This method was first introduced in the v0.9.11 release. == tcpsock:send == '''syntax:''' ''bytes, err = tcpsock:send(data)'' -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*'' +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*'' Sends data without blocking on the current TCP or Unix Domain Socket connection. @@ -5535,7 +5642,7 @@ This feature was first introduced in the v0.5.0rc1 release. '''syntax:''' ''data, err, partial = tcpsock:receive(pattern?)'' -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*'' +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*'' Receives data from the connected socket according to the reading pattern or size. @@ -5573,7 +5680,7 @@ This feature was first introduced in the v0.5.0rc1 release. == tcpsock:receiveuntil == '''syntax:''' ''iterator = tcpsock:receiveuntil(pattern, options?)'' -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*'' +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*'' This method returns an iterator Lua function that can be called to read the data stream until it sees the specified pattern or an error occurs. @@ -5665,7 +5772,7 @@ This method was first introduced in the v0.5.0rc1 release. == tcpsock:close == '''syntax:''' ''ok, err = tcpsock:close()'' -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*'' +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*'' Closes the current TCP or stream unix domain socket. It returns the 1 in case of success and returns nil with a string describing the error otherwise. @@ -5678,7 +5785,7 @@ This feature was first introduced in the v0.5.0rc1 release. == tcpsock:settimeout == '''syntax:''' ''tcpsock:settimeout(time)'' -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*'' +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*'' Set the timeout value in milliseconds for subsequent socket operations ([[#tcpsock:connect|connect]], [[#tcpsock:receive|receive]], and iterators returned from [[#tcpsock:receiveuntil|receiveuntil]]). @@ -5691,7 +5798,7 @@ This feature was first introduced in the v0.5.0rc1 release. == tcpsock:setoption == '''syntax:''' ''tcpsock:setoption(option, value?)'' -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*'' +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*'' This function is added for [http://w3.impa.br/~diego/software/luasocket/tcp.html LuaSocket] API compatibility and does nothing for now. Its functionality will be implemented in future. @@ -5700,7 +5807,7 @@ This feature was first introduced in the v0.5.0rc1 release. == tcpsock:setkeepalive == '''syntax:''' ''ok, err = tcpsock:setkeepalive(timeout?, size?)'' -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*'' +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*'' Puts the current socket's connection immediately into the cosocket built-in connection pool and keep it alive until other [[#tcpsock:connect|connect]] method calls request it or the associated maximal idle timeout is expired. @@ -5725,7 +5832,7 @@ This feature was first introduced in the v0.5.0rc1 release. == tcpsock:getreusedtimes == '''syntax:''' ''count, err = tcpsock:getreusedtimes()'' -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*'' +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*'' This method returns the (successfully) reused times for the current connection. In case of error, it returns nil and a string describing the error. @@ -5758,7 +5865,7 @@ This feature was first introduced in the v0.5.0rc1 release. == ngx.get_phase == '''syntax:''' ''str = ngx.get_phase()'' -'''context:''' ''init_by_lua*, init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''init_by_lua*, init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' Retrieves the current running phase name. Possible return values are @@ -5768,6 +5875,10 @@ Retrieves the current running phase name. Possible return values are : for the context of [[#init_worker_by_lua|init_worker_by_lua]] or [[#init_worker_by_lua_file|init_worker_by_lua_file]]. * ssl_cert : for the context of [[#ssl_certificate_by_lua_block|ssl_certificate_by_lua_block]] or [[#ssl_certificate_by_lua_file|ssl_certificate_by_lua_file]]. +* ssl_session_fetch +: for the context of [[#ssl_session_fetch_by_lua_block|ssl_session_fetch_by_lua*]]. +* ssl_session_store +: for the context of [[#ssl_session_store_by_lua_block|ssl_session_store_by_lua*]]. * set : for the context of [[#set_by_lua|set_by_lua]] or [[#set_by_lua_file|set_by_lua_file]]. * rewrite @@ -5792,7 +5903,7 @@ This API was first introduced in the v0.5.10 release. == ngx.thread.spawn == '''syntax:''' ''co = ngx.thread.spawn(func, arg1, arg2, ...)'' -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*'' +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*'' Spawns a new user "light thread" with the Lua function func as well as those optional arguments arg1, arg2, and etc. Returns a Lua thread (or Lua coroutine) object represents this "light thread". @@ -5925,7 +6036,7 @@ This API was first enabled in the v0.7.0 release. == ngx.thread.wait == '''syntax:''' ''ok, res1, res2, ... = ngx.thread.wait(thread1, thread2, ...)'' -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*'' +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*'' Waits on one or more child "light threads" and returns the results of the first "light thread" that terminates (either successfully or with an error). @@ -6070,7 +6181,7 @@ See also [[#lua_check_client_abort|lua_check_client_abort]]. == ngx.timer.at == '''syntax:''' ''ok, err = ngx.timer.at(delay, callback, user_arg1, user_arg2, ...)'' -'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' Creates an Nginx timer with a user callback function as well as optional user arguments. @@ -6191,7 +6302,7 @@ This API was first introduced in the v0.8.0 release. == ngx.timer.running_count == '''syntax:''' ''count = ngx.timer.running_count()'' -'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' Returns the number of timers currently running. @@ -6200,7 +6311,7 @@ This directive was first introduced in the v0.9.20 release. == ngx.timer.pending_count == '''syntax:''' ''count = ngx.timer.pending_count()'' -'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' Returns the number of pending timers. @@ -6386,7 +6497,7 @@ This feature requires at least ngx_lua v0.10.0. == ndk.set_var.DIRECTIVE == '''syntax:''' ''res = ndk.set_var.DIRECTIVE_NAME'' -'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' This mechanism allows calling other nginx C modules' directives that are implemented by [https://github.com/simpl/ngx_devel_kit Nginx Devel Kit] (NDK)'s set_var submodule's ndk_set_var_value. @@ -6423,7 +6534,7 @@ This feature requires the [https://github.com/simpl/ngx_devel_kit ngx_devel_kit] == coroutine.create == '''syntax:''' ''co = coroutine.create(f)'' -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, init_by_lua*, ngx.timer.*, header_filter_by_lua*, body_filter_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, init_by_lua*, ngx.timer.*, header_filter_by_lua*, body_filter_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' Creates a user Lua coroutines with a Lua function, and returns a coroutine object. @@ -6436,7 +6547,7 @@ This API was first introduced in the v0.6.0 release. == coroutine.resume == '''syntax:''' ''ok, ... = coroutine.resume(co, ...)'' -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, init_by_lua*, ngx.timer.*, header_filter_by_lua*, body_filter_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, init_by_lua*, ngx.timer.*, header_filter_by_lua*, body_filter_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' Resumes the executation of a user Lua coroutine object previously yielded or just created. @@ -6449,7 +6560,7 @@ This API was first introduced in the v0.6.0 release. == coroutine.yield == '''syntax:''' ''... = coroutine.yield(...)'' -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, init_by_lua*, ngx.timer.*, header_filter_by_lua*, body_filter_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, init_by_lua*, ngx.timer.*, header_filter_by_lua*, body_filter_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' Yields the execution of the current user Lua coroutine. @@ -6462,7 +6573,7 @@ This API was first introduced in the v0.6.0 release. == coroutine.wrap == '''syntax:''' ''co = coroutine.wrap(f)'' -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, init_by_lua*, ngx.timer.*, header_filter_by_lua*, body_filter_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, init_by_lua*, ngx.timer.*, header_filter_by_lua*, body_filter_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' Similar to the standard Lua [http://www.lua.org/manual/5.1/manual.html#pdf-coroutine.wrap coroutine.wrap] API, but works in the context of the Lua coroutines created by ngx_lua. @@ -6473,7 +6584,7 @@ This API was first introduced in the v0.6.0 release. == coroutine.running == '''syntax:''' ''co = coroutine.running()'' -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, init_by_lua*, ngx.timer.*, header_filter_by_lua*, body_filter_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, init_by_lua*, ngx.timer.*, header_filter_by_lua*, body_filter_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' Identical to the standard Lua [http://www.lua.org/manual/5.1/manual.html#pdf-coroutine.running coroutine.running] API. @@ -6484,7 +6595,7 @@ This API was first enabled in the v0.6.0 release. == coroutine.status == '''syntax:''' ''status = coroutine.status(co)'' -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, init_by_lua*, ngx.timer.*, header_filter_by_lua*, body_filter_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, init_by_lua*, ngx.timer.*, header_filter_by_lua*, body_filter_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' Identical to the standard Lua [http://www.lua.org/manual/5.1/manual.html#pdf-coroutine.status coroutine.status] API. diff --git a/src/ngx_http_lua_common.h b/src/ngx_http_lua_common.h index e5fed0afd7..d5e0dc8052 100644 --- a/src/ngx_http_lua_common.h +++ b/src/ngx_http_lua_common.h @@ -103,17 +103,19 @@ typedef struct { /* must be within 16 bit */ -#define NGX_HTTP_LUA_CONTEXT_SET 0x001 -#define NGX_HTTP_LUA_CONTEXT_REWRITE 0x002 -#define NGX_HTTP_LUA_CONTEXT_ACCESS 0x004 -#define NGX_HTTP_LUA_CONTEXT_CONTENT 0x008 -#define NGX_HTTP_LUA_CONTEXT_LOG 0x010 -#define NGX_HTTP_LUA_CONTEXT_HEADER_FILTER 0x020 -#define NGX_HTTP_LUA_CONTEXT_BODY_FILTER 0x040 -#define NGX_HTTP_LUA_CONTEXT_TIMER 0x080 -#define NGX_HTTP_LUA_CONTEXT_INIT_WORKER 0x100 -#define NGX_HTTP_LUA_CONTEXT_BALANCER 0x200 -#define NGX_HTTP_LUA_CONTEXT_SSL_CERT 0x400 +#define NGX_HTTP_LUA_CONTEXT_SET 0x0001 +#define NGX_HTTP_LUA_CONTEXT_REWRITE 0x0002 +#define NGX_HTTP_LUA_CONTEXT_ACCESS 0x0004 +#define NGX_HTTP_LUA_CONTEXT_CONTENT 0x0008 +#define NGX_HTTP_LUA_CONTEXT_LOG 0x0010 +#define NGX_HTTP_LUA_CONTEXT_HEADER_FILTER 0x0020 +#define NGX_HTTP_LUA_CONTEXT_BODY_FILTER 0x0040 +#define NGX_HTTP_LUA_CONTEXT_TIMER 0x0080 +#define NGX_HTTP_LUA_CONTEXT_INIT_WORKER 0x0100 +#define NGX_HTTP_LUA_CONTEXT_BALANCER 0x0200 +#define NGX_HTTP_LUA_CONTEXT_SSL_CERT 0x0400 +#define NGX_HTTP_LUA_CONTEXT_SSL_SESS_STORE 0x0800 +#define NGX_HTTP_LUA_CONTEXT_SSL_SESS_FETCH 0x1000 #ifndef NGX_LUA_NO_FFI_API @@ -204,10 +206,18 @@ struct ngx_http_lua_main_conf_s { union ngx_http_lua_srv_conf_u { #if (NGX_HTTP_SSL) struct { - ngx_http_lua_srv_conf_handler_pt cert_handler; - ngx_str_t cert_src; - u_char *cert_src_key; - } ssl; + ngx_http_lua_srv_conf_handler_pt ssl_cert_handler; + ngx_str_t ssl_cert_src; + u_char *ssl_cert_src_key; + + ngx_http_lua_srv_conf_handler_pt ssl_sess_store_handler; + ngx_str_t ssl_sess_store_src; + u_char *ssl_sess_store_src_key; + + ngx_http_lua_srv_conf_handler_pt ssl_sess_fetch_handler; + ngx_str_t ssl_sess_fetch_src; + u_char *ssl_sess_fetch_src_key; + } srv; #endif struct { diff --git a/src/ngx_http_lua_control.c b/src/ngx_http_lua_control.c index 4c5f65e13d..7a9c4261b6 100644 --- a/src/ngx_http_lua_control.c +++ b/src/ngx_http_lua_control.c @@ -318,11 +318,16 @@ ngx_http_lua_ngx_exit(lua_State *L) | NGX_HTTP_LUA_CONTEXT_TIMER | NGX_HTTP_LUA_CONTEXT_HEADER_FILTER | NGX_HTTP_LUA_CONTEXT_BALANCER - | NGX_HTTP_LUA_CONTEXT_SSL_CERT); + | NGX_HTTP_LUA_CONTEXT_SSL_CERT + | NGX_HTTP_LUA_CONTEXT_SSL_SESS_STORE + | NGX_HTTP_LUA_CONTEXT_SSL_SESS_FETCH); rc = (ngx_int_t) luaL_checkinteger(L, 1); - if (ctx->context == NGX_HTTP_LUA_CONTEXT_SSL_CERT) { + if (ctx->context & (NGX_HTTP_LUA_CONTEXT_SSL_CERT + | NGX_HTTP_LUA_CONTEXT_SSL_SESS_STORE + | NGX_HTTP_LUA_CONTEXT_SSL_SESS_FETCH)) + { #if (NGX_HTTP_SSL) @@ -332,6 +337,10 @@ ngx_http_lua_ngx_exit(lua_State *L) ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua exit with code %i", rc); + if (ctx->context == NGX_HTTP_LUA_CONTEXT_SSL_SESS_STORE) { + return 0; + } + return lua_yield(L, 0); #else diff --git a/src/ngx_http_lua_coroutine.c b/src/ngx_http_lua_coroutine.c index cb819c693b..b790814a2b 100644 --- a/src/ngx_http_lua_coroutine.c +++ b/src/ngx_http_lua_coroutine.c @@ -77,7 +77,8 @@ ngx_http_lua_coroutine_create_helper(lua_State *L, ngx_http_request_t *r, | NGX_HTTP_LUA_CONTEXT_ACCESS | NGX_HTTP_LUA_CONTEXT_CONTENT | NGX_HTTP_LUA_CONTEXT_TIMER - | NGX_HTTP_LUA_CONTEXT_SSL_CERT); + | NGX_HTTP_LUA_CONTEXT_SSL_CERT + | NGX_HTTP_LUA_CONTEXT_SSL_SESS_FETCH); vm = ngx_http_lua_get_lua_vm(r, ctx); @@ -153,7 +154,8 @@ ngx_http_lua_coroutine_resume(lua_State *L) | NGX_HTTP_LUA_CONTEXT_ACCESS | NGX_HTTP_LUA_CONTEXT_CONTENT | NGX_HTTP_LUA_CONTEXT_TIMER - | NGX_HTTP_LUA_CONTEXT_SSL_CERT); + | NGX_HTTP_LUA_CONTEXT_SSL_CERT + | NGX_HTTP_LUA_CONTEXT_SSL_SESS_FETCH); p_coctx = ctx->cur_co_ctx; if (p_coctx == NULL) { @@ -213,7 +215,8 @@ ngx_http_lua_coroutine_yield(lua_State *L) | NGX_HTTP_LUA_CONTEXT_ACCESS | NGX_HTTP_LUA_CONTEXT_CONTENT | NGX_HTTP_LUA_CONTEXT_TIMER - | NGX_HTTP_LUA_CONTEXT_SSL_CERT); + | NGX_HTTP_LUA_CONTEXT_SSL_CERT + | NGX_HTTP_LUA_CONTEXT_SSL_SESS_FETCH); coctx = ctx->cur_co_ctx; @@ -362,7 +365,8 @@ ngx_http_lua_coroutine_status(lua_State *L) | NGX_HTTP_LUA_CONTEXT_ACCESS | NGX_HTTP_LUA_CONTEXT_CONTENT | NGX_HTTP_LUA_CONTEXT_TIMER - | NGX_HTTP_LUA_CONTEXT_SSL_CERT); + | NGX_HTTP_LUA_CONTEXT_SSL_CERT + | NGX_HTTP_LUA_CONTEXT_SSL_SESS_FETCH); coctx = ngx_http_lua_get_co_ctx(co, ctx); if (coctx == NULL) { diff --git a/src/ngx_http_lua_module.c b/src/ngx_http_lua_module.c index 4694666522..c5e10f9159 100644 --- a/src/ngx_http_lua_module.c +++ b/src/ngx_http_lua_module.c @@ -26,6 +26,8 @@ #include "ngx_http_lua_semaphore.h" #include "ngx_http_lua_balancer.h" #include "ngx_http_lua_ssl_certby.h" +#include "ngx_http_lua_ssl_session_storeby.h" +#include "ngx_http_lua_ssl_session_fetchby.h" static void *ngx_http_lua_create_main_conf(ngx_conf_t *cf); @@ -525,6 +527,34 @@ static ngx_command_t ngx_http_lua_cmds[] = { 0, (void *) ngx_http_lua_ssl_cert_handler_file }, + { ngx_string("ssl_session_store_by_lua_block"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_BLOCK|NGX_CONF_NOARGS, + ngx_http_lua_ssl_sess_store_by_lua_block, + NGX_HTTP_SRV_CONF_OFFSET, + 0, + (void *) ngx_http_lua_ssl_sess_store_handler_inline }, + + { ngx_string("ssl_session_store_by_lua_file"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, + ngx_http_lua_ssl_sess_store_by_lua, + NGX_HTTP_SRV_CONF_OFFSET, + 0, + (void *) ngx_http_lua_ssl_sess_store_handler_file }, + + { ngx_string("ssl_session_fetch_by_lua_block"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_BLOCK|NGX_CONF_NOARGS, + ngx_http_lua_ssl_sess_fetch_by_lua_block, + NGX_HTTP_SRV_CONF_OFFSET, + 0, + (void *) ngx_http_lua_ssl_sess_fetch_handler_inline }, + + { ngx_string("ssl_session_fetch_by_lua_file"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, + ngx_http_lua_ssl_sess_fetch_by_lua, + NGX_HTTP_SRV_CONF_OFFSET, + 0, + (void *) ngx_http_lua_ssl_sess_fetch_handler_file }, + { ngx_string("lua_ssl_verify_depth"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, ngx_conf_set_num_slot, @@ -855,9 +885,18 @@ ngx_http_lua_create_srv_conf(ngx_conf_t *cf) } /* set by ngx_pcalloc: - * lscf->ssl.cert_handler = NULL; - * lscf->ssl.cert_src = { 0, NULL }; - * lscf->ssl.cert_src_key = NULL; + * lscf->srv.ssl_cert_handler = NULL; + * lscf->srv.ssl_cert_src = { 0, NULL }; + * lscf->srv.ssl_cert_src_key = NULL; + * + * lscf->srv.ssl_session_store_handler = NULL; + * lscf->srv.ssl_session_store_src = { 0, NULL }; + * lscf->srv.ssl_session_store_src_key = NULL; + * + * lscf->srv.ssl_session_fetch_handler = NULL; + * lscf->srv.ssl_session_fetch_src = { 0, NULL }; + * lscf->srv.ssl_session_fetch_src_key = NULL; + * * lscf->balancer.handler = NULL; * lscf->balancer.src = { 0, NULL }; * lscf->balancer.src_key = NULL; @@ -878,13 +917,13 @@ ngx_http_lua_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) dd("merge srv conf"); - if (conf->ssl.cert_src.len == 0) { - conf->ssl.cert_src = prev->ssl.cert_src; - conf->ssl.cert_src_key = prev->ssl.cert_src_key; - conf->ssl.cert_handler = prev->ssl.cert_handler; + if (conf->srv.ssl_cert_src.len == 0) { + conf->srv.ssl_cert_src = prev->srv.ssl_cert_src; + conf->srv.ssl_cert_src_key = prev->srv.ssl_cert_src_key; + conf->srv.ssl_cert_handler = prev->srv.ssl_cert_handler; } - if (conf->ssl.cert_src.len) { + if (conf->srv.ssl_cert_src.len) { sscf = ngx_http_conf_get_module_srv_conf(cf, ngx_http_ssl_module); if (sscf == NULL || sscf->ssl.ctx == NULL) { ngx_log_error(NGX_LOG_EMERG, cf->log, 0, @@ -913,6 +952,56 @@ ngx_http_lua_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) # endif +#endif + } + + if (conf->srv.ssl_sess_store_src.len == 0) { + conf->srv.ssl_sess_store_src = prev->srv.ssl_sess_store_src; + conf->srv.ssl_sess_store_src_key = prev->srv.ssl_sess_store_src_key; + conf->srv.ssl_sess_store_handler = prev->srv.ssl_sess_store_handler; + } + + if (conf->srv.ssl_sess_store_src.len) { + sscf = ngx_http_conf_get_module_srv_conf(cf, ngx_http_ssl_module); + if (sscf == NULL || sscf->ssl.ctx == NULL) { + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "no ssl configured for the server"); + + return NGX_CONF_ERROR; + } + +#ifdef LIBRESSL_VERSION_NUMBER + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "LibreSSL does not support ssl_session_store_by_lua*"); + return NGX_CONF_ERROR; +#else + SSL_CTX_sess_set_new_cb(sscf->ssl.ctx, + ngx_http_lua_ssl_sess_store_handler); +#endif + } + + if (conf->srv.ssl_sess_fetch_src.len == 0) { + conf->srv.ssl_sess_fetch_src = prev->srv.ssl_sess_fetch_src; + conf->srv.ssl_sess_fetch_src_key = prev->srv.ssl_sess_fetch_src_key; + conf->srv.ssl_sess_fetch_handler = prev->srv.ssl_sess_fetch_handler; + } + + if (conf->srv.ssl_sess_fetch_src.len) { + sscf = ngx_http_conf_get_module_srv_conf(cf, ngx_http_ssl_module); + if (sscf == NULL || sscf->ssl.ctx == NULL) { + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "no ssl configured for the server"); + + return NGX_CONF_ERROR; + } + +#ifdef LIBRESSL_VERSION_NUMBER + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "LibreSSL does not support ssl_session_fetch_by_lua*"); + return NGX_CONF_ERROR; +#else + SSL_CTX_sess_set_get_cb(sscf->ssl.ctx, + ngx_http_lua_ssl_sess_fetch_handler); #endif } diff --git a/src/ngx_http_lua_phase.c b/src/ngx_http_lua_phase.c index b8e936a3b6..50c53110b8 100644 --- a/src/ngx_http_lua_phase.c +++ b/src/ngx_http_lua_phase.c @@ -84,8 +84,16 @@ ngx_http_lua_ngx_get_phase(lua_State *L) lua_pushliteral(L, "ssl_cert"); break; + case NGX_HTTP_LUA_CONTEXT_SSL_SESS_STORE: + lua_pushliteral(L, "ssl_session_store"); + break; + + case NGX_HTTP_LUA_CONTEXT_SSL_SESS_FETCH: + lua_pushliteral(L, "ssl_session_fetch"); + break; + default: - return luaL_error(L, "unknown phase: %d", (int) ctx->context); + return luaL_error(L, "unknown phase: %#x", (int) ctx->context); } return 1; diff --git a/src/ngx_http_lua_sleep.c b/src/ngx_http_lua_sleep.c index a887c3a6e7..4c0d016672 100644 --- a/src/ngx_http_lua_sleep.c +++ b/src/ngx_http_lua_sleep.c @@ -56,7 +56,8 @@ ngx_http_lua_ngx_sleep(lua_State *L) | NGX_HTTP_LUA_CONTEXT_ACCESS | NGX_HTTP_LUA_CONTEXT_CONTENT | NGX_HTTP_LUA_CONTEXT_TIMER - | NGX_HTTP_LUA_CONTEXT_SSL_CERT); + | NGX_HTTP_LUA_CONTEXT_SSL_CERT + | NGX_HTTP_LUA_CONTEXT_SSL_SESS_FETCH); coctx = ctx->cur_co_ctx; if (coctx == NULL) { diff --git a/src/ngx_http_lua_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c index 21bf8848ea..fe6001ff4f 100644 --- a/src/ngx_http_lua_socket_tcp.c +++ b/src/ngx_http_lua_socket_tcp.c @@ -386,7 +386,8 @@ ngx_http_lua_socket_tcp(lua_State *L) | NGX_HTTP_LUA_CONTEXT_ACCESS | NGX_HTTP_LUA_CONTEXT_CONTENT | NGX_HTTP_LUA_CONTEXT_TIMER - | NGX_HTTP_LUA_CONTEXT_SSL_CERT); + | NGX_HTTP_LUA_CONTEXT_SSL_CERT + | NGX_HTTP_LUA_CONTEXT_SSL_SESS_FETCH); lua_createtable(L, 3 /* narr */, 1 /* nrec */); lua_pushlightuserdata(L, &ngx_http_lua_tcp_socket_metatable_key); @@ -444,7 +445,8 @@ ngx_http_lua_socket_tcp_connect(lua_State *L) | NGX_HTTP_LUA_CONTEXT_ACCESS | NGX_HTTP_LUA_CONTEXT_CONTENT | NGX_HTTP_LUA_CONTEXT_TIMER - | NGX_HTTP_LUA_CONTEXT_SSL_CERT); + | NGX_HTTP_LUA_CONTEXT_SSL_CERT + | NGX_HTTP_LUA_CONTEXT_SSL_SESS_FETCH); luaL_checktype(L, 1, LUA_TTABLE); diff --git a/src/ngx_http_lua_ssl.c b/src/ngx_http_lua_ssl.c new file mode 100644 index 0000000000..8ed7b95417 --- /dev/null +++ b/src/ngx_http_lua_ssl.c @@ -0,0 +1,37 @@ + +/* + * Copyright (C) Yichun Zhang (agentzh) + */ + + +#ifndef DDEBUG +#define DDEBUG 0 +#endif +#include "ddebug.h" + + +#if (NGX_HTTP_SSL) + + +int ngx_http_lua_ssl_ctx_index = -1; + + +ngx_int_t +ngx_http_lua_ssl_init(ngx_log_t *log) +{ + if (ngx_http_lua_ssl_ctx_index == -1) { + ngx_http_lua_ssl_ctx_index = SSL_get_ex_new_index(0, NULL, NULL, + NULL, NULL); + + if (ngx_http_lua_ssl_ctx_index == -1) { + ngx_ssl_error(NGX_LOG_ALERT, log, 0, + "lua: SSL_get_ex_new_index() for ctx failed"); + return NGX_ERROR; + } + } + + return NGX_OK; +} + + +#endif /* NGX_HTTP_SSL */ diff --git a/src/ngx_http_lua_ssl.h b/src/ngx_http_lua_ssl.h new file mode 100644 index 0000000000..7a245ffda7 --- /dev/null +++ b/src/ngx_http_lua_ssl.h @@ -0,0 +1,43 @@ + +/* + * Copyright (C) Yichun Zhang (agentzh) + */ + + +#ifndef _NGX_HTTP_LUA_SSL_H_INCLUDED_ +#define _NGX_HTTP_LUA_SSL_H_INCLUDED_ + + +#include "ngx_http_lua_common.h" + + +#if (NGX_HTTP_SSL) +typedef struct { + ngx_connection_t *connection; /* original true connection */ + ngx_http_request_t *request; /* fake request */ + ngx_pool_cleanup_pt *cleanup; + + ngx_ssl_session_t *session; /* retrurn value for openssl's + * session_get_cb */ + + ngx_str_t session_id; + + int exit_code; /* exit code for openssl's + set_cert_cb callback */ + + unsigned done:1; + unsigned aborted:1; + + unsigned entered_cert_handler:1; + unsigned entered_sess_fetch_handler:1; +} ngx_http_lua_ssl_ctx_t; +#endif + + +ngx_int_t ngx_http_lua_ssl_init(ngx_log_t *log); + + +extern int ngx_http_lua_ssl_ctx_index; + + +#endif /* _NGX_HTTP_LUA_SSL_H_INCLUDED_ */ diff --git a/src/ngx_http_lua_ssl_certby.c b/src/ngx_http_lua_ssl_certby.c index 171e8718f9..aca473557c 100644 --- a/src/ngx_http_lua_ssl_certby.c +++ b/src/ngx_http_lua_ssl_certby.c @@ -20,6 +20,7 @@ #include "ngx_http_lua_contentby.h" #include "ngx_http_lua_ssl_certby.h" #include "ngx_http_lua_directive.h" +#include "ngx_http_lua_ssl.h" enum { @@ -37,9 +38,6 @@ static ngx_int_t ngx_http_lua_ssl_cert_by_chunk(lua_State *L, ngx_http_request_t *r); -int ngx_http_lua_ssl_ctx_index = -1; - - ngx_int_t ngx_http_lua_ssl_cert_handler_file(ngx_http_request_t *r, ngx_http_lua_srv_conf_t *lscf, lua_State *L) @@ -47,8 +45,8 @@ ngx_http_lua_ssl_cert_handler_file(ngx_http_request_t *r, ngx_int_t rc; rc = ngx_http_lua_cache_loadfile(r->connection->log, L, - lscf->ssl.cert_src.data, - lscf->ssl.cert_src_key); + lscf->srv.ssl_cert_src.data, + lscf->srv.ssl_cert_src_key); if (rc != NGX_OK) { return rc; } @@ -67,9 +65,9 @@ ngx_http_lua_ssl_cert_handler_inline(ngx_http_request_t *r, ngx_int_t rc; rc = ngx_http_lua_cache_loadbuffer(r->connection->log, L, - lscf->ssl.cert_src.data, - lscf->ssl.cert_src.len, - lscf->ssl.cert_src_key, + lscf->srv.ssl_cert_src.data, + lscf->srv.ssl_cert_src.len, + lscf->srv.ssl_cert_src_key, "=ssl_certificate_by_lua"); if (rc != NGX_OK) { return rc; @@ -125,24 +123,17 @@ ngx_http_lua_ssl_cert_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, return NGX_CONF_ERROR; } - if (lscf->ssl.cert_handler) { + if (lscf->srv.ssl_cert_handler) { return "is duplicate"; } - if (ngx_http_lua_ssl_ctx_index == -1) { - ngx_http_lua_ssl_ctx_index = SSL_get_ex_new_index(0, NULL, NULL, - NULL, NULL); - - if (ngx_http_lua_ssl_ctx_index == -1) { - ngx_ssl_error(NGX_LOG_ALERT, cf->log, 0, - "lua: SSL_get_ex_new_index() for ctx failed"); - return NGX_CONF_ERROR; - } + if (ngx_http_lua_ssl_init(cf->log) != NGX_OK) { + return NGX_CONF_ERROR; } value = cf->args->elts; - lscf->ssl.cert_handler = (ngx_http_lua_srv_conf_handler_pt) cmd->post; + lscf->srv.ssl_cert_handler = (ngx_http_lua_srv_conf_handler_pt) cmd->post; if (cmd->post == ngx_http_lua_ssl_cert_handler_file) { /* Lua code in an external file */ @@ -153,15 +144,15 @@ ngx_http_lua_ssl_cert_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, return NGX_CONF_ERROR; } - lscf->ssl.cert_src.data = name; - lscf->ssl.cert_src.len = ngx_strlen(name); + lscf->srv.ssl_cert_src.data = name; + lscf->srv.ssl_cert_src.len = ngx_strlen(name); p = ngx_palloc(cf->pool, NGX_HTTP_LUA_FILE_KEY_LEN + 1); if (p == NULL) { return NGX_CONF_ERROR; } - lscf->ssl.cert_src_key = p; + lscf->srv.ssl_cert_src_key = p; p = ngx_copy(p, NGX_HTTP_LUA_FILE_TAG, NGX_HTTP_LUA_FILE_TAG_LEN); p = ngx_http_lua_digest_hex(p, value[1].data, value[1].len); @@ -170,14 +161,14 @@ ngx_http_lua_ssl_cert_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, } else { /* inlined Lua code */ - lscf->ssl.cert_src = value[1]; + lscf->srv.ssl_cert_src = value[1]; p = ngx_palloc(cf->pool, NGX_HTTP_LUA_INLINE_KEY_LEN + 1); if (p == NULL) { return NGX_CONF_ERROR; } - lscf->ssl.cert_src_key = p; + lscf->srv.ssl_cert_src_key = p; p = ngx_copy(p, NGX_HTTP_LUA_INLINE_TAG, NGX_HTTP_LUA_INLINE_TAG_LEN); p = ngx_http_lua_digest_hex(p, value[1].data, value[1].len); @@ -201,7 +192,7 @@ ngx_http_lua_ssl_cert_handler(ngx_ssl_conn_t *ssl_conn, void *data) ngx_http_connection_t *hc; ngx_http_lua_srv_conf_t *lscf; ngx_http_core_loc_conf_t *clcf; - ngx_http_lua_ssl_cert_ctx_t *cctx; + ngx_http_lua_ssl_ctx_t *cctx; c = ngx_ssl_get_connection(ssl_conn); @@ -211,7 +202,7 @@ ngx_http_lua_ssl_cert_handler(ngx_ssl_conn_t *ssl_conn, void *data) dd("ssl cert handler, cert-ctx=%p", cctx); - if (cctx) { + if (cctx && cctx->entered_cert_handler) { /* not the first time */ if (cctx->done) { @@ -226,8 +217,6 @@ ngx_http_lua_ssl_cert_handler(ngx_ssl_conn_t *ssl_conn, void *data) return -1; } - /* cctx == NULL */ - dd("first time"); hc = c->data; @@ -280,14 +269,18 @@ ngx_http_lua_ssl_cert_handler(ngx_ssl_conn_t *ssl_conn, void *data) #endif - cctx = ngx_pcalloc(c->pool, sizeof(ngx_http_lua_ssl_cert_ctx_t)); if (cctx == NULL) { - goto failed; /* error */ + cctx = ngx_pcalloc(c->pool, sizeof(ngx_http_lua_ssl_ctx_t)); + if (cctx == NULL) { + goto failed; /* error */ + } } cctx->exit_code = 1; /* successful by default */ cctx->connection = c; cctx->request = r; + cctx->entered_cert_handler = 1; + cctx->done = 0; dd("setting cctx"); @@ -305,11 +298,15 @@ ngx_http_lua_ssl_cert_handler(ngx_ssl_conn_t *ssl_conn, void *data) c->log->action = "loading SSL certificate by lua"; - rc = lscf->ssl.cert_handler(r, lscf, L); + rc = lscf->srv.ssl_cert_handler(r, lscf, L); if (rc >= NGX_OK || rc == NGX_ERROR) { cctx->done = 1; + if (cctx->cleanup) { + *cctx->cleanup = NULL; + } + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, "lua_certificate_by_lua: handler return value: %i, " "cert cb exit code: %d", rc, cctx->exit_code); @@ -328,13 +325,17 @@ ngx_http_lua_ssl_cert_handler(ngx_ssl_conn_t *ssl_conn, void *data) cln->handler = ngx_http_lua_ssl_cert_done; cln->data = cctx; - cln = ngx_pool_cleanup_add(c->pool, 0); - if (cln == NULL) { - goto failed; + if (cctx->cleanup == NULL) { + cln = ngx_pool_cleanup_add(c->pool, 0); + if (cln == NULL) { + goto failed; + } + + cln->data = cctx; + cctx->cleanup = &cln->handler; } - cln->handler = ngx_http_lua_ssl_cert_aborted; - cln->data = cctx; + *cctx->cleanup = ngx_http_lua_ssl_cert_aborted; return -1; @@ -358,7 +359,7 @@ static void ngx_http_lua_ssl_cert_done(void *data) { ngx_connection_t *c; - ngx_http_lua_ssl_cert_ctx_t *cctx = data; + ngx_http_lua_ssl_ctx_t *cctx = data; dd("lua ssl cert done"); @@ -370,6 +371,10 @@ ngx_http_lua_ssl_cert_done(void *data) cctx->done = 1; + if (cctx->cleanup) { + *cctx->cleanup = NULL; + } + c = cctx->connection; c->log->action = "SSL handshaking"; @@ -381,7 +386,7 @@ ngx_http_lua_ssl_cert_done(void *data) static void ngx_http_lua_ssl_cert_aborted(void *data) { - ngx_http_lua_ssl_cert_ctx_t *cctx = data; + ngx_http_lua_ssl_ctx_t *cctx = data; dd("lua ssl cert done"); diff --git a/src/ngx_http_lua_ssl_certby.h b/src/ngx_http_lua_ssl_certby.h index 11cb9634f8..fb07e01106 100644 --- a/src/ngx_http_lua_ssl_certby.h +++ b/src/ngx_http_lua_ssl_certby.h @@ -14,16 +14,6 @@ #if (NGX_HTTP_SSL) -typedef struct { - ngx_connection_t *connection; /* original true connection */ - ngx_http_request_t *request; /* fake request */ - int exit_code; /* exit code for openssl's - set_cert_cb callback */ - unsigned done; /* :1 */ - unsigned aborted; /* :1 */ -} ngx_http_lua_ssl_cert_ctx_t; - - ngx_int_t ngx_http_lua_ssl_cert_handler_inline(ngx_http_request_t *r, ngx_http_lua_srv_conf_t *lscf, lua_State *L); diff --git a/src/ngx_http_lua_ssl_session_fetchby.c b/src/ngx_http_lua_ssl_session_fetchby.c new file mode 100644 index 0000000000..87b9f28170 --- /dev/null +++ b/src/ngx_http_lua_ssl_session_fetchby.c @@ -0,0 +1,592 @@ + +/* + * Copyright (C) Yichun Zhang (agentzh) + */ + + +#ifndef DDEBUG +#define DDEBUG 0 +#endif +#include "ddebug.h" + + +#if (NGX_HTTP_SSL) + + +#include "ngx_http_lua_cache.h" +#include "ngx_http_lua_initworkerby.h" +#include "ngx_http_lua_util.h" +#include "ngx_http_ssl_module.h" +#include "ngx_http_lua_contentby.h" +#include "ngx_http_lua_ssl_session_fetchby.h" +#include "ngx_http_lua_ssl.h" +#include "ngx_http_lua_directive.h" + + +/* Lua SSL cached session loading routines */ +static void ngx_http_lua_ssl_sess_fetch_done(void *data); +static void ngx_http_lua_ssl_sess_fetch_aborted(void *data); +static u_char *ngx_http_lua_log_ssl_sess_fetch_error(ngx_log_t *log, + u_char *buf, size_t len); +static ngx_int_t ngx_http_lua_ssl_sess_fetch_by_chunk(lua_State *L, + ngx_http_request_t *r); + + +/* load Lua code from a file for fetching cached SSL session */ +ngx_int_t +ngx_http_lua_ssl_sess_fetch_handler_file(ngx_http_request_t *r, + ngx_http_lua_srv_conf_t *lscf, lua_State *L) +{ + ngx_int_t rc; + + rc = ngx_http_lua_cache_loadfile(r->connection->log, L, + lscf->srv.ssl_sess_fetch_src.data, + lscf->srv.ssl_sess_fetch_src_key); + if (rc != NGX_OK) { + return rc; + } + + /* make sure we have a valid code chunk */ + ngx_http_lua_assert(lua_isfunction(L, -1)); + + return ngx_http_lua_ssl_sess_fetch_by_chunk(L, r); +} + + +/* load lua code from an inline snippet for fetching cached SSL session */ +ngx_int_t +ngx_http_lua_ssl_sess_fetch_handler_inline(ngx_http_request_t *r, + ngx_http_lua_srv_conf_t *lscf, lua_State *L) +{ + ngx_int_t rc; + + rc = ngx_http_lua_cache_loadbuffer(r->connection->log, L, + lscf->srv.ssl_sess_fetch_src.data, + lscf->srv.ssl_sess_fetch_src.len, + lscf->srv.ssl_sess_fetch_src_key, + "=ssl_session_fetch_by_lua_block"); + if (rc != NGX_OK) { + return rc; + } + + /* make sure we have a valid code chunk */ + ngx_http_lua_assert(lua_isfunction(L, -1)); + + return ngx_http_lua_ssl_sess_fetch_by_chunk(L, r); +} + + +char * +ngx_http_lua_ssl_sess_fetch_by_lua_block(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf) +{ + char *rv; + ngx_conf_t save; + + save = *cf; + cf->handler = ngx_http_lua_ssl_sess_fetch_by_lua; + cf->handler_conf = conf; + + rv = ngx_http_lua_conf_lua_block_parse(cf, cmd); + + *cf = save; + + return rv; +} + + +/* conf parser for directive ssl_session_fetch_by_lua */ +char * +ngx_http_lua_ssl_sess_fetch_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf) +{ + u_char *p; + u_char *name; + ngx_str_t *value; + ngx_http_lua_srv_conf_t *lscf = conf; + + dd("enter"); + + /* must specifiy a content handler */ + if (cmd->post == NULL) { + return NGX_CONF_ERROR; + } + + if (lscf->srv.ssl_sess_fetch_handler) { + return "is duplicate"; + } + + if (ngx_http_lua_ssl_init(cf->log) != NGX_OK) { + return NGX_CONF_ERROR; + } + + value = cf->args->elts; + + lscf->srv.ssl_sess_fetch_handler = + (ngx_http_lua_srv_conf_handler_pt) cmd->post; + + if (cmd->post == ngx_http_lua_ssl_sess_fetch_handler_file) { + /* Lua code in an external file */ + + name = ngx_http_lua_rebase_path(cf->pool, value[1].data, + value[1].len); + if (name == NULL) { + return NGX_CONF_ERROR; + } + + lscf->srv.ssl_sess_fetch_src.data = name; + lscf->srv.ssl_sess_fetch_src.len = ngx_strlen(name); + + p = ngx_palloc(cf->pool, NGX_HTTP_LUA_FILE_KEY_LEN + 1); + if (p == NULL) { + return NGX_CONF_ERROR; + } + + lscf->srv.ssl_sess_fetch_src_key = p; + + p = ngx_copy(p, NGX_HTTP_LUA_FILE_TAG, NGX_HTTP_LUA_FILE_TAG_LEN); + p = ngx_http_lua_digest_hex(p, value[1].data, value[1].len); + *p = '\0'; + + } else { + /* inlined Lua code */ + + lscf->srv.ssl_sess_fetch_src = value[1]; + + p = ngx_palloc(cf->pool, NGX_HTTP_LUA_INLINE_KEY_LEN + 1); + if (p == NULL) { + return NGX_CONF_ERROR; + } + + lscf->srv.ssl_sess_fetch_src_key = p; + + p = ngx_copy(p, NGX_HTTP_LUA_INLINE_TAG, NGX_HTTP_LUA_INLINE_TAG_LEN); + p = ngx_http_lua_digest_hex(p, value[1].data, value[1].len); + *p = '\0'; + } + + return NGX_CONF_OK; +} + + +/* cached session fetching callback to be set with SSL_CTX_sess_set_get_cb */ +ngx_ssl_session_t * +ngx_http_lua_ssl_sess_fetch_handler(ngx_ssl_conn_t *ssl_conn, u_char *id, + int len, int *copy) +{ + lua_State *L; + ngx_int_t rc; + ngx_connection_t *c, *fc = NULL; + ngx_http_request_t *r = NULL; + ngx_pool_cleanup_t *cln; + ngx_http_connection_t *hc; + ngx_http_lua_ssl_ctx_t *cctx; + ngx_http_lua_srv_conf_t *lscf; + ngx_http_core_loc_conf_t *clcf; + + /* set copy to 0 as we expect OpenSSL to handle + * the memory of returned session */ + + *copy = 0; + + c = ngx_ssl_get_connection(ssl_conn); + + dd("c = %p", c); + + cctx = ngx_http_lua_ssl_get_ctx(c->ssl->connection); + + dd("ssl sess_fetch handler, sess_fetch-ctx=%p", cctx); + + if (cctx && cctx->entered_sess_fetch_handler) { + /* not the first time */ + + dd("here: %d", (int) cctx->entered_sess_fetch_handler); + + if (cctx->done) { + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, + "ssl_session_fetch_by_lua*: " + "sess get cb exit code: %d", + cctx->exit_code); + + dd("lua ssl sess_fetch done, finally"); + return cctx->session; + } + +#ifdef SSL_ERROR_PENDING_SESSION + return SSL_magic_pending_session_ptr(); +#else + ngx_log_error(NGX_LOG_CRIT, r->connection->log, 0, + "lua: cannot yield in sess get cb: " + "missing async sess get cb support in OpenSSL"); + return NULL; +#endif + } + + dd("first time"); + + hc = c->data; + + fc = ngx_http_lua_create_fake_connection(NULL); + if (fc == NULL) { + goto failed; + } + + fc->log->handler = ngx_http_lua_log_ssl_sess_fetch_error; + fc->log->data = fc; + + fc->addr_text = c->addr_text; + fc->listening = c->listening; + + r = ngx_http_lua_create_fake_request(fc); + if (r == NULL) { + goto failed; + } + + r->main_conf = hc->conf_ctx->main_conf; + r->srv_conf = hc->conf_ctx->srv_conf; + r->loc_conf = hc->conf_ctx->loc_conf; + + fc->log->file = c->log->file; + fc->log->log_level = c->log->log_level; + fc->ssl = c->ssl; + + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + +#if defined(nginx_version) && nginx_version >= 1003014 + +# if nginx_version >= 1009000 + + ngx_set_connection_log(fc, clcf->error_log); + +# else + + ngx_http_set_connection_log(fc, clcf->error_log); + +# endif + +#else + + fc->log->file = clcf->error_log->file; + + if (!(fc->log->log_level & NGX_LOG_DEBUG_CONNECTION)) { + fc->log->log_level = clcf->error_log->log_level; + } + +#endif + + if (cctx == NULL) { + cctx = ngx_pcalloc(c->pool, sizeof(ngx_http_lua_ssl_ctx_t)); + if (cctx == NULL) { + goto failed; /* error */ + } + } + + cctx->exit_code = 1; /* successful by default */ + cctx->connection = c; + cctx->request = r; + cctx->session_id.data = id; + cctx->session_id.len = len; + cctx->entered_sess_fetch_handler = 1; + cctx->done = 0; + + dd("setting cctx = %p", cctx); + + if (SSL_set_ex_data(c->ssl->connection, ngx_http_lua_ssl_ctx_index, cctx) + == 0) + { + ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "SSL_set_ex_data() failed"); + goto failed; + } + + lscf = ngx_http_get_module_srv_conf(r, ngx_http_lua_module); + + /* TODO honor lua_code_cache off */ + L = ngx_http_lua_get_lua_vm(r, NULL); + + c->log->action = "fetching SSL session by lua"; + + rc = lscf->srv.ssl_sess_fetch_handler(r, lscf, L); + + if (rc >= NGX_OK || rc == NGX_ERROR) { + cctx->done = 1; + + if (cctx->cleanup) { + *cctx->cleanup = NULL; + } + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, + "ssl_session_fetch_by_lua*: handler return value: %i, " + "sess get cb exit code: %d", rc, cctx->exit_code); + + c->log->action = "SSL handshaking"; + return cctx->session; + } + + /* rc == NGX_DONE */ + + cln = ngx_pool_cleanup_add(fc->pool, 0); + if (cln == NULL) { + goto failed; + } + + cln->handler = ngx_http_lua_ssl_sess_fetch_done; + cln->data = cctx; + + if (cctx->cleanup == NULL) { + /* we only want exactly one cleanup handler to be registered with the + * connection to clean up cctx when connection is aborted */ + cln = ngx_pool_cleanup_add(c->pool, 0); + if (cln == NULL) { + goto failed; + } + + cln->data = cctx; + cctx->cleanup = &cln->handler; + } + + *cctx->cleanup = ngx_http_lua_ssl_sess_fetch_aborted; + +#ifdef SSL_ERROR_PENDING_SESSION + return SSL_magic_pending_session_ptr(); +#else + ngx_log_error(NGX_LOG_CRIT, r->connection->log, 0, + "lua: cannot yield in sess get cb: " + "missing async sess get cb support in OpenSSL"); + + /* fall through to the "failed" label below */ +#endif + +failed: + + if (r && r->pool) { + ngx_http_lua_free_fake_request(r); + } + + if (fc) { + ngx_http_lua_close_fake_connection(fc); + } + + return NULL; +} + + +static void +ngx_http_lua_ssl_sess_fetch_done(void *data) +{ + ngx_connection_t *c; + ngx_http_lua_ssl_ctx_t *cctx = data; + + dd("lua ssl sess_fetch done"); + + if (cctx->aborted) { + return; + } + + ngx_http_lua_assert(cctx->done == 0); + + cctx->done = 1; + + if (cctx->cleanup) { + *cctx->cleanup = NULL; + } + + c = cctx->connection; + + c->log->action = "SSL handshaking"; + + ngx_post_event(c->write, &ngx_posted_events); +} + + +static void +ngx_http_lua_ssl_sess_fetch_aborted(void *data) +{ + ngx_http_lua_ssl_ctx_t *cctx = data; + + dd("lua ssl sess_fetch done"); + + if (cctx->done) { + /* completed successfully already */ + return; + } + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cctx->connection->log, 0, + "ssl_session_fetch_by_lua*: sess_fetch cb aborted"); + + cctx->aborted = 1; + cctx->request->connection->ssl = NULL; + + ngx_http_lua_finalize_fake_request(cctx->request, NGX_ERROR); +} + + +static u_char * +ngx_http_lua_log_ssl_sess_fetch_error(ngx_log_t *log, u_char *buf, size_t len) +{ + u_char *p; + ngx_connection_t *c; + + if (log->action) { + p = ngx_snprintf(buf, len, " while %s", log->action); + len -= p - buf; + buf = p; + } + + p = ngx_snprintf(buf, len, ", context: ssl_session_fetch_by_lua*"); + len -= p - buf; + buf = p; + + c = log->data; + + if (c->addr_text.len) { + p = ngx_snprintf(buf, len, ", client: %V", &c->addr_text); + len -= p - buf; + buf = p; + } + + if (c && c->listening && c->listening->addr_text.len) { + p = ngx_snprintf(buf, len, ", server: %V", &c->listening->addr_text); + buf = p; + } + + return buf; +} + + +/* initialize lua coroutine for fetching cached session */ +static ngx_int_t +ngx_http_lua_ssl_sess_fetch_by_chunk(lua_State *L, ngx_http_request_t *r) +{ + int co_ref; + ngx_int_t rc; + lua_State *co; + ngx_http_lua_ctx_t *ctx; + ngx_http_cleanup_t *cln; + + ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + + if (ctx == NULL) { + ctx = ngx_http_lua_create_ctx(r); + if (ctx == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + } else { + dd("reset ctx"); + ngx_http_lua_reset_ctx(r, L, ctx); + } + + ctx->entered_content_phase = 1; + + /* {{{ new coroutine to handle request */ + co = ngx_http_lua_new_thread(r, L, &co_ref); + + if (co == NULL) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "lua: failed to create new coroutine to handle request"); + + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + /* move code closure to new coroutine */ + lua_xmove(L, co, 1); + + /* set closure's env table to new coroutine's globals table */ + ngx_http_lua_get_globals_table(co); + lua_setfenv(co, -2); + + /* save nginx request in coroutine globals table */ + ngx_http_lua_set_req(co, r); + + ctx->cur_co_ctx = &ctx->entry_co_ctx; + ctx->cur_co_ctx->co = co; + ctx->cur_co_ctx->co_ref = co_ref; +#ifdef NGX_LUA_USE_ASSERT + ctx->cur_co_ctx->co_top = 1; +#endif + + /* register request cleanup hooks */ + if (ctx->cleanup == NULL) { + cln = ngx_http_cleanup_add(r, 0); + if (cln == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + cln->handler = ngx_http_lua_request_cleanup_handler; + cln->data = ctx; + ctx->cleanup = &cln->handler; + } + + ctx->context = NGX_HTTP_LUA_CONTEXT_SSL_SESS_FETCH; + + rc = ngx_http_lua_run_thread(L, r, ctx, 0); + + if (rc == NGX_ERROR || rc >= NGX_OK) { + /* do nothing */ + + } else if (rc == NGX_AGAIN) { + rc = ngx_http_lua_content_run_posted_threads(L, r, ctx, 0); + + } else if (rc == NGX_DONE) { + rc = ngx_http_lua_content_run_posted_threads(L, r, ctx, 1); + + } else { + rc = NGX_OK; + } + + ngx_http_lua_finalize_request(r, rc); + return rc; +} + + +#ifndef NGX_LUA_NO_FFI_API + +/* de-serialized a SSL session and set it back to the request at lua context */ +int +ngx_http_lua_ffi_ssl_set_serialized_session(ngx_http_request_t *r, + const unsigned char *data, int len, char **err) +{ + u_char *p; + u_char buf[NGX_SSL_MAX_SESSION_SIZE]; + ngx_ssl_conn_t *ssl_conn; + ngx_connection_t *c; + ngx_ssl_session_t *session = NULL; + ngx_http_lua_ssl_ctx_t *cctx; + + c = r->connection; + + if (c == NULL || c->ssl == NULL) { + *err = "bad request"; + return NGX_ERROR; + } + + ssl_conn = c->ssl->connection; + if (ssl_conn == NULL) { + *err = "bad ssl conn"; + return NGX_ERROR; + } + + ngx_memcpy(buf, data, len); + p = buf; + session = d2i_SSL_SESSION(NULL, (const unsigned char **)&p, len); + if (session == NULL) { + ERR_clear_error(); + *err = "failed to de-serialize session"; + return NGX_ERROR; + } + + cctx = ngx_http_lua_ssl_get_ctx(c->ssl->connection); + if (cctx == NULL) { + *err = "bad lua context"; + return NGX_ERROR; + } + + cctx->session = session; + + return NGX_OK; +} + +#endif /* NGX_LUA_NO_FFI_API */ + + +#endif /* NGX_HTTP_SSL */ diff --git a/src/ngx_http_lua_ssl_session_fetchby.h b/src/ngx_http_lua_ssl_session_fetchby.h new file mode 100644 index 0000000000..e172278227 --- /dev/null +++ b/src/ngx_http_lua_ssl_session_fetchby.h @@ -0,0 +1,32 @@ + +/* + * Copyright (C) Yichun Zhang (agentzh) + */ + + +#ifndef _NGX_HTTP_LUA_SSL_SESSION_FETCHBY_H_INCLUDED_ +#define _NGX_HTTP_LUA_SSL_SESSION_FETCHBY_H_INCLUDED_ + + +#include "ngx_http_lua_common.h" + + +ngx_int_t ngx_http_lua_ssl_sess_fetch_handler_inline(ngx_http_request_t *r, + ngx_http_lua_srv_conf_t *lscf, lua_State *L); + +ngx_int_t ngx_http_lua_ssl_sess_fetch_handler_file(ngx_http_request_t *r, + ngx_http_lua_srv_conf_t *lscf, lua_State *L); + +char *ngx_http_lua_ssl_sess_fetch_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); + +char *ngx_http_lua_ssl_sess_fetch_by_lua_block(ngx_conf_t *cf, + ngx_command_t *cmd, void *conf); + +ngx_ssl_session_t *ngx_http_lua_ssl_sess_fetch_handler( + ngx_ssl_conn_t *ssl_conn, u_char *id, int len, int *copy); + + +#endif /* _NGX_HTTP_LUA_SSL_SESSION_FETCHBY_H_INCLUDED_ */ + +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_ssl_session_storeby.c b/src/ngx_http_lua_ssl_session_storeby.c new file mode 100644 index 0000000000..b5596bc71c --- /dev/null +++ b/src/ngx_http_lua_ssl_session_storeby.c @@ -0,0 +1,602 @@ + +/* + * Copyright (C) Yichun Zhang (agentzh) + */ + + +#ifndef DDEBUG +#define DDEBUG 0 +#endif +#include "ddebug.h" + + +#if (NGX_HTTP_SSL) + + +#include "ngx_http_lua_cache.h" +#include "ngx_http_lua_initworkerby.h" +#include "ngx_http_lua_util.h" +#include "ngx_http_ssl_module.h" +#include "ngx_http_lua_contentby.h" +#include "ngx_http_lua_ssl_session_storeby.h" +#include "ngx_http_lua_ssl.h" +#include "ngx_http_lua_directive.h" + + +/* Lua SSL new session store routines */ +static u_char *ngx_http_lua_log_ssl_sess_store_error(ngx_log_t *log, + u_char *buf, size_t len); +static ngx_int_t ngx_http_lua_ssl_sess_store_by_chunk(lua_State *L, + ngx_http_request_t *r); + + +/* load Lua code from a file for caching new SSL session. */ +ngx_int_t +ngx_http_lua_ssl_sess_store_handler_file(ngx_http_request_t *r, + ngx_http_lua_srv_conf_t *lscf, lua_State *L) +{ + ngx_int_t rc; + + rc = ngx_http_lua_cache_loadfile(r->connection->log, L, + lscf->srv.ssl_sess_store_src.data, + lscf->srv.ssl_sess_store_src_key); + if (rc != NGX_OK) { + return rc; + } + + /* make sure we have a valid code chunk */ + ngx_http_lua_assert(lua_isfunction(L, -1)); + + return ngx_http_lua_ssl_sess_store_by_chunk(L, r); +} + + +/* load lua code from an inline snippet for caching new SSL session */ +ngx_int_t +ngx_http_lua_ssl_sess_store_handler_inline(ngx_http_request_t *r, + ngx_http_lua_srv_conf_t *lscf, lua_State *L) +{ + ngx_int_t rc; + + rc = ngx_http_lua_cache_loadbuffer(r->connection->log, L, + lscf->srv.ssl_sess_store_src.data, + lscf->srv.ssl_sess_store_src.len, + lscf->srv.ssl_sess_store_src_key, + "=ssl_session_store_by_lua_block"); + if (rc != NGX_OK) { + return rc; + } + + /* make sure we have a valid code chunk */ + ngx_http_lua_assert(lua_isfunction(L, -1)); + + return ngx_http_lua_ssl_sess_store_by_chunk(L, r); +} + + +char * +ngx_http_lua_ssl_sess_store_by_lua_block(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf) +{ + char *rv; + ngx_conf_t save; + + save = *cf; + cf->handler = ngx_http_lua_ssl_sess_store_by_lua; + cf->handler_conf = conf; + + rv = ngx_http_lua_conf_lua_block_parse(cf, cmd); + + *cf = save; + + return rv; +} + + +/* conf parser for directive ssl_session_store_by_lua */ +char * +ngx_http_lua_ssl_sess_store_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf) +{ + u_char *p; + u_char *name; + ngx_str_t *value; + ngx_http_lua_srv_conf_t *lscf = conf; + + dd("enter"); + + /* must specifiy a content handler */ + if (cmd->post == NULL) { + return NGX_CONF_ERROR; + } + + if (lscf->srv.ssl_sess_store_handler) { + return "is duplicate"; + } + + if (ngx_http_lua_ssl_init(cf->log) != NGX_OK) { + return NGX_CONF_ERROR; + } + + value = cf->args->elts; + + lscf->srv.ssl_sess_store_handler = + (ngx_http_lua_srv_conf_handler_pt) cmd->post; + + if (cmd->post == ngx_http_lua_ssl_sess_store_handler_file) { + /* Lua code in an external file */ + + name = ngx_http_lua_rebase_path(cf->pool, value[1].data, + value[1].len); + if (name == NULL) { + return NGX_CONF_ERROR; + } + + lscf->srv.ssl_sess_store_src.data = name; + lscf->srv.ssl_sess_store_src.len = ngx_strlen(name); + + p = ngx_palloc(cf->pool, NGX_HTTP_LUA_FILE_KEY_LEN + 1); + if (p == NULL) { + return NGX_CONF_ERROR; + } + + lscf->srv.ssl_sess_store_src_key = p; + + p = ngx_copy(p, NGX_HTTP_LUA_FILE_TAG, NGX_HTTP_LUA_FILE_TAG_LEN); + p = ngx_http_lua_digest_hex(p, value[1].data, value[1].len); + *p = '\0'; + + } else { + /* inlined Lua code */ + + lscf->srv.ssl_sess_store_src = value[1]; + + p = ngx_palloc(cf->pool, NGX_HTTP_LUA_INLINE_KEY_LEN + 1); + if (p == NULL) { + return NGX_CONF_ERROR; + } + + lscf->srv.ssl_sess_store_src_key = p; + + p = ngx_copy(p, NGX_HTTP_LUA_INLINE_TAG, NGX_HTTP_LUA_INLINE_TAG_LEN); + p = ngx_http_lua_digest_hex(p, value[1].data, value[1].len); + *p = '\0'; + } + + return NGX_CONF_OK; +} + + +/* callback for new session caching, to be set with SSL_CTX_sess_set_new_cb */ +int +ngx_http_lua_ssl_sess_store_handler(ngx_ssl_conn_t *ssl_conn, + ngx_ssl_session_t *sess) +{ + lua_State *L; + ngx_int_t rc; + ngx_connection_t *c, *fc = NULL; + ngx_http_request_t *r = NULL; + ngx_http_connection_t *hc; + ngx_http_lua_ssl_ctx_t *cctx; + ngx_http_lua_srv_conf_t *lscf; + ngx_http_core_loc_conf_t *clcf; + + c = ngx_ssl_get_connection(ssl_conn); + + dd("c = %p", c); + + cctx = ngx_http_lua_ssl_get_ctx(c->ssl->connection); + + dd("ssl sess_store handler, sess_store-ctx=%p", cctx); + + hc = c->data; + + fc = ngx_http_lua_create_fake_connection(NULL); + if (fc == NULL) { + goto failed; + } + + fc->log->handler = ngx_http_lua_log_ssl_sess_store_error; + fc->log->data = fc; + + fc->addr_text = c->addr_text; + fc->listening = c->listening; + + r = ngx_http_lua_create_fake_request(fc); + if (r == NULL) { + goto failed; + } + + r->main_conf = hc->conf_ctx->main_conf; + r->srv_conf = hc->conf_ctx->srv_conf; + r->loc_conf = hc->conf_ctx->loc_conf; + + fc->log->file = c->log->file; + fc->log->log_level = c->log->log_level; + fc->ssl = c->ssl; + + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + +#if defined(nginx_version) && nginx_version >= 1003014 + +# if nginx_version >= 1009000 + + ngx_set_connection_log(fc, clcf->error_log); + +# else + + ngx_http_set_connection_log(fc, clcf->error_log); + +# endif + +#else + + fc->log->file = clcf->error_log->file; + + if (!(fc->log->log_level & NGX_LOG_DEBUG_CONNECTION)) { + fc->log->log_level = clcf->error_log->log_level; + } + +#endif + + if (cctx == NULL) { + cctx = ngx_pcalloc(c->pool, sizeof(ngx_http_lua_ssl_ctx_t)); + if (cctx == NULL) { + goto failed; /* error */ + } + } + + cctx->connection = c; + cctx->request = r; + cctx->session = sess; + cctx->session_id.data = sess->session_id; + cctx->session_id.len = sess->session_id_length; + cctx->done = 0; + + dd("setting cctx"); + + if (SSL_set_ex_data(c->ssl->connection, ngx_http_lua_ssl_ctx_index, cctx) + == 0) + { + ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "SSL_set_ex_data() failed"); + goto failed; + } + + lscf = ngx_http_get_module_srv_conf(r, ngx_http_lua_module); + + /* TODO honor lua_code_cache off */ + L = ngx_http_lua_get_lua_vm(r, NULL); + + c->log->action = "storing SSL session by lua"; + + rc = lscf->srv.ssl_sess_store_handler(r, lscf, L); + + if (rc >= NGX_OK || rc == NGX_ERROR) { + cctx->done = 1; + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, + "ssl_session_store_by_lua*: handler return value: %i, " + "sess new cb exit code: %d", rc, cctx->exit_code); + + c->log->action = "SSL handshaking"; + + /* Return value is a flag indicating whether the passed-in session + * has been freed by this callback; always return 0 so OpenSSL will + * free the session. Nginx's own session caching logic has the same + * practice. */ + return 0; + } + + /* impossible to reach here */ + ngx_http_lua_assert(0); + +failed: + + if (r && r->pool) { + ngx_http_lua_free_fake_request(r); + } + + if (fc) { + ngx_http_lua_close_fake_connection(fc); + } + + return 0; +} + + +static u_char * +ngx_http_lua_log_ssl_sess_store_error(ngx_log_t *log, u_char *buf, size_t len) +{ + u_char *p; + ngx_connection_t *c; + + if (log->action) { + p = ngx_snprintf(buf, len, " while %s", log->action); + len -= p - buf; + buf = p; + } + + p = ngx_snprintf(buf, len, ", context: ssl_session_store_by_lua*"); + len -= p - buf; + buf = p; + + c = log->data; + + if (c->addr_text.len) { + p = ngx_snprintf(buf, len, ", client: %V", &c->addr_text); + len -= p - buf; + buf = p; + } + + if (c && c->listening && c->listening->addr_text.len) { + p = ngx_snprintf(buf, len, ", server: %V", &c->listening->addr_text); + buf = p; + } + + return buf; +} + + +/* initialize lua coroutine for caching new SSL session */ +static ngx_int_t +ngx_http_lua_ssl_sess_store_by_chunk(lua_State *L, ngx_http_request_t *r) +{ + size_t len; + u_char *err_msg; + ngx_int_t rc; + ngx_http_lua_ctx_t *ctx; + + ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + + if (ctx == NULL) { + ctx = ngx_http_lua_create_ctx(r); + if (ctx == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + } else { + dd("reset ctx"); + ngx_http_lua_reset_ctx(r, L, ctx); + } + + ctx->entered_content_phase = 1; + ctx->context = NGX_HTTP_LUA_CONTEXT_SSL_SESS_STORE; + + /* init nginx context in Lua VM */ + ngx_http_lua_set_req(L, r); + ngx_http_lua_create_new_globals_table(L, 0 /* narr */, 1 /* nrec */); + + /* {{{ make new env inheriting main thread's globals table */ + lua_createtable(L, 0, 1 /* nrec */); /* the metatable for the new env */ + ngx_http_lua_get_globals_table(L); + lua_setfield(L, -2, "__index"); + lua_setmetatable(L, -2); /* setmetatable({}, {__index = _G}) */ + /* }}} */ + + lua_setfenv(L, -2); /* set new running env for the code closure */ + + lua_pushcfunction(L, ngx_http_lua_traceback); + lua_insert(L, 1); /* put it under chunk and args */ + + /* protected call user code */ + rc = lua_pcall(L, 0, 1, 1); + + lua_remove(L, 1); /* remove traceback function */ + + dd("rc == %d", (int) rc); + + if (rc != 0) { + /* error occured when running loaded code */ + err_msg = (u_char *) lua_tolstring(L, -1, &len); + + if (err_msg == NULL) { + err_msg = (u_char *) "unknown reason"; + len = sizeof("unknown reason") - 1; + } + + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "failed to run session_store_by_lua*: %*s", len, err_msg); + + lua_settop(L, 0); /* clear remaining elems on stack */ + ngx_http_lua_finalize_request(r, rc); + + return NGX_ERROR; + } + + lua_settop(L, 0); /* clear remaining elems on stack */ + ngx_http_lua_finalize_request(r, rc); + return rc; +} + + +#ifndef NGX_LUA_NO_FFI_API + +/* serialize a session from lua context into buf. + * the memory allocation of buf should be handled externally. */ +int +ngx_http_lua_ffi_ssl_get_serialized_session(ngx_http_request_t *r, + u_char *buf, char **err) +{ + ngx_ssl_conn_t *ssl_conn; + ngx_connection_t *c; + ngx_ssl_session_t *session; + ngx_http_lua_ssl_ctx_t *cctx; + + c = r->connection; + + if (c == NULL || c->ssl == NULL) { + *err = "bad request"; + return NGX_ERROR; + } + + ssl_conn = c->ssl->connection; + if (ssl_conn == NULL) { + *err = "bad ssl conn"; + return NGX_ERROR; + } + + dd("get cctx session"); + + cctx = ngx_http_lua_ssl_get_ctx(c->ssl->connection); + if (cctx == NULL) { + *err = "bad lua context"; + return NGX_ERROR; + } + + session = cctx->session; + if (session == NULL) { + *err = "bad session in lua context"; + return NGX_ERROR; + } + + if (i2d_SSL_SESSION(session, &buf) == 0) { + *err = "i2d_SSL_SESSION() failed"; + return NGX_ERROR; + } + + return NGX_OK; +} + + +/* return the size of serialized session. */ +int +ngx_http_lua_ffi_ssl_get_serialized_session_size(ngx_http_request_t *r, + char **err) +{ + int len; + ngx_ssl_conn_t *ssl_conn; + ngx_connection_t *c; + ngx_ssl_session_t *session; + ngx_http_lua_ssl_ctx_t *cctx; + + c = r->connection; + + if (c == NULL || c->ssl == NULL) { + *err = "bad request"; + return NGX_ERROR; + } + + ssl_conn = c->ssl->connection; + if (ssl_conn == NULL) { + *err = "bad ssl conn"; + return NGX_ERROR; + } + + dd("get cctx session size"); + cctx = ngx_http_lua_ssl_get_ctx(c->ssl->connection); + if (cctx == NULL) { + *err = "bad lua context"; + return NGX_ERROR; + } + + session = cctx->session; + if (session == NULL) { + *err = "bad session in lua context"; + return NGX_ERROR; + } + + len = i2d_SSL_SESSION(session, NULL); + if (len == 0) { + *err = "i2d_SSL_SESSION() failed"; + return NGX_ERROR; + } + + return len; +} + + +/* serialize the session id from lua context into buf. + * the memory allocation of buf should be handled externally. */ +int +ngx_http_lua_ffi_ssl_get_session_id(ngx_http_request_t *r, + u_char *buf, char **err) +{ + int id_len; + u_char *id; + ngx_ssl_conn_t *ssl_conn; + ngx_connection_t *c; + ngx_http_lua_ssl_ctx_t *cctx; + + c = r->connection; + + if (c == NULL || c->ssl == NULL) { + *err = "bad request"; + return NGX_ERROR; + } + + ssl_conn = c->ssl->connection; + if (ssl_conn == NULL) { + *err = "bad ssl conn"; + return NGX_ERROR; + } + + dd("get cctx session"); + cctx = ngx_http_lua_ssl_get_ctx(c->ssl->connection); + if (cctx == NULL) { + *err = "bad lua context"; + return NGX_ERROR; + } + + id = cctx->session_id.data; + if (id == NULL) { + *err = "uninitialized session id in lua context"; + return NGX_ERROR; + } + + id_len = cctx->session_id.len; + if (id_len == 0) { + *err = "uninitialized session id len in lua context"; + return NGX_ERROR; + } + + ngx_hex_dump(buf, id, id_len); + + return NGX_OK; +} + + +/* return the size of serialized session id. */ +int +ngx_http_lua_ffi_ssl_get_session_id_size(ngx_http_request_t *r, + char **err) +{ + ngx_ssl_conn_t *ssl_conn; + ngx_connection_t *c; + ngx_http_lua_ssl_ctx_t *cctx; + + c = r->connection; + + if (c == NULL || c->ssl == NULL) { + *err = "bad request"; + return NGX_ERROR; + } + + ssl_conn = c->ssl->connection; + if (ssl_conn == NULL) { + *err = "bad ssl conn"; + return NGX_ERROR; + } + + dd("get cctx session"); + cctx = ngx_http_lua_ssl_get_ctx(c->ssl->connection); + if (cctx == NULL) { + *err = "bad lua context"; + return NGX_ERROR; + } + + if (cctx->session_id.len == 0) { + *err = "uninitialized session id len in lua context"; + return NGX_ERROR; + } + + /* since the session id will be hex dumped to serialize, the serialized + * session will be twice the size of the session id: each byte will be a + * 2-digit hex value. */ + + return 2 * cctx->session_id.len; +} + +#endif /* NGX_LUA_NO_FFI_API */ + + +#endif /* NGX_HTTP_SSL */ diff --git a/src/ngx_http_lua_ssl_session_storeby.h b/src/ngx_http_lua_ssl_session_storeby.h new file mode 100644 index 0000000000..53ae99e1fe --- /dev/null +++ b/src/ngx_http_lua_ssl_session_storeby.h @@ -0,0 +1,32 @@ + +/* + * Copyright (C) Yichun Zhang (agentzh) + */ + + +#ifndef _NGX_HTTP_LUA_SSL_SESSION_STOREBY_H_INCLUDED_ +#define _NGX_HTTP_LUA_SSL_SESSION_STOREBY_H_INCLUDED_ + + +#include "ngx_http_lua_common.h" + + +ngx_int_t ngx_http_lua_ssl_sess_store_handler_inline(ngx_http_request_t *r, + ngx_http_lua_srv_conf_t *lscf, lua_State *L); + +ngx_int_t ngx_http_lua_ssl_sess_store_handler_file(ngx_http_request_t *r, + ngx_http_lua_srv_conf_t *lscf, lua_State *L); + +char *ngx_http_lua_ssl_sess_store_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); + +char *ngx_http_lua_ssl_sess_store_by_lua_block(ngx_conf_t *cf, + ngx_command_t *cmd, void *conf); + +int ngx_http_lua_ssl_sess_store_handler(ngx_ssl_conn_t *ssl_conn, + ngx_ssl_session_t *sess); + + +#endif /* _NGX_HTTP_LUA_SSL_SESSION_STOREBY_H_INCLUDED_ */ + +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index 76e6f9595a..2daaf07123 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -50,6 +50,7 @@ #include "ngx_http_lua_worker.h" #include "ngx_http_lua_socket_tcp.h" #include "ngx_http_lua_ssl_certby.h" +#include "ngx_http_lua_ssl.h" #if 1 @@ -3553,8 +3554,7 @@ ngx_http_lua_finalize_fake_request(ngx_http_request_t *r, ngx_int_t rc) ngx_connection_t *c; #if (NGX_HTTP_SSL) ngx_ssl_conn_t *ssl_conn; - - ngx_http_lua_ssl_cert_ctx_t *cctx; + ngx_http_lua_ssl_ctx_t *cctx; #endif c = r->connection; diff --git a/src/ngx_http_lua_util.h b/src/ngx_http_lua_util.h index f0e8923c24..a37852f27e 100644 --- a/src/ngx_http_lua_util.h +++ b/src/ngx_http_lua_util.h @@ -87,6 +87,10 @@ extern char ngx_http_lua_headers_metatable_key; : (c) == NGX_HTTP_LUA_CONTEXT_INIT_WORKER ? "init_worker_by_lua*" \ : (c) == NGX_HTTP_LUA_CONTEXT_BALANCER ? "balancer_by_lua*" \ : (c) == NGX_HTTP_LUA_CONTEXT_SSL_CERT ? "ssl_certificate_by_lua*" \ + : (c) == NGX_HTTP_LUA_CONTEXT_SSL_SESS_STORE ? \ + "ssl_session_store_by_lua*" \ + : (c) == NGX_HTTP_LUA_CONTEXT_SSL_SESS_FETCH ? \ + "ssl_session_fetch_by_lua*" \ : "(unknown)") @@ -433,7 +437,6 @@ ngx_http_lua_get_flush_chain(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx) extern ngx_uint_t ngx_http_lua_location_hash; extern ngx_uint_t ngx_http_lua_content_length_hash; -extern int ngx_http_lua_ssl_ctx_index; #endif /* _NGX_HTTP_LUA_UTIL_H_INCLUDED_ */ diff --git a/t/142-ssl-session-store.t b/t/142-ssl-session-store.t new file mode 100644 index 0000000000..da84a8dfd5 --- /dev/null +++ b/t/142-ssl-session-store.t @@ -0,0 +1,750 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use Test::Nginx::Socket::Lua; +use Cwd qw(abs_path realpath); +use File::Basename; + +repeat_each(3); + +plan tests => repeat_each() * (blocks() * 6 + 2); + +$ENV{TEST_NGINX_HTML_DIR} ||= html_dir(); + +$ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211; +$ENV{TEST_NGINX_RESOLVER} ||= '8.8.8.8'; +$ENV{TEST_NGINX_CERT_DIR} ||= dirname(realpath(abs_path(__FILE__))); + +#log_level 'warn'; +log_level 'debug'; + +no_long_string(); +#no_diff(); + +run_tests(); + +__DATA__ + +=== TEST 1: simple logging +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + server_name test.com; + ssl_session_store_by_lua_block { print("ssl session store by lua is running!") } + ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; + ssl_protocols SSLv3; + + server_tokens off; + } +--- config + server_tokens off; + resolver $TEST_NGINX_RESOLVER; + lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + + content_by_lua_block { + do + local sock = ngx.socket.tcp() + + sock:settimeout(5000) + + local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local sess, err = sock:sslhandshake(nil, "test.com", true) + if not sess then + ngx.say("failed to do SSL handshake: ", err) + return + end + + ngx.say("ssl handshake: ", type(sess)) + + local ok, err = sock:close() + ngx.say("close: ", ok, " ", err) + end -- do + -- collectgarbage() + } + } + +--- request +GET /t +--- response_body +connected: 1 +ssl handshake: userdata +close: 1 nil + +--- error_log +lua ssl server name: "test.com" +ssl_session_store_by_lua_block:1: ssl session store by lua is running! + +--- no_error_log +[error] +[alert] + + + +=== TEST 2: sleep is not allowed +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + server_name test.com; + ssl_session_store_by_lua_block { + local begin = ngx.now() + ngx.sleep(0.1) + print("elapsed in ssl store session by lua: ", ngx.now() - begin) + } + ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; + ssl_protocols SSLv3; + + server_tokens off; + } +--- config + server_tokens off; + resolver $TEST_NGINX_RESOLVER; + lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + + content_by_lua_block { + do + local sock = ngx.socket.tcp() + + sock:settimeout(5000) + + local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local sess, err = sock:sslhandshake(nil, "test.com", true) + if not sess then + ngx.say("failed to do SSL handshake: ", err) + return + end + + ngx.say("ssl handshake: ", type(sess)) + + local ok, err = sock:close() + ngx.say("close: ", ok, " ", err) + end -- do + -- collectgarbage() + } + } + +--- request +GET /t +--- response_body +connected: 1 +ssl handshake: userdata +close: 1 nil + +--- error_log +lua ssl server name: "test.com" +API disabled in the context of ssl_session_store_by_lua* + +--- no_error_log +[alert] +[emerg] + + + +=== TEST 3: timer +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + server_name test.com; + ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; + ssl_session_store_by_lua_block { + local function f() + print("my timer run!") + end + local ok, err = ngx.timer.at(0, f) + if not ok then + ngx.log(ngx.ERR, "failed to create timer: ", err) + return + end + } + ssl_protocols SSLv3; + + server_tokens off; + } +--- config + server_tokens off; + resolver $TEST_NGINX_RESOLVER; + lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + + content_by_lua_block { + do + local sock = ngx.socket.tcp() + + sock:settimeout(5000) + + local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local sess, err = sock:sslhandshake(nil, "test.com", true) + if not sess then + ngx.say("failed to do SSL handshake: ", err) + return + end + + ngx.say("ssl handshake: ", type(sess)) + + local ok, err = sock:close() + ngx.say("close: ", ok, " ", err) + end -- do + -- collectgarbage() + } + } + +--- request +GET /t +--- response_body +connected: 1 +ssl handshake: userdata +close: 1 nil + +--- error_log +lua ssl server name: "test.com" +my timer run! + +--- no_error_log +[error] +[alert] + + + +=== TEST 4: cosocket is not allowed +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + server_name test.com; + ssl_session_store_by_lua_block { + local sock = ngx.socket.tcp() + + sock:settimeout(5000) + + local ok, err = sock:connect("127.0.0.1", $TEST_NGINX_MEMCACHED_PORT) + if not ok then + ngx.log(ngx.ERR, "failed to connect to memc: ", err) + return + end + + local bytes, err = sock:send("flush_all\\r\\n") + if not bytes then + ngx.log(ngx.ERR, "failed to send flush_all command: ", err) + return + end + + local res, err = sock:receive() + if not res then + ngx.log(ngx.ERR, "failed to receive memc reply: ", err) + return + end + + print("received memc reply: ", res) + } + + ssl_protocols SSLv3; + ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; + + server_tokens off; + } +--- config + server_tokens off; + resolver $TEST_NGINX_RESOLVER; + lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + + content_by_lua_block { + do + local sock = ngx.socket.tcp() + + sock:settimeout(5000) + + local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local sess, err = sock:sslhandshake(nil, "test.com", true) + if not sess then + ngx.say("failed to do SSL handshake: ", err) + return + end + + ngx.say("ssl handshake: ", type(sess)) + + local ok, err = sock:close() + ngx.say("close: ", ok, " ", err) + end -- do + -- collectgarbage() + } + } + +--- request +GET /t +--- response_body +connected: 1 +ssl handshake: userdata +close: 1 nil + +--- error_log +lua ssl server name: "test.com" +API disabled in the context of ssl_session_store_by_lua* + +--- no_error_log +[alert] +[emerg] + + + +=== TEST 5: ngx.exit(0) - no yield +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + server_name test.com; + ssl_session_store_by_lua_block { + ngx.exit(0) + } + ssl_protocols SSLv3; + ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; + + server_tokens off; + } +--- config + server_tokens off; + resolver $TEST_NGINX_RESOLVER; + lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + lua_ssl_verify_depth 3; + + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + + content_by_lua_block { + do + local sock = ngx.socket.tcp() + + sock:settimeout(5000) + + local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local sess, err = sock:sslhandshake(package.loaded.session, "test.com", true) + if not sess then + ngx.say("failed to do SSL handshake: ", err) + return + end + + ngx.say("ssl handshake: ", type(sess)) + + package.loaded.session = sess + + local ok, err = sock:close() + ngx.say("close: ", ok, " ", err) + end -- do + -- collectgarbage() + } + } + +--- request +GET /t +--- response_body +connected: 1 +ssl handshake: userdata +close: 1 nil + +--- error_log +lua exit with code 0 + +--- no_error_log +[error] +[alert] +[emerg] + + + +=== TEST 6: ngx.exit(ngx.ERROR) - no yield +ngx.exit does not yield and the error code is eaten. +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + server_name test.com; + ssl_session_store_by_lua_block { + ngx.exit(ngx.ERROR) + } + ssl_protocols SSLv3; + ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; + + server_tokens off; + } +--- config + server_tokens off; + resolver $TEST_NGINX_RESOLVER; + lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + lua_ssl_verify_depth 3; + + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + + content_by_lua_block { + do + local sock = ngx.socket.tcp() + + sock:settimeout(5000) + + local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local sess, err = sock:sslhandshake(package.loaded.session, "test.com", true) + if not sess then + ngx.say("failed to do SSL handshake: ", err) + return + end + + ngx.say("ssl handshake: ", type(sess)) + + package.loaded.session = sess + + local ok, err = sock:close() + ngx.say("close: ", ok, " ", err) + end -- do + -- collectgarbage() + } + } + +--- request +GET /t +--- response_body +connected: 1 +ssl handshake: userdata +close: 1 nil + +--- error_log +lua exit with code -1 +ssl_session_store_by_lua*: handler return value: 0, sess new cb exit code: 0 + +--- no_error_log +[error] +[alert] +[emerg] + + + +=== TEST 7: lua exception - no yield +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + server_name test.com; + ssl_session_store_by_lua_block { + error("bad bad bad") + ngx.log(ngx.ERR, "should never reached here...") + } + ssl_protocols SSLv3; + ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; + + server_tokens off; + } +--- config + server_tokens off; + resolver $TEST_NGINX_RESOLVER; + lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + lua_ssl_verify_depth 3; + + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + + content_by_lua_block { + do + local sock = ngx.socket.tcp() + + sock:settimeout(5000) + + local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local sess, err = sock:sslhandshake(nil, "test.com", true) + if not sess then + ngx.say("failed to do SSL handshake: ", err) + return + end + + ngx.say("ssl handshake: ", type(sess)) + + local ok, err = sock:close() + ngx.say("close: ", ok, " ", err) + end -- do + } + } + +--- request +GET /t +--- response_body +connected: 1 +ssl handshake: userdata +close: 1 nil + +--- error_log +failed to run session_store_by_lua*: ssl_session_store_by_lua_block:2: bad bad bad + +--- no_error_log +should never reached here +[alert] +[emerg] + + + +=== TEST 8: get phase +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + server_name test.com; + ssl_session_store_by_lua_block { + print("get_phase: ", ngx.get_phase()) + } + ssl_protocols SSLv3; + ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; + + server_tokens off; + } +--- config + server_tokens off; + resolver $TEST_NGINX_RESOLVER; + lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + lua_ssl_verify_depth 3; + + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + + content_by_lua_block { + do + local sock = ngx.socket.tcp() + + sock:settimeout(5000) + + local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local sess, err = sock:sslhandshake(nil, "test.com", true) + if not sess then + ngx.say("failed to do SSL handshake: ", err) + return + end + + ngx.say("ssl handshake: ", type(sess)) + + local ok, err = sock:close() + ngx.say("close: ", ok, " ", err) + end -- do + } + } + +--- request +GET /t +--- response_body +connected: 1 +ssl handshake: userdata +close: 1 nil + +--- error_log +get_phase: ssl_session_store + +--- no_error_log +[alert] +[emerg] +[error] + + + +=== TEST 9: inter-operation with ssl_certificate_by_lua +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + server_name test.com; + ssl_certificate_by_lua_block { + local begin = ngx.now() + ngx.sleep(0.1) + print("elapsed in ssl cert by lua: ", ngx.now() - begin) + } + ssl_session_store_by_lua_block { print("ssl store session by lua is running!") } + ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; + ssl_protocols SSLv3; + + server_tokens off; + } +--- config + server_tokens off; + resolver $TEST_NGINX_RESOLVER; + lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + + content_by_lua_block { + do + local sock = ngx.socket.tcp() + + sock:settimeout(5000) + + local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local sess, err = sock:sslhandshake(nil, "test.com", true) + if not sess then + ngx.say("failed to do SSL handshake: ", err) + return + end + + ngx.say("ssl handshake: ", type(sess)) + + local ok, err = sock:close() + ngx.say("close: ", ok, " ", err) + end -- do + -- collectgarbage() + } + } + +--- request +GET /t +--- response_body +connected: 1 +ssl handshake: userdata +close: 1 nil + +--- error_log eval +[ +'lua ssl server name: "test.com"', +qr/elapsed in ssl cert by lua: 0.(?:09|1[01])\d+,/, +'ssl_session_store_by_lua_block:1: ssl store session by lua is running!', +] + +--- no_error_log +[error] +[alert] + + + +=== TEST 10: simple logging (by file) +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + server_name test.com; + ssl_session_store_by_lua_file html/a.lua; + ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; + ssl_protocols SSLv3; + + server_tokens off; + } +--- config + server_tokens off; + resolver $TEST_NGINX_RESOLVER; + lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + + content_by_lua_block { + do + local sock = ngx.socket.tcp() + + sock:settimeout(5000) + + local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local sess, err = sock:sslhandshake(nil, "test.com", true) + if not sess then + ngx.say("failed to do SSL handshake: ", err) + return + end + + ngx.say("ssl handshake: ", type(sess)) + + local ok, err = sock:close() + ngx.say("close: ", ok, " ", err) + end -- do + -- collectgarbage() + } + } + +--- user_files +>>> a.lua +print("ssl store session by lua is running!") + +--- request +GET /t +--- response_body +connected: 1 +ssl handshake: userdata +close: 1 nil + +--- error_log +lua ssl server name: "test.com" +a.lua:1: ssl store session by lua is running! + +--- no_error_log +[error] +[alert] diff --git a/t/143-ssl-sesison-fetch.t b/t/143-ssl-sesison-fetch.t new file mode 100644 index 0000000000..ef4b2f3eb3 --- /dev/null +++ b/t/143-ssl-sesison-fetch.t @@ -0,0 +1,1027 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use lib 'lib'; +use Test::Nginx::Socket::Lua; +use Cwd qw(abs_path realpath); +use File::Basename; + +repeat_each(3); + +plan tests => repeat_each() * (blocks() * 6); + +$ENV{TEST_NGINX_HTML_DIR} ||= html_dir(); + +$ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211; +$ENV{TEST_NGINX_RESOLVER} ||= '8.8.8.8'; +$ENV{TEST_NGINX_CERT_DIR} ||= dirname(realpath(abs_path(__FILE__))); + +#log_level 'warn'; +log_level 'debug'; + +no_long_string(); +#no_diff(); + +run_tests(); + +__DATA__ + +=== TEST 1: simple logging +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + server_name test.com; + ssl_session_fetch_by_lua_block { print("ssl fetch sess by lua is running!") } + ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; + ssl_protocols SSLv3; + + server_tokens off; + } +--- config + server_tokens off; + resolver $TEST_NGINX_RESOLVER; + lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + + content_by_lua_block { + do + local sock = ngx.socket.tcp() + + sock:settimeout(5000) + + local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local sess, err = sock:sslhandshake(package.loaded.session, "test.com", true) + if not sess then + ngx.say("failed to do SSL handshake: ", err) + return + end + + ngx.say("ssl handshake: ", type(sess)) + + package.loaded.session = sess + + local ok, err = sock:close() + ngx.say("close: ", ok, " ", err) + end -- do + -- collectgarbage() + } + } + +--- request +GET /t +--- response_body +connected: 1 +ssl handshake: userdata +close: 1 nil + +--- grep_error_log eval +qr/ssl_session_fetch_by_lua_block:1: ssl fetch sess by lua is running!/s + +--- grep_error_log_out eval +[ +'', +'ssl_session_fetch_by_lua_block:1: ssl fetch sess by lua is running! +', +'ssl_session_fetch_by_lua_block:1: ssl fetch sess by lua is running! +', +] + +--- no_error_log +[error] +[alert] +[emerg] + + + +=== TEST 2: sleep +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + server_name test.com; + ssl_session_fetch_by_lua_block { + local begin = ngx.now() + ngx.sleep(0.1) + print("elapsed in ssl fetch session by lua: ", ngx.now() - begin) + } + ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; + ssl_protocols SSLv3; + + server_tokens off; + } +--- config + server_tokens off; + resolver $TEST_NGINX_RESOLVER; + lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + + content_by_lua_block { + do + local sock = ngx.socket.tcp() + + sock:settimeout(5000) + + local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local sess, err = sock:sslhandshake(package.loaded.session, "test.com", true) + if not sess then + ngx.say("failed to do SSL handshake: ", err) + return + end + + ngx.say("ssl handshake: ", type(sess)) + + package.loaded.session = sess + + local ok, err = sock:close() + ngx.say("close: ", ok, " ", err) + end -- do + -- collectgarbage() + } + } + +--- request +GET /t +--- response_body +connected: 1 +ssl handshake: userdata +close: 1 nil + +--- grep_error_log eval +qr/elapsed in ssl fetch session by lua: 0.(?:09|1[01])\d+,/, + +--- grep_error_log_out eval +[ +'', +qr/elapsed in ssl fetch session by lua: 0.(?:09|1[01])\d+,/, +qr/elapsed in ssl fetch session by lua: 0.(?:09|1[01])\d+,/, +] + +--- no_error_log +[error] +[alert] +[emerg] + + + +=== TEST 3: timer +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + server_name test.com; + ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; + ssl_session_fetch_by_lua_block { + local function f() + print("my timer run!") + end + local ok, err = ngx.timer.at(0, f) + if not ok then + ngx.log(ngx.ERR, "failed to create timer: ", err) + return + end + } + ssl_protocols SSLv3; + + server_tokens off; + } +--- config + server_tokens off; + resolver $TEST_NGINX_RESOLVER; + lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + + content_by_lua_block { + do + local sock = ngx.socket.tcp() + + sock:settimeout(5000) + + local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local sess, err = sock:sslhandshake(package.loaded.session, "test.com", true) + if not sess then + ngx.say("failed to do SSL handshake: ", err) + return + end + + ngx.say("ssl handshake: ", type(sess)) + + package.loaded.session = sess + + local ok, err = sock:close() + ngx.say("close: ", ok, " ", err) + end -- do + -- collectgarbage() + } + } + +--- request +GET /t +--- response_body +connected: 1 +ssl handshake: userdata +close: 1 nil + +--- grep_error_log eval +qr/my timer run!/s + +--- grep_error_log_out eval +[ +'', +'my timer run! +', +'my timer run! +', +] + +--- no_error_log +[error] +[alert] +[emerg] + + + +=== TEST 4: cosocket +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + server_name test.com; + ssl_session_fetch_by_lua_block { + local sock = ngx.socket.tcp() + + sock:settimeout(5000) + + local ok, err = sock:connect("127.0.0.1", $TEST_NGINX_MEMCACHED_PORT) + if not ok then + ngx.log(ngx.ERR, "failed to connect to memc: ", err) + return + end + + local bytes, err = sock:send("flush_all\r\n") + if not bytes then + ngx.log(ngx.ERR, "failed to send flush_all command: ", err) + return + end + + local res, err = sock:receive() + if not res then + ngx.log(ngx.ERR, "failed to receive memc reply: ", err) + return + end + + print("received memc reply: ", res) + } + ssl_protocols SSLv3; + ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; + + server_tokens off; + } +--- config + server_tokens off; + resolver $TEST_NGINX_RESOLVER; + lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + + content_by_lua_block { + do + local sock = ngx.socket.tcp() + + sock:settimeout(5000) + + local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local sess, err = sock:sslhandshake(package.loaded.session, "test.com", true) + if not sess then + ngx.say("failed to do SSL handshake: ", err) + return + end + + ngx.say("ssl handshake: ", type(sess)) + + package.loaded.session = sess + + local ok, err = sock:close() + ngx.say("close: ", ok, " ", err) + end -- do + -- collectgarbage() + } + } + +--- request +GET /t +--- response_body +connected: 1 +ssl handshake: userdata +close: 1 nil + +--- grep_error_log eval +qr/received memc reply: OK/s + +--- grep_error_log_out eval +[ +'', +'received memc reply: OK +', +'received memc reply: OK +', +] + +--- no_error_log +[alert] +[error] +[emerg] + + + +=== TEST 5: ngx.exit(0) - yield +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + server_name test.com; + ssl_session_fetch_by_lua_block { + ngx.exit(0) + ngx.log(ngx.ERR, "should never reached here...") + } + ssl_protocols SSLv3; + ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; + + server_tokens off; + } +--- config + server_tokens off; + resolver $TEST_NGINX_RESOLVER; + lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + lua_ssl_verify_depth 3; + + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + + content_by_lua_block { + do + local sock = ngx.socket.tcp() + + sock:settimeout(5000) + + local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local sess, err = sock:sslhandshake(package.loaded.session, "test.com", true) + if not sess then + ngx.say("failed to do SSL handshake: ", err) + return + end + + ngx.say("ssl handshake: ", type(sess)) + + package.loaded.session = sess + + local ok, err = sock:close() + ngx.say("close: ", ok, " ", err) + end -- do + -- collectgarbage() + } + } + +--- request +GET /t +--- response_body +connected: 1 +ssl handshake: userdata +close: 1 nil + +--- grep_error_log eval +qr/lua exit with code 0/s + +--- grep_error_log_out eval +[ +'', +'lua exit with code 0 +', +'lua exit with code 0 +', +] + +--- no_error_log +should never reached here +[alert] +[emerg] + + + +=== TEST 6: ngx.exit(ngx.ERROR) - yield +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + server_name test.com; + ssl_session_fetch_by_lua_block { + ngx.exit(ngx.ERROR) + ngx.log(ngx.ERR, "should never reached here...") + } + ssl_protocols SSLv3; + ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; + + server_tokens off; + } +--- config + server_tokens off; + resolver $TEST_NGINX_RESOLVER; + lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + lua_ssl_verify_depth 3; + + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + + content_by_lua_block { + do + local sock = ngx.socket.tcp() + + sock:settimeout(5000) + + local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local sess, err = sock:sslhandshake(package.loaded.session, "test.com", true) + if not sess then + ngx.say("failed to do SSL handshake: ", err) + return + end + + ngx.say("ssl handshake: ", type(sess)) + + package.loaded.session = sess + + local ok, err = sock:close() + ngx.say("close: ", ok, " ", err) + end -- do + -- collectgarbage() + } + } + +--- request +GET /t +--- response_body +connected: 1 +ssl handshake: userdata +close: 1 nil + +--- grep_error_log eval +qr/ssl_session_fetch_by_lua\*: handler return value: -1, sess get cb exit code: 0/s + +--- grep_error_log_out eval +[ +'', +'ssl_session_fetch_by_lua*: handler return value: -1, sess get cb exit code: 0 +', +'ssl_session_fetch_by_lua*: handler return value: -1, sess get cb exit code: 0 +', +] + +--- no_error_log +should never reached here +[alert] +[emerg] + + + +=== TEST 7: ngx.exit(ngx.ERROR) - yield +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + server_name test.com; + ssl_session_fetch_by_lua_block { + ngx.sleep(0.001) + ngx.exit(ngx.ERROR) + ngx.log(ngx.ERR, "should never reached here...") + } + ssl_protocols SSLv3; + ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; + + server_tokens off; + } +--- config + server_tokens off; + resolver $TEST_NGINX_RESOLVER; + lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + lua_ssl_verify_depth 3; + + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + + content_by_lua_block { + do + local sock = ngx.socket.tcp() + + sock:settimeout(5000) + + local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local sess, err = sock:sslhandshake(package.loaded.session, "test.com", true) + if not sess then + ngx.say("failed to do SSL handshake: ", err) + return + end + + ngx.say("ssl handshake: ", type(sess)) + + package.loaded.session = sess + + local ok, err = sock:close() + ngx.say("close: ", ok, " ", err) + end -- do + -- collectgarbage() + } + } + +--- request +GET /t +--- response_body +connected: 1 +ssl handshake: userdata +close: 1 nil + +--- grep_error_log eval +qr/ssl_session_fetch_by_lua\*: sess get cb exit code: 0/s + +--- grep_error_log_out eval +[ +'', +'ssl_session_fetch_by_lua*: sess get cb exit code: 0 +', +'ssl_session_fetch_by_lua*: sess get cb exit code: 0 +', +] + +--- no_error_log +should never reached here +[alert] +[emerg] + + + +=== TEST 8: lua exception - no yield +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + server_name test.com; + ssl_session_fetch_by_lua_block { + error("bad bad bad") + ngx.log(ngx.ERR, "should never reached here...") + } + ssl_protocols SSLv3; + ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; + + server_tokens off; + } +--- config + server_tokens off; + resolver $TEST_NGINX_RESOLVER; + lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + lua_ssl_verify_depth 3; + + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + + content_by_lua_block { + do + local sock = ngx.socket.tcp() + + sock:settimeout(5000) + + local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local sess, err = sock:sslhandshake(package.loaded.session, "test.com", true) + if not sess then + ngx.say("failed to do SSL handshake: ", err) + return + end + + ngx.say("ssl handshake: ", type(sess)) + + package.loaded.session = sess + + local ok, err = sock:close() + ngx.say("close: ", ok, " ", err) + end -- do + -- collectgarbage() + } + } + +--- request +GET /t +--- response_body +connected: 1 +ssl handshake: userdata +close: 1 nil + +--- grep_error_log eval +qr/ssl_session_fetch_by_lua_block:2: bad bad bad/s + +--- grep_error_log_out eval +[ +'', +'ssl_session_fetch_by_lua_block:2: bad bad bad +', +'ssl_session_fetch_by_lua_block:2: bad bad bad +', + +] + +--- no_error_log +should never reached here +[alert] +[emerg] + + + +=== TEST 9: lua exception - yield +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + server_name test.com; + ssl_session_fetch_by_lua_block { + ngx.sleep(0.001) + error("bad bad bad") + ngx.log(ngx.ERR, "should never reached here...") + } + ssl_protocols SSLv3; + ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; + + server_tokens off; + } +--- config + server_tokens off; + resolver $TEST_NGINX_RESOLVER; + lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + lua_ssl_verify_depth 3; + + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + + content_by_lua_block { + do + local sock = ngx.socket.tcp() + + sock:settimeout(5000) + + local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local sess, err = sock:sslhandshake(package.loaded.session, "test.com", true) + if not sess then + ngx.say("failed to do SSL handshake: ", err) + return + end + + ngx.say("ssl handshake: ", type(sess)) + + package.loaded.session = sess + + local ok, err = sock:close() + ngx.say("close: ", ok, " ", err) + end -- do + -- collectgarbage() + } + } + +--- request +GET /t +--- response_body +connected: 1 +ssl handshake: userdata +close: 1 nil + +--- grep_error_log eval +qr/ssl_session_fetch_by_lua_block:3: bad bad bad|ssl_session_fetch_by_lua\*: sess get cb exit code: 0/s + +--- grep_error_log_out eval +[ +'', +'ssl_session_fetch_by_lua_block:3: bad bad bad +ssl_session_fetch_by_lua*: sess get cb exit code: 0 +', +'ssl_session_fetch_by_lua_block:3: bad bad bad +ssl_session_fetch_by_lua*: sess get cb exit code: 0 +', + +] + +--- no_error_log +should never reached here +[alert] +[emerg] + + + +=== TEST 10: get phase +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + server_name test.com; + ssl_session_fetch_by_lua_block { print("get_phase: ", ngx.get_phase()) } + ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; + ssl_protocols SSLv3; + + server_tokens off; + } +--- config + server_tokens off; + resolver $TEST_NGINX_RESOLVER; + lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + + content_by_lua_block { + do + local sock = ngx.socket.tcp() + + sock:settimeout(5000) + + local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local sess, err = sock:sslhandshake(package.loaded.session, "test.com", true) + if not sess then + ngx.say("failed to do SSL handshake: ", err) + return + end + + ngx.say("ssl handshake: ", type(sess)) + + package.loaded.session = sess + + local ok, err = sock:close() + ngx.say("close: ", ok, " ", err) + end -- do + -- collectgarbage() + } + } + +--- request +GET /t +--- response_body +connected: 1 +ssl handshake: userdata +close: 1 nil + +--- grep_error_log eval +qr/get_phase: ssl_session_fetch/s + +--- grep_error_log_out eval +[ +'', +'get_phase: ssl_session_fetch +', +'get_phase: ssl_session_fetch +', +] + +--- no_error_log +[error] +[alert] +[emerg] + + + +=== TEST 15: inter-operation with ssl_certificate_by_lua +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + server_name test.com; + ssl_certificate_by_lua_block { + ngx.sleep(0.1) + print("ssl cert by lua is running!") + } + ssl_session_store_by_lua_block { print("ssl store session by lua is running!") } + ssl_session_fetch_by_lua_block { + ngx.sleep(0.1) + print("ssl fetch session by lua is running!") + } + ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; + ssl_protocols SSLv3; + + server_tokens off; + } + +--- config + server_tokens off; + resolver $TEST_NGINX_RESOLVER; + lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + + content_by_lua_block { + do + local sock = ngx.socket.tcp() + + sock:settimeout(5000) + + local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local sess, err = sock:sslhandshake(package.loaded.session, "test.com", true) + if not sess then + ngx.say("failed to do SSL handshake: ", err) + return + end + + ngx.say("ssl handshake: ", type(sess)) + + package.loaded.session = sess + + local ok, err = sock:close() + ngx.say("close: ", ok, " ", err) + end -- do + -- collectgarbage() + } + } + +--- request +GET /t +--- response_body +connected: 1 +ssl handshake: userdata +close: 1 nil + +--- grep_error_log eval +qr/ssl ((fetch|store) session|cert) by lua is running!/s + +--- grep_error_log_out eval +[ +'ssl cert by lua is running! +ssl store session by lua is running! +', +'ssl fetch session by lua is running! +ssl cert by lua is running! +ssl store session by lua is running! +', +'ssl fetch session by lua is running! +ssl cert by lua is running! +ssl store session by lua is running! +', +] + +--- no_error_log +[error] +[alert] +[emerg] + + + +=== TEST 16: simple logging (by file) +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + server_name test.com; + ssl_session_fetch_by_lua_file html/a.lua; + ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; + ssl_protocols SSLv3; + + server_tokens off; + } +--- config + server_tokens off; + lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + + content_by_lua_block { + do + local sock = ngx.socket.tcp() + + sock:settimeout(5000) + + local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local sess, err = sock:sslhandshake(package.loaded.session, "test.com", true) + if not sess then + ngx.say("failed to do SSL handshake: ", err) + return + end + + ngx.say("ssl handshake: ", type(sess)) + + package.loaded.session = sess + + local ok, err = sock:close() + ngx.say("close: ", ok, " ", err) + end -- do + -- collectgarbage() + } + } + +--- user_files +>>> a.lua +print("ssl fetch sess by lua is running!") + +--- request +GET /t +--- response_body +connected: 1 +ssl handshake: userdata +close: 1 nil + +--- grep_error_log eval +qr/\S+:\d+: ssl fetch sess by lua is running!/s + +--- grep_error_log_out eval +[ +'', +'a.lua:1: ssl fetch sess by lua is running! +', +'a.lua:1: ssl fetch sess by lua is running! +', +] + +--- no_error_log +[error] +[alert] +[emerg]