From a7390fb4fc98e509e2346e59752337653c231ab9 Mon Sep 17 00:00:00 2001 From: monkeyDluffy6017 Date: Wed, 26 Jul 2023 22:01:30 +0800 Subject: [PATCH 1/2] refactor: ngx_lua-skip_filter.patch --- patch/1.21.4/ngx_lua-skip_filter.patch | 36 +++++++++++++------------- patch/patch.sh | 10 +++++-- 2 files changed, 26 insertions(+), 20 deletions(-) diff --git a/patch/1.21.4/ngx_lua-skip_filter.patch b/patch/1.21.4/ngx_lua-skip_filter.patch index e65f72a..fb6ab5d 100644 --- a/patch/1.21.4/ngx_lua-skip_filter.patch +++ b/patch/1.21.4/ngx_lua-skip_filter.patch @@ -1,5 +1,5 @@ diff --git src/ngx_http_lua_bodyfilterby.c src/ngx_http_lua_bodyfilterby.c -index 9024889..88af761 100644 +index 78e3b5c2..bfdb01b3 100644 --- src/ngx_http_lua_bodyfilterby.c +++ src/ngx_http_lua_bodyfilterby.c @@ -22,6 +22,9 @@ @@ -9,40 +9,40 @@ index 9024889..88af761 100644 +#if (NGX_HTTP_APISIX) +#include "ngx_http_apisix_module.h" +#endif - - + + static void ngx_http_lua_body_filter_by_lua_env(lua_State *L, -@@ -241,6 +244,12 @@ ngx_http_lua_body_filter(ngx_http_request_t *r, ngx_chain_t *in) +@@ -242,6 +245,12 @@ ngx_http_lua_body_filter(ngx_http_request_t *r, ngx_chain_t *in) ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua body filter for user lua code, uri \"%V\"", &r->uri); - -+#if (NGX_HTTP_APISIX) -+ if (ngx_http_apisix_is_body_filter_by_lua_skipped(r)) { -+ return ngx_http_next_body_filter(r, in); -+ } -+#endif + ++ #if (NGX_HTTP_APISIX) ++ if (ngx_http_apisix_is_body_filter_by_lua_skipped(r)) { ++ return ngx_http_next_body_filter(r, in); ++ } ++ #endif + llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); - + if (llcf->body_filter_handler == NULL || r->header_only) { diff --git src/ngx_http_lua_headerfilterby.c src/ngx_http_lua_headerfilterby.c -index ed0c3a6..5f04992 100644 +index 71553558..71d9edf2 100644 --- src/ngx_http_lua_headerfilterby.c +++ src/ngx_http_lua_headerfilterby.c -@@ -19,6 +19,9 @@ - #include "ngx_http_lua_string.h" +@@ -20,6 +20,9 @@ #include "ngx_http_lua_misc.h" #include "ngx_http_lua_consts.h" + #include "ngx_http_lua_shdict.h" +#if (NGX_HTTP_APISIX) +#include "ngx_http_apisix_module.h" +#endif - - + + static ngx_http_output_header_filter_pt ngx_http_next_header_filter; -@@ -80,6 +83,12 @@ ngx_http_lua_header_filter_by_chunk(lua_State *L, ngx_http_request_t *r) +@@ -81,6 +84,12 @@ ngx_http_lua_header_filter_by_chunk(lua_State *L, ngx_http_request_t *r) #endif ngx_http_lua_ctx_t *ctx; - + +#if (NGX_HTTP_APISIX) + if (ngx_http_apisix_is_header_filter_by_lua_skipped(r)) { + return NGX_OK; diff --git a/patch/patch.sh b/patch/patch.sh index 07a6bc7..e7116b3 100755 --- a/patch/patch.sh +++ b/patch/patch.sh @@ -48,12 +48,18 @@ elif [[ "$root" == *openresty-1.19.9.* ]]; then apply_patch "$patch_dir" "$root" "ngx_lua" "0.10.20" apply_patch "$patch_dir" "$root" "ngx_stream_lua" "0.0.10" apply_patch "$patch_dir" "$root" "LuaJIT-2.1" "20210510" -elif [[ "$root" == *openresty-1.21.4.* ]]; then - patch_dir="$PWD/1.21.4" +elif [[ "$root" == *openresty-1.21.4.1 ]]; then + patch_dir="$PWD/1.21.4.1" apply_patch "$patch_dir" "$root" "nginx" "1.21.4" apply_patch "$patch_dir" "$root" "lua-resty-core" "0.1.23" apply_patch "$patch_dir" "$root" "ngx_lua" "0.10.21" apply_patch "$patch_dir" "$root" "ngx_stream_lua" "0.0.11" +elif [[ "$root" == *openresty-1.21.4.* ]]; then + patch_dir="$PWD/1.21.4" + apply_patch "$patch_dir" "$root" "nginx" "1.21.4" + apply_patch "$patch_dir" "$root" "lua-resty-core" "0.1.27" + apply_patch "$patch_dir" "$root" "ngx_lua" "0.10.25" + apply_patch "$patch_dir" "$root" "ngx_stream_lua" "0.0.13" else err "can't detect OpenResty version" exit 1 From 076c65d40cfdbf6f739101f14ff05b9e2e19a4e5 Mon Sep 17 00:00:00 2001 From: monkeyDluffy6017 Date: Wed, 26 Jul 2023 22:01:56 +0800 Subject: [PATCH 2/2] refactor: support openresty 1.21.4.2 --- ...ilicon-FFI-ABI-limitation-workaround.patch | 90 + .../lua-resty-core-enable_keepalive.patch | 219 ++ .../lua-resty-core-reject-in-handshake.patch | 48 + .../lua-resty-core-shared_shdict.patch | 276 ++ .../lua-resty-core-tlshandshake.patch | 319 ++ .../1.21.4.1/nginx-client_max_body_size.patch | 127 + .../nginx-connection-original-dst.patch | 112 + patch/1.21.4.1/nginx-enable_ntls.patch | 27 + .../nginx-error_page_contains_apisix.patch | 47 + .../1.21.4.1/nginx-get_last_reopen_time.patch | 72 + .../nginx-grpc_set_header_authority.patch | 18 + patch/1.21.4.1/nginx-gzip.patch | 143 + .../nginx-listen-in-privileged-agent.patch | 141 + patch/1.21.4.1/nginx-mirror.patch | 70 + ...ginx-privileged_agent_process_thread.patch | 14 + .../nginx-proxy_request_buffering.patch | 26 + patch/1.21.4.1/nginx-real_ip.patch | 52 + patch/1.21.4.1/nginx-tcp_over_tls.patch | 40 + patch/1.21.4.1/nginx-upstream_mtls.patch | 25 + ...ilicon-FFI-ABI-limitation-workaround.patch | 48 + patch/1.21.4.1/ngx_lua-enable_keepalive.patch | 1156 +++++++ .../ngx_lua-ngx-buf-double-free-bugfix.patch | 39 + .../ngx_lua-reject-in-handshake.patch | 38 + .../1.21.4.1/ngx_lua-request_header_set.patch | 25 + patch/1.21.4.1/ngx_lua-shared_shdict.patch | 2965 +++++++++++++++++ patch/1.21.4.1/ngx_lua-skip_filter.patch | 54 + patch/1.21.4.1/ngx_lua-tlshandshake.patch | 704 ++++ ...ngx_stream_lua-expose_request_struct.patch | 15 + .../ngx_stream_lua-reject-in-handshake.patch | 40 + .../ngx_stream_lua-shared_shdict.patch | 2790 ++++++++++++++++ .../ngx_stream_lua-tlshandshake.patch | 718 ++++ patch/1.21.4.1/ngx_stream_lua-xrpc.patch | 845 +++++ 32 files changed, 11303 insertions(+) create mode 100644 patch/1.21.4.1/lua-resty-core-bugfix-Apple-Silicon-FFI-ABI-limitation-workaround.patch create mode 100644 patch/1.21.4.1/lua-resty-core-enable_keepalive.patch create mode 100644 patch/1.21.4.1/lua-resty-core-reject-in-handshake.patch create mode 100644 patch/1.21.4.1/lua-resty-core-shared_shdict.patch create mode 100644 patch/1.21.4.1/lua-resty-core-tlshandshake.patch create mode 100644 patch/1.21.4.1/nginx-client_max_body_size.patch create mode 100644 patch/1.21.4.1/nginx-connection-original-dst.patch create mode 100644 patch/1.21.4.1/nginx-enable_ntls.patch create mode 100644 patch/1.21.4.1/nginx-error_page_contains_apisix.patch create mode 100644 patch/1.21.4.1/nginx-get_last_reopen_time.patch create mode 100644 patch/1.21.4.1/nginx-grpc_set_header_authority.patch create mode 100644 patch/1.21.4.1/nginx-gzip.patch create mode 100644 patch/1.21.4.1/nginx-listen-in-privileged-agent.patch create mode 100644 patch/1.21.4.1/nginx-mirror.patch create mode 100644 patch/1.21.4.1/nginx-privileged_agent_process_thread.patch create mode 100644 patch/1.21.4.1/nginx-proxy_request_buffering.patch create mode 100644 patch/1.21.4.1/nginx-real_ip.patch create mode 100644 patch/1.21.4.1/nginx-tcp_over_tls.patch create mode 100644 patch/1.21.4.1/nginx-upstream_mtls.patch create mode 100644 patch/1.21.4.1/ngx_lua-bugfix-Apple-Silicon-FFI-ABI-limitation-workaround.patch create mode 100644 patch/1.21.4.1/ngx_lua-enable_keepalive.patch create mode 100644 patch/1.21.4.1/ngx_lua-ngx-buf-double-free-bugfix.patch create mode 100644 patch/1.21.4.1/ngx_lua-reject-in-handshake.patch create mode 100644 patch/1.21.4.1/ngx_lua-request_header_set.patch create mode 100644 patch/1.21.4.1/ngx_lua-shared_shdict.patch create mode 100644 patch/1.21.4.1/ngx_lua-skip_filter.patch create mode 100644 patch/1.21.4.1/ngx_lua-tlshandshake.patch create mode 100644 patch/1.21.4.1/ngx_stream_lua-expose_request_struct.patch create mode 100644 patch/1.21.4.1/ngx_stream_lua-reject-in-handshake.patch create mode 100644 patch/1.21.4.1/ngx_stream_lua-shared_shdict.patch create mode 100644 patch/1.21.4.1/ngx_stream_lua-tlshandshake.patch create mode 100644 patch/1.21.4.1/ngx_stream_lua-xrpc.patch diff --git a/patch/1.21.4.1/lua-resty-core-bugfix-Apple-Silicon-FFI-ABI-limitation-workaround.patch b/patch/1.21.4.1/lua-resty-core-bugfix-Apple-Silicon-FFI-ABI-limitation-workaround.patch new file mode 100644 index 0000000..524b953 --- /dev/null +++ b/patch/1.21.4.1/lua-resty-core-bugfix-Apple-Silicon-FFI-ABI-limitation-workaround.patch @@ -0,0 +1,90 @@ +diff --git lib/resty/core/response.lua lib/resty/core/response.lua +index 891a07e..986de74 100644 +--- lib/resty/core/response.lua ++++ lib/resty/core/response.lua +@@ -45,6 +45,61 @@ ffi.cdef[[ + ]] + + ++local ngx_lua_ffi_set_resp_header ++ ++local MACOS = jit and jit.os == "OSX" ++ ++if MACOS then ++ ffi.cdef[[ ++ typedef struct { ++ ngx_http_request_t *r; ++ const char *key_data; ++ size_t key_len; ++ int is_nil; ++ const char *sval; ++ size_t sval_len; ++ void *mvals; ++ size_t mvals_len; ++ int override; ++ char **errmsg; ++ } ngx_http_lua_set_resp_header_params_t; ++ ++ int ngx_http_lua_ffi_set_resp_header_macos( ++ ngx_http_lua_set_resp_header_params_t *p); ++ ]] ++ ++ local set_params = ffi.new("ngx_http_lua_set_resp_header_params_t") ++ ++ ngx_lua_ffi_set_resp_header = function(r, key, key_len, is_nil, ++ sval, sval_len, mvals, ++ mvals_len, override, err) ++ ++ set_params.r = r ++ set_params.key_data = key ++ set_params.key_len = key_len ++ set_params.is_nil = is_nil ++ set_params.sval = sval ++ set_params.sval_len = sval_len ++ set_params.mvals = mvals ++ set_params.mvals_len = mvals_len ++ set_params.override = override ++ set_params.errmsg = err ++ ++ return C.ngx_http_lua_ffi_set_resp_header_macos(set_params) ++ end ++ ++else ++ ngx_lua_ffi_set_resp_header = function(r, key, key_len, is_nil, ++ sval, sval_len, mvals, ++ mvals_len, override, err) ++ ++ return C.ngx_http_lua_ffi_set_resp_header(r, key, key_len, is_nil, ++ sval, sval_len, mvals, ++ mvals_len, override, err) ++ end ++end ++ ++ + local function set_resp_header(tb, key, value, no_override) + local r = get_request() + if not r then +@@ -61,8 +116,8 @@ local function set_resp_header(tb, key, value, no_override) + error("invalid header value", 3) + end + +- rc = C.ngx_http_lua_ffi_set_resp_header(r, key, #key, true, nil, 0, nil, +- 0, 1, errmsg) ++ rc = ngx_lua_ffi_set_resp_header(r, key, #key, true, nil, 0, nil, ++ 0, 1, errmsg) + else + local sval, sval_len, mvals, mvals_len, buf + +@@ -99,9 +154,9 @@ local function set_resp_header(tb, key, value, no_override) + end + + local override_int = no_override and 0 or 1 +- rc = C.ngx_http_lua_ffi_set_resp_header(r, key, #key, false, sval, +- sval_len, mvals, mvals_len, +- override_int, errmsg) ++ rc = ngx_lua_ffi_set_resp_header(r, key, #key, false, sval, ++ sval_len, mvals, mvals_len, ++ override_int, errmsg) + end + + if rc == 0 or rc == FFI_DECLINED then diff --git a/patch/1.21.4.1/lua-resty-core-enable_keepalive.patch b/patch/1.21.4.1/lua-resty-core-enable_keepalive.patch new file mode 100644 index 0000000..4a0df12 --- /dev/null +++ b/patch/1.21.4.1/lua-resty-core-enable_keepalive.patch @@ -0,0 +1,219 @@ +diff --git lib/ngx/balancer.lua lib/ngx/balancer.lua +index 7d64d63..781cbd1 100644 +--- lib/ngx/balancer.lua ++++ lib/ngx/balancer.lua +@@ -3,6 +3,7 @@ + + local base = require "resty.core.base" + base.allows_subsystem('http', 'stream') ++require "resty.core.hash" + + + local ffi = require "ffi" +@@ -17,8 +18,10 @@ local error = error + local type = type + local tonumber = tonumber + local max = math.max ++local ngx_crc32_long = ngx.crc32_long + local subsystem = ngx.config.subsystem + local ngx_lua_ffi_balancer_set_current_peer ++local ngx_lua_ffi_balancer_enable_keepalive + local ngx_lua_ffi_balancer_set_more_tries + local ngx_lua_ffi_balancer_get_last_failure + local ngx_lua_ffi_balancer_set_timeouts -- used by both stream and http +@@ -27,7 +30,11 @@ local ngx_lua_ffi_balancer_set_timeouts -- used by both stream and http + if subsystem == 'http' then + ffi.cdef[[ + int ngx_http_lua_ffi_balancer_set_current_peer(ngx_http_request_t *r, +- const unsigned char *addr, size_t addr_len, int port, char **err); ++ const unsigned char *addr, size_t addr_len, int port, ++ unsigned int cpool_crc32, unsigned int cpool_size, char **err); ++ ++ int ngx_http_lua_ffi_balancer_enable_keepalive(ngx_http_request_t *r, ++ unsigned long timeout, unsigned int max_requests, char **err); + + int ngx_http_lua_ffi_balancer_set_more_tries(ngx_http_request_t *r, + int count, char **err); +@@ -46,6 +53,9 @@ if subsystem == 'http' then + ngx_lua_ffi_balancer_set_current_peer = + C.ngx_http_lua_ffi_balancer_set_current_peer + ++ ngx_lua_ffi_balancer_enable_keepalive = ++ C.ngx_http_lua_ffi_balancer_enable_keepalive ++ + ngx_lua_ffi_balancer_set_more_tries = + C.ngx_http_lua_ffi_balancer_set_more_tries + +@@ -96,6 +106,11 @@ else + end + + ++local DEFAULT_KEEPALIVE_POOL_SIZE = 30 ++local DEFAULT_KEEPALIVE_IDLE_TIMEOUT = 60000 ++local DEFAULT_KEEPALIVE_MAX_REQUESTS = 100 ++ ++ + local peer_state_names = { + [1] = "keepalive", + [2] = "next", +@@ -106,25 +121,147 @@ local peer_state_names = { + local _M = { version = base.version } + + +-function _M.set_current_peer(addr, port) +- local r = get_request() +- if not r then +- error("no request found") ++if subsystem == "http" then ++ function _M.set_current_peer(addr, port, opts) ++ local r = get_request() ++ if not r then ++ error("no request found") ++ end ++ ++ local pool_crc32 ++ local pool_size ++ ++ if opts then ++ if type(opts) ~= "table" then ++ error("bad argument #3 to 'set_current_peer' " .. ++ "(table expected, got " .. type(opts) .. ")", 2) ++ end ++ ++ local pool = opts.pool ++ pool_size = opts.pool_size ++ ++ if pool then ++ if type(pool) ~= "string" then ++ error("bad option 'pool' to 'set_current_peer' " .. ++ "(string expected, got " .. type(pool) .. ")", 2) ++ end ++ ++ pool_crc32 = ngx_crc32_long(pool) ++ end ++ ++ if pool_size then ++ if type(pool_size) ~= "number" then ++ error("bad option 'pool_size' to 'set_current_peer' " .. ++ "(number expected, got " .. type(pool_size) .. ")", 2) ++ ++ elseif pool_size < 1 then ++ error("bad option 'pool_size' to 'set_current_peer' " .. ++ "(expected > 0)", 2) ++ end ++ end ++ end ++ ++ if not port then ++ port = 0 ++ ++ elseif type(port) ~= "number" then ++ port = tonumber(port) ++ end ++ ++ if not pool_crc32 then ++ pool_crc32 = 0 ++ end ++ ++ if not pool_size then ++ pool_size = DEFAULT_KEEPALIVE_POOL_SIZE ++ end ++ ++ local rc = ngx_lua_ffi_balancer_set_current_peer(r, addr, #addr, port, ++ pool_crc32, pool_size, ++ errmsg) ++ if rc == FFI_OK then ++ return true ++ end ++ ++ return nil, ffi_str(errmsg[0]) + end + +- if not port then +- port = 0 +- elseif type(port) ~= "number" then +- port = tonumber(port) ++else ++ function _M.set_current_peer(addr, port, opts) ++ local r = get_request() ++ if not r then ++ error("no request found") ++ end ++ ++ if opts then ++ error("bad argument #3 to 'set_current_peer' ('opts' not yet " .. ++ "implemented in " .. subsystem .. " subsystem)", 2) ++ end ++ ++ if not port then ++ port = 0 ++ ++ elseif type(port) ~= "number" then ++ port = tonumber(port) ++ end ++ ++ local rc = ngx_lua_ffi_balancer_set_current_peer(r, addr, #addr, ++ port, errmsg) ++ if rc == FFI_OK then ++ return true ++ end ++ ++ return nil, ffi_str(errmsg[0]) + end ++end + +- local rc = ngx_lua_ffi_balancer_set_current_peer(r, addr, #addr, +- port, errmsg) +- if rc == FFI_OK then +- return true ++ ++if subsystem == "http" then ++ function _M.enable_keepalive(idle_timeout, max_requests) ++ local r = get_request() ++ if not r then ++ error("no request found") ++ end ++ ++ if not idle_timeout then ++ idle_timeout = DEFAULT_KEEPALIVE_IDLE_TIMEOUT ++ ++ elseif type(idle_timeout) ~= "number" then ++ error("bad argument #1 to 'enable_keepalive' " .. ++ "(number expected, got " .. type(idle_timeout) .. ")", 2) ++ ++ elseif idle_timeout < 0 then ++ error("bad argument #1 to 'enable_keepalive' (expected >= 0)", 2) ++ ++ else ++ idle_timeout = idle_timeout * 1000 ++ end ++ ++ if not max_requests then ++ max_requests = DEFAULT_KEEPALIVE_MAX_REQUESTS ++ ++ elseif type(max_requests) ~= "number" then ++ error("bad argument #2 to 'enable_keepalive' " .. ++ "(number expected, got " .. type(max_requests) .. ")", 2) ++ ++ elseif max_requests < 0 then ++ error("bad argument #2 to 'enable_keepalive' (expected >= 0)", 2) ++ end ++ ++ local rc = ngx_lua_ffi_balancer_enable_keepalive(r, idle_timeout, ++ max_requests, errmsg) ++ if rc == FFI_OK then ++ return true ++ end ++ ++ return nil, ffi_str(errmsg[0]) + end + +- return nil, ffi_str(errmsg[0]) ++else ++ function _M.enable_keepalive() ++ error("'enable_keepalive' not yet implemented in " .. subsystem .. ++ " subsystem", 2) ++ end + end + + diff --git a/patch/1.21.4.1/lua-resty-core-reject-in-handshake.patch b/patch/1.21.4.1/lua-resty-core-reject-in-handshake.patch new file mode 100644 index 0000000..6957a12 --- /dev/null +++ b/patch/1.21.4.1/lua-resty-core-reject-in-handshake.patch @@ -0,0 +1,48 @@ +diff --git lib/ngx/ssl.lua lib/ngx/ssl.lua +index b769fd8..89ccabe 100644 +--- lib/ngx/ssl.lua ++++ lib/ngx/ssl.lua +@@ -85,7 +85,7 @@ if subsystem == 'http' then + void ngx_http_lua_ffi_free_priv_key(void *cdata); + + int ngx_http_lua_ffi_ssl_verify_client(void *r, +- void *cdata, int depth, char **err); ++ void *cdata, int depth, int reject_in_handshake, char **err); + ]] + + ngx_lua_ffi_ssl_set_der_certificate = +@@ -155,7 +155,7 @@ elseif subsystem == 'stream' then + void ngx_stream_lua_ffi_free_priv_key(void *cdata); + + int ngx_stream_lua_ffi_ssl_verify_client(void *r, +- void *cdata, int depth, char **err); ++ void *cdata, int depth, int reject_in_handshake, char **err); + ]] + + ngx_lua_ffi_ssl_set_der_certificate = +@@ -414,7 +414,7 @@ function _M.set_priv_key(priv_key) + end + + +-function _M.verify_client(ca_certs, depth) ++function _M.verify_client(ca_certs, depth, reject_in_handshake) + local r = get_request() + if not r then + error("no request found") +@@ -424,7 +424,15 @@ function _M.verify_client(ca_certs, depth) + depth = -1 + end + +- local rc = ngx_lua_ffi_ssl_verify_client(r, ca_certs, depth, errmsg) ++ if reject_in_handshake == nil then ++ -- reject by default so we can migrate to the new behavior ++ -- without modifying Lua code ++ reject_in_handshake = true ++ end ++ ++ local reject_in_handshake_int = reject_in_handshake and 1 or 0 ++ local rc = ngx_lua_ffi_ssl_verify_client(r, ca_certs, depth, ++ reject_in_handshake_int, errmsg) + if rc == FFI_OK then + return true + end diff --git a/patch/1.21.4.1/lua-resty-core-shared_shdict.patch b/patch/1.21.4.1/lua-resty-core-shared_shdict.patch new file mode 100644 index 0000000..9b25fc2 --- /dev/null +++ b/patch/1.21.4.1/lua-resty-core-shared_shdict.patch @@ -0,0 +1,276 @@ +diff --git lib/resty/core/shdict.lua lib/resty/core/shdict.lua +index dedf12c..7644b77 100644 +--- lib/resty/core/shdict.lua ++++ lib/resty/core/shdict.lua +@@ -28,7 +28,6 @@ local type = type + local error = error + local getmetatable = getmetatable + local FFI_DECLINED = base.FFI_DECLINED +-local subsystem = ngx.config.subsystem + + + local ngx_lua_ffi_shdict_get +@@ -42,117 +41,175 @@ local ngx_lua_ffi_shdict_free_space + local ngx_lua_ffi_shdict_udata_to_zone + + +-if subsystem == 'http' then +- ffi.cdef[[ +-int ngx_http_lua_ffi_shdict_get(void *zone, const unsigned char *key, ++ffi.cdef[[ ++int ngx_meta_lua_ffi_shdict_get(void *zone, const unsigned char *key, + size_t key_len, int *value_type, unsigned char **str_value_buf, + size_t *str_value_len, double *num_value, int *user_flags, + int get_stale, int *is_stale, char **errmsg); + +-int ngx_http_lua_ffi_shdict_incr(void *zone, const unsigned char *key, ++int ngx_meta_lua_ffi_shdict_incr(void *zone, const unsigned char *key, + size_t key_len, double *value, char **err, int has_init, + double init, long init_ttl, int *forcible); + +-int ngx_http_lua_ffi_shdict_store(void *zone, int op, ++int ngx_meta_lua_ffi_shdict_store(void *zone, int op, + const unsigned char *key, size_t key_len, int value_type, + const unsigned char *str_value_buf, size_t str_value_len, + double num_value, long exptime, int user_flags, char **errmsg, + int *forcible); + +-int ngx_http_lua_ffi_shdict_flush_all(void *zone); ++int ngx_meta_lua_ffi_shdict_flush_all(void *zone); + +-long ngx_http_lua_ffi_shdict_get_ttl(void *zone, ++long ngx_meta_lua_ffi_shdict_get_ttl(void *zone, + const unsigned char *key, size_t key_len); + +-int ngx_http_lua_ffi_shdict_set_expire(void *zone, ++int ngx_meta_lua_ffi_shdict_set_expire(void *zone, + const unsigned char *key, size_t key_len, long exptime); + +-size_t ngx_http_lua_ffi_shdict_capacity(void *zone); +- +-void *ngx_http_lua_ffi_shdict_udata_to_zone(void *zone_udata); +- ]] +- +- ngx_lua_ffi_shdict_get = C.ngx_http_lua_ffi_shdict_get +- ngx_lua_ffi_shdict_incr = C.ngx_http_lua_ffi_shdict_incr +- ngx_lua_ffi_shdict_store = C.ngx_http_lua_ffi_shdict_store +- ngx_lua_ffi_shdict_flush_all = C.ngx_http_lua_ffi_shdict_flush_all +- ngx_lua_ffi_shdict_get_ttl = C.ngx_http_lua_ffi_shdict_get_ttl +- ngx_lua_ffi_shdict_set_expire = C.ngx_http_lua_ffi_shdict_set_expire +- ngx_lua_ffi_shdict_capacity = C.ngx_http_lua_ffi_shdict_capacity +- ngx_lua_ffi_shdict_udata_to_zone = +- C.ngx_http_lua_ffi_shdict_udata_to_zone +- +- if not pcall(function () +- return C.ngx_http_lua_ffi_shdict_free_space +- end) +- then +- ffi.cdef[[ +-size_t ngx_http_lua_ffi_shdict_free_space(void *zone); +- ]] +- end +- +- pcall(function () +- ngx_lua_ffi_shdict_free_space = C.ngx_http_lua_ffi_shdict_free_space +- end) ++size_t ngx_meta_lua_ffi_shdict_capacity(void *zone); + +-elseif subsystem == 'stream' then ++void *ngx_meta_lua_ffi_shdict_udata_to_zone(void *zone_udata); ++]] + ++if not pcall(function () ++ return C.ngx_meta_lua_ffi_shdict_free_space ++end) ++then + ffi.cdef[[ +-int ngx_stream_lua_ffi_shdict_get(void *zone, const unsigned char *key, +- size_t key_len, int *value_type, unsigned char **str_value_buf, +- size_t *str_value_len, double *num_value, int *user_flags, +- int get_stale, int *is_stale, char **errmsg); +- +-int ngx_stream_lua_ffi_shdict_incr(void *zone, const unsigned char *key, +- size_t key_len, double *value, char **err, int has_init, +- double init, long init_ttl, int *forcible); +- +-int ngx_stream_lua_ffi_shdict_store(void *zone, int op, +- const unsigned char *key, size_t key_len, int value_type, +- const unsigned char *str_value_buf, size_t str_value_len, +- double num_value, long exptime, int user_flags, char **errmsg, +- int *forcible); +- +-int ngx_stream_lua_ffi_shdict_flush_all(void *zone); +- +-long ngx_stream_lua_ffi_shdict_get_ttl(void *zone, +- const unsigned char *key, size_t key_len); +- +-int ngx_stream_lua_ffi_shdict_set_expire(void *zone, +- const unsigned char *key, size_t key_len, long exptime); +- +-size_t ngx_stream_lua_ffi_shdict_capacity(void *zone); +- +-void *ngx_stream_lua_ffi_shdict_udata_to_zone(void *zone_udata); ++size_t ngx_meta_lua_ffi_shdict_free_space(void *zone); + ]] +- +- ngx_lua_ffi_shdict_get = C.ngx_stream_lua_ffi_shdict_get +- ngx_lua_ffi_shdict_incr = C.ngx_stream_lua_ffi_shdict_incr +- ngx_lua_ffi_shdict_store = C.ngx_stream_lua_ffi_shdict_store +- ngx_lua_ffi_shdict_flush_all = C.ngx_stream_lua_ffi_shdict_flush_all +- ngx_lua_ffi_shdict_get_ttl = C.ngx_stream_lua_ffi_shdict_get_ttl +- ngx_lua_ffi_shdict_set_expire = C.ngx_stream_lua_ffi_shdict_set_expire +- ngx_lua_ffi_shdict_capacity = C.ngx_stream_lua_ffi_shdict_capacity +- ngx_lua_ffi_shdict_udata_to_zone = +- C.ngx_stream_lua_ffi_shdict_udata_to_zone +- +- if not pcall(function () +- return C.ngx_stream_lua_ffi_shdict_free_space +- end) +- then +- ffi.cdef[[ +-size_t ngx_stream_lua_ffi_shdict_free_space(void *zone); +- ]] +- end +- +- -- ngx_stream_lua is only compatible with NGINX >= 1.13.6, meaning it +- -- cannot lack support for ngx_stream_lua_ffi_shdict_free_space. +- ngx_lua_ffi_shdict_free_space = C.ngx_stream_lua_ffi_shdict_free_space +- +-else +- error("unknown subsystem: " .. subsystem) + end + ++pcall(function () ++ ngx_lua_ffi_shdict_get = C.ngx_meta_lua_ffi_shdict_get ++ ngx_lua_ffi_shdict_incr = C.ngx_meta_lua_ffi_shdict_incr ++ ngx_lua_ffi_shdict_store = C.ngx_meta_lua_ffi_shdict_store ++ ngx_lua_ffi_shdict_flush_all = C.ngx_meta_lua_ffi_shdict_flush_all ++ ngx_lua_ffi_shdict_get_ttl = C.ngx_meta_lua_ffi_shdict_get_ttl ++ ngx_lua_ffi_shdict_set_expire = C.ngx_meta_lua_ffi_shdict_set_expire ++ ngx_lua_ffi_shdict_capacity = C.ngx_meta_lua_ffi_shdict_capacity ++ ngx_lua_ffi_shdict_free_space = C.ngx_meta_lua_ffi_shdict_free_space ++ ngx_lua_ffi_shdict_udata_to_zone = C.ngx_meta_lua_ffi_shdict_udata_to_zone ++end) ++ ++ ++local MACOS = jit and jit.os == "OSX" ++ ++if MACOS then ++ ffi.cdef[[ ++typedef struct { ++ void *zone; ++ const unsigned char *key; ++ size_t key_len; ++ int *value_type; ++ unsigned char **str_value_buf; ++ size_t *str_value_len; ++ double *num_value; ++ int *user_flags; ++ int get_stale; ++ int *is_stale; ++ char **errmsg; ++} ngx_meta_lua_shdict_get_params_t; ++ ++typedef struct { ++ void *zone; ++ int op; ++ const unsigned char *key; ++ size_t key_len; ++ int value_type; ++ const unsigned char *str_value_buf; ++ size_t str_value_len; ++ double num_value; ++ long exptime; ++ int user_flags; ++ char **errmsg; ++ int *forcible; ++} ngx_meta_lua_shdict_store_params_t; ++ ++typedef struct { ++ void *zone; ++ const unsigned char *key; ++ size_t key_len; ++ double *num_value; ++ char **errmsg; ++ int has_init; ++ double init; ++ long init_ttl; ++ int *forcible; ++} ngx_meta_lua_shdict_incr_params_t; ++ ++int ngx_meta_lua_ffi_shdict_get_macos( ++ ngx_meta_lua_shdict_get_params_t *p); ++int ngx_meta_lua_ffi_shdict_store_macos( ++ ngx_meta_lua_shdict_store_params_t *p); ++int ngx_meta_lua_ffi_shdict_incr_macos( ++ ngx_meta_lua_shdict_incr_params_t *p); ++ ]] ++ ++ local get_params = ffi_new("ngx_meta_lua_shdict_get_params_t") ++ local incr_params = ffi_new("ngx_meta_lua_shdict_incr_params_t") ++ local store_params = ffi_new("ngx_meta_lua_shdict_store_params_t") ++ ++ ngx_lua_ffi_shdict_get = function(zone, key, key_len, value_type, ++ str_value_buf, value_len, ++ num_value, user_flags, ++ get_stale, is_stale, errmsg) ++ ++ get_params.zone = zone ++ get_params.key = key ++ get_params.key_len = key_len ++ get_params.value_type = value_type ++ get_params.str_value_buf = str_value_buf ++ get_params.str_value_len = value_len ++ get_params.num_value = num_value ++ get_params.user_flags = user_flags ++ get_params.get_stale = get_stale ++ get_params.is_stale = is_stale ++ get_params.errmsg = errmsg ++ ++ return C.ngx_meta_lua_ffi_shdict_get_macos(get_params) ++ end ++ ++ ngx_lua_ffi_shdict_incr = function(zone, key, ++ key_len, value, err, has_init, ++ init, init_ttl, forcible) ++ ++ incr_params.zone = zone ++ incr_params.key = key ++ incr_params.key_len = key_len ++ incr_params.num_value = value ++ incr_params.errmsg = err ++ incr_params.has_init = has_init ++ incr_params.init = init ++ incr_params.init_ttl = init_ttl ++ incr_params.forcible = forcible ++ ++ return C.ngx_meta_lua_ffi_shdict_incr_macos(incr_params) ++ end ++ ++ ngx_lua_ffi_shdict_store = function(zone, op, ++ key, key_len, value_type, ++ str_value_buf, str_value_len, ++ num_value, exptime, user_flags, ++ errmsg, forcible) ++ ++ store_params.zone = zone ++ store_params.op = op ++ store_params.key = key ++ store_params.key_len = key_len ++ store_params.value_type = value_type ++ store_params.str_value_buf = str_value_buf ++ store_params.str_value_len = str_value_len ++ store_params.num_value = num_value ++ store_params.exptime = exptime ++ store_params.user_flags = user_flags ++ store_params.errmsg = errmsg ++ store_params.forcible = forcible ++ ++ return C.ngx_meta_lua_ffi_shdict_store_macos(store_params) ++ end ++end ++ ++ + if not pcall(function () return C.free end) then + ffi.cdef[[ + void free(void *ptr); diff --git a/patch/1.21.4.1/lua-resty-core-tlshandshake.patch b/patch/1.21.4.1/lua-resty-core-tlshandshake.patch new file mode 100644 index 0000000..3b046fe --- /dev/null +++ b/patch/1.21.4.1/lua-resty-core-tlshandshake.patch @@ -0,0 +1,319 @@ +diff --git Makefile Makefile +index 3caabe2..6361a23 100644 +--- Makefile ++++ Makefile +@@ -12,10 +12,12 @@ all: ; + + install: all + $(INSTALL) -d $(DESTDIR)$(LUA_LIB_DIR)/resty/core/ ++ $(INSTALL) -d $(DESTDIR)$(LUA_LIB_DIR)/resty/core/socket + $(INSTALL) -d $(DESTDIR)$(LUA_LIB_DIR)/ngx/ + $(INSTALL) -d $(DESTDIR)$(LUA_LIB_DIR)/ngx/ssl + $(INSTALL) lib/resty/*.lua $(DESTDIR)$(LUA_LIB_DIR)/resty/ + $(INSTALL) lib/resty/core/*.lua $(DESTDIR)$(LUA_LIB_DIR)/resty/core/ ++ $(INSTALL) lib/resty/core/socket/*.lua $(DESTDIR)$(LUA_LIB_DIR)/resty/core/socket + $(INSTALL) lib/ngx/*.lua $(DESTDIR)$(LUA_LIB_DIR)/ngx/ + $(INSTALL) lib/ngx/ssl/*.lua $(DESTDIR)$(LUA_LIB_DIR)/ngx/ssl/ + +diff --git lib/resty/core.lua lib/resty/core.lua +index 5472230..7d3ab16 100644 +--- lib/resty/core.lua ++++ lib/resty/core.lua +@@ -23,6 +23,7 @@ if subsystem == 'http' then + end + + ++require "resty.core.socket.tcp" + require "resty.core.misc" + require "resty.core.ctx" + +diff --git lib/resty/core/socket/tcp.lua lib/resty/core/socket/tcp.lua +new file mode 100644 +index 0000000..89454ad +--- /dev/null ++++ lib/resty/core/socket/tcp.lua +@@ -0,0 +1,284 @@ ++-- Copyright (C) by OpenResty Inc. ++ ++ ++local base = require "resty.core.base" ++local ffi = require "ffi" ++local ssl = require "ngx.ssl" ++ ++ ++local C = ffi.C ++local ffi_str = ffi.string ++local ffi_gc = ffi.gc ++local FFI_ERROR = base.FFI_ERROR ++local FFI_DONE = base.FFI_DONE ++local FFI_OK = base.FFI_OK ++local FFI_AGAIN = base.FFI_AGAIN ++local FFI_NO_REQ_CTX = base.FFI_NO_REQ_CTX ++local get_request = base.get_request ++local new_tab = base.new_tab ++local clear_tab = base.clear_tab ++local error = error ++local assert = assert ++local type = type ++local pcall = pcall ++local select = select ++local co_yield = coroutine._yield ++local io_open = io.open ++local subsystem = ngx.config.subsystem ++ ++ ++local ngx_lua_ffi_socket_tcp_tlshandshake ++local ngx_lua_ffi_socket_tcp_get_tlshandshake_result ++local ngx_lua_ffi_tls_free_session ++ ++if subsystem == 'http' then ++ ffi.cdef[[ ++typedef struct ngx_http_lua_socket_tcp_upstream_s ++ ngx_http_lua_socket_tcp_upstream_t; ++ ++int ngx_http_lua_ffi_socket_tcp_tlshandshake(ngx_http_request_t *r, ++ ngx_http_lua_socket_tcp_upstream_t *u, void *sess, ++ int enable_session_reuse, ngx_str_t *server_name, int verify, ++ int ocsp_status_req, void *chain, void *pkey, char **errmsg); ++ ++int ngx_http_lua_ffi_socket_tcp_get_tlshandshake_result(ngx_http_request_t *r, ++ ngx_http_lua_socket_tcp_upstream_t *u, void **sess, char **errmsg, ++ int *openssl_error_code); ++ ++void ngx_http_lua_ffi_tls_free_session(void *sess); ++]] ++ ++ ngx_lua_ffi_socket_tcp_tlshandshake = ++ C.ngx_http_lua_ffi_socket_tcp_tlshandshake ++ ngx_lua_ffi_socket_tcp_get_tlshandshake_result = ++ C.ngx_http_lua_ffi_socket_tcp_get_tlshandshake_result ++ ngx_lua_ffi_tls_free_session = C.ngx_http_lua_ffi_tls_free_session ++ ++elseif subsystem == 'stream' then ++ ffi.cdef[[ ++typedef struct ngx_stream_lua_socket_tcp_upstream_s ++ ngx_stream_lua_socket_tcp_upstream_t; ++ ++int ngx_stream_lua_ffi_socket_tcp_tlshandshake(ngx_stream_lua_request_t *r, ++ ngx_stream_lua_socket_tcp_upstream_t *u, void *sess, ++ int enable_session_reuse, ngx_str_t *server_name, int verify, ++ int ocsp_status_req, void *chain, void *pkey, char **errmsg); ++ ++int ngx_stream_lua_ffi_socket_tcp_get_tlshandshake_result( ++ ngx_stream_lua_request_t *r, ++ ngx_stream_lua_socket_tcp_upstream_t *u, void **sess, char **errmsg, ++ int *openssl_error_code); ++ ++void ngx_stream_lua_ffi_tls_free_session(void *sess); ++]] ++ ++ ngx_lua_ffi_socket_tcp_tlshandshake = ++ C.ngx_stream_lua_ffi_socket_tcp_tlshandshake ++ ngx_lua_ffi_socket_tcp_get_tlshandshake_result = ++ C.ngx_stream_lua_ffi_socket_tcp_get_tlshandshake_result ++ ngx_lua_ffi_tls_free_session = C.ngx_stream_lua_ffi_tls_free_session ++end ++ ++ ++local SOCKET_CTX_INDEX = 1 ++ ++ ++local errmsg = base.get_errmsg_ptr() ++local session_ptr = ffi.new("void *[1]") ++local server_name_str = ffi.new("ngx_str_t[1]") ++local openssl_error_code = ffi.new("int[1]") ++local cached_options = new_tab(0, 4) ++ ++ ++local function read_file(path) ++ local f, err = io_open(path) ++ if not f then ++ return nil, err ++ end ++ ++ local txt, err = f:read("*a") ++ f:close() ++ if not txt then ++ return nil, err ++ end ++ ++ return txt ++end ++ ++ ++local function report_handshake_error(errmsg, openssl_error_code) ++ if openssl_error_code[0] ~= 0 then ++ return nil, openssl_error_code[0] .. ": " .. ffi_str(errmsg[0]) ++ end ++ ++ return nil, ffi_str(errmsg[0]) ++end ++ ++ ++local function tlshandshake(self, options) ++ if not options then ++ clear_tab(cached_options) ++ options = cached_options ++ ++ elseif type(options) ~= "table" then ++ error("bad options arg: table expected", 2) ++ end ++ ++ local r = get_request() ++ if not r then ++ error("no request found", 2) ++ end ++ ++ local reused_session = options.reused_session ++ session_ptr[0] = type(reused_session) == "cdata" and reused_session or nil ++ ++ if options.server_name then ++ server_name_str[0].data = options.server_name ++ server_name_str[0].len = #options.server_name ++ ++ else ++ server_name_str[0].data = nil ++ server_name_str[0].len = 0 ++ end ++ ++ local client_cert, client_pkey ++ ++ local client_cert_path = options.client_cert_path ++ local client_pkey_path = options.client_priv_key_path ++ if client_cert_path then ++ if not client_pkey_path then ++ error("client certificate supplied without corresponding " .. ++ "private key", 2) ++ end ++ ++ if type(client_cert_path) ~= "string" then ++ error("bad client_cert option type", 2) ++ end ++ ++ if type(client_pkey_path) ~= "string" then ++ error("bad client_priv_key option type", 2) ++ end ++ ++ local txt, err = read_file(client_cert_path) ++ if not txt then ++ return nil, err ++ end ++ ++ local cert, err = ssl.parse_pem_cert(txt) ++ if not cert then ++ return nil, err ++ end ++ ++ client_cert = cert ++ ++ local txt, err = read_file(client_pkey_path) ++ if not txt then ++ return nil, err ++ end ++ ++ local pkey, err = ssl.parse_pem_priv_key(txt) ++ if not pkey then ++ return nil, err ++ end ++ ++ client_pkey = pkey ++ end ++ ++ local u = self[SOCKET_CTX_INDEX] ++ ++ local rc = ngx_lua_ffi_socket_tcp_tlshandshake(r, u, ++ session_ptr[0], ++ reused_session ~= false, ++ server_name_str, ++ options.verify and 1 or 0, ++ options.ocsp_status_req and 1 or 0, ++ client_cert, client_pkey, errmsg) ++ ++ if rc == FFI_NO_REQ_CTX then ++ error("no request ctx found", 2) ++ end ++ ++ if rc == FFI_ERROR then ++ return nil, ffi_str(errmsg[0]) ++ end ++ ++ if rc == FFI_DONE then ++ return reused_session ++ end ++ ++ while true do ++ if rc == FFI_OK then ++ if reused_session == false then ++ return true ++ end ++ ++ rc = ngx_lua_ffi_socket_tcp_get_tlshandshake_result(r, u, ++ session_ptr, errmsg, openssl_error_code) ++ ++ if rc == FFI_ERROR then ++ return report_handshake_error(errmsg, openssl_error_code) ++ end ++ ++ if session_ptr[0] == nil then ++ return nil ++ end ++ ++ return ffi_gc(session_ptr[0], ngx_lua_ffi_tls_free_session) ++ end ++ ++ assert(rc == FFI_AGAIN) ++ ++ co_yield() ++ ++ rc = ngx_lua_ffi_socket_tcp_get_tlshandshake_result(r, u, ++ session_ptr, errmsg, openssl_error_code) ++ ++ if rc == FFI_ERROR then ++ return report_handshake_error(errmsg, openssl_error_code) ++ end ++ end ++end ++ ++ ++local function sslhandshake(self, reused_session, server_name, ssl_verify, ++ send_status_req, ...) ++ ++ local n = select("#", ...) ++ if not self or n > 1 then ++ error("ngx.socket sslhandshake: expecting 1 ~ 5 arguments " .. ++ "(including the object), but seen " .. (self and 5 + n or 0)) ++ end ++ ++ cached_options.reused_session = reused_session ++ cached_options.server_name = server_name ++ cached_options.verify = ssl_verify ++ cached_options.ocsp_status_req = send_status_req ++ ++ local res, err = tlshandshake(self, cached_options) ++ ++ clear_tab(cached_options) ++ ++ return res, err ++end ++ ++ ++do ++ local old_socket_tcp = ngx.socket.tcp ++ ++ function ngx.socket.tcp() ++ local ok, sock = pcall(old_socket_tcp) ++ if not ok then ++ error(sock, 2) ++ end ++ ++ sock.tlshandshake = tlshandshake ++ sock.sslhandshake = sslhandshake ++ ++ return sock ++ end ++end ++ ++ ++return { ++ version = base.version ++} diff --git a/patch/1.21.4.1/nginx-client_max_body_size.patch b/patch/1.21.4.1/nginx-client_max_body_size.patch new file mode 100644 index 0000000..d8519b2 --- /dev/null +++ b/patch/1.21.4.1/nginx-client_max_body_size.patch @@ -0,0 +1,127 @@ +diff --git src/http/ngx_http_core_module.c src/http/ngx_http_core_module.c +index 6388140..b900467 100644 +--- src/http/ngx_http_core_module.c ++++ src/http/ngx_http_core_module.c +@@ -8,6 +8,9 @@ + #include + #include + #include ++#if (NGX_HTTP_APISIX) ++#include ++#endif + + + typedef struct { +@@ -985,7 +988,12 @@ ngx_http_core_find_config_phase(ngx_http_request_t *r, + "http cl:%O max:%O", + r->headers_in.content_length_n, clcf->client_max_body_size); + ++#if (NGX_HTTP_APISIX) ++ if (!ngx_http_apisix_delay_client_max_body_check(r) ++ && r->headers_in.content_length_n != -1 ++#else + if (r->headers_in.content_length_n != -1 ++#endif + && !r->discard_body + && clcf->client_max_body_size + && clcf->client_max_body_size < r->headers_in.content_length_n) +diff --git src/http/ngx_http_request_body.c src/http/ngx_http_request_body.c +index 71d7e9a..99fcbad 100644 +--- src/http/ngx_http_request_body.c ++++ src/http/ngx_http_request_body.c +@@ -8,6 +8,9 @@ + #include + #include + #include ++#if (NGX_HTTP_APISIX) ++#include ++#endif + + + static void ngx_http_read_client_request_body_handler(ngx_http_request_t *r); +@@ -48,6 +51,25 @@ ngx_http_read_client_request_body(ngx_http_request_t *r, + return NGX_OK; + } + ++#if (NGX_HTTP_APISIX) ++ if (ngx_http_apisix_delay_client_max_body_check(r)) { ++ off_t max_body_size = ngx_http_apisix_client_max_body_size(r); ++ ++ if (r->headers_in.content_length_n != -1 ++ && max_body_size ++ && max_body_size < r->headers_in.content_length_n) ++ { ++ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, ++ "client intended to send too large body: %O bytes", ++ r->headers_in.content_length_n); ++ ++ r->expect_tested = 1; ++ rc = NGX_HTTP_REQUEST_ENTITY_TOO_LARGE; ++ goto done; ++ } ++ } ++#endif ++ + if (ngx_http_test_expect(r) != NGX_OK) { + rc = NGX_HTTP_INTERNAL_SERVER_ERROR; + goto done; +@@ -1025,6 +1047,10 @@ ngx_http_request_body_chunked_filter(ngx_http_request_t *r, ngx_chain_t *in) + out = NULL; + ll = &out; + ++#if (NGX_HTTP_APISIX) ++ off_t max_body_size = ngx_http_apisix_client_max_body_size(r); ++#endif ++ + if (rb->rest == -1) { + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, +@@ -1048,8 +1074,15 @@ ngx_http_request_body_chunked_filter(ngx_http_request_t *r, ngx_chain_t *in) + + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + ++#if (NGX_HTTP_APISIX) ++ (void) clcf; /* unused */ ++ ++ if (max_body_size ++ && max_body_size ++#else + if (clcf->client_max_body_size + && clcf->client_max_body_size ++#endif + - r->headers_in.content_length_n < rb->chunked->size) + { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, +diff --git src/http/v2/ngx_http_v2.c src/http/v2/ngx_http_v2.c +index 43a4fde..43c78f9 100644 +--- src/http/v2/ngx_http_v2.c ++++ src/http/v2/ngx_http_v2.c +@@ -9,6 +9,9 @@ + #include + #include + #include ++#if (NGX_HTTP_APISIX) ++#include ++#endif + + + typedef struct { +@@ -4211,10 +4214,18 @@ ngx_http_v2_filter_request_body(ngx_http_request_t *r) + } + + } else { ++#if (NGX_HTTP_APISIX) ++ off_t max_body_size = ngx_http_apisix_client_max_body_size(r); ++ ++ (void) clcf; /* unused */ ++ ++ if (max_body_size && rb->received > max_body_size) ++#else + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + + if (clcf->client_max_body_size + && rb->received > clcf->client_max_body_size) ++#endif + { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "client intended to send too large chunked body: " diff --git a/patch/1.21.4.1/nginx-connection-original-dst.patch b/patch/1.21.4.1/nginx-connection-original-dst.patch new file mode 100644 index 0000000..b88da20 --- /dev/null +++ b/patch/1.21.4.1/nginx-connection-original-dst.patch @@ -0,0 +1,112 @@ +diff --git auto/os/linux auto/os/linux +index 5e280eca..086e5372 100644 +--- auto/os/linux ++++ auto/os/linux +@@ -190,6 +190,21 @@ ngx_feature_test="struct __user_cap_data_struct data; + (void) SYS_capset" + . auto/feature + ++# netfilter_ipv4 ++ ++ngx_feature="netfilter_ipv4" ++ngx_feature_name="NGX_HAVE_NETFILTER_IPV4" ++ngx_feature_run=no ++ngx_feature_incs="#include " ++ngx_feature_path= ++ngx_feature_libs= ++ngx_feature_test="int so_original_dst; ++ ++ so_original_dst = SO_ORIGINAL_DST; ++ ++ (void) so_original_dst;" ++. auto/feature ++ + + # crypt_r() + +diff --git src/http/ngx_http_variables.c src/http/ngx_http_variables.c +index c2113c84..1c2a06a7 100644 +--- src/http/ngx_http_variables.c ++++ src/http/ngx_http_variables.c +@@ -130,6 +130,11 @@ static ngx_int_t ngx_http_variable_connection(ngx_http_request_t *r, + static ngx_int_t ngx_http_variable_connection_requests(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data); + ++#if (NGX_HAVE_NETFILTER_IPV4) ++static ngx_int_t ngx_http_variable_connection_dst(ngx_http_request_t *r, ++ ngx_http_variable_value_t *v, uintptr_t data); ++#endif ++ + static ngx_int_t ngx_http_variable_nginx_version(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data); + static ngx_int_t ngx_http_variable_hostname(ngx_http_request_t *r, +@@ -342,6 +347,11 @@ static ngx_http_variable_t ngx_http_core_variables[] = { + { ngx_string("connection_requests"), NULL, + ngx_http_variable_connection_requests, 0, 0, 0 }, + ++#if (NGX_HAVE_NETFILTER_IPV4) ++ { ngx_string("connection_original_dst"), NULL, ++ ngx_http_variable_connection_dst, 0, 0, 0 }, ++#endif ++ + { ngx_string("nginx_version"), NULL, ngx_http_variable_nginx_version, + 0, 0, 0 }, + +@@ -2252,6 +2262,43 @@ ngx_http_variable_connection_requests(ngx_http_request_t *r, + } + + ++#if (NGX_HAVE_NETFILTER_IPV4) ++static ngx_int_t ++ngx_http_variable_connection_dst(ngx_http_request_t *r, ++ ngx_http_variable_value_t *v, uintptr_t data) ++{ ++ struct sockaddr_in dst; ++ socklen_t socklen; ++ int rn; ++ u_char *p; ++ ++ socklen = sizeof(struct sockaddr_in); ++ ++ rn = getsockopt(r->connection->fd, SOL_IP, SO_ORIGINAL_DST, (void *) &dst, ++ &socklen); ++ if (rn < 0) { ++ ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_socket_errno, ++ "getsockopt(SO_ORIGINAL_DST) failed"); ++ return NGX_ERROR; ++ } ++ ++ p = ngx_pnalloc(r->pool, NGX_SOCKADDR_STRLEN); ++ if (p == NULL) { ++ return NGX_ERROR; ++ } ++ ++ v->len = ngx_sock_ntop((struct sockaddr *) &dst, socklen, p, ++ NGX_SOCKADDR_STRLEN, dst.sin_port); ++ v->valid = 1; ++ v->no_cacheable = 0; ++ v->not_found = 0; ++ v->data = p; ++ ++ return NGX_OK; ++} ++#endif ++ ++ + static ngx_int_t + ngx_http_variable_nginx_version(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data) +diff --git src/os/unix/ngx_linux_config.h src/os/unix/ngx_linux_config.h +index 3036caeb..2353e9b3 100644 +--- src/os/unix/ngx_linux_config.h ++++ src/os/unix/ngx_linux_config.h +@@ -103,6 +103,9 @@ typedef struct iocb ngx_aiocb_t; + #include + #endif + ++#if (NGX_HAVE_NETFILTER_IPV4) ++#include ++#endif + + #define NGX_LISTEN_BACKLOG 511 + diff --git a/patch/1.21.4.1/nginx-enable_ntls.patch b/patch/1.21.4.1/nginx-enable_ntls.patch new file mode 100644 index 0000000..641e243 --- /dev/null +++ b/patch/1.21.4.1/nginx-enable_ntls.patch @@ -0,0 +1,27 @@ +diff --git src/http/ngx_http_request.c src/http/ngx_http_request.c +index 013b715..96be553 100644 +--- src/http/ngx_http_request.c ++++ src/http/ngx_http_request.c +@@ -8,6 +8,9 @@ + #include + #include + #include ++#if (NGX_HTTP_APISIX) ++#include ++#endif + + + static void ngx_http_wait_request_handler(ngx_event_t *ev); +@@ -754,6 +757,12 @@ ngx_http_ssl_handshake(ngx_event_t *rev) + return; + } + ++#if (TONGSUO_VERSION_NUMBER && NGX_HTTP_APISIX) ++ if (ngx_http_apisix_is_ntls_enabled(hc->conf_ctx)) { ++ SSL_enable_ntls(c->ssl->connection); ++ } ++#endif ++ + ngx_reusable_connection(c, 0); + + rc = ngx_ssl_handshake(c); diff --git a/patch/1.21.4.1/nginx-error_page_contains_apisix.patch b/patch/1.21.4.1/nginx-error_page_contains_apisix.patch new file mode 100644 index 0000000..e882e36 --- /dev/null +++ b/patch/1.21.4.1/nginx-error_page_contains_apisix.patch @@ -0,0 +1,47 @@ +diff --git docs/html/50x.html docs/html/50x.html +index 356d6df..cd67297 100644 +--- docs/html/50x.html ++++ docs/html/50x.html +@@ -14,12 +14,7 @@ + + +

An error occurred.

+-

Sorry, the page you are looking for is currently unavailable.
+-Please try again later.

+-

If you are the system administrator of this resource then you should check +-the error log for details.

+-

We have articles on troubleshooting issues like high CPU usage and +-large memory usage on our official blog site. +-

Faithfully yours, OpenResty.

++

You can report issue to APISIX

++

Faithfully yours, APISIX.

+ + +diff --git src/http/ngx_http_special_response.c src/http/ngx_http_special_response.c +index 0cfc299..79493e2 100644 +--- src/http/ngx_http_special_response.c ++++ src/http/ngx_http_special_response.c +@@ -20,6 +20,7 @@ static ngx_int_t ngx_http_send_refresh(ngx_http_request_t *r); + + static u_char ngx_http_error_full_tail[] = + "
" NGINX_VER "
" CRLF ++"

Powered by APISIX.

" + "" CRLF + "" CRLF + ; +@@ -27,6 +28,7 @@ static u_char ngx_http_error_full_tail[] = + + static u_char ngx_http_error_build_tail[] = + "
" NGINX_VER_BUILD "
" CRLF ++"

Powered by APISIX.

" + "" CRLF + "" CRLF + ; +@@ -34,6 +36,7 @@ static u_char ngx_http_error_build_tail[] = + + static u_char ngx_http_error_tail[] = + "
openresty
" CRLF ++"

Powered by APISIX.

" + "" CRLF + "" CRLF + ; diff --git a/patch/1.21.4.1/nginx-get_last_reopen_time.patch b/patch/1.21.4.1/nginx-get_last_reopen_time.patch new file mode 100644 index 0000000..d009116 --- /dev/null +++ b/patch/1.21.4.1/nginx-get_last_reopen_time.patch @@ -0,0 +1,72 @@ +diff --git src/os/unix/ngx_process_cycle.c src/os/unix/ngx_process_cycle.c +index fe5f34a..e8ebf3d 100644 +--- src/os/unix/ngx_process_cycle.c ++++ src/os/unix/ngx_process_cycle.c +@@ -45,6 +45,9 @@ sig_atomic_t ngx_debug_quit; + ngx_uint_t ngx_exiting; + sig_atomic_t ngx_reconfigure; + sig_atomic_t ngx_reopen; ++#if (NGX_HTTP_APISIX) ++ngx_uint_t ngx_last_reopen_msec; ++#endif + + sig_atomic_t ngx_change_binary; + ngx_pid_t ngx_new_binary; +@@ -287,6 +290,9 @@ ngx_master_process_cycle(ngx_cycle_t *cycle) + void + ngx_single_process_cycle(ngx_cycle_t *cycle) + { ++#if (NGX_HTTP_APISIX) ++ ngx_time_t *tp; ++#endif + ngx_uint_t i; + + if (ngx_set_environment(cycle, NULL) == NULL) { +@@ -363,6 +369,10 @@ ngx_single_process_cycle(ngx_cycle_t *cycle) + + if (ngx_reopen) { + ngx_reopen = 0; ++#if (NGX_HTTP_APISIX) ++ tp = ngx_timeofday(); ++ ngx_last_reopen_msec = tp->sec * 1000 + tp->msec; ++#endif + ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "reopening logs"); + ngx_reopen_files(cycle, (ngx_uid_t) -1); + } +@@ -759,6 +769,9 @@ ngx_master_process_exit(ngx_cycle_t *cycle) + static void + ngx_worker_process_cycle(ngx_cycle_t *cycle, void *data) + { ++#if (NGX_HTTP_APISIX) ++ ngx_time_t *tp; ++#endif + ngx_int_t worker = (intptr_t) data; + + ngx_process = NGX_PROCESS_WORKER; +@@ -802,6 +815,10 @@ ngx_worker_process_cycle(ngx_cycle_t *cycle, void *data) + + if (ngx_reopen) { + ngx_reopen = 0; ++#if (NGX_HTTP_APISIX) ++ tp = ngx_timeofday(); ++ ngx_last_reopen_msec = tp->sec * 1000 + tp->msec; ++#endif + ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "reopening logs"); + ngx_reopen_files(cycle, -1); + } +@@ -809,6 +826,15 @@ ngx_worker_process_cycle(ngx_cycle_t *cycle, void *data) + } + + ++#if (NGX_HTTP_APISIX) ++ngx_uint_t ++ngx_worker_process_get_last_reopen_ms() ++{ ++ return ngx_last_reopen_msec; ++} ++#endif ++ ++ + static void + ngx_worker_process_init(ngx_cycle_t *cycle, ngx_int_t worker) + { diff --git a/patch/1.21.4.1/nginx-grpc_set_header_authority.patch b/patch/1.21.4.1/nginx-grpc_set_header_authority.patch new file mode 100644 index 0000000..4a9a25a --- /dev/null +++ b/patch/1.21.4.1/nginx-grpc_set_header_authority.patch @@ -0,0 +1,18 @@ +diff --git src/http/modules/ngx_http_grpc_module.c src/http/modules/ngx_http_grpc_module.c +index 58332866..01c0f489 100644 +--- src/http/modules/ngx_http_grpc_module.c ++++ src/http/modules/ngx_http_grpc_module.c +@@ -4621,6 +4621,13 @@ ngx_http_grpc_init_headers(ngx_conf_t *cf, ngx_http_grpc_loc_conf_t *conf, + conf->host_set = 1; + } + ++#if (NGX_HTTP_APISIX) ++ if (src[i].key.len == 10 ++ && ngx_strncasecmp(src[i].key.data, (u_char *) ":authority", 10) == 0) ++ { ++ conf->host_set = 1; ++ } ++#endif + s = ngx_array_push(&headers_merged); + if (s == NULL) { + return NGX_ERROR; diff --git a/patch/1.21.4.1/nginx-gzip.patch b/patch/1.21.4.1/nginx-gzip.patch new file mode 100644 index 0000000..9b6b6f4 --- /dev/null +++ b/patch/1.21.4.1/nginx-gzip.patch @@ -0,0 +1,143 @@ +diff --git src/http/modules/ngx_http_gzip_filter_module.c src/http/modules/ngx_http_gzip_filter_module.c +index c75169c..723b040 100644 +--- src/http/modules/ngx_http_gzip_filter_module.c ++++ src/http/modules/ngx_http_gzip_filter_module.c +@@ -8,6 +8,9 @@ + #include + #include + #include ++#if (NGX_HTTP_APISIX) ++#include ++#endif + + #include + +@@ -225,6 +228,26 @@ ngx_http_gzip_header_filter(ngx_http_request_t *r) + + conf = ngx_http_get_module_loc_conf(r, ngx_http_gzip_filter_module); + ++#if (NGX_HTTP_APISIX) ++ if ((r->headers_out.status != NGX_HTTP_OK ++ && r->headers_out.status != NGX_HTTP_FORBIDDEN ++ && r->headers_out.status != NGX_HTTP_NOT_FOUND) ++ || (r->headers_out.content_encoding ++ && r->headers_out.content_encoding->value.len) ++ || r->header_only) ++ { ++ return ngx_http_next_header_filter(r); ++ } ++ ++ if (!ngx_http_apisix_is_gzip_set(r) ++ && (!conf->enable ++ || (r->headers_out.content_length_n != -1 ++ && r->headers_out.content_length_n < conf->min_length) ++ || ngx_http_test_content_type(r, &conf->types) == NULL)) ++ { ++ return ngx_http_next_header_filter(r); ++ } ++#else + if (!conf->enable + || (r->headers_out.status != NGX_HTTP_OK + && r->headers_out.status != NGX_HTTP_FORBIDDEN +@@ -238,6 +261,7 @@ ngx_http_gzip_header_filter(ngx_http_request_t *r) + { + return ngx_http_next_header_filter(r); + } ++#endif + + r->gzip_vary = 1; + +@@ -515,7 +539,18 @@ ngx_http_gzip_filter_memory(ngx_http_request_t *r, ngx_http_gzip_ctx_t *ctx) + * uses 128K hash. + */ + ++#if (NGX_HTTP_APISIX) ++ ngx_int_t level; ++ ++ level = ngx_http_apisix_get_gzip_compress_level(r); ++ if (level == NGX_DECLINED) { ++ level = conf->level; ++ } ++ ++ if (level == 1) { ++#else + if (conf->level == 1) { ++#endif + wbits = ngx_max(wbits, 13); + } + +@@ -615,8 +650,20 @@ ngx_http_gzip_filter_deflate_start(ngx_http_request_t *r, + ctx->zstream.zfree = ngx_http_gzip_filter_free; + ctx->zstream.opaque = ctx; + ++#if (NGX_HTTP_APISIX) ++ ngx_int_t level; ++ ++ level = ngx_http_apisix_get_gzip_compress_level(r); ++ if (level == NGX_DECLINED) { ++ level = conf->level; ++ } ++ ++ rc = deflateInit2(&ctx->zstream, (int) level, Z_DEFLATED, ++ ctx->wbits + 16, ctx->memlevel, Z_DEFAULT_STRATEGY); ++#else + rc = deflateInit2(&ctx->zstream, (int) conf->level, Z_DEFLATED, + ctx->wbits + 16, ctx->memlevel, Z_DEFAULT_STRATEGY); ++#endif + + if (rc != Z_OK) { + ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, +@@ -705,6 +752,16 @@ ngx_http_gzip_filter_get_buf(ngx_http_request_t *r, ngx_http_gzip_ctx_t *ctx) + + conf = ngx_http_get_module_loc_conf(r, ngx_http_gzip_filter_module); + ++#if (NGX_HTTP_APISIX) ++ ngx_int_t num; ++ size_t size; ++ ++ if (ngx_http_apisix_get_gzip_buffer_conf(r, &num, &size) == NGX_DECLINED) { ++ num = conf->bufs.num; ++ size = conf->bufs.size; ++ } ++#endif ++ + if (ctx->free) { + + cl = ctx->free; +@@ -713,9 +770,15 @@ ngx_http_gzip_filter_get_buf(ngx_http_request_t *r, ngx_http_gzip_ctx_t *ctx) + + ngx_free_chain(r->pool, cl); + ++#if (NGX_HTTP_APISIX) ++ } else if (ctx->bufs < num) { ++ ++ ctx->out_buf = ngx_create_temp_buf(r->pool, size); ++#else + } else if (ctx->bufs < conf->bufs.num) { + + ctx->out_buf = ngx_create_temp_buf(r->pool, conf->bufs.size); ++#endif + if (ctx->out_buf == NULL) { + return NGX_ERROR; + } +diff --git src/http/ngx_http_core_module.c src/http/ngx_http_core_module.c +index b900467..160e512 100644 +--- src/http/ngx_http_core_module.c ++++ src/http/ngx_http_core_module.c +@@ -2065,9 +2065,16 @@ ngx_http_gzip_ok(ngx_http_request_t *r) + return NGX_DECLINED; + } + ++#if (NGX_HTTP_APISIX) ++ if (!ngx_http_apisix_is_gzip_set(r) ++ && r->http_version < clcf->gzip_http_version) { ++ return NGX_DECLINED; ++ } ++#else + if (r->http_version < clcf->gzip_http_version) { + return NGX_DECLINED; + } ++#endif + + if (r->headers_in.via == NULL) { + goto ok; diff --git a/patch/1.21.4.1/nginx-listen-in-privileged-agent.patch b/patch/1.21.4.1/nginx-listen-in-privileged-agent.patch new file mode 100644 index 0000000..79db34b --- /dev/null +++ b/patch/1.21.4.1/nginx-listen-in-privileged-agent.patch @@ -0,0 +1,141 @@ +diff --git src/core/ngx_connection.c src/core/ngx_connection.c +index 568ae3d..e22c990 100644 +--- src/core/ngx_connection.c ++++ src/core/ngx_connection.c +@@ -434,6 +434,10 @@ ngx_open_listening_sockets(ngx_cycle_t *cycle) + continue; + } + ++ if (ngx_is_privileged_agent != ls[i].privileged_agent) { ++ continue; ++ } ++ + #if (NGX_HAVE_REUSEPORT) + + if (ls[i].add_reuseport) { +diff --git src/core/ngx_connection.h src/core/ngx_connection.h +index be75d82..12c8694 100644 +--- src/core/ngx_connection.h ++++ src/core/ngx_connection.h +@@ -66,6 +66,7 @@ struct ngx_listening_s { + unsigned shared:1; /* shared between threads or processes */ + unsigned addr_ntop:1; + unsigned wildcard:1; ++ unsigned privileged_agent:1; + + #if (NGX_HAVE_INET6) + unsigned ipv6only:1; +diff --git src/event/ngx_event.c src/event/ngx_event.c +index d800af0..f73e57c 100644 +--- src/event/ngx_event.c ++++ src/event/ngx_event.c +@@ -818,7 +818,9 @@ ngx_event_process_init(ngx_cycle_t *cycle) + for (i = 0; i < cycle->listening.nelts; i++) { + + #if (NGX_HAVE_REUSEPORT) +- if (ls[i].reuseport && ls[i].worker != ngx_worker) { ++ if ((ngx_is_privileged_agent && !ls[i].privileged_agent) ++ || (ls[i].reuseport && ls[i].worker != ngx_worker)) ++ { + ngx_log_debug2(NGX_LOG_DEBUG_CORE, cycle->log, 0, + "closing unused fd:%d listening on %V", + ls[i].fd, &ls[i].addr_text); +@@ -833,6 +835,10 @@ ngx_event_process_init(ngx_cycle_t *cycle) + + continue; + } ++ ++ if (!ngx_is_privileged_agent && ls[i].privileged_agent) { ++ continue; ++ } + #endif + + c = ngx_get_connection(ls[i].fd, cycle->log); +diff --git src/http/ngx_http.c src/http/ngx_http.c +index e1d3d00..7ad72e3 100644 +--- src/http/ngx_http.c ++++ src/http/ngx_http.c +@@ -1217,6 +1217,13 @@ ngx_http_add_addresses(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf, + continue; + } + ++ if (lsopt->privileged_agent != addr[i].opt.privileged_agent) { ++ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, ++ "%V is already occupied by privileged agent", ++ &addr[i].opt.addr_text); ++ return NGX_ERROR; ++ } ++ + /* the address is already in the address list */ + + if (ngx_http_add_server(cf, cscf, &addr[i]) != NGX_OK) { +@@ -1769,6 +1776,8 @@ ngx_http_add_listening(ngx_conf_t *cf, ngx_http_conf_addr_t *addr) + ls->reuseport = addr->opt.reuseport; + #endif + ++ ls->privileged_agent = addr->opt.privileged_agent; ++ + return ls; + } + +diff --git src/http/ngx_http_core_module.c src/http/ngx_http_core_module.c +index 6287d6e..a84dd80 100644 +--- src/http/ngx_http_core_module.c ++++ src/http/ngx_http_core_module.c +@@ -4202,6 +4202,20 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) + continue; + } + ++ if (ngx_strncmp(value[n].data, "enable_process=", 15) == 0) { ++ if (ngx_strcmp(&value[n].data[15], "privileged_agent") == 0) { ++ lsopt.privileged_agent = 1; ++ ++ } else { ++ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, ++ "invalid enable_process value: \"%s\"", ++ &value[n].data[15]); ++ return NGX_CONF_ERROR; ++ } ++ ++ continue; ++ } ++ + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid parameter \"%V\"", &value[n]); + return NGX_CONF_ERROR; +diff --git src/http/ngx_http_core_module.h src/http/ngx_http_core_module.h +index 2aadae7..6ba3a90 100644 +--- src/http/ngx_http_core_module.h ++++ src/http/ngx_http_core_module.h +@@ -82,6 +82,7 @@ typedef struct { + unsigned reuseport:1; + unsigned so_keepalive:2; + unsigned proxy_protocol:1; ++ unsigned privileged_agent:1; + + int backlog; + int rcvbuf; +diff --git src/os/unix/ngx_process_cycle.c src/os/unix/ngx_process_cycle.c +index e8ebf3d..8227ecf 100644 +--- src/os/unix/ngx_process_cycle.c ++++ src/os/unix/ngx_process_cycle.c +@@ -1250,7 +1250,11 @@ ngx_privileged_agent_process_cycle(ngx_cycle_t *cycle, void *data) + ngx_process = NGX_PROCESS_HELPER; + ngx_is_privileged_agent = 1; + +- ngx_close_listening_sockets(cycle); ++ if (ngx_open_listening_sockets(cycle) != NGX_OK) { ++ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, ++ "failed to init privileged agent listeners"); ++ exit(2); ++ } + + /* Set a moderate number of connections for a helper process. */ + cycle->connection_n = 512; +@@ -1265,6 +1269,7 @@ ngx_privileged_agent_process_cycle(ngx_cycle_t *cycle, void *data) + + if (ngx_terminate || ngx_quit) { + ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "exiting"); ++ ngx_close_listening_sockets(cycle); + ngx_worker_process_exit(cycle); + } diff --git a/patch/1.21.4.1/nginx-mirror.patch b/patch/1.21.4.1/nginx-mirror.patch new file mode 100644 index 0000000..66a49be --- /dev/null +++ b/patch/1.21.4.1/nginx-mirror.patch @@ -0,0 +1,70 @@ +diff --git src/http/modules/ngx_http_mirror_module.c src/http/modules/ngx_http_mirror_module.c +index 787adb3..61d0fd3 100644 +--- src/http/modules/ngx_http_mirror_module.c ++++ src/http/modules/ngx_http_mirror_module.c +@@ -8,10 +8,16 @@ + #include + #include + #include ++#if (NGX_HTTP_APISIX) ++#include ++#endif + + + typedef struct { + ngx_array_t *mirror; ++#if (NGX_HTTP_APISIX) ++ ngx_flag_t on_demand; ++#endif + ngx_flag_t request_body; + } ngx_http_mirror_loc_conf_t; + +@@ -33,6 +39,15 @@ static ngx_int_t ngx_http_mirror_init(ngx_conf_t *cf); + + static ngx_command_t ngx_http_mirror_commands[] = { + ++#if (NGX_HTTP_APISIX) ++ { ngx_string("apisix_mirror_on_demand"), ++ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, ++ ngx_conf_set_flag_slot, ++ NGX_HTTP_LOC_CONF_OFFSET, ++ offsetof(ngx_http_mirror_loc_conf_t, on_demand), ++ NULL }, ++#endif ++ + { ngx_string("mirror"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_http_mirror, +@@ -99,6 +114,12 @@ ngx_http_mirror_handler(ngx_http_request_t *r) + return NGX_DECLINED; + } + ++#if (NGX_HTTP_APISIX) ++ if (mlcf->on_demand && !ngx_http_apisix_is_mirror_enabled(r)) { ++ return NGX_DECLINED; ++ } ++#endif ++ + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "mirror handler"); + + if (mlcf->request_body) { +@@ -186,6 +207,9 @@ ngx_http_mirror_create_loc_conf(ngx_conf_t *cf) + } + + mlcf->mirror = NGX_CONF_UNSET_PTR; ++#if (NGX_HTTP_APISIX) ++ mlcf->on_demand = NGX_CONF_UNSET; ++#endif + mlcf->request_body = NGX_CONF_UNSET; + + return mlcf; +@@ -198,6 +222,9 @@ ngx_http_mirror_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) + ngx_http_mirror_loc_conf_t *prev = parent; + ngx_http_mirror_loc_conf_t *conf = child; + ++#if (NGX_HTTP_APISIX) ++ ngx_conf_merge_value(conf->on_demand, prev->on_demand, 0); ++#endif + ngx_conf_merge_ptr_value(conf->mirror, prev->mirror, NULL); + ngx_conf_merge_value(conf->request_body, prev->request_body, 1); + diff --git a/patch/1.21.4.1/nginx-privileged_agent_process_thread.patch b/patch/1.21.4.1/nginx-privileged_agent_process_thread.patch new file mode 100644 index 0000000..59160a1 --- /dev/null +++ b/patch/1.21.4.1/nginx-privileged_agent_process_thread.patch @@ -0,0 +1,14 @@ +diff --git src/core/ngx_thread_pool.c src/core/ngx_thread_pool.c +index 7fb0f7f..95081a6 100644 +--- src/core/ngx_thread_pool.c ++++ src/core/ngx_thread_pool.c +@@ -587,6 +587,9 @@ ngx_thread_pool_init_worker(ngx_cycle_t *cycle) + ngx_thread_pool_conf_t *tcf; + + if (ngx_process != NGX_PROCESS_WORKER ++#if HAVE_PRIVILEGED_PROCESS_PATCH ++ && !ngx_is_privileged_agent ++#endif + && ngx_process != NGX_PROCESS_SINGLE) + { + return NGX_OK; diff --git a/patch/1.21.4.1/nginx-proxy_request_buffering.patch b/patch/1.21.4.1/nginx-proxy_request_buffering.patch new file mode 100644 index 0000000..f103407 --- /dev/null +++ b/patch/1.21.4.1/nginx-proxy_request_buffering.patch @@ -0,0 +1,26 @@ +diff --git src/http/modules/ngx_http_proxy_module.c src/http/modules/ngx_http_proxy_module.c +index 3f05235..41c2313 100644 +--- src/http/modules/ngx_http_proxy_module.c ++++ src/http/modules/ngx_http_proxy_module.c +@@ -8,6 +8,9 @@ + #include + #include + #include ++#if (NGX_HTTP_APISIX) ++#include "ngx_http_apisix_module.h" ++#endif + + + #define NGX_HTTP_PROXY_COOKIE_SECURE 0x0001 +@@ -1013,7 +1016,11 @@ ngx_http_proxy_handler(ngx_http_request_t *r) + + u->accel = 1; + ++#if (NGX_HTTP_APISIX) ++ if (!ngx_http_apisix_is_request_buffering(r, plcf->upstream.request_buffering) ++#else + if (!plcf->upstream.request_buffering ++#endif + && plcf->body_values == NULL && plcf->upstream.pass_request_body + && (!r->headers_in.chunked + || plcf->http_version == NGX_HTTP_VERSION_11)) diff --git a/patch/1.21.4.1/nginx-real_ip.patch b/patch/1.21.4.1/nginx-real_ip.patch new file mode 100644 index 0000000..9551ff0 --- /dev/null +++ b/patch/1.21.4.1/nginx-real_ip.patch @@ -0,0 +1,52 @@ +diff --git auto/modules auto/modules +index f1c63f3..a71f9d7 100644 +--- auto/modules ++++ auto/modules +@@ -578,7 +578,7 @@ if [ $HTTP = YES ]; then + + ngx_module_name=ngx_http_realip_module + ngx_module_incs= +- ngx_module_deps= ++ ngx_module_deps=src/http/modules/ngx_http_realip_module.h + ngx_module_srcs=src/http/modules/ngx_http_realip_module.c + ngx_module_libs= + ngx_module_link=$HTTP_REALIP +diff --git src/http/modules/ngx_http_realip_module.c src/http/modules/ngx_http_realip_module.c +index 9586ebe..05a40ea 100644 +--- src/http/modules/ngx_http_realip_module.c ++++ src/http/modules/ngx_http_realip_module.c +@@ -311,6 +311,15 @@ ngx_http_realip_cleanup(void *data) + } + + ++#if (NGX_HTTP_APISIX) ++ngx_int_t ++ngx_http_realip_set_real_addr(ngx_http_request_t *r, ngx_addr_t *addr) ++{ ++ return ngx_http_realip_set_addr(r, addr); ++} ++#endif ++ ++ + static char * + ngx_http_realip_from(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) + { +diff --git src/http/modules/ngx_http_realip_module.h src/http/modules/ngx_http_realip_module.h +new file mode 100644 +index 0000000..8593c4b +--- /dev/null ++++ src/http/modules/ngx_http_realip_module.h +@@ -0,0 +1,13 @@ ++#ifndef _NGX_HTTP_REALIP_H_INCLUDED_ ++#define _NGX_HTTP_REALIP_H_INCLUDED_ ++ ++ ++#include ++#include ++#include ++ ++ ++ngx_int_t ngx_http_realip_set_real_addr(ngx_http_request_t *r, ngx_addr_t *addr); ++ ++ ++#endif /* _NGX_HTTP_REALIP_H_INCLUDED_ */ diff --git a/patch/1.21.4.1/nginx-tcp_over_tls.patch b/patch/1.21.4.1/nginx-tcp_over_tls.patch new file mode 100644 index 0000000..173c2b2 --- /dev/null +++ b/patch/1.21.4.1/nginx-tcp_over_tls.patch @@ -0,0 +1,40 @@ +diff --git src/stream/ngx_stream_proxy_module.c src/stream/ngx_stream_proxy_module.c +index b3d8a43..424c381 100644 +--- src/stream/ngx_stream_proxy_module.c ++++ src/stream/ngx_stream_proxy_module.c +@@ -8,6 +8,9 @@ + #include + #include + #include ++#if (NGX_STREAM_APISIX) ++#include ++#endif + + + typedef struct { +@@ -812,7 +815,13 @@ ngx_stream_proxy_init_upstream(ngx_stream_session_t *s) + + #if (NGX_STREAM_SSL) + ++#if (NGX_STREAM_APISIX) ++ if (pc->type == SOCK_STREAM && ++ (ngx_stream_apisix_is_proxy_ssl_enabled(s) || pscf->ssl_enable)) ++ { ++#else + if (pc->type == SOCK_STREAM && pscf->ssl) { ++#endif + + if (u->proxy_protocol) { + if (ngx_stream_proxy_send_proxy_protocol(s) != NGX_OK) { +@@ -2126,7 +2135,11 @@ ngx_stream_proxy_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) + ngx_conf_merge_ptr_value(conf->ssl_conf_commands, + prev->ssl_conf_commands, NULL); + ++#if (NGX_STREAM_APISIX) ++ if (ngx_stream_proxy_set_ssl(cf, conf) != NGX_OK) { ++#else + if (conf->ssl_enable && ngx_stream_proxy_set_ssl(cf, conf) != NGX_OK) { ++#endif + return NGX_CONF_ERROR; + } + diff --git a/patch/1.21.4.1/nginx-upstream_mtls.patch b/patch/1.21.4.1/nginx-upstream_mtls.patch new file mode 100644 index 0000000..535bd53 --- /dev/null +++ b/patch/1.21.4.1/nginx-upstream_mtls.patch @@ -0,0 +1,25 @@ +diff --git src/http/ngx_http_upstream.c src/http/ngx_http_upstream.c +index 76045c4..cee3e2a 100644 +--- src/http/ngx_http_upstream.c ++++ src/http/ngx_http_upstream.c +@@ -8,6 +8,9 @@ + #include + #include + #include ++#if (NGX_HTTP_APISIX) ++#include ++#endif + + #if (T_NGX_MULTI_UPSTREAM) + #include +@@ -1766,6 +1769,10 @@ ngx_http_upstream_ssl_init_connection(ngx_http_request_t *r, + + r->connection->log->action = "SSL handshaking to upstream"; + ++#if (NGX_HTTP_APISIX) ++ ngx_http_apisix_set_upstream_ssl(r, c); ++#endif ++ + rc = ngx_ssl_handshake(c); + + if (rc == NGX_AGAIN) { diff --git a/patch/1.21.4.1/ngx_lua-bugfix-Apple-Silicon-FFI-ABI-limitation-workaround.patch b/patch/1.21.4.1/ngx_lua-bugfix-Apple-Silicon-FFI-ABI-limitation-workaround.patch new file mode 100644 index 0000000..77a4d34 --- /dev/null +++ b/patch/1.21.4.1/ngx_lua-bugfix-Apple-Silicon-FFI-ABI-limitation-workaround.patch @@ -0,0 +1,48 @@ +diff --git src/ngx_http_lua_headers.c src/ngx_http_lua_headers.c +index 54977dce..8098615d 100644 +--- src/ngx_http_lua_headers.c ++++ src/ngx_http_lua_headers.c +@@ -1240,4 +1240,16 @@ ngx_http_lua_ngx_raw_header_cleanup(void *data) + #endif + + ++#if (NGX_DARWIN) ++int ++ngx_http_lua_ffi_set_resp_header_macos(ngx_http_lua_set_resp_header_params_t *p) ++{ ++ return ngx_http_lua_ffi_set_resp_header(p->r, p->key_data, p->key_len, ++ p->is_nil, p->sval, p->sval_len, ++ p->mvals, p->mvals_len, ++ p->override, p->errmsg); ++} ++#endif ++ ++ + /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ +diff --git src/ngx_http_lua_headers_out.h src/ngx_http_lua_headers_out.h +index 944f57a4..eb3c7947 100644 +--- src/ngx_http_lua_headers_out.h ++++ src/ngx_http_lua_headers_out.h +@@ -12,6 +12,22 @@ + #include "ngx_http_lua_common.h" + + ++#if (NGX_DARWIN) ++typedef struct { ++ ngx_http_request_t *r; ++ const char *key_data; ++ size_t key_len; ++ int is_nil; ++ const char *sval; ++ size_t sval_len; ++ void *mvals; ++ size_t mvals_len; ++ int override; ++ char **errmsg; ++} ngx_http_lua_set_resp_header_params_t; ++#endif ++ ++ + ngx_int_t ngx_http_lua_set_output_header(ngx_http_request_t *r, + ngx_http_lua_ctx_t *ctx, ngx_str_t key, ngx_str_t value, unsigned override); + int ngx_http_lua_get_output_header(lua_State *L, ngx_http_request_t *r, diff --git a/patch/1.21.4.1/ngx_lua-enable_keepalive.patch b/patch/1.21.4.1/ngx_lua-enable_keepalive.patch new file mode 100644 index 0000000..5c37ba5 --- /dev/null +++ b/patch/1.21.4.1/ngx_lua-enable_keepalive.patch @@ -0,0 +1,1156 @@ +diff --git src/ngx_http_lua_balancer.c src/ngx_http_lua_balancer.c +index e4ac57a..b5ffe2e 100644 +--- src/ngx_http_lua_balancer.c ++++ src/ngx_http_lua_balancer.c +@@ -16,46 +16,103 @@ + #include "ngx_http_lua_directive.h" + + ++typedef struct { ++ ngx_uint_t size; ++ ngx_uint_t connections; ++ ++ uint32_t crc32; ++ ++ lua_State *lua_vm; ++ ++ ngx_queue_t cache; ++ ngx_queue_t free; ++} ngx_http_lua_balancer_keepalive_pool_t; ++ ++ ++typedef struct { ++ ngx_queue_t queue; ++ ngx_connection_t *connection; ++ ++ ngx_http_lua_balancer_keepalive_pool_t *cpool; ++} ngx_http_lua_balancer_keepalive_item_t; ++ ++ + struct ngx_http_lua_balancer_peer_data_s { +- /* the round robin data must be first */ +- ngx_http_upstream_rr_peer_data_t rrp; ++ ngx_uint_t cpool_size; ++ ngx_uint_t keepalive_requests; ++ ngx_msec_t keepalive_timeout; ++ ++ ngx_uint_t more_tries; ++ ngx_uint_t total_tries; ++ ++ int last_peer_state; ++ ++ uint32_t cpool_crc32; ++ ++ void *data; + +- ngx_http_lua_srv_conf_t *conf; +- ngx_http_request_t *request; ++ ngx_event_get_peer_pt original_get_peer; ++ ngx_event_free_peer_pt original_free_peer; + +- ngx_uint_t more_tries; +- ngx_uint_t total_tries; ++#if (NGX_HTTP_SSL) ++ ngx_event_set_peer_session_pt original_set_session; ++ ngx_event_save_peer_session_pt original_save_session; ++#endif ++ ++ ngx_http_request_t *request; ++ ngx_http_lua_srv_conf_t *conf; ++ ngx_http_lua_balancer_keepalive_pool_t *cpool; + +- struct sockaddr *sockaddr; +- socklen_t socklen; ++ ngx_str_t *host; + +- ngx_str_t *host; +- in_port_t port; ++ struct sockaddr *sockaddr; ++ socklen_t socklen; + +- int last_peer_state; ++ unsigned keepalive:1; + + #if !(HAVE_NGX_UPSTREAM_TIMEOUT_FIELDS) +- unsigned cloned_upstream_conf; /* :1 */ ++ unsigned cloned_upstream_conf:1; + #endif + }; + + +-#if (NGX_HTTP_SSL) +-static ngx_int_t ngx_http_lua_balancer_set_session(ngx_peer_connection_t *pc, +- void *data); +-static void ngx_http_lua_balancer_save_session(ngx_peer_connection_t *pc, +- void *data); +-#endif ++static ngx_int_t ngx_http_lua_balancer_by_chunk(lua_State *L, ++ ngx_http_request_t *r); + static ngx_int_t ngx_http_lua_balancer_init(ngx_conf_t *cf, + ngx_http_upstream_srv_conf_t *us); + static ngx_int_t ngx_http_lua_balancer_init_peer(ngx_http_request_t *r, + ngx_http_upstream_srv_conf_t *us); + static ngx_int_t ngx_http_lua_balancer_get_peer(ngx_peer_connection_t *pc, + void *data); +-static ngx_int_t ngx_http_lua_balancer_by_chunk(lua_State *L, +- ngx_http_request_t *r); + static void ngx_http_lua_balancer_free_peer(ngx_peer_connection_t *pc, + void *data, ngx_uint_t state); ++static ngx_int_t ngx_http_lua_balancer_create_keepalive_pool(lua_State *L, ++ ngx_log_t *log, uint32_t cpool_crc32, ngx_uint_t cpool_size, ++ ngx_http_lua_balancer_keepalive_pool_t **cpool); ++static void ngx_http_lua_balancer_get_keepalive_pool(lua_State *L, ++ uint32_t cpool_crc32, ngx_http_lua_balancer_keepalive_pool_t **cpool); ++static void ngx_http_lua_balancer_free_keepalive_pool(ngx_log_t *log, ++ ngx_http_lua_balancer_keepalive_pool_t *cpool); ++static void ngx_http_lua_balancer_close(ngx_connection_t *c); ++static void ngx_http_lua_balancer_dummy_handler(ngx_event_t *ev); ++static void ngx_http_lua_balancer_close_handler(ngx_event_t *ev); ++#if (NGX_HTTP_SSL) ++static ngx_int_t ngx_http_lua_balancer_set_session(ngx_peer_connection_t *pc, ++ void *data); ++static void ngx_http_lua_balancer_save_session(ngx_peer_connection_t *pc, ++ void *data); ++#endif ++ ++ ++#define ngx_http_lua_balancer_keepalive_is_enabled(bp) \ ++ ((bp)->keepalive) ++ ++#define ngx_http_lua_balancer_peer_set(bp) \ ++ ((bp)->sockaddr && (bp)->socklen) ++ ++ ++static char ngx_http_lua_balancer_keepalive_pools_table_key; ++static struct sockaddr *ngx_http_lua_balancer_default_server_sockaddr; + + + ngx_int_t +@@ -102,6 +159,61 @@ ngx_http_lua_balancer_handler_inline(ngx_http_request_t *r, + } + + ++static ngx_int_t ++ngx_http_lua_balancer_by_chunk(lua_State *L, ngx_http_request_t *r) ++{ ++ u_char *err_msg; ++ size_t len; ++ ngx_int_t rc; ++ ++ /* init nginx context in Lua VM */ ++ ngx_http_lua_set_req(L, r); ++ ++#ifndef OPENRESTY_LUAJIT ++ ngx_http_lua_create_new_globals_table(L, 0 /* narr */, 1 /* nrec */); ++ ++ /* {{{ make new env inheriting main thread's globals table */ ++ 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 */ ++#endif /* OPENRESTY_LUAJIT */ ++ ++ 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 occurred when running loaded code */ ++ err_msg = (u_char *) lua_tolstring(L, -1, &len); ++ ++ if (err_msg == NULL) { ++ err_msg = (u_char *) "unknown reason"; ++ len = sizeof("unknown reason") - 1; ++ } ++ ++ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, ++ "failed to run balancer_by_lua*: %*s", len, err_msg); ++ ++ lua_settop(L, 0); /* clear remaining elems on stack */ ++ ++ return NGX_ERROR; ++ } ++ ++ lua_settop(L, 0); /* clear remaining elems on stack */ ++ return rc; ++} ++ ++ + char * + ngx_http_lua_balancer_by_lua_block(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf) +@@ -125,16 +237,18 @@ char * + ngx_http_lua_balancer_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf) + { +- u_char *cache_key = NULL; +- u_char *name; +- ngx_str_t *value; +- ngx_http_lua_srv_conf_t *lscf = conf; +- ++ u_char *cache_key = NULL; ++ u_char *name; ++ ngx_str_t *value; ++ ngx_url_t url; + ngx_http_upstream_srv_conf_t *uscf; ++ ngx_http_upstream_server_t *us; ++ ngx_http_lua_srv_conf_t *lscf = conf; + + dd("enter"); + +- /* must specify a content handler */ ++ /* content handler setup */ ++ + if (cmd->post == NULL) { + return NGX_CONF_ERROR; + } +@@ -178,11 +292,40 @@ ngx_http_lua_balancer_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, + + lscf->balancer.src_key = cache_key; + ++ /* balancer setup */ ++ + uscf = ngx_http_conf_get_module_srv_conf(cf, ngx_http_upstream_module); + ++ if (uscf->servers->nelts == 0) { ++ us = ngx_array_push(uscf->servers); ++ if (us == NULL) { ++ return NGX_CONF_ERROR; ++ } ++ ++ ngx_memzero(us, sizeof(ngx_http_upstream_server_t)); ++ ngx_memzero(&url, sizeof(ngx_url_t)); ++ ++ /* just an invalid address as a place holder*/ ++ ngx_str_set(&url.url, "0.0.0.1"); ++ url.default_port = 80; ++ ++ if (ngx_parse_url(cf->pool, &url) != NGX_OK) { ++ return NGX_CONF_ERROR; ++ } ++ ++ us->name = url.url; ++ us->addrs = url.addrs; ++ us->naddrs = url.naddrs; ++ ++ ngx_http_lua_balancer_default_server_sockaddr = us->addrs[0].sockaddr; ++ } ++ + if (uscf->peer.init_upstream) { +- ngx_conf_log_error(NGX_LOG_WARN, cf, 0, +- "load balancing method redefined"); ++ lscf->balancer.original_init_upstream = uscf->peer.init_upstream; ++ ++ } else { ++ lscf->balancer.original_init_upstream = ++ ngx_http_upstream_init_round_robin; + } + + uscf->peer.init_upstream = ngx_http_lua_balancer_init; +@@ -198,14 +341,18 @@ ngx_http_lua_balancer_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, + + + static ngx_int_t +-ngx_http_lua_balancer_init(ngx_conf_t *cf, +- ngx_http_upstream_srv_conf_t *us) ++ngx_http_lua_balancer_init(ngx_conf_t *cf, ngx_http_upstream_srv_conf_t *us) + { +- if (ngx_http_upstream_init_round_robin(cf, us) != NGX_OK) { ++ ngx_http_lua_srv_conf_t *lscf; ++ ++ lscf = ngx_http_conf_upstream_srv_conf(us, ngx_http_lua_module); ++ ++ if (lscf->balancer.original_init_upstream(cf, us) != NGX_OK) { + return NGX_ERROR; + } + +- /* this callback is called upon individual requests */ ++ lscf->balancer.original_init_peer = us->peer.init; ++ + us->peer.init = ngx_http_lua_balancer_init_peer; + + return NGX_OK; +@@ -216,33 +363,38 @@ static ngx_int_t + ngx_http_lua_balancer_init_peer(ngx_http_request_t *r, + ngx_http_upstream_srv_conf_t *us) + { +- ngx_http_lua_srv_conf_t *bcf; ++ ngx_http_lua_srv_conf_t *lscf; + ngx_http_lua_balancer_peer_data_t *bp; + +- bp = ngx_pcalloc(r->pool, sizeof(ngx_http_lua_balancer_peer_data_t)); +- if (bp == NULL) { ++ lscf = ngx_http_conf_upstream_srv_conf(us, ngx_http_lua_module); ++ ++ if (lscf->balancer.original_init_peer(r, us) != NGX_OK) { + return NGX_ERROR; + } + +- r->upstream->peer.data = &bp->rrp; +- +- if (ngx_http_upstream_init_round_robin_peer(r, us) != NGX_OK) { ++ bp = ngx_pcalloc(r->pool, sizeof(ngx_http_lua_balancer_peer_data_t)); ++ if (bp == NULL) { + return NGX_ERROR; + } + ++ bp->conf = lscf; ++ bp->request = r; ++ bp->data = r->upstream->peer.data; ++ bp->original_get_peer = r->upstream->peer.get; ++ bp->original_free_peer = r->upstream->peer.free; ++ ++ r->upstream->peer.data = bp; + r->upstream->peer.get = ngx_http_lua_balancer_get_peer; + r->upstream->peer.free = ngx_http_lua_balancer_free_peer; + + #if (NGX_HTTP_SSL) ++ bp->original_set_session = r->upstream->peer.set_session; ++ bp->original_save_session = r->upstream->peer.save_session; ++ + r->upstream->peer.set_session = ngx_http_lua_balancer_set_session; + r->upstream->peer.save_session = ngx_http_lua_balancer_save_session; + #endif + +- bcf = ngx_http_conf_upstream_srv_conf(us, ngx_http_lua_module); +- +- bp->conf = bcf; +- bp->request = r; +- + return NGX_OK; + } + +@@ -250,25 +402,26 @@ ngx_http_lua_balancer_init_peer(ngx_http_request_t *r, + static ngx_int_t + ngx_http_lua_balancer_get_peer(ngx_peer_connection_t *pc, void *data) + { +- lua_State *L; +- ngx_int_t rc; +- ngx_http_request_t *r; +- ngx_http_lua_ctx_t *ctx; +- ngx_http_lua_srv_conf_t *lscf; +- ngx_http_lua_main_conf_t *lmcf; +- ngx_http_lua_balancer_peer_data_t *bp = data; ++ lua_State *L; ++ ngx_int_t rc; ++ ngx_queue_t *q; ++ ngx_connection_t *c; ++ ngx_http_request_t *r; ++ ngx_http_lua_ctx_t *ctx; ++ ngx_http_lua_srv_conf_t *lscf; ++ ngx_http_lua_balancer_keepalive_item_t *item; ++ ngx_http_lua_balancer_peer_data_t *bp = data; ++ void *pdata; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0, +- "lua balancer peer, tries: %ui", pc->tries); +- +- lscf = bp->conf; ++ "lua balancer: get peer, tries: %ui", pc->tries); + + r = bp->request; ++ lscf = bp->conf; + + ngx_http_lua_assert(lscf->balancer.handler && r); + + ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); +- + if (ctx == NULL) { + ctx = ngx_http_lua_create_ctx(r); + if (ctx == NULL) { +@@ -286,21 +439,24 @@ ngx_http_lua_balancer_get_peer(ngx_peer_connection_t *pc, void *data) + + ctx->context = NGX_HTTP_LUA_CONTEXT_BALANCER; + ++ bp->cpool = NULL; + bp->sockaddr = NULL; + bp->socklen = 0; + bp->more_tries = 0; ++ bp->cpool_crc32 = 0; ++ bp->cpool_size = 0; ++ bp->keepalive_requests = 0; ++ bp->keepalive_timeout = 0; ++ bp->keepalive = 0; + bp->total_tries++; + +- lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); +- +- /* balancer_by_lua does not support yielding and +- * there cannot be any conflicts among concurrent requests, +- * thus it is safe to store the peer data in the main conf. +- */ +- lmcf->balancer_peer_data = bp; ++ pdata = r->upstream->peer.data; ++ r->upstream->peer.data = bp; + + rc = lscf->balancer.handler(r, lscf, L); + ++ r->upstream->peer.data = pdata; ++ + if (rc == NGX_ERROR) { + return NGX_ERROR; + } +@@ -322,79 +478,87 @@ ngx_http_lua_balancer_get_peer(ngx_peer_connection_t *pc, void *data) + } + } + +- if (bp->sockaddr && bp->socklen) { ++ if (ngx_http_lua_balancer_peer_set(bp)) { + pc->sockaddr = bp->sockaddr; + pc->socklen = bp->socklen; ++ pc->name = bp->host; + pc->cached = 0; + pc->connection = NULL; +- pc->name = bp->host; +- +- bp->rrp.peers->single = 0; + + if (bp->more_tries) { + r->upstream->peer.tries += bp->more_tries; + } + +- dd("tries: %d", (int) r->upstream->peer.tries); +- +- return NGX_OK; +- } +- +- return ngx_http_upstream_get_round_robin_peer(pc, &bp->rrp); +-} ++ if (ngx_http_lua_balancer_keepalive_is_enabled(bp)) { ++ ngx_http_lua_balancer_get_keepalive_pool(L, bp->cpool_crc32, ++ &bp->cpool); + ++ if (bp->cpool == NULL ++ && ngx_http_lua_balancer_create_keepalive_pool(L, pc->log, ++ bp->cpool_crc32, ++ bp->cpool_size, ++ &bp->cpool) ++ != NGX_OK) ++ { ++ return NGX_ERROR; ++ } + +-static ngx_int_t +-ngx_http_lua_balancer_by_chunk(lua_State *L, ngx_http_request_t *r) +-{ +- u_char *err_msg; +- size_t len; +- ngx_int_t rc; ++ ngx_http_lua_assert(bp->cpool); + +- /* init nginx context in Lua VM */ +- ngx_http_lua_set_req(L, r); ++ if (!ngx_queue_empty(&bp->cpool->cache)) { ++ q = ngx_queue_head(&bp->cpool->cache); + +-#ifndef OPENRESTY_LUAJIT +- ngx_http_lua_create_new_globals_table(L, 0 /* narr */, 1 /* nrec */); ++ item = ngx_queue_data(q, ngx_http_lua_balancer_keepalive_item_t, ++ queue); ++ c = item->connection; + +- /* {{{ 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}) */ +- /* }}} */ ++ ngx_queue_remove(q); ++ ngx_queue_insert_head(&bp->cpool->free, q); + +- lua_setfenv(L, -2); /* set new running env for the code closure */ +-#endif /* OPENRESTY_LUAJIT */ ++ c->idle = 0; ++ c->sent = 0; ++ c->log = pc->log; ++ c->read->log = pc->log; ++ c->write->log = pc->log; ++ c->pool->log = pc->log; + +- lua_pushcfunction(L, ngx_http_lua_traceback); +- lua_insert(L, 1); /* put it under chunk and args */ ++ if (c->read->timer_set) { ++ ngx_del_timer(c->read); ++ } + +- /* protected call user code */ +- rc = lua_pcall(L, 0, 1, 1); ++ pc->cached = 1; ++ pc->connection = c; + +- lua_remove(L, 1); /* remove traceback function */ ++ ngx_log_debug3(NGX_LOG_DEBUG_HTTP, pc->log, 0, ++ "lua balancer: keepalive reusing connection %p, " ++ "requests: %ui, cpool: %p", ++ c, c->requests, bp->cpool); + +- dd("rc == %d", (int) rc); ++ return NGX_DONE; ++ } + +- if (rc != 0) { +- /* error occurred when running loaded code */ +- err_msg = (u_char *) lua_tolstring(L, -1, &len); ++ bp->cpool->connections++; + +- if (err_msg == NULL) { +- err_msg = (u_char *) "unknown reason"; +- len = sizeof("unknown reason") - 1; ++ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0, ++ "lua balancer: keepalive no free connection, " ++ "cpool: %p", bp->cpool); + } + +- ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, +- "failed to run balancer_by_lua*: %*s", len, err_msg); ++ return NGX_OK; ++ } + +- lua_settop(L, 0); /* clear remaining elems on stack */ ++ rc = bp->original_get_peer(pc, bp->data); ++ if (rc == NGX_ERROR) { ++ return rc; ++ } ++ ++ if (pc->sockaddr == ngx_http_lua_balancer_default_server_sockaddr) { ++ ngx_log_error(NGX_LOG_ERR, pc->log, 0, ++ "lua balancer: no peer set"); + + return NGX_ERROR; + } + +- lua_settop(L, 0); /* clear remaining elems on stack */ + return rc; + } + +@@ -403,24 +567,335 @@ static void + ngx_http_lua_balancer_free_peer(ngx_peer_connection_t *pc, void *data, + ngx_uint_t state) + { +- ngx_http_lua_balancer_peer_data_t *bp = data; ++ ngx_queue_t *q; ++ ngx_connection_t *c; ++ ngx_http_upstream_t *u; ++ ngx_http_lua_balancer_keepalive_item_t *item; ++ ngx_http_lua_balancer_keepalive_pool_t *cpool; ++ ngx_http_lua_balancer_peer_data_t *bp = data; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0, +- "lua balancer free peer, tries: %ui", pc->tries); ++ "lua balancer: free peer, tries: %ui", pc->tries); ++ ++ u = bp->request->upstream; ++ c = pc->connection; + +- if (bp->sockaddr && bp->socklen) { ++ if (ngx_http_lua_balancer_peer_set(bp)) { + bp->last_peer_state = (int) state; + + if (pc->tries) { + pc->tries--; + } + ++ if (ngx_http_lua_balancer_keepalive_is_enabled(bp)) { ++ cpool = bp->cpool; ++ ++ if (state & NGX_PEER_FAILED ++ || c == NULL ++ || c->read->eof ++ || c->read->error ++ || c->read->timedout ++ || c->write->error ++ || c->write->timedout) ++ { ++ goto invalid; ++ } ++ ++ if (bp->keepalive_requests ++ && c->requests >= bp->keepalive_requests) ++ { ++ goto invalid; ++ } ++ ++ if (!u->keepalive) { ++ goto invalid; ++ } ++ ++ if (!u->request_body_sent) { ++ goto invalid; ++ } ++ ++ if (ngx_terminate || ngx_exiting) { ++ goto invalid; ++ } ++ ++ if (ngx_handle_read_event(c->read, 0) != NGX_OK) { ++ goto invalid; ++ } ++ ++ if (ngx_queue_empty(&cpool->free)) { ++ q = ngx_queue_last(&cpool->cache); ++ ngx_queue_remove(q); ++ ++ item = ngx_queue_data(q, ngx_http_lua_balancer_keepalive_item_t, ++ queue); ++ ++ ngx_http_lua_balancer_close(item->connection); ++ ++ } else { ++ q = ngx_queue_head(&cpool->free); ++ ngx_queue_remove(q); ++ ++ item = ngx_queue_data(q, ngx_http_lua_balancer_keepalive_item_t, ++ queue); ++ } ++ ++ ngx_log_debug3(NGX_LOG_DEBUG_HTTP, pc->log, 0, ++ "lua balancer: keepalive saving connection %p, " ++ "cpool: %p, connections: %ui", ++ c, cpool, cpool->connections); ++ ++ ngx_queue_insert_head(&cpool->cache, q); ++ ++ item->connection = c; ++ ++ pc->connection = NULL; ++ ++ if (bp->keepalive_timeout) { ++ c->read->delayed = 0; ++ ngx_add_timer(c->read, bp->keepalive_timeout); ++ ++ } else if (c->read->timer_set) { ++ ngx_del_timer(c->read); ++ } ++ ++ if (c->write->timer_set) { ++ ngx_del_timer(c->write); ++ } ++ ++ c->write->handler = ngx_http_lua_balancer_dummy_handler; ++ c->read->handler = ngx_http_lua_balancer_close_handler; ++ ++ c->data = item; ++ c->idle = 1; ++ c->log = ngx_cycle->log; ++ c->read->log = ngx_cycle->log; ++ c->write->log = ngx_cycle->log; ++ c->pool->log = ngx_cycle->log; ++ ++ if (c->read->ready) { ++ ngx_http_lua_balancer_close_handler(c->read); ++ } ++ ++ return; ++ ++invalid: ++ ++ cpool->connections--; ++ ++ ngx_log_debug3(NGX_LOG_DEBUG_HTTP, pc->log, 0, ++ "lua balancer: keepalive not saving connection %p, " ++ "cpool: %p, connections: %ui", ++ c, cpool, cpool->connections); ++ ++ if (cpool->connections == 0) { ++ ngx_http_lua_balancer_free_keepalive_pool(pc->log, cpool); ++ } ++ } ++ + return; + } + +- /* fallback */ ++ bp->original_free_peer(pc, bp->data, state); ++} ++ ++ ++static ngx_int_t ++ngx_http_lua_balancer_create_keepalive_pool(lua_State *L, ngx_log_t *log, ++ uint32_t cpool_crc32, ngx_uint_t cpool_size, ++ ngx_http_lua_balancer_keepalive_pool_t **cpool) ++{ ++ size_t size; ++ ngx_uint_t i; ++ ngx_http_lua_balancer_keepalive_pool_t *upool; ++ ngx_http_lua_balancer_keepalive_item_t *items; ++ ++ /* get upstream connection pools table */ ++ lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( ++ balancer_keepalive_pools_table_key)); ++ lua_rawget(L, LUA_REGISTRYINDEX); /* pools? */ ++ ++ ngx_http_lua_assert(lua_istable(L, -1)); + +- ngx_http_upstream_free_round_robin_peer(pc, data, state); ++ size = sizeof(ngx_http_lua_balancer_keepalive_pool_t) ++ + sizeof(ngx_http_lua_balancer_keepalive_item_t) * cpool_size; ++ ++ upool = lua_newuserdata(L, size); /* pools upool */ ++ if (upool == NULL) { ++ return NGX_ERROR; ++ } ++ ++ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, log, 0, ++ "lua balancer: keepalive create pool, crc32: %ui, " ++ "size: %ui", cpool_crc32, cpool_size); ++ ++ upool->lua_vm = L; ++ upool->crc32 = cpool_crc32; ++ upool->size = cpool_size; ++ upool->connections = 0; ++ ++ ngx_queue_init(&upool->cache); ++ ngx_queue_init(&upool->free); ++ ++ lua_rawseti(L, -2, cpool_crc32); /* pools */ ++ lua_pop(L, 1); /* orig stack */ ++ ++ items = (ngx_http_lua_balancer_keepalive_item_t *) (&upool->free + 1); ++ ++ for (i = 0; i < cpool_size; i++) { ++ ngx_queue_insert_head(&upool->free, &items[i].queue); ++ items[i].cpool = upool; ++ } ++ ++ *cpool = upool; ++ ++ return NGX_OK; ++} ++ ++ ++static void ++ngx_http_lua_balancer_get_keepalive_pool(lua_State *L, uint32_t cpool_crc32, ++ ngx_http_lua_balancer_keepalive_pool_t **cpool) ++{ ++ ngx_http_lua_balancer_keepalive_pool_t *upool; ++ ++ /* get upstream connection pools table */ ++ lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( ++ balancer_keepalive_pools_table_key)); ++ lua_rawget(L, LUA_REGISTRYINDEX); /* pools? */ ++ ++ if (lua_isnil(L, -1)) { ++ lua_pop(L, 1); /* orig stack */ ++ ++ /* create upstream connection pools table */ ++ lua_createtable(L, 0, 0); /* pools */ ++ lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( ++ balancer_keepalive_pools_table_key)); ++ lua_pushvalue(L, -2); /* pools pools_table_key pools */ ++ lua_rawset(L, LUA_REGISTRYINDEX); /* pools */ ++ } ++ ++ ngx_http_lua_assert(lua_istable(L, -1)); ++ ++ lua_rawgeti(L, -1, cpool_crc32); /* pools upool? */ ++ upool = lua_touserdata(L, -1); ++ lua_pop(L, 2); /* orig stack */ ++ ++ *cpool = upool; ++} ++ ++ ++static void ++ngx_http_lua_balancer_free_keepalive_pool(ngx_log_t *log, ++ ngx_http_lua_balancer_keepalive_pool_t *cpool) ++{ ++ lua_State *L; ++ ++ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, log, 0, ++ "lua balancer: keepalive free pool %p, crc32: %ui", ++ cpool, cpool->crc32); ++ ++ ngx_http_lua_assert(cpool->connections == 0); ++ ++ L = cpool->lua_vm; ++ ++ /* get upstream connection pools table */ ++ lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( ++ balancer_keepalive_pools_table_key)); ++ lua_rawget(L, LUA_REGISTRYINDEX); /* pools? */ ++ ++ if (lua_isnil(L, -1)) { ++ lua_pop(L, 1); /* orig stack */ ++ return; ++ } ++ ++ ngx_http_lua_assert(lua_istable(L, -1)); ++ ++ lua_pushnil(L); /* pools nil */ ++ lua_rawseti(L, -2, cpool->crc32); /* pools */ ++ lua_pop(L, 1); /* orig stack */ ++} ++ ++ ++static void ++ngx_http_lua_balancer_close(ngx_connection_t *c) ++{ ++ ngx_http_lua_balancer_keepalive_item_t *item; ++ ++ item = c->data; ++ ++#if (NGX_HTTP_SSL) ++ if (c->ssl) { ++ c->ssl->no_wait_shutdown = 1; ++ c->ssl->no_send_shutdown = 1; ++ ++ if (ngx_ssl_shutdown(c) == NGX_AGAIN) { ++ c->ssl->handler = ngx_http_lua_balancer_close; ++ return; ++ } ++ } ++#endif ++ ++ ngx_destroy_pool(c->pool); ++ ngx_close_connection(c); ++ ++ item->cpool->connections--; ++ ++ ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0, ++ "lua balancer: keepalive closing connection %p, cpool: %p, " ++ "connections: %ui", ++ c, item->cpool, item->cpool->connections); ++} ++ ++ ++static void ++ngx_http_lua_balancer_dummy_handler(ngx_event_t *ev) ++{ ++ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ev->log, 0, ++ "lua balancer: dummy handler"); ++} ++ ++ ++static void ++ngx_http_lua_balancer_close_handler(ngx_event_t *ev) ++{ ++ ngx_http_lua_balancer_keepalive_item_t *item; ++ ++ int n; ++ char buf[1]; ++ ngx_connection_t *c; ++ ++ c = ev->data; ++ ++ if (c->close || c->read->timedout) { ++ goto close; ++ } ++ ++ n = recv(c->fd, buf, 1, MSG_PEEK); ++ ++ if (n == -1 && ngx_socket_errno == NGX_EAGAIN) { ++ ev->ready = 0; ++ ++ if (ngx_handle_read_event(c->read, 0) != NGX_OK) { ++ goto close; ++ } ++ ++ return; ++ } ++ ++close: ++ ++ item = c->data; ++ c->log = ev->log; ++ ++ ngx_http_lua_balancer_close(c); ++ ++ ngx_queue_remove(&item->queue); ++ ngx_queue_insert_head(&item->cpool->free, &item->queue); ++ ++ if (item->cpool->connections == 0) { ++ ngx_http_lua_balancer_free_keepalive_pool(ev->log, item->cpool); ++ } + } + + +@@ -431,12 +908,12 @@ ngx_http_lua_balancer_set_session(ngx_peer_connection_t *pc, void *data) + { + ngx_http_lua_balancer_peer_data_t *bp = data; + +- if (bp->sockaddr && bp->socklen) { ++ if (ngx_http_lua_balancer_peer_set(bp)) { + /* TODO */ + return NGX_OK; + } + +- return ngx_http_upstream_set_round_robin_peer_session(pc, &bp->rrp); ++ return bp->original_set_session(pc, bp->data); + } + + +@@ -445,13 +922,12 @@ ngx_http_lua_balancer_save_session(ngx_peer_connection_t *pc, void *data) + { + ngx_http_lua_balancer_peer_data_t *bp = data; + +- if (bp->sockaddr && bp->socklen) { ++ if (ngx_http_lua_balancer_peer_set(bp)) { + /* TODO */ + return; + } + +- ngx_http_upstream_save_round_robin_peer_session(pc, &bp->rrp); +- return; ++ bp->original_save_session(pc, bp->data); + } + + #endif +@@ -459,14 +935,13 @@ ngx_http_lua_balancer_save_session(ngx_peer_connection_t *pc, void *data) + + int + ngx_http_lua_ffi_balancer_set_current_peer(ngx_http_request_t *r, +- const u_char *addr, size_t addr_len, int port, char **err) ++ const u_char *addr, size_t addr_len, int port, unsigned int cpool_crc32, ++ unsigned int cpool_size, char **err) + { +- ngx_url_t url; +- ngx_http_lua_ctx_t *ctx; +- ngx_http_upstream_t *u; +- +- ngx_http_lua_main_conf_t *lmcf; +- ngx_http_lua_balancer_peer_data_t *bp; ++ ngx_url_t url; ++ ngx_http_upstream_t *u; ++ ngx_http_lua_ctx_t *ctx; ++ ngx_http_lua_balancer_peer_data_t *bp; + + if (r == NULL) { + *err = "no request found"; +@@ -491,18 +966,6 @@ ngx_http_lua_ffi_balancer_set_current_peer(ngx_http_request_t *r, + return NGX_ERROR; + } + +- lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); +- +- /* we cannot read r->upstream->peer.data here directly because +- * it could be overridden by other modules like +- * ngx_http_upstream_keepalive_module. +- */ +- bp = lmcf->balancer_peer_data; +- if (bp == NULL) { +- *err = "no upstream peer data found"; +- return NGX_ERROR; +- } +- + ngx_memzero(&url, sizeof(ngx_url_t)); + + url.url.data = ngx_palloc(r->pool, addr_len); +@@ -526,6 +989,8 @@ ngx_http_lua_ffi_balancer_set_current_peer(ngx_http_request_t *r, + return NGX_ERROR; + } + ++ bp = (ngx_http_lua_balancer_peer_data_t *) u->peer.data; ++ + if (url.addrs && url.addrs[0].sockaddr) { + bp->sockaddr = url.addrs[0].sockaddr; + bp->socklen = url.addrs[0].socklen; +@@ -536,6 +1001,59 @@ ngx_http_lua_ffi_balancer_set_current_peer(ngx_http_request_t *r, + return NGX_ERROR; + } + ++ bp->cpool_crc32 = (uint32_t) cpool_crc32; ++ bp->cpool_size = (ngx_uint_t) cpool_size; ++ ++ return NGX_OK; ++} ++ ++ ++int ++ngx_http_lua_ffi_balancer_enable_keepalive(ngx_http_request_t *r, ++ unsigned long timeout, unsigned int max_requests, char **err) ++{ ++ ngx_http_upstream_t *u; ++ ngx_http_lua_ctx_t *ctx; ++ ngx_http_lua_balancer_peer_data_t *bp; ++ ++ if (r == NULL) { ++ *err = "no request found"; ++ return NGX_ERROR; ++ } ++ ++ u = r->upstream; ++ ++ if (u == NULL) { ++ *err = "no upstream found"; ++ return NGX_ERROR; ++ } ++ ++ ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); ++ if (ctx == NULL) { ++ *err = "no ctx found"; ++ return NGX_ERROR; ++ } ++ ++ if ((ctx->context & NGX_HTTP_LUA_CONTEXT_BALANCER) == 0) { ++ *err = "API disabled in the current context"; ++ return NGX_ERROR; ++ } ++ ++ bp = (ngx_http_lua_balancer_peer_data_t *) u->peer.data; ++ ++ if (!ngx_http_lua_balancer_peer_set(bp)) { ++ *err = "no current peer set"; ++ return NGX_ERROR; ++ } ++ ++ if (!bp->cpool_crc32) { ++ bp->cpool_crc32 = ngx_crc32_long(bp->host->data, bp->host->len); ++ } ++ ++ bp->keepalive_timeout = (ngx_msec_t) timeout; ++ bp->keepalive_requests = (ngx_uint_t) max_requests; ++ bp->keepalive = 1; ++ + return NGX_OK; + } + +@@ -545,14 +1063,13 @@ ngx_http_lua_ffi_balancer_set_timeouts(ngx_http_request_t *r, + long connect_timeout, long send_timeout, long read_timeout, + char **err) + { +- ngx_http_lua_ctx_t *ctx; +- ngx_http_upstream_t *u; ++ ngx_http_lua_ctx_t *ctx; ++ ngx_http_upstream_t *u; + + #if !(HAVE_NGX_UPSTREAM_TIMEOUT_FIELDS) + ngx_http_upstream_conf_t *ucf; +-#endif +- ngx_http_lua_main_conf_t *lmcf; + ngx_http_lua_balancer_peer_data_t *bp; ++#endif + + if (r == NULL) { + *err = "no request found"; +@@ -577,15 +1094,9 @@ ngx_http_lua_ffi_balancer_set_timeouts(ngx_http_request_t *r, + return NGX_ERROR; + } + +- lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); +- +- bp = lmcf->balancer_peer_data; +- if (bp == NULL) { +- *err = "no upstream peer data found"; +- return NGX_ERROR; +- } +- + #if !(HAVE_NGX_UPSTREAM_TIMEOUT_FIELDS) ++ bp = (ngx_http_lua_balancer_peer_data_t *) u->peer.data; ++ + if (!bp->cloned_upstream_conf) { + /* we clone the upstream conf for the current request so that + * we do not affect other requests at all. */ +@@ -640,12 +1151,10 @@ ngx_http_lua_ffi_balancer_set_more_tries(ngx_http_request_t *r, + int count, char **err) + { + #if (nginx_version >= 1007005) +- ngx_uint_t max_tries, total; ++ ngx_uint_t max_tries, total; + #endif +- ngx_http_lua_ctx_t *ctx; +- ngx_http_upstream_t *u; +- +- ngx_http_lua_main_conf_t *lmcf; ++ ngx_http_lua_ctx_t *ctx; ++ ngx_http_upstream_t *u; + ngx_http_lua_balancer_peer_data_t *bp; + + if (r == NULL) { +@@ -671,13 +1180,7 @@ ngx_http_lua_ffi_balancer_set_more_tries(ngx_http_request_t *r, + return NGX_ERROR; + } + +- lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); +- +- bp = lmcf->balancer_peer_data; +- if (bp == NULL) { +- *err = "no upstream peer data found"; +- return NGX_ERROR; +- } ++ bp = (ngx_http_lua_balancer_peer_data_t *) u->peer.data; + + #if (nginx_version >= 1007005) + max_tries = r->upstream->conf->next_upstream_tries; +@@ -703,12 +1206,10 @@ int + ngx_http_lua_ffi_balancer_get_last_failure(ngx_http_request_t *r, + int *status, char **err) + { +- ngx_http_lua_ctx_t *ctx; +- ngx_http_upstream_t *u; +- ngx_http_upstream_state_t *state; +- ++ ngx_http_lua_ctx_t *ctx; ++ ngx_http_upstream_t *u; ++ ngx_http_upstream_state_t *state; + ngx_http_lua_balancer_peer_data_t *bp; +- ngx_http_lua_main_conf_t *lmcf; + + if (r == NULL) { + *err = "no request found"; +@@ -733,13 +1234,7 @@ ngx_http_lua_ffi_balancer_get_last_failure(ngx_http_request_t *r, + return NGX_ERROR; + } + +- lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); +- +- bp = lmcf->balancer_peer_data; +- if (bp == NULL) { +- *err = "no upstream peer data found"; +- return NGX_ERROR; +- } ++ bp = (ngx_http_lua_balancer_peer_data_t *) u->peer.data; + + if (r->upstream_states && r->upstream_states->nelts > 1) { + state = r->upstream_states->elts; +diff --git src/ngx_http_lua_common.h src/ngx_http_lua_common.h +index 0751a11..7a66cb1 100644 +--- src/ngx_http_lua_common.h ++++ src/ngx_http_lua_common.h +@@ -239,13 +239,6 @@ struct ngx_http_lua_main_conf_s { + ngx_http_lua_main_conf_handler_pt exit_worker_handler; + ngx_str_t exit_worker_src; + +- ngx_http_lua_balancer_peer_data_t *balancer_peer_data; +- /* neither yielding nor recursion is possible in +- * balancer_by_lua*, so there cannot be any races among +- * concurrent requests and it is safe to store the peer +- * data pointer in the main conf. +- */ +- + ngx_chain_t *body_filter_chain; + /* neither yielding nor recursion is possible in + * body_filter_by_lua*, so there cannot be any races among +@@ -320,6 +313,10 @@ union ngx_http_lua_srv_conf_u { + #endif + + struct { ++ ngx_http_upstream_init_pt original_init_upstream; ++ ngx_http_upstream_init_peer_pt original_init_peer; ++ uintptr_t data; ++ + ngx_http_lua_srv_conf_handler_pt handler; + ngx_str_t src; + u_char *src_key; +diff --git src/ngx_http_lua_module.c src/ngx_http_lua_module.c +index 7358a95..21bf8f1 100644 +--- src/ngx_http_lua_module.c ++++ src/ngx_http_lua_module.c +@@ -1068,6 +1068,9 @@ ngx_http_lua_create_srv_conf(ngx_conf_t *cf) + * lscf->srv.ssl_session_fetch_src = { 0, NULL }; + * lscf->srv.ssl_session_fetch_src_key = NULL; + * ++ * lscf->balancer.original_init_upstream = NULL; ++ * lscf->balancer.original_init_peer = NULL; ++ * lscf->balancer.data = NULL; + * lscf->balancer.handler = NULL; + * lscf->balancer.src = { 0, NULL }; + * lscf->balancer.src_key = NULL; diff --git a/patch/1.21.4.1/ngx_lua-ngx-buf-double-free-bugfix.patch b/patch/1.21.4.1/ngx_lua-ngx-buf-double-free-bugfix.patch new file mode 100644 index 0000000..de6f1e7 --- /dev/null +++ b/patch/1.21.4.1/ngx_lua-ngx-buf-double-free-bugfix.patch @@ -0,0 +1,39 @@ +diff --git src/ngx_http_lua_bodyfilterby.c src/ngx_http_lua_bodyfilterby.c +index 632f5afe..a8a382ac 100644 +--- src/ngx_http_lua_bodyfilterby.c ++++ src/ngx_http_lua_bodyfilterby.c +@@ -299,7 +299,7 @@ ngx_http_lua_body_filter(ngx_http_request_t *r, ngx_chain_t *in) + out = NULL; + ngx_chain_update_chains(r->pool, + &ctx->free_bufs, &ctx->filter_busy_bufs, &out, +- (ngx_buf_tag_t) &ngx_http_lua_module); ++ (ngx_buf_tag_t) &ngx_http_lua_body_filter); + if (rc != NGX_OK + && ctx->filter_busy_bufs != NULL + && (r->connection->buffered +@@ -378,7 +378,7 @@ ngx_http_lua_body_filter(ngx_http_request_t *r, ngx_chain_t *in) + + ngx_chain_update_chains(r->pool, + &ctx->free_bufs, &ctx->filter_busy_bufs, &out, +- (ngx_buf_tag_t) &ngx_http_lua_module); ++ (ngx_buf_tag_t) &ngx_http_lua_body_filter); + + return rc; + } +@@ -657,6 +657,7 @@ ngx_http_lua_body_filter_param_set(lua_State *L, ngx_http_request_t *r, + return luaL_error(L, "no memory"); + } + ++ cl->buf->tag = (ngx_buf_tag_t) &ngx_http_lua_body_filter; + if (type == LUA_TTABLE) { + cl->buf->last = ngx_http_lua_copy_str_in_table(L, 3, cl->buf->last); + +@@ -674,6 +675,8 @@ done: + if (cl == NULL) { + return luaL_error(L, "no memory"); + } ++ ++ cl->buf->tag = (ngx_buf_tag_t) &ngx_http_lua_body_filter; + } + + if (last) { diff --git a/patch/1.21.4.1/ngx_lua-reject-in-handshake.patch b/patch/1.21.4.1/ngx_lua-reject-in-handshake.patch new file mode 100644 index 0000000..b76fbb9 --- /dev/null +++ b/patch/1.21.4.1/ngx_lua-reject-in-handshake.patch @@ -0,0 +1,38 @@ +diff --git src/ngx_http_lua_ssl_certby.c src/ngx_http_lua_ssl_certby.c +index 6ed2f3f..c46cc91 100644 +--- src/ngx_http_lua_ssl_certby.c ++++ src/ngx_http_lua_ssl_certby.c +@@ -1346,9 +1346,16 @@ ngx_http_lua_ssl_verify_callback(int ok, X509_STORE_CTX *x509_store) + } + + ++static int ++ngx_http_lua_ssl_verify_reject_in_handshake_callback(int ok, X509_STORE_CTX *x509_store) ++{ ++ return ok; ++} ++ ++ + int + ngx_http_lua_ffi_ssl_verify_client(ngx_http_request_t *r, void *ca_certs, +- int depth, char **err) ++ int depth, int reject_in_handshake, char **err) + { + ngx_http_lua_ctx_t *ctx; + ngx_ssl_conn_t *ssl_conn; +@@ -1388,7 +1395,14 @@ ngx_http_lua_ffi_ssl_verify_client(ngx_http_request_t *r, void *ca_certs, + + /* enable verify */ + +- SSL_set_verify(ssl_conn, SSL_VERIFY_PEER, ngx_http_lua_ssl_verify_callback); ++ if (reject_in_handshake) { ++ SSL_set_verify(ssl_conn, ++ SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT , ++ ngx_http_lua_ssl_verify_reject_in_handshake_callback); ++ ++ } else { ++ SSL_set_verify(ssl_conn, SSL_VERIFY_PEER, ngx_http_lua_ssl_verify_callback); ++ } + + /* set depth */ + diff --git a/patch/1.21.4.1/ngx_lua-request_header_set.patch b/patch/1.21.4.1/ngx_lua-request_header_set.patch new file mode 100644 index 0000000..6212e92 --- /dev/null +++ b/patch/1.21.4.1/ngx_lua-request_header_set.patch @@ -0,0 +1,25 @@ +diff --git src/ngx_http_lua_headers.c src/ngx_http_lua_headers.c +index d8d5edc..bd17dd8 100644 +--- src/ngx_http_lua_headers.c ++++ src/ngx_http_lua_headers.c +@@ -15,6 +15,9 @@ + #include "ngx_http_lua_headers_out.h" + #include "ngx_http_lua_headers_in.h" + #include "ngx_http_lua_util.h" ++#if (NGX_HTTP_APISIX) ++#include "ngx_http_apisix_module.h" ++#endif + + + static int ngx_http_lua_ngx_req_http_version(lua_State *L); +@@ -982,6 +985,10 @@ ngx_http_lua_ffi_req_set_header(ngx_http_request_t *r, const u_char *key, + ngx_uint_t i; + ngx_str_t k, v; + ++#if (NGX_HTTP_APISIX) ++ ngx_http_apisix_mark_request_header_set(r); ++#endif ++ + if (r->connection->fd == (ngx_socket_t) -1) { /* fake request */ + return NGX_HTTP_LUA_FFI_BAD_CONTEXT; + } diff --git a/patch/1.21.4.1/ngx_lua-shared_shdict.patch b/patch/1.21.4.1/ngx_lua-shared_shdict.patch new file mode 100644 index 0000000..982c2ac --- /dev/null +++ b/patch/1.21.4.1/ngx_lua-shared_shdict.patch @@ -0,0 +1,2965 @@ +diff --git config config +index 4b32d383..06ec0da0 100644 +--- config ++++ config +@@ -268,7 +268,6 @@ HTTP_LUA_SRCS=" \ + $ngx_addon_dir/src/ngx_http_lua_clfactory.c \ + $ngx_addon_dir/src/ngx_http_lua_pcrefix.c \ + $ngx_addon_dir/src/ngx_http_lua_headerfilterby.c \ +- $ngx_addon_dir/src/ngx_http_lua_shdict.c \ + $ngx_addon_dir/src/ngx_http_lua_socket_tcp.c \ + $ngx_addon_dir/src/ngx_http_lua_api.c \ + $ngx_addon_dir/src/ngx_http_lua_logby.c \ +@@ -330,7 +329,6 @@ HTTP_LUA_DEPS=" \ + $ngx_addon_dir/src/ngx_http_lua_clfactory.h \ + $ngx_addon_dir/src/ngx_http_lua_pcrefix.h \ + $ngx_addon_dir/src/ngx_http_lua_headerfilterby.h \ +- $ngx_addon_dir/src/ngx_http_lua_shdict.h \ + $ngx_addon_dir/src/ngx_http_lua_socket_tcp.h \ + $ngx_addon_dir/src/api/ngx_http_lua_api.h \ + $ngx_addon_dir/src/ngx_http_lua_logby.h \ +diff --git src/api/ngx_http_lua_api.h src/api/ngx_http_lua_api.h +index 43f90bd0..7530add0 100644 +--- src/api/ngx_http_lua_api.h ++++ src/api/ngx_http_lua_api.h +@@ -48,14 +48,6 @@ ngx_http_request_t *ngx_http_lua_get_request(lua_State *L); + ngx_int_t ngx_http_lua_add_package_preload(ngx_conf_t *cf, const char *package, + lua_CFunction func); + +-ngx_int_t ngx_http_lua_shared_dict_get(ngx_shm_zone_t *shm_zone, +- u_char *key_data, size_t key_len, ngx_http_lua_value_t *value); +- +-ngx_shm_zone_t *ngx_http_lua_find_zone(u_char *name_data, size_t name_len); +- +-ngx_shm_zone_t *ngx_http_lua_shared_memory_add(ngx_conf_t *cf, ngx_str_t *name, +- size_t size, void *tag); +- + + #endif /* _NGX_HTTP_LUA_API_H_INCLUDED_ */ + +diff --git src/ngx_http_lua_api.c src/ngx_http_lua_api.c +index b69d627d..691b3212 100644 +--- src/ngx_http_lua_api.c ++++ src/ngx_http_lua_api.c +@@ -12,7 +12,6 @@ + + #include "ngx_http_lua_common.h" + #include "api/ngx_http_lua_api.h" +-#include "ngx_http_lua_shdict.h" + #include "ngx_http_lua_util.h" + + +@@ -34,10 +33,6 @@ ngx_http_lua_get_request(lua_State *L) + } + + +-static ngx_int_t ngx_http_lua_shared_memory_init(ngx_shm_zone_t *shm_zone, +- void *data); +- +- + ngx_int_t + ngx_http_lua_add_package_preload(ngx_conf_t *cf, const char *package, + lua_CFunction func) +@@ -83,134 +78,4 @@ ngx_http_lua_add_package_preload(ngx_conf_t *cf, const char *package, + } + + +-ngx_shm_zone_t * +-ngx_http_lua_shared_memory_add(ngx_conf_t *cf, ngx_str_t *name, size_t size, +- void *tag) +-{ +- ngx_http_lua_main_conf_t *lmcf; +- ngx_shm_zone_t **zp; +- ngx_shm_zone_t *zone; +- ngx_http_lua_shm_zone_ctx_t *ctx; +- ngx_int_t n; +- +- lmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_lua_module); +- if (lmcf == NULL) { +- return NULL; +- } +- +- if (lmcf->shm_zones == NULL) { +- lmcf->shm_zones = ngx_palloc(cf->pool, sizeof(ngx_array_t)); +- if (lmcf->shm_zones == NULL) { +- return NULL; +- } +- +- if (ngx_array_init(lmcf->shm_zones, cf->pool, 2, +- sizeof(ngx_shm_zone_t *)) +- != NGX_OK) +- { +- return NULL; +- } +- } +- +- zone = ngx_shared_memory_add(cf, name, (size_t) size, tag); +- if (zone == NULL) { +- return NULL; +- } +- +- if (zone->data) { +- ctx = (ngx_http_lua_shm_zone_ctx_t *) zone->data; +- return &ctx->zone; +- } +- +- n = sizeof(ngx_http_lua_shm_zone_ctx_t); +- +- ctx = ngx_pcalloc(cf->pool, n); +- if (ctx == NULL) { +- return NULL; +- } +- +- ctx->lmcf = lmcf; +- ctx->log = &cf->cycle->new_log; +- ctx->cycle = cf->cycle; +- +- ngx_memcpy(&ctx->zone, zone, sizeof(ngx_shm_zone_t)); +- +- zp = ngx_array_push(lmcf->shm_zones); +- if (zp == NULL) { +- return NULL; +- } +- +- *zp = zone; +- +- /* set zone init */ +- zone->init = ngx_http_lua_shared_memory_init; +- zone->data = ctx; +- +- lmcf->requires_shm = 1; +- +- return &ctx->zone; +-} +- +- +-static ngx_int_t +-ngx_http_lua_shared_memory_init(ngx_shm_zone_t *shm_zone, void *data) +-{ +- ngx_http_lua_shm_zone_ctx_t *octx = data; +- ngx_shm_zone_t *ozone; +- void *odata; +- +- ngx_int_t rc; +- volatile ngx_cycle_t *saved_cycle; +- ngx_http_lua_main_conf_t *lmcf; +- ngx_http_lua_shm_zone_ctx_t *ctx; +- ngx_shm_zone_t *zone; +- +- ctx = (ngx_http_lua_shm_zone_ctx_t *) shm_zone->data; +- zone = &ctx->zone; +- +- odata = NULL; +- if (octx) { +- ozone = &octx->zone; +- odata = ozone->data; +- } +- +- zone->shm = shm_zone->shm; +-#if (nginx_version >= 1009000) +- zone->noreuse = shm_zone->noreuse; +-#endif +- +- if (zone->init(zone, odata) != NGX_OK) { +- return NGX_ERROR; +- } +- +- dd("get lmcf"); +- +- lmcf = ctx->lmcf; +- if (lmcf == NULL) { +- return NGX_ERROR; +- } +- +- dd("lmcf->lua: %p", lmcf->lua); +- +- lmcf->shm_zones_inited++; +- +- if (lmcf->shm_zones_inited == lmcf->shm_zones->nelts +- && lmcf->init_handler && !ngx_test_config) +- { +- saved_cycle = ngx_cycle; +- ngx_cycle = ctx->cycle; +- +- rc = lmcf->init_handler(ctx->log, lmcf, lmcf->lua); +- +- ngx_cycle = saved_cycle; +- +- if (rc != NGX_OK) { +- /* an error happened */ +- return NGX_ERROR; +- } +- } +- +- return NGX_OK; +-} +- + /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ +diff --git src/ngx_http_lua_common.h src/ngx_http_lua_common.h +index 0751a112..1e2e4fe1 100644 +--- src/ngx_http_lua_common.h ++++ src/ngx_http_lua_common.h +@@ -23,6 +23,8 @@ + #include + #include + ++#include "ngx_meta_lua_api.h" ++ + + #if defined(NDK) && NDK + #include +@@ -67,6 +69,10 @@ typedef struct { + # error at least nginx 1.6.0 is required but found an older version + #endif + ++#if !defined(ngx_meta_lua_version) || ngx_meta_lua_version < 00001 ++# error ngx_meta_lua_module 0.0.1 or above is required ++#endif ++ + #if LUA_VERSION_NUM != 501 + # error unsupported Lua language version + #endif +@@ -169,9 +175,6 @@ typedef struct ngx_http_lua_posted_thread_s ngx_http_lua_posted_thread_t; + typedef struct ngx_http_lua_balancer_peer_data_s + ngx_http_lua_balancer_peer_data_t; + +-typedef ngx_int_t (*ngx_http_lua_main_conf_handler_pt)(ngx_log_t *log, +- ngx_http_lua_main_conf_t *lmcf, lua_State *L); +- + typedef ngx_int_t (*ngx_http_lua_srv_conf_handler_pt)(ngx_http_request_t *r, + ngx_http_lua_srv_conf_t *lscf, lua_State *L); + +@@ -221,22 +224,18 @@ struct ngx_http_lua_main_conf_s { + # endif + #endif + +- ngx_array_t *shm_zones; /* of ngx_shm_zone_t* */ +- +- ngx_array_t *shdict_zones; /* shm zones of "shdict" */ +- + ngx_array_t *preload_hooks; /* of ngx_http_lua_preload_hook_t */ + + ngx_flag_t postponed_to_rewrite_phase_end; + ngx_flag_t postponed_to_access_phase_end; + +- ngx_http_lua_main_conf_handler_pt init_handler; ++ ngx_meta_lua_main_conf_handler_pt init_handler; + ngx_str_t init_src; + +- ngx_http_lua_main_conf_handler_pt init_worker_handler; ++ ngx_meta_lua_main_conf_handler_pt init_worker_handler; + ngx_str_t init_worker_src; + +- ngx_http_lua_main_conf_handler_pt exit_worker_handler; ++ ngx_meta_lua_main_conf_handler_pt exit_worker_handler; + ngx_str_t exit_worker_src; + + ngx_http_lua_balancer_peer_data_t *balancer_peer_data; +@@ -267,8 +266,6 @@ struct ngx_http_lua_main_conf_s { + * main conf. + */ + +- ngx_uint_t shm_zones_inited; +- + ngx_http_lua_sema_mm_t *sema_mm; + + ngx_uint_t malloc_trim_cycle; /* a cycle is defined as the number +@@ -294,7 +291,6 @@ struct ngx_http_lua_main_conf_s { + unsigned requires_rewrite:1; + unsigned requires_access:1; + unsigned requires_log:1; +- unsigned requires_shm:1; + unsigned requires_capture_log:1; + }; + +diff --git src/ngx_http_lua_directive.c src/ngx_http_lua_directive.c +index 1ec641e0..6d4329a1 100644 +--- src/ngx_http_lua_directive.c ++++ src/ngx_http_lua_directive.c +@@ -24,7 +24,6 @@ + #include "ngx_http_lua_initby.h" + #include "ngx_http_lua_initworkerby.h" + #include "ngx_http_lua_exitworkerby.h" +-#include "ngx_http_lua_shdict.h" + #include "ngx_http_lua_ssl_certby.h" + #include "ngx_http_lua_lex.h" + #include "api/ngx_http_lua_api.h" +@@ -71,91 +70,6 @@ enum { + }; + + +-char * +-ngx_http_lua_shared_dict(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +-{ +- ngx_http_lua_main_conf_t *lmcf = conf; +- +- ngx_str_t *value, name; +- ngx_shm_zone_t *zone; +- ngx_shm_zone_t **zp; +- ngx_http_lua_shdict_ctx_t *ctx; +- ssize_t size; +- +- if (lmcf->shdict_zones == NULL) { +- lmcf->shdict_zones = ngx_palloc(cf->pool, sizeof(ngx_array_t)); +- if (lmcf->shdict_zones == NULL) { +- return NGX_CONF_ERROR; +- } +- +- if (ngx_array_init(lmcf->shdict_zones, cf->pool, 2, +- sizeof(ngx_shm_zone_t *)) +- != NGX_OK) +- { +- return NGX_CONF_ERROR; +- } +- } +- +- value = cf->args->elts; +- +- ctx = NULL; +- +- if (value[1].len == 0) { +- ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, +- "invalid lua shared dict name \"%V\"", &value[1]); +- return NGX_CONF_ERROR; +- } +- +- name = value[1]; +- +- size = ngx_parse_size(&value[2]); +- +- if (size <= 8191) { +- ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, +- "invalid lua shared dict size \"%V\"", &value[2]); +- return NGX_CONF_ERROR; +- } +- +- ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_lua_shdict_ctx_t)); +- if (ctx == NULL) { +- return NGX_CONF_ERROR; +- } +- +- ctx->name = name; +- ctx->main_conf = lmcf; +- ctx->log = &cf->cycle->new_log; +- +- zone = ngx_http_lua_shared_memory_add(cf, &name, (size_t) size, +- &ngx_http_lua_module); +- if (zone == NULL) { +- return NGX_CONF_ERROR; +- } +- +- if (zone->data) { +- ctx = zone->data; +- +- ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, +- "lua_shared_dict \"%V\" is already defined as " +- "\"%V\"", &name, &ctx->name); +- return NGX_CONF_ERROR; +- } +- +- zone->init = ngx_http_lua_shdict_init_zone; +- zone->data = ctx; +- +- zp = ngx_array_push(lmcf->shdict_zones); +- if (zp == NULL) { +- return NGX_CONF_ERROR; +- } +- +- *zp = zone; +- +- lmcf->requires_shm = 1; +- +- return NGX_CONF_OK; +-} +- +- + char * + ngx_http_lua_code_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) + { +@@ -191,6 +105,15 @@ ngx_http_lua_load_resty_core(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) + } + + ++char * ++ngx_http_lua_shdict_directive(ngx_conf_t *cf, ngx_command_t *cmd, ++ void *conf) ++{ ++ return ngx_meta_lua_shdict_directive_helper(cf, ++ &ngx_http_lua_module); ++} ++ ++ + char * + ngx_http_lua_package_cpath(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) + { +@@ -1121,7 +1044,7 @@ ngx_http_lua_init_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, + return NGX_CONF_ERROR; + } + +- lmcf->init_handler = (ngx_http_lua_main_conf_handler_pt) cmd->post; ++ lmcf->init_handler = (ngx_meta_lua_main_conf_handler_pt) cmd->post; + + if (cmd->post == ngx_http_lua_init_by_file) { + name = ngx_http_lua_rebase_path(cf->pool, value[1].data, +@@ -1181,7 +1104,7 @@ ngx_http_lua_init_worker_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, + + value = cf->args->elts; + +- lmcf->init_worker_handler = (ngx_http_lua_main_conf_handler_pt) cmd->post; ++ lmcf->init_worker_handler = (ngx_meta_lua_main_conf_handler_pt) cmd->post; + + if (cmd->post == ngx_http_lua_init_worker_by_file) { + name = ngx_http_lua_rebase_path(cf->pool, value[1].data, +@@ -1239,7 +1162,7 @@ ngx_http_lua_exit_worker_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, + + value = cf->args->elts; + +- lmcf->exit_worker_handler = (ngx_http_lua_main_conf_handler_pt) cmd->post; ++ lmcf->exit_worker_handler = (ngx_meta_lua_main_conf_handler_pt) cmd->post; + + if (cmd->post == ngx_http_lua_exit_worker_by_file) { + name = ngx_http_lua_rebase_path(cf->pool, value[1].data, +diff --git src/ngx_http_lua_directive.h src/ngx_http_lua_directive.h +index adfba127..83d082ee 100644 +--- src/ngx_http_lua_directive.h ++++ src/ngx_http_lua_directive.h +@@ -12,7 +12,7 @@ + #include "ngx_http_lua_common.h" + + +-char *ngx_http_lua_shared_dict(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); ++char *ngx_http_lua_shdict_directive(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); + char *ngx_http_lua_package_cpath(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); + char *ngx_http_lua_package_path(ngx_conf_t *cf, ngx_command_t *cmd, +diff --git src/ngx_http_lua_exitworkerby.c src/ngx_http_lua_exitworkerby.c +index cd59dc4b..9765c218 100644 +--- src/ngx_http_lua_exitworkerby.c ++++ src/ngx_http_lua_exitworkerby.c +@@ -67,7 +67,8 @@ ngx_http_lua_exit_worker(ngx_cycle_t *cycle) + + ngx_http_lua_set_req(lmcf->lua, r); + +- (void) lmcf->exit_worker_handler(cycle->log, lmcf, lmcf->lua); ++ (void) lmcf->exit_worker_handler(cycle->log, lmcf->exit_worker_src, ++ lmcf->lua); + + ngx_destroy_pool(c->pool); + return; +@@ -84,12 +85,12 @@ failed: + + ngx_int_t + ngx_http_lua_exit_worker_by_inline(ngx_log_t *log, +- ngx_http_lua_main_conf_t *lmcf, lua_State *L) ++ ngx_str_t init_src, lua_State *L) + { + int status; + +- status = luaL_loadbuffer(L, (char *) lmcf->exit_worker_src.data, +- lmcf->exit_worker_src.len, "=exit_worker_by_lua") ++ status = luaL_loadbuffer(L, (char *) init_src.data, init_src.len, ++ "=exit_worker_by_lua") + || ngx_http_lua_do_call(log, L); + + return ngx_http_lua_report(log, L, status, "exit_worker_by_lua"); +@@ -97,12 +98,12 @@ ngx_http_lua_exit_worker_by_inline(ngx_log_t *log, + + + ngx_int_t +-ngx_http_lua_exit_worker_by_file(ngx_log_t *log, ngx_http_lua_main_conf_t *lmcf, ++ngx_http_lua_exit_worker_by_file(ngx_log_t *log, ngx_str_t init_src, + lua_State *L) + { + int status; + +- status = luaL_loadfile(L, (char *) lmcf->exit_worker_src.data) ++ status = luaL_loadfile(L, (char *) init_src.data) + || ngx_http_lua_do_call(log, L); + + return ngx_http_lua_report(log, L, status, "exit_worker_by_lua_file"); +diff --git src/ngx_http_lua_exitworkerby.h src/ngx_http_lua_exitworkerby.h +index 3a4274c0..ad8f63b6 100644 +--- src/ngx_http_lua_exitworkerby.h ++++ src/ngx_http_lua_exitworkerby.h +@@ -12,10 +12,10 @@ + + + ngx_int_t ngx_http_lua_exit_worker_by_inline(ngx_log_t *log, +- ngx_http_lua_main_conf_t *lmcf, lua_State *L); ++ ngx_str_t init_src, lua_State *L); + + ngx_int_t ngx_http_lua_exit_worker_by_file(ngx_log_t *log, +- ngx_http_lua_main_conf_t *lmcf, lua_State *L); ++ ngx_str_t init_src, lua_State *L); + + void ngx_http_lua_exit_worker(ngx_cycle_t *cycle); + +diff --git src/ngx_http_lua_headerfilterby.c src/ngx_http_lua_headerfilterby.c +index 4741c722..ed0c3a6c 100644 +--- src/ngx_http_lua_headerfilterby.c ++++ src/ngx_http_lua_headerfilterby.c +@@ -19,7 +19,6 @@ + #include "ngx_http_lua_string.h" + #include "ngx_http_lua_misc.h" + #include "ngx_http_lua_consts.h" +-#include "ngx_http_lua_shdict.h" + + + static ngx_http_output_header_filter_pt ngx_http_next_header_filter; +diff --git src/ngx_http_lua_initby.c src/ngx_http_lua_initby.c +index e8941da6..4e8d898f 100644 +--- src/ngx_http_lua_initby.c ++++ src/ngx_http_lua_initby.c +@@ -14,13 +14,13 @@ + + + ngx_int_t +-ngx_http_lua_init_by_inline(ngx_log_t *log, ngx_http_lua_main_conf_t *lmcf, ++ngx_http_lua_init_by_inline(ngx_log_t *log, ngx_str_t init_src, + lua_State *L) + { + int status; + +- status = luaL_loadbuffer(L, (char *) lmcf->init_src.data, +- lmcf->init_src.len, "=init_by_lua") ++ status = luaL_loadbuffer(L, (char *) init_src.data, init_src.len, ++ "=init_by_lua") + || ngx_http_lua_do_call(log, L); + + return ngx_http_lua_report(log, L, status, "init_by_lua"); +@@ -28,12 +28,12 @@ ngx_http_lua_init_by_inline(ngx_log_t *log, ngx_http_lua_main_conf_t *lmcf, + + + ngx_int_t +-ngx_http_lua_init_by_file(ngx_log_t *log, ngx_http_lua_main_conf_t *lmcf, ++ngx_http_lua_init_by_file(ngx_log_t *log, ngx_str_t init_src, + lua_State *L) + { + int status; + +- status = luaL_loadfile(L, (char *) lmcf->init_src.data) ++ status = luaL_loadfile(L, (char *) init_src.data) + || ngx_http_lua_do_call(log, L); + + return ngx_http_lua_report(log, L, status, "init_by_lua_file"); +diff --git src/ngx_http_lua_initby.h src/ngx_http_lua_initby.h +index 67ac0b6c..cbd439aa 100644 +--- src/ngx_http_lua_initby.h ++++ src/ngx_http_lua_initby.h +@@ -12,10 +12,10 @@ + + + ngx_int_t ngx_http_lua_init_by_inline(ngx_log_t *log, +- ngx_http_lua_main_conf_t *lmcf, lua_State *L); ++ ngx_str_t init_src, lua_State *L); + + ngx_int_t ngx_http_lua_init_by_file(ngx_log_t *log, +- ngx_http_lua_main_conf_t *lmcf, lua_State *L); ++ ngx_str_t init_src, lua_State *L); + + + #endif /* _NGX_HTTP_LUA_INITBY_H_INCLUDED_ */ +diff --git src/ngx_http_lua_initworkerby.c src/ngx_http_lua_initworkerby.c +index 94de796a..bba63c5b 100644 +--- src/ngx_http_lua_initworkerby.c ++++ src/ngx_http_lua_initworkerby.c +@@ -293,7 +293,8 @@ ngx_http_lua_init_worker(ngx_cycle_t *cycle) + + ngx_http_lua_set_req(lmcf->lua, r); + +- (void) lmcf->init_worker_handler(cycle->log, lmcf, lmcf->lua); ++ (void) lmcf->init_worker_handler(cycle->log, lmcf->init_worker_src, ++ lmcf->lua); + + ngx_destroy_pool(c->pool); + return NGX_OK; +@@ -314,12 +315,12 @@ failed: + + ngx_int_t + ngx_http_lua_init_worker_by_inline(ngx_log_t *log, +- ngx_http_lua_main_conf_t *lmcf, lua_State *L) ++ ngx_str_t init_worker_src, lua_State *L) + { + int status; + +- status = luaL_loadbuffer(L, (char *) lmcf->init_worker_src.data, +- lmcf->init_worker_src.len, "=init_worker_by_lua") ++ status = luaL_loadbuffer(L, (char *) init_worker_src.data, ++ init_worker_src.len, "=init_worker_by_lua") + || ngx_http_lua_do_call(log, L); + + return ngx_http_lua_report(log, L, status, "init_worker_by_lua"); +@@ -327,12 +328,12 @@ ngx_http_lua_init_worker_by_inline(ngx_log_t *log, + + + ngx_int_t +-ngx_http_lua_init_worker_by_file(ngx_log_t *log, ngx_http_lua_main_conf_t *lmcf, +- lua_State *L) ++ngx_http_lua_init_worker_by_file(ngx_log_t *log, ++ ngx_str_t init_worker_src, lua_State *L) + { + int status; + +- status = luaL_loadfile(L, (char *) lmcf->init_worker_src.data) ++ status = luaL_loadfile(L, (char *) init_worker_src.data) + || ngx_http_lua_do_call(log, L); + + return ngx_http_lua_report(log, L, status, "init_worker_by_lua_file"); +diff --git src/ngx_http_lua_initworkerby.h src/ngx_http_lua_initworkerby.h +index 40b2db0e..d4c399cf 100644 +--- src/ngx_http_lua_initworkerby.h ++++ src/ngx_http_lua_initworkerby.h +@@ -12,10 +12,10 @@ + + + ngx_int_t ngx_http_lua_init_worker_by_inline(ngx_log_t *log, +- ngx_http_lua_main_conf_t *lmcf, lua_State *L); ++ ngx_str_t init_worker_src, lua_State *L); + + ngx_int_t ngx_http_lua_init_worker_by_file(ngx_log_t *log, +- ngx_http_lua_main_conf_t *lmcf, lua_State *L); ++ ngx_str_t init_worker_src, lua_State *L); + + ngx_int_t ngx_http_lua_init_worker(ngx_cycle_t *cycle); + +diff --git src/ngx_http_lua_logby.c src/ngx_http_lua_logby.c +index b47058be..a31d424b 100644 +--- src/ngx_http_lua_logby.c ++++ src/ngx_http_lua_logby.c +@@ -21,7 +21,6 @@ + #include "ngx_http_lua_string.h" + #include "ngx_http_lua_misc.h" + #include "ngx_http_lua_consts.h" +-#include "ngx_http_lua_shdict.h" + #if (NGX_HTTP_LUA_HAVE_MALLOC_TRIM) + #include + #endif +diff --git src/ngx_http_lua_module.c src/ngx_http_lua_module.c +index 7358a956..857deb45 100644 +--- src/ngx_http_lua_module.c ++++ src/ngx_http_lua_module.c +@@ -11,6 +11,7 @@ + #include "ddebug.h" + + ++#include "ngx_meta_lua_api.h" + #include "ngx_http_lua_directive.h" + #include "ngx_http_lua_capturefilter.h" + #include "ngx_http_lua_contentby.h" +@@ -108,7 +109,7 @@ static ngx_command_t ngx_http_lua_cmds[] = { + + { ngx_string("lua_shared_dict"), + NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE2, +- ngx_http_lua_shared_dict, ++ ngx_http_lua_shdict_directive, + 0, + 0, + NULL }, +@@ -671,7 +672,6 @@ ngx_http_lua_init(ngx_conf_t *cf) + ngx_int_t rc; + ngx_array_t *arr; + ngx_http_handler_pt *h; +- volatile ngx_cycle_t *saved_cycle; + ngx_http_core_main_conf_t *cmcf; + ngx_http_lua_main_conf_t *lmcf; + ngx_pool_cleanup_t *cln; +@@ -850,18 +850,11 @@ ngx_http_lua_init(ngx_conf_t *cf) + + ngx_http_lua_assert(lmcf->lua != NULL); + +- if (!lmcf->requires_shm && lmcf->init_handler) { +- saved_cycle = ngx_cycle; +- ngx_cycle = cf->cycle; +- +- rc = lmcf->init_handler(cf->log, lmcf, lmcf->lua); +- +- ngx_cycle = saved_cycle; +- +- if (rc != NGX_OK) { +- /* an error happened */ +- return NGX_ERROR; +- } ++ if (ngx_meta_lua_post_init_handler(cf, lmcf->init_handler, ++ lmcf->init_src, lmcf->lua) ++ != NGX_OK) ++ { ++ return NGX_ERROR; + } + + dd("Lua VM initialized!"); +@@ -921,11 +914,8 @@ ngx_http_lua_create_main_conf(ngx_conf_t *cf) + * lmcf->watcher = NULL; + * lmcf->regex_cache_entries = 0; + * lmcf->jit_stack = NULL; +- * lmcf->shm_zones = NULL; + * lmcf->init_handler = NULL; + * lmcf->init_src = { 0, NULL }; +- * lmcf->shm_zones_inited = 0; +- * lmcf->shdict_zones = NULL; + * lmcf->preload_hooks = NULL; + * lmcf->requires_header_filter = 0; + * lmcf->requires_body_filter = 0; +@@ -933,7 +923,6 @@ ngx_http_lua_create_main_conf(ngx_conf_t *cf) + * lmcf->requires_rewrite = 0; + * lmcf->requires_access = 0; + * lmcf->requires_log = 0; +- * lmcf->requires_shm = 0; + */ + + lmcf->pool = cf->pool; +diff --git src/ngx_http_lua_setby.c src/ngx_http_lua_setby.c +index f00468c9..c6ef36f4 100644 +--- src/ngx_http_lua_setby.c ++++ src/ngx_http_lua_setby.c +@@ -19,7 +19,6 @@ + #include "ngx_http_lua_string.h" + #include "ngx_http_lua_misc.h" + #include "ngx_http_lua_consts.h" +-#include "ngx_http_lua_shdict.h" + #include "ngx_http_lua_util.h" + + +diff --git src/ngx_http_lua_shdict.c src/ngx_http_lua_shdict.c +deleted file mode 100644 +index 07effa88..00000000 +--- src/ngx_http_lua_shdict.c ++++ /dev/null +@@ -1,2095 +0,0 @@ +- +-/* +- * Copyright (C) Yichun Zhang (agentzh) +- */ +- +- +-#ifndef DDEBUG +-#define DDEBUG 0 +-#endif +-#include "ddebug.h" +- +- +-#include "ngx_http_lua_shdict.h" +-#include "ngx_http_lua_util.h" +-#include "ngx_http_lua_api.h" +- +- +-static int ngx_http_lua_shdict_expire(ngx_http_lua_shdict_ctx_t *ctx, +- ngx_uint_t n); +-static ngx_int_t ngx_http_lua_shdict_lookup(ngx_shm_zone_t *shm_zone, +- ngx_uint_t hash, u_char *kdata, size_t klen, +- ngx_http_lua_shdict_node_t **sdp); +-static int ngx_http_lua_shdict_flush_expired(lua_State *L); +-static int ngx_http_lua_shdict_get_keys(lua_State *L); +-static int ngx_http_lua_shdict_lpush(lua_State *L); +-static int ngx_http_lua_shdict_rpush(lua_State *L); +-static int ngx_http_lua_shdict_push_helper(lua_State *L, int flags); +-static int ngx_http_lua_shdict_lpop(lua_State *L); +-static int ngx_http_lua_shdict_rpop(lua_State *L); +-static int ngx_http_lua_shdict_pop_helper(lua_State *L, int flags); +-static int ngx_http_lua_shdict_llen(lua_State *L); +- +- +-static ngx_inline ngx_shm_zone_t *ngx_http_lua_shdict_get_zone(lua_State *L, +- int index); +- +- +-#define NGX_HTTP_LUA_SHDICT_ADD 0x0001 +-#define NGX_HTTP_LUA_SHDICT_REPLACE 0x0002 +-#define NGX_HTTP_LUA_SHDICT_SAFE_STORE 0x0004 +- +- +-#define NGX_HTTP_LUA_SHDICT_LEFT 0x0001 +-#define NGX_HTTP_LUA_SHDICT_RIGHT 0x0002 +- +- +-enum { +- SHDICT_USERDATA_INDEX = 1, +-}; +- +- +-enum { +- SHDICT_TNIL = 0, /* same as LUA_TNIL */ +- SHDICT_TBOOLEAN = 1, /* same as LUA_TBOOLEAN */ +- SHDICT_TNUMBER = 3, /* same as LUA_TNUMBER */ +- SHDICT_TSTRING = 4, /* same as LUA_TSTRING */ +- SHDICT_TLIST = 5, +-}; +- +- +-static ngx_inline ngx_queue_t * +-ngx_http_lua_shdict_get_list_head(ngx_http_lua_shdict_node_t *sd, size_t len) +-{ +- return (ngx_queue_t *) ngx_align_ptr(((u_char *) &sd->data + len), +- NGX_ALIGNMENT); +-} +- +- +-ngx_int_t +-ngx_http_lua_shdict_init_zone(ngx_shm_zone_t *shm_zone, void *data) +-{ +- ngx_http_lua_shdict_ctx_t *octx = data; +- +- size_t len; +- ngx_http_lua_shdict_ctx_t *ctx; +- +- dd("init zone"); +- +- ctx = shm_zone->data; +- +- if (octx) { +- ctx->sh = octx->sh; +- ctx->shpool = octx->shpool; +- +- return NGX_OK; +- } +- +- ctx->shpool = (ngx_slab_pool_t *) shm_zone->shm.addr; +- +- if (shm_zone->shm.exists) { +- ctx->sh = ctx->shpool->data; +- +- return NGX_OK; +- } +- +- ctx->sh = ngx_slab_alloc(ctx->shpool, sizeof(ngx_http_lua_shdict_shctx_t)); +- if (ctx->sh == NULL) { +- return NGX_ERROR; +- } +- +- ctx->shpool->data = ctx->sh; +- +- ngx_rbtree_init(&ctx->sh->rbtree, &ctx->sh->sentinel, +- ngx_http_lua_shdict_rbtree_insert_value); +- +- ngx_queue_init(&ctx->sh->lru_queue); +- +- len = sizeof(" in lua_shared_dict zone \"\"") + shm_zone->shm.name.len; +- +- ctx->shpool->log_ctx = ngx_slab_alloc(ctx->shpool, len); +- if (ctx->shpool->log_ctx == NULL) { +- return NGX_ERROR; +- } +- +- ngx_sprintf(ctx->shpool->log_ctx, " in lua_shared_dict zone \"%V\"%Z", +- &shm_zone->shm.name); +- +- ctx->shpool->log_nomem = 0; +- +- return NGX_OK; +-} +- +- +-void +-ngx_http_lua_shdict_rbtree_insert_value(ngx_rbtree_node_t *temp, +- ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel) +-{ +- ngx_rbtree_node_t **p; +- ngx_http_lua_shdict_node_t *sdn, *sdnt; +- +- for ( ;; ) { +- +- if (node->key < temp->key) { +- +- p = &temp->left; +- +- } else if (node->key > temp->key) { +- +- p = &temp->right; +- +- } else { /* node->key == temp->key */ +- +- sdn = (ngx_http_lua_shdict_node_t *) &node->color; +- sdnt = (ngx_http_lua_shdict_node_t *) &temp->color; +- +- p = ngx_memn2cmp(sdn->data, sdnt->data, sdn->key_len, +- sdnt->key_len) < 0 ? &temp->left : &temp->right; +- } +- +- if (*p == sentinel) { +- break; +- } +- +- temp = *p; +- } +- +- *p = node; +- node->parent = temp; +- node->left = sentinel; +- node->right = sentinel; +- ngx_rbt_red(node); +-} +- +- +-static ngx_int_t +-ngx_http_lua_shdict_lookup(ngx_shm_zone_t *shm_zone, ngx_uint_t hash, +- u_char *kdata, size_t klen, ngx_http_lua_shdict_node_t **sdp) +-{ +- ngx_int_t rc; +- ngx_time_t *tp; +- uint64_t now; +- int64_t ms; +- ngx_rbtree_node_t *node, *sentinel; +- ngx_http_lua_shdict_ctx_t *ctx; +- ngx_http_lua_shdict_node_t *sd; +- +- ctx = shm_zone->data; +- +- node = ctx->sh->rbtree.root; +- sentinel = ctx->sh->rbtree.sentinel; +- +- while (node != sentinel) { +- +- if (hash < node->key) { +- node = node->left; +- continue; +- } +- +- if (hash > node->key) { +- node = node->right; +- continue; +- } +- +- /* hash == node->key */ +- +- sd = (ngx_http_lua_shdict_node_t *) &node->color; +- +- rc = ngx_memn2cmp(kdata, sd->data, klen, (size_t) sd->key_len); +- +- if (rc == 0) { +- ngx_queue_remove(&sd->queue); +- ngx_queue_insert_head(&ctx->sh->lru_queue, &sd->queue); +- +- *sdp = sd; +- +- dd("node expires: %lld", (long long) sd->expires); +- +- if (sd->expires != 0) { +- tp = ngx_timeofday(); +- +- now = (uint64_t) tp->sec * 1000 + tp->msec; +- ms = sd->expires - now; +- +- dd("time to live: %lld", (long long) ms); +- +- if (ms < 0) { +- dd("node already expired"); +- return NGX_DONE; +- } +- } +- +- return NGX_OK; +- } +- +- node = (rc < 0) ? node->left : node->right; +- } +- +- *sdp = NULL; +- +- return NGX_DECLINED; +-} +- +- +-static int +-ngx_http_lua_shdict_expire(ngx_http_lua_shdict_ctx_t *ctx, ngx_uint_t n) +-{ +- ngx_time_t *tp; +- uint64_t now; +- ngx_queue_t *q, *list_queue, *lq; +- int64_t ms; +- ngx_rbtree_node_t *node; +- ngx_http_lua_shdict_node_t *sd; +- int freed = 0; +- ngx_http_lua_shdict_list_node_t *lnode; +- +- tp = ngx_timeofday(); +- +- now = (uint64_t) tp->sec * 1000 + tp->msec; +- +- /* +- * n == 1 deletes one or two expired entries +- * n == 0 deletes oldest entry by force +- * and one or two zero rate entries +- */ +- +- while (n < 3) { +- +- if (ngx_queue_empty(&ctx->sh->lru_queue)) { +- return freed; +- } +- +- q = ngx_queue_last(&ctx->sh->lru_queue); +- +- sd = ngx_queue_data(q, ngx_http_lua_shdict_node_t, queue); +- +- if (n++ != 0) { +- +- if (sd->expires == 0) { +- return freed; +- } +- +- ms = sd->expires - now; +- if (ms > 0) { +- return freed; +- } +- } +- +- if (sd->value_type == SHDICT_TLIST) { +- list_queue = ngx_http_lua_shdict_get_list_head(sd, sd->key_len); +- +- for (lq = ngx_queue_head(list_queue); +- lq != ngx_queue_sentinel(list_queue); +- lq = ngx_queue_next(lq)) +- { +- lnode = ngx_queue_data(lq, ngx_http_lua_shdict_list_node_t, +- queue); +- +- ngx_slab_free_locked(ctx->shpool, lnode); +- } +- } +- +- ngx_queue_remove(q); +- +- node = (ngx_rbtree_node_t *) +- ((u_char *) sd - offsetof(ngx_rbtree_node_t, color)); +- +- ngx_rbtree_delete(&ctx->sh->rbtree, node); +- +- ngx_slab_free_locked(ctx->shpool, node); +- +- freed++; +- } +- +- return freed; +-} +- +- +-void +-ngx_http_lua_inject_shdict_api(ngx_http_lua_main_conf_t *lmcf, lua_State *L) +-{ +- ngx_http_lua_shdict_ctx_t *ctx; +- ngx_uint_t i; +- ngx_shm_zone_t **zone; +- ngx_shm_zone_t **zone_udata; +- +- if (lmcf->shdict_zones != NULL) { +- lua_createtable(L, 0, lmcf->shdict_zones->nelts /* nrec */); +- /* ngx.shared */ +- +- lua_createtable(L, 0 /* narr */, 22 /* nrec */); /* shared mt */ +- +- lua_pushcfunction(L, ngx_http_lua_shdict_lpush); +- lua_setfield(L, -2, "lpush"); +- +- lua_pushcfunction(L, ngx_http_lua_shdict_rpush); +- lua_setfield(L, -2, "rpush"); +- +- lua_pushcfunction(L, ngx_http_lua_shdict_lpop); +- lua_setfield(L, -2, "lpop"); +- +- lua_pushcfunction(L, ngx_http_lua_shdict_rpop); +- lua_setfield(L, -2, "rpop"); +- +- lua_pushcfunction(L, ngx_http_lua_shdict_llen); +- lua_setfield(L, -2, "llen"); +- +- lua_pushcfunction(L, ngx_http_lua_shdict_flush_expired); +- lua_setfield(L, -2, "flush_expired"); +- +- lua_pushcfunction(L, ngx_http_lua_shdict_get_keys); +- lua_setfield(L, -2, "get_keys"); +- +- lua_pushvalue(L, -1); /* shared mt mt */ +- lua_setfield(L, -2, "__index"); /* shared mt */ +- +- zone = lmcf->shdict_zones->elts; +- +- for (i = 0; i < lmcf->shdict_zones->nelts; i++) { +- ctx = zone[i]->data; +- +- lua_pushlstring(L, (char *) ctx->name.data, ctx->name.len); +- /* shared mt key */ +- +- lua_createtable(L, 1 /* narr */, 0 /* nrec */); +- /* table of zone[i] */ +- zone_udata = lua_newuserdata(L, sizeof(ngx_shm_zone_t *)); +- /* shared mt key ud */ +- *zone_udata = zone[i]; +- lua_rawseti(L, -2, SHDICT_USERDATA_INDEX); /* {zone[i]} */ +- lua_pushvalue(L, -3); /* shared mt key ud mt */ +- lua_setmetatable(L, -2); /* shared mt key ud */ +- lua_rawset(L, -4); /* shared mt */ +- } +- +- lua_pop(L, 1); /* shared */ +- +- } else { +- lua_newtable(L); /* ngx.shared */ +- } +- +- lua_setfield(L, -2, "shared"); +-} +- +- +-static ngx_inline ngx_shm_zone_t * +-ngx_http_lua_shdict_get_zone(lua_State *L, int index) +-{ +- ngx_shm_zone_t *zone; +- ngx_shm_zone_t **zone_udata; +- +- lua_rawgeti(L, index, SHDICT_USERDATA_INDEX); +- zone_udata = lua_touserdata(L, -1); +- lua_pop(L, 1); +- +- if (zone_udata == NULL) { +- return NULL; +- } +- +- zone = *zone_udata; +- return zone; +-} +- +- +-static int +-ngx_http_lua_shdict_flush_expired(lua_State *L) +-{ +- ngx_queue_t *q, *prev, *list_queue, *lq; +- ngx_http_lua_shdict_node_t *sd; +- ngx_http_lua_shdict_ctx_t *ctx; +- ngx_shm_zone_t *zone; +- ngx_time_t *tp; +- int freed = 0; +- int attempts = 0; +- ngx_rbtree_node_t *node; +- uint64_t now; +- int n; +- ngx_http_lua_shdict_list_node_t *lnode; +- +- n = lua_gettop(L); +- +- if (n != 1 && n != 2) { +- return luaL_error(L, "expecting 1 or 2 argument(s), but saw %d", n); +- } +- +- luaL_checktype(L, 1, LUA_TTABLE); +- +- zone = ngx_http_lua_shdict_get_zone(L, 1); +- if (zone == NULL) { +- return luaL_error(L, "bad user data for the ngx_shm_zone_t pointer"); +- } +- +- if (n == 2) { +- attempts = luaL_checkint(L, 2); +- } +- +- ctx = zone->data; +- +- ngx_shmtx_lock(&ctx->shpool->mutex); +- +- if (ngx_queue_empty(&ctx->sh->lru_queue)) { +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- lua_pushnumber(L, 0); +- return 1; +- } +- +- tp = ngx_timeofday(); +- +- now = (uint64_t) tp->sec * 1000 + tp->msec; +- +- q = ngx_queue_last(&ctx->sh->lru_queue); +- +- while (q != ngx_queue_sentinel(&ctx->sh->lru_queue)) { +- prev = ngx_queue_prev(q); +- +- sd = ngx_queue_data(q, ngx_http_lua_shdict_node_t, queue); +- +- if (sd->expires != 0 && sd->expires <= now) { +- +- if (sd->value_type == SHDICT_TLIST) { +- list_queue = ngx_http_lua_shdict_get_list_head(sd, sd->key_len); +- +- for (lq = ngx_queue_head(list_queue); +- lq != ngx_queue_sentinel(list_queue); +- lq = ngx_queue_next(lq)) +- { +- lnode = ngx_queue_data(lq, ngx_http_lua_shdict_list_node_t, +- queue); +- +- ngx_slab_free_locked(ctx->shpool, lnode); +- } +- } +- +- ngx_queue_remove(q); +- +- node = (ngx_rbtree_node_t *) +- ((u_char *) sd - offsetof(ngx_rbtree_node_t, color)); +- +- ngx_rbtree_delete(&ctx->sh->rbtree, node); +- ngx_slab_free_locked(ctx->shpool, node); +- freed++; +- +- if (attempts && freed == attempts) { +- break; +- } +- } +- +- q = prev; +- } +- +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- lua_pushnumber(L, freed); +- return 1; +-} +- +- +-/* +- * This trades CPU for memory. This is potentially slow. O(2n) +- */ +- +-static int +-ngx_http_lua_shdict_get_keys(lua_State *L) +-{ +- ngx_queue_t *q, *prev; +- ngx_http_lua_shdict_node_t *sd; +- ngx_http_lua_shdict_ctx_t *ctx; +- ngx_shm_zone_t *zone; +- ngx_time_t *tp; +- int total = 0; +- int attempts = 1024; +- uint64_t now; +- int n; +- +- n = lua_gettop(L); +- +- if (n != 1 && n != 2) { +- return luaL_error(L, "expecting 1 or 2 argument(s), " +- "but saw %d", n); +- } +- +- luaL_checktype(L, 1, LUA_TTABLE); +- +- zone = ngx_http_lua_shdict_get_zone(L, 1); +- if (zone == NULL) { +- return luaL_error(L, "bad user data for the ngx_shm_zone_t pointer"); +- } +- +- if (n == 2) { +- attempts = luaL_checkint(L, 2); +- } +- +- ctx = zone->data; +- +- ngx_shmtx_lock(&ctx->shpool->mutex); +- +- if (ngx_queue_empty(&ctx->sh->lru_queue)) { +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- lua_createtable(L, 0, 0); +- return 1; +- } +- +- tp = ngx_timeofday(); +- +- now = (uint64_t) tp->sec * 1000 + tp->msec; +- +- /* first run through: get total number of elements we need to allocate */ +- +- q = ngx_queue_last(&ctx->sh->lru_queue); +- +- while (q != ngx_queue_sentinel(&ctx->sh->lru_queue)) { +- prev = ngx_queue_prev(q); +- +- sd = ngx_queue_data(q, ngx_http_lua_shdict_node_t, queue); +- +- if (sd->expires == 0 || sd->expires > now) { +- total++; +- if (attempts && total == attempts) { +- break; +- } +- } +- +- q = prev; +- } +- +- lua_createtable(L, total, 0); +- +- /* second run through: add keys to table */ +- +- total = 0; +- q = ngx_queue_last(&ctx->sh->lru_queue); +- +- while (q != ngx_queue_sentinel(&ctx->sh->lru_queue)) { +- prev = ngx_queue_prev(q); +- +- sd = ngx_queue_data(q, ngx_http_lua_shdict_node_t, queue); +- +- if (sd->expires == 0 || sd->expires > now) { +- lua_pushlstring(L, (char *) sd->data, sd->key_len); +- lua_rawseti(L, -2, ++total); +- if (attempts && total == attempts) { +- break; +- } +- } +- +- q = prev; +- } +- +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- /* table is at top of stack */ +- return 1; +-} +- +- +-ngx_int_t +-ngx_http_lua_shared_dict_get(ngx_shm_zone_t *zone, u_char *key_data, +- size_t key_len, ngx_http_lua_value_t *value) +-{ +- u_char *data; +- size_t len; +- uint32_t hash; +- ngx_int_t rc; +- ngx_http_lua_shdict_ctx_t *ctx; +- ngx_http_lua_shdict_node_t *sd; +- +- if (zone == NULL) { +- return NGX_ERROR; +- } +- +- hash = ngx_crc32_short(key_data, key_len); +- +- ctx = zone->data; +- +- ngx_shmtx_lock(&ctx->shpool->mutex); +- +- rc = ngx_http_lua_shdict_lookup(zone, hash, key_data, key_len, &sd); +- +- dd("shdict lookup returned %d", (int) rc); +- +- if (rc == NGX_DECLINED || rc == NGX_DONE) { +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- return rc; +- } +- +- /* rc == NGX_OK */ +- +- value->type = sd->value_type; +- +- dd("type: %d", (int) value->type); +- +- data = sd->data + sd->key_len; +- len = (size_t) sd->value_len; +- +- switch (value->type) { +- +- case SHDICT_TSTRING: +- +- if (value->value.s.data == NULL || value->value.s.len == 0) { +- ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, "no string buffer " +- "initialized"); +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- return NGX_ERROR; +- } +- +- if (len > value->value.s.len) { +- len = value->value.s.len; +- +- } else { +- value->value.s.len = len; +- } +- +- ngx_memcpy(value->value.s.data, data, len); +- break; +- +- case SHDICT_TNUMBER: +- +- if (len != sizeof(double)) { +- ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, "bad lua number " +- "value size found for key %*s: %lu", key_len, +- key_data, (unsigned long) len); +- +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- return NGX_ERROR; +- } +- +- ngx_memcpy(&value->value.b, data, len); +- break; +- +- case SHDICT_TBOOLEAN: +- +- if (len != sizeof(u_char)) { +- ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, "bad lua boolean " +- "value size found for key %*s: %lu", key_len, +- key_data, (unsigned long) len); +- +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- return NGX_ERROR; +- } +- +- value->value.b = *data; +- break; +- +- default: +- ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, "bad lua value type " +- "found for key %*s: %d", key_len, key_data, +- (int) value->type); +- +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- return NGX_ERROR; +- } +- +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- return NGX_OK; +-} +- +- +-static int +-ngx_http_lua_shdict_lpush(lua_State *L) +-{ +- return ngx_http_lua_shdict_push_helper(L, NGX_HTTP_LUA_SHDICT_LEFT); +-} +- +- +-static int +-ngx_http_lua_shdict_rpush(lua_State *L) +-{ +- return ngx_http_lua_shdict_push_helper(L, NGX_HTTP_LUA_SHDICT_RIGHT); +-} +- +- +-static int +-ngx_http_lua_shdict_push_helper(lua_State *L, int flags) +-{ +- int n; +- ngx_str_t key; +- uint32_t hash; +- ngx_int_t rc; +- ngx_http_lua_shdict_ctx_t *ctx; +- ngx_http_lua_shdict_node_t *sd; +- ngx_str_t value; +- int value_type; +- double num; +- ngx_rbtree_node_t *node; +- ngx_shm_zone_t *zone; +- ngx_queue_t *queue, *q; +- ngx_http_lua_shdict_list_node_t *lnode; +- +- n = lua_gettop(L); +- +- if (n != 3) { +- return luaL_error(L, "expecting 3 arguments, " +- "but only seen %d", n); +- } +- +- if (lua_type(L, 1) != LUA_TTABLE) { +- return luaL_error(L, "bad \"zone\" argument"); +- } +- +- zone = ngx_http_lua_shdict_get_zone(L, 1); +- if (zone == NULL) { +- return luaL_error(L, "bad \"zone\" argument"); +- } +- +- ctx = zone->data; +- +- if (lua_isnil(L, 2)) { +- lua_pushnil(L); +- lua_pushliteral(L, "nil key"); +- return 2; +- } +- +- key.data = (u_char *) luaL_checklstring(L, 2, &key.len); +- +- if (key.len == 0) { +- lua_pushnil(L); +- lua_pushliteral(L, "empty key"); +- return 2; +- } +- +- if (key.len > 65535) { +- lua_pushnil(L); +- lua_pushliteral(L, "key too long"); +- return 2; +- } +- +- hash = ngx_crc32_short(key.data, key.len); +- +- value_type = lua_type(L, 3); +- +- switch (value_type) { +- +- case SHDICT_TSTRING: +- value.data = (u_char *) lua_tolstring(L, 3, &value.len); +- break; +- +- case SHDICT_TNUMBER: +- value.len = sizeof(double); +- num = lua_tonumber(L, 3); +- value.data = (u_char *) # +- break; +- +- default: +- lua_pushnil(L); +- lua_pushliteral(L, "bad value type"); +- return 2; +- } +- +- ngx_shmtx_lock(&ctx->shpool->mutex); +- +-#if 1 +- ngx_http_lua_shdict_expire(ctx, 1); +-#endif +- +- rc = ngx_http_lua_shdict_lookup(zone, hash, key.data, key.len, &sd); +- +- dd("shdict lookup returned %d", (int) rc); +- +- /* exists but expired */ +- +- if (rc == NGX_DONE) { +- +- if (sd->value_type != SHDICT_TLIST) { +- /* TODO: reuse when length matched */ +- +- ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ctx->log, 0, +- "lua shared dict push: found old entry and value " +- "type not matched, remove it first"); +- +- ngx_queue_remove(&sd->queue); +- +- node = (ngx_rbtree_node_t *) +- ((u_char *) sd - offsetof(ngx_rbtree_node_t, color)); +- +- ngx_rbtree_delete(&ctx->sh->rbtree, node); +- +- ngx_slab_free_locked(ctx->shpool, node); +- +- dd("go to init_list"); +- goto init_list; +- } +- +- ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ctx->log, 0, +- "lua shared dict push: found old entry and value " +- "type matched, reusing it"); +- +- sd->expires = 0; +- sd->value_len = 0; +- /* free list nodes */ +- +- queue = ngx_http_lua_shdict_get_list_head(sd, key.len); +- +- for (q = ngx_queue_head(queue); +- q != ngx_queue_sentinel(queue); +- q = ngx_queue_next(q)) +- { +- /* TODO: reuse matched size list node */ +- lnode = ngx_queue_data(q, ngx_http_lua_shdict_list_node_t, queue); +- ngx_slab_free_locked(ctx->shpool, lnode); +- } +- +- ngx_queue_init(queue); +- +- ngx_queue_remove(&sd->queue); +- ngx_queue_insert_head(&ctx->sh->lru_queue, &sd->queue); +- +- dd("go to push_node"); +- goto push_node; +- } +- +- /* exists and not expired */ +- +- if (rc == NGX_OK) { +- +- if (sd->value_type != SHDICT_TLIST) { +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- lua_pushnil(L); +- lua_pushliteral(L, "value not a list"); +- return 2; +- } +- +- queue = ngx_http_lua_shdict_get_list_head(sd, key.len); +- +- ngx_queue_remove(&sd->queue); +- ngx_queue_insert_head(&ctx->sh->lru_queue, &sd->queue); +- +- dd("go to push_node"); +- goto push_node; +- } +- +- /* rc == NGX_DECLINED, not found */ +- +-init_list: +- +- ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ctx->log, 0, +- "lua shared dict list: creating a new entry"); +- +- /* NOTICE: we assume the begin point aligned in slab, be careful */ +- n = offsetof(ngx_rbtree_node_t, color) +- + offsetof(ngx_http_lua_shdict_node_t, data) +- + key.len +- + sizeof(ngx_queue_t); +- +- dd("length before aligned: %d", n); +- +- n = (int) (uintptr_t) ngx_align_ptr(n, NGX_ALIGNMENT); +- +- dd("length after aligned: %d", n); +- +- node = ngx_slab_alloc_locked(ctx->shpool, n); +- +- if (node == NULL) { +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- lua_pushboolean(L, 0); +- lua_pushliteral(L, "no memory"); +- return 2; +- } +- +- sd = (ngx_http_lua_shdict_node_t *) &node->color; +- +- queue = ngx_http_lua_shdict_get_list_head(sd, key.len); +- +- node->key = hash; +- sd->key_len = (u_short) key.len; +- +- sd->expires = 0; +- +- sd->value_len = 0; +- +- dd("setting value type to %d", (int) SHDICT_TLIST); +- +- sd->value_type = (uint8_t) SHDICT_TLIST; +- +- ngx_memcpy(sd->data, key.data, key.len); +- +- ngx_queue_init(queue); +- +- ngx_rbtree_insert(&ctx->sh->rbtree, node); +- +- ngx_queue_insert_head(&ctx->sh->lru_queue, &sd->queue); +- +-push_node: +- +- ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ctx->log, 0, +- "lua shared dict list: creating a new list node"); +- +- n = offsetof(ngx_http_lua_shdict_list_node_t, data) +- + value.len; +- +- dd("list node length: %d", n); +- +- lnode = ngx_slab_alloc_locked(ctx->shpool, n); +- +- if (lnode == NULL) { +- +- if (sd->value_len == 0) { +- +- ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ctx->log, 0, +- "lua shared dict list: no memory for create" +- " list node and list empty, remove it"); +- +- ngx_queue_remove(&sd->queue); +- +- node = (ngx_rbtree_node_t *) +- ((u_char *) sd - offsetof(ngx_rbtree_node_t, color)); +- +- ngx_rbtree_delete(&ctx->sh->rbtree, node); +- +- ngx_slab_free_locked(ctx->shpool, node); +- } +- +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- lua_pushboolean(L, 0); +- lua_pushliteral(L, "no memory"); +- return 2; +- } +- +- dd("setting list length to %d", sd->value_len + 1); +- +- sd->value_len = sd->value_len + 1; +- +- dd("setting list node value length to %d", (int) value.len); +- +- lnode->value_len = (uint32_t) value.len; +- +- dd("setting list node value type to %d", value_type); +- +- lnode->value_type = (uint8_t) value_type; +- +- ngx_memcpy(lnode->data, value.data, value.len); +- +- if (flags == NGX_HTTP_LUA_SHDICT_LEFT) { +- ngx_queue_insert_head(queue, &lnode->queue); +- +- } else { +- ngx_queue_insert_tail(queue, &lnode->queue); +- } +- +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- lua_pushnumber(L, sd->value_len); +- return 1; +-} +- +- +-static int +-ngx_http_lua_shdict_lpop(lua_State *L) +-{ +- return ngx_http_lua_shdict_pop_helper(L, NGX_HTTP_LUA_SHDICT_LEFT); +-} +- +- +-static int +-ngx_http_lua_shdict_rpop(lua_State *L) +-{ +- return ngx_http_lua_shdict_pop_helper(L, NGX_HTTP_LUA_SHDICT_RIGHT); +-} +- +- +-static int +-ngx_http_lua_shdict_pop_helper(lua_State *L, int flags) +-{ +- int n; +- ngx_str_t name; +- ngx_str_t key; +- uint32_t hash; +- ngx_int_t rc; +- ngx_http_lua_shdict_ctx_t *ctx; +- ngx_http_lua_shdict_node_t *sd; +- ngx_str_t value; +- int value_type; +- double num; +- ngx_rbtree_node_t *node; +- ngx_shm_zone_t *zone; +- ngx_queue_t *queue; +- ngx_http_lua_shdict_list_node_t *lnode; +- +- n = lua_gettop(L); +- +- if (n != 2) { +- return luaL_error(L, "expecting 2 arguments, " +- "but only seen %d", n); +- } +- +- if (lua_type(L, 1) != LUA_TTABLE) { +- return luaL_error(L, "bad \"zone\" argument"); +- } +- +- zone = ngx_http_lua_shdict_get_zone(L, 1); +- if (zone == NULL) { +- return luaL_error(L, "bad \"zone\" argument"); +- } +- +- ctx = zone->data; +- name = ctx->name; +- +- if (lua_isnil(L, 2)) { +- lua_pushnil(L); +- lua_pushliteral(L, "nil key"); +- return 2; +- } +- +- key.data = (u_char *) luaL_checklstring(L, 2, &key.len); +- +- if (key.len == 0) { +- lua_pushnil(L); +- lua_pushliteral(L, "empty key"); +- return 2; +- } +- +- if (key.len > 65535) { +- lua_pushnil(L); +- lua_pushliteral(L, "key too long"); +- return 2; +- } +- +- hash = ngx_crc32_short(key.data, key.len); +- +- ngx_shmtx_lock(&ctx->shpool->mutex); +- +-#if 1 +- ngx_http_lua_shdict_expire(ctx, 1); +-#endif +- +- rc = ngx_http_lua_shdict_lookup(zone, hash, key.data, key.len, &sd); +- +- dd("shdict lookup returned %d", (int) rc); +- +- if (rc == NGX_DECLINED || rc == NGX_DONE) { +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- lua_pushnil(L); +- return 1; +- } +- +- /* rc == NGX_OK */ +- +- if (sd->value_type != SHDICT_TLIST) { +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- lua_pushnil(L); +- lua_pushliteral(L, "value not a list"); +- return 2; +- } +- +- if (sd->value_len <= 0) { +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- return luaL_error(L, "bad lua list length found for key %s " +- "in shared_dict %s: %lu", key.data, name.data, +- (unsigned long) sd->value_len); +- } +- +- queue = ngx_http_lua_shdict_get_list_head(sd, key.len); +- +- if (flags == NGX_HTTP_LUA_SHDICT_LEFT) { +- queue = ngx_queue_head(queue); +- +- } else { +- queue = ngx_queue_last(queue); +- } +- +- lnode = ngx_queue_data(queue, ngx_http_lua_shdict_list_node_t, queue); +- +- value_type = lnode->value_type; +- +- dd("data: %p", lnode->data); +- dd("value len: %d", (int) sd->value_len); +- +- value.data = lnode->data; +- value.len = (size_t) lnode->value_len; +- +- switch (value_type) { +- +- case SHDICT_TSTRING: +- +- lua_pushlstring(L, (char *) value.data, value.len); +- break; +- +- case SHDICT_TNUMBER: +- +- if (value.len != sizeof(double)) { +- +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- return luaL_error(L, "bad lua list node number value size found " +- "for key %s in shared_dict %s: %lu", key.data, +- name.data, (unsigned long) value.len); +- } +- +- ngx_memcpy(&num, value.data, sizeof(double)); +- +- lua_pushnumber(L, num); +- break; +- +- default: +- +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- return luaL_error(L, "bad list node value type found for key %s in " +- "shared_dict %s: %d", key.data, name.data, +- value_type); +- } +- +- ngx_queue_remove(queue); +- +- ngx_slab_free_locked(ctx->shpool, lnode); +- +- if (sd->value_len == 1) { +- +- ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ctx->log, 0, +- "lua shared dict list: empty node after pop, " +- "remove it"); +- +- ngx_queue_remove(&sd->queue); +- +- node = (ngx_rbtree_node_t *) +- ((u_char *) sd - offsetof(ngx_rbtree_node_t, color)); +- +- ngx_rbtree_delete(&ctx->sh->rbtree, node); +- +- ngx_slab_free_locked(ctx->shpool, node); +- +- } else { +- sd->value_len = sd->value_len - 1; +- +- ngx_queue_remove(&sd->queue); +- ngx_queue_insert_head(&ctx->sh->lru_queue, &sd->queue); +- } +- +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- return 1; +-} +- +- +-static int +-ngx_http_lua_shdict_llen(lua_State *L) +-{ +- int n; +- ngx_str_t key; +- uint32_t hash; +- ngx_int_t rc; +- ngx_http_lua_shdict_ctx_t *ctx; +- ngx_http_lua_shdict_node_t *sd; +- ngx_shm_zone_t *zone; +- +- n = lua_gettop(L); +- +- if (n != 2) { +- return luaL_error(L, "expecting 2 arguments, " +- "but only seen %d", n); +- } +- +- if (lua_type(L, 1) != LUA_TTABLE) { +- return luaL_error(L, "bad \"zone\" argument"); +- } +- +- zone = ngx_http_lua_shdict_get_zone(L, 1); +- if (zone == NULL) { +- return luaL_error(L, "bad \"zone\" argument"); +- } +- +- ctx = zone->data; +- +- if (lua_isnil(L, 2)) { +- lua_pushnil(L); +- lua_pushliteral(L, "nil key"); +- return 2; +- } +- +- key.data = (u_char *) luaL_checklstring(L, 2, &key.len); +- +- if (key.len == 0) { +- lua_pushnil(L); +- lua_pushliteral(L, "empty key"); +- return 2; +- } +- +- if (key.len > 65535) { +- lua_pushnil(L); +- lua_pushliteral(L, "key too long"); +- return 2; +- } +- +- hash = ngx_crc32_short(key.data, key.len); +- +- ngx_shmtx_lock(&ctx->shpool->mutex); +- +-#if 1 +- ngx_http_lua_shdict_expire(ctx, 1); +-#endif +- +- rc = ngx_http_lua_shdict_lookup(zone, hash, key.data, key.len, &sd); +- +- dd("shdict lookup returned %d", (int) rc); +- +- if (rc == NGX_OK) { +- +- if (sd->value_type != SHDICT_TLIST) { +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- lua_pushnil(L); +- lua_pushliteral(L, "value not a list"); +- return 2; +- } +- +- ngx_queue_remove(&sd->queue); +- ngx_queue_insert_head(&ctx->sh->lru_queue, &sd->queue); +- +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- lua_pushnumber(L, (lua_Number) sd->value_len); +- return 1; +- } +- +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- lua_pushnumber(L, 0); +- return 1; +-} +- +- +-ngx_shm_zone_t * +-ngx_http_lua_find_zone(u_char *name_data, size_t name_len) +-{ +- ngx_str_t *name; +- ngx_uint_t i; +- ngx_shm_zone_t *zone; +- ngx_http_lua_shm_zone_ctx_t *ctx; +- volatile ngx_list_part_t *part; +- +- part = &ngx_cycle->shared_memory.part; +- zone = part->elts; +- +- for (i = 0; /* void */ ; i++) { +- +- if (i >= part->nelts) { +- if (part->next == NULL) { +- break; +- } +- +- part = part->next; +- zone = part->elts; +- i = 0; +- } +- +- name = &zone[i].shm.name; +- +- dd("name: [%.*s] %d", (int) name->len, name->data, (int) name->len); +- dd("name2: [%.*s] %d", (int) name_len, name_data, (int) name_len); +- +- if (name->len == name_len +- && ngx_strncmp(name->data, name_data, name_len) == 0) +- { +- ctx = (ngx_http_lua_shm_zone_ctx_t *) zone[i].data; +- return &ctx->zone; +- } +- } +- +- return NULL; +-} +- +- +-ngx_shm_zone_t * +-ngx_http_lua_ffi_shdict_udata_to_zone(void *zone_udata) +-{ +- if (zone_udata == NULL) { +- return NULL; +- } +- +- return *(ngx_shm_zone_t **) zone_udata; +-} +- +- +-int +-ngx_http_lua_ffi_shdict_store(ngx_shm_zone_t *zone, int op, u_char *key, +- size_t key_len, int value_type, u_char *str_value_buf, +- size_t str_value_len, double num_value, long exptime, int user_flags, +- char **errmsg, int *forcible) +-{ +- int i, n; +- u_char c, *p; +- uint32_t hash; +- ngx_int_t rc; +- ngx_time_t *tp; +- ngx_queue_t *queue, *q; +- ngx_rbtree_node_t *node; +- ngx_http_lua_shdict_ctx_t *ctx; +- ngx_http_lua_shdict_node_t *sd; +- +- dd("exptime: %ld", exptime); +- +- ctx = zone->data; +- +- *forcible = 0; +- +- hash = ngx_crc32_short(key, key_len); +- +- switch (value_type) { +- +- case SHDICT_TSTRING: +- /* do nothing */ +- break; +- +- case SHDICT_TNUMBER: +- dd("num value: %lf", num_value); +- str_value_buf = (u_char *) &num_value; +- str_value_len = sizeof(double); +- break; +- +- case SHDICT_TBOOLEAN: +- c = num_value ? 1 : 0; +- str_value_buf = &c; +- str_value_len = sizeof(u_char); +- break; +- +- case LUA_TNIL: +- if (op & (NGX_HTTP_LUA_SHDICT_ADD|NGX_HTTP_LUA_SHDICT_REPLACE)) { +- *errmsg = "attempt to add or replace nil values"; +- return NGX_ERROR; +- } +- +- str_value_buf = NULL; +- str_value_len = 0; +- break; +- +- default: +- *errmsg = "unsupported value type"; +- return NGX_ERROR; +- } +- +- ngx_shmtx_lock(&ctx->shpool->mutex); +- +-#if 1 +- ngx_http_lua_shdict_expire(ctx, 1); +-#endif +- +- rc = ngx_http_lua_shdict_lookup(zone, hash, key, key_len, &sd); +- +- dd("lookup returns %d", (int) rc); +- +- if (op & NGX_HTTP_LUA_SHDICT_REPLACE) { +- +- if (rc == NGX_DECLINED || rc == NGX_DONE) { +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- *errmsg = "not found"; +- return NGX_DECLINED; +- } +- +- /* rc == NGX_OK */ +- +- goto replace; +- } +- +- if (op & NGX_HTTP_LUA_SHDICT_ADD) { +- +- if (rc == NGX_OK) { +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- *errmsg = "exists"; +- return NGX_DECLINED; +- } +- +- if (rc == NGX_DONE) { +- /* exists but expired */ +- +- dd("go to replace"); +- goto replace; +- } +- +- /* rc == NGX_DECLINED */ +- +- dd("go to insert"); +- goto insert; +- } +- +- if (rc == NGX_OK || rc == NGX_DONE) { +- +- if (value_type == LUA_TNIL) { +- goto remove; +- } +- +-replace: +- +- if (str_value_buf +- && str_value_len == (size_t) sd->value_len +- && sd->value_type != SHDICT_TLIST) +- { +- +- ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ctx->log, 0, +- "lua shared dict set: found old entry and value " +- "size matched, reusing it"); +- +- ngx_queue_remove(&sd->queue); +- ngx_queue_insert_head(&ctx->sh->lru_queue, &sd->queue); +- +- if (exptime > 0) { +- tp = ngx_timeofday(); +- sd->expires = (uint64_t) tp->sec * 1000 + tp->msec +- + (uint64_t) exptime; +- +- } else { +- sd->expires = 0; +- } +- +- sd->user_flags = user_flags; +- +- dd("setting value type to %d", value_type); +- +- sd->value_type = (uint8_t) value_type; +- +- ngx_memcpy(sd->data + key_len, str_value_buf, str_value_len); +- +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- return NGX_OK; +- } +- +- ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ctx->log, 0, +- "lua shared dict set: found old entry but value size " +- "NOT matched, removing it first"); +- +-remove: +- +- if (sd->value_type == SHDICT_TLIST) { +- queue = ngx_http_lua_shdict_get_list_head(sd, key_len); +- +- for (q = ngx_queue_head(queue); +- q != ngx_queue_sentinel(queue); +- q = ngx_queue_next(q)) +- { +- p = (u_char *) ngx_queue_data(q, +- ngx_http_lua_shdict_list_node_t, +- queue); +- +- ngx_slab_free_locked(ctx->shpool, p); +- } +- } +- +- ngx_queue_remove(&sd->queue); +- +- node = (ngx_rbtree_node_t *) +- ((u_char *) sd - offsetof(ngx_rbtree_node_t, color)); +- +- ngx_rbtree_delete(&ctx->sh->rbtree, node); +- +- ngx_slab_free_locked(ctx->shpool, node); +- +- } +- +-insert: +- +- /* rc == NGX_DECLINED or value size unmatch */ +- +- if (str_value_buf == NULL) { +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- return NGX_OK; +- } +- +- ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ctx->log, 0, +- "lua shared dict set: creating a new entry"); +- +- n = offsetof(ngx_rbtree_node_t, color) +- + offsetof(ngx_http_lua_shdict_node_t, data) +- + key_len +- + str_value_len; +- +- node = ngx_slab_alloc_locked(ctx->shpool, n); +- +- if (node == NULL) { +- +- if (op & NGX_HTTP_LUA_SHDICT_SAFE_STORE) { +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- *errmsg = "no memory"; +- return NGX_ERROR; +- } +- +- ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ctx->log, 0, +- "lua shared dict set: overriding non-expired items " +- "due to memory shortage for entry \"%*s\"", key_len, +- key); +- +- for (i = 0; i < 30; i++) { +- if (ngx_http_lua_shdict_expire(ctx, 0) == 0) { +- break; +- } +- +- *forcible = 1; +- +- node = ngx_slab_alloc_locked(ctx->shpool, n); +- if (node != NULL) { +- goto allocated; +- } +- } +- +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- *errmsg = "no memory"; +- return NGX_ERROR; +- } +- +-allocated: +- +- sd = (ngx_http_lua_shdict_node_t *) &node->color; +- +- node->key = hash; +- sd->key_len = (u_short) key_len; +- +- if (exptime > 0) { +- tp = ngx_timeofday(); +- sd->expires = (uint64_t) tp->sec * 1000 + tp->msec +- + (uint64_t) exptime; +- +- } else { +- sd->expires = 0; +- } +- +- sd->user_flags = user_flags; +- sd->value_len = (uint32_t) str_value_len; +- dd("setting value type to %d", value_type); +- sd->value_type = (uint8_t) value_type; +- +- p = ngx_copy(sd->data, key, key_len); +- ngx_memcpy(p, str_value_buf, str_value_len); +- +- ngx_rbtree_insert(&ctx->sh->rbtree, node); +- ngx_queue_insert_head(&ctx->sh->lru_queue, &sd->queue); +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- return NGX_OK; +-} +- +- +-int +-ngx_http_lua_ffi_shdict_get(ngx_shm_zone_t *zone, u_char *key, +- size_t key_len, int *value_type, u_char **str_value_buf, +- size_t *str_value_len, double *num_value, int *user_flags, +- int get_stale, int *is_stale, char **err) +-{ +- ngx_str_t name; +- uint32_t hash; +- ngx_int_t rc; +- ngx_http_lua_shdict_ctx_t *ctx; +- ngx_http_lua_shdict_node_t *sd; +- ngx_str_t value; +- +- *err = NULL; +- +- ctx = zone->data; +- name = ctx->name; +- +- hash = ngx_crc32_short(key, key_len); +- +-#if (NGX_DEBUG) +- ngx_log_debug3(NGX_LOG_DEBUG_HTTP, ctx->log, 0, +- "fetching key \"%*s\" in shared dict \"%V\"", key_len, +- key, &name); +-#endif /* NGX_DEBUG */ +- +- ngx_shmtx_lock(&ctx->shpool->mutex); +- +-#if 1 +- if (!get_stale) { +- ngx_http_lua_shdict_expire(ctx, 1); +- } +-#endif +- +- rc = ngx_http_lua_shdict_lookup(zone, hash, key, key_len, &sd); +- +- dd("shdict lookup returns %d", (int) rc); +- +- if (rc == NGX_DECLINED || (rc == NGX_DONE && !get_stale)) { +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- *value_type = LUA_TNIL; +- return NGX_OK; +- } +- +- /* rc == NGX_OK || (rc == NGX_DONE && get_stale) */ +- +- *value_type = sd->value_type; +- +- dd("data: %p", sd->data); +- dd("key len: %d", (int) sd->key_len); +- +- value.data = sd->data + sd->key_len; +- value.len = (size_t) sd->value_len; +- +- if (*str_value_len < (size_t) value.len) { +- if (*value_type == SHDICT_TBOOLEAN) { +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- return NGX_ERROR; +- } +- +- if (*value_type == SHDICT_TSTRING) { +- *str_value_buf = malloc(value.len); +- if (*str_value_buf == NULL) { +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- return NGX_ERROR; +- } +- } +- } +- +- switch (*value_type) { +- +- case SHDICT_TSTRING: +- *str_value_len = value.len; +- ngx_memcpy(*str_value_buf, value.data, value.len); +- break; +- +- case SHDICT_TNUMBER: +- +- if (value.len != sizeof(double)) { +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, +- "bad lua number value size found for key %*s " +- "in shared_dict %V: %z", key_len, key, +- &name, value.len); +- return NGX_ERROR; +- } +- +- *str_value_len = value.len; +- ngx_memcpy(num_value, value.data, sizeof(double)); +- break; +- +- case SHDICT_TBOOLEAN: +- +- if (value.len != sizeof(u_char)) { +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, +- "bad lua boolean value size found for key %*s " +- "in shared_dict %V: %z", key_len, key, &name, +- value.len); +- return NGX_ERROR; +- } +- +- ngx_memcpy(*str_value_buf, value.data, value.len); +- break; +- +- case SHDICT_TLIST: +- +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- *err = "value is a list"; +- return NGX_ERROR; +- +- default: +- +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, +- "bad value type found for key %*s in " +- "shared_dict %V: %d", key_len, key, &name, +- *value_type); +- return NGX_ERROR; +- } +- +- *user_flags = sd->user_flags; +- dd("user flags: %d", *user_flags); +- +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- if (get_stale) { +- +- /* always return value, flags, stale */ +- +- *is_stale = (rc == NGX_DONE); +- return NGX_OK; +- } +- +- return NGX_OK; +-} +- +- +-int +-ngx_http_lua_ffi_shdict_incr(ngx_shm_zone_t *zone, u_char *key, +- size_t key_len, double *value, char **err, int has_init, double init, +- long init_ttl, int *forcible) +-{ +- int i, n; +- uint32_t hash; +- ngx_int_t rc; +- ngx_time_t *tp = NULL; +- ngx_http_lua_shdict_ctx_t *ctx; +- ngx_http_lua_shdict_node_t *sd; +- double num; +- ngx_rbtree_node_t *node; +- u_char *p; +- ngx_queue_t *queue, *q; +- +- if (init_ttl > 0) { +- tp = ngx_timeofday(); +- } +- +- ctx = zone->data; +- +- *forcible = 0; +- +- hash = ngx_crc32_short(key, key_len); +- +- dd("looking up key %.*s in shared dict %.*s", (int) key_len, key, +- (int) ctx->name.len, ctx->name.data); +- +- ngx_shmtx_lock(&ctx->shpool->mutex); +-#if 1 +- ngx_http_lua_shdict_expire(ctx, 1); +-#endif +- rc = ngx_http_lua_shdict_lookup(zone, hash, key, key_len, &sd); +- +- dd("shdict lookup returned %d", (int) rc); +- +- if (rc == NGX_DECLINED || rc == NGX_DONE) { +- if (!has_init) { +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- *err = "not found"; +- return NGX_ERROR; +- } +- +- /* add value */ +- num = *value + init; +- +- if (rc == NGX_DONE) { +- +- /* found an expired item */ +- +- if ((size_t) sd->value_len == sizeof(double) +- && sd->value_type != SHDICT_TLIST) +- { +- ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ctx->log, 0, +- "lua shared dict incr: found old entry and " +- "value size matched, reusing it"); +- +- ngx_queue_remove(&sd->queue); +- ngx_queue_insert_head(&ctx->sh->lru_queue, &sd->queue); +- +- dd("go to setvalue"); +- goto setvalue; +- } +- +- dd("go to remove"); +- goto remove; +- } +- +- dd("go to insert"); +- goto insert; +- } +- +- /* rc == NGX_OK */ +- +- if (sd->value_type != SHDICT_TNUMBER || sd->value_len != sizeof(double)) { +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- *err = "not a number"; +- return NGX_ERROR; +- } +- +- ngx_queue_remove(&sd->queue); +- ngx_queue_insert_head(&ctx->sh->lru_queue, &sd->queue); +- +- dd("setting value type to %d", (int) sd->value_type); +- +- p = sd->data + key_len; +- +- ngx_memcpy(&num, p, sizeof(double)); +- num += *value; +- +- ngx_memcpy(p, (double *) &num, sizeof(double)); +- +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- *value = num; +- return NGX_OK; +- +-remove: +- +- ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ctx->log, 0, +- "lua shared dict incr: found old entry but value size " +- "NOT matched, removing it first"); +- +- if (sd->value_type == SHDICT_TLIST) { +- queue = ngx_http_lua_shdict_get_list_head(sd, key_len); +- +- for (q = ngx_queue_head(queue); +- q != ngx_queue_sentinel(queue); +- q = ngx_queue_next(q)) +- { +- p = (u_char *) ngx_queue_data(q, ngx_http_lua_shdict_list_node_t, +- queue); +- +- ngx_slab_free_locked(ctx->shpool, p); +- } +- } +- +- ngx_queue_remove(&sd->queue); +- +- node = (ngx_rbtree_node_t *) +- ((u_char *) sd - offsetof(ngx_rbtree_node_t, color)); +- +- ngx_rbtree_delete(&ctx->sh->rbtree, node); +- +- ngx_slab_free_locked(ctx->shpool, node); +- +-insert: +- +- ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ctx->log, 0, +- "lua shared dict incr: creating a new entry"); +- +- n = offsetof(ngx_rbtree_node_t, color) +- + offsetof(ngx_http_lua_shdict_node_t, data) +- + key_len +- + sizeof(double); +- +- node = ngx_slab_alloc_locked(ctx->shpool, n); +- +- if (node == NULL) { +- +- ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ctx->log, 0, +- "lua shared dict incr: overriding non-expired items " +- "due to memory shortage for entry \"%*s\"", key_len, +- key); +- +- for (i = 0; i < 30; i++) { +- if (ngx_http_lua_shdict_expire(ctx, 0) == 0) { +- break; +- } +- +- *forcible = 1; +- +- node = ngx_slab_alloc_locked(ctx->shpool, n); +- if (node != NULL) { +- goto allocated; +- } +- } +- +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- *err = "no memory"; +- return NGX_ERROR; +- } +- +-allocated: +- +- sd = (ngx_http_lua_shdict_node_t *) &node->color; +- +- node->key = hash; +- +- sd->key_len = (u_short) key_len; +- +- sd->value_len = (uint32_t) sizeof(double); +- +- ngx_rbtree_insert(&ctx->sh->rbtree, node); +- +- ngx_queue_insert_head(&ctx->sh->lru_queue, &sd->queue); +- +-setvalue: +- +- sd->user_flags = 0; +- +- if (init_ttl > 0) { +- sd->expires = (uint64_t) tp->sec * 1000 + tp->msec +- + (uint64_t) init_ttl; +- +- } else { +- sd->expires = 0; +- } +- +- dd("setting value type to %d", LUA_TNUMBER); +- +- sd->value_type = (uint8_t) LUA_TNUMBER; +- +- p = ngx_copy(sd->data, key, key_len); +- ngx_memcpy(p, (double *) &num, sizeof(double)); +- +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- *value = num; +- return NGX_OK; +-} +- +- +-int +-ngx_http_lua_ffi_shdict_flush_all(ngx_shm_zone_t *zone) +-{ +- ngx_queue_t *q; +- ngx_http_lua_shdict_node_t *sd; +- ngx_http_lua_shdict_ctx_t *ctx; +- +- ctx = zone->data; +- +- ngx_shmtx_lock(&ctx->shpool->mutex); +- +- for (q = ngx_queue_head(&ctx->sh->lru_queue); +- q != ngx_queue_sentinel(&ctx->sh->lru_queue); +- q = ngx_queue_next(q)) +- { +- sd = ngx_queue_data(q, ngx_http_lua_shdict_node_t, queue); +- sd->expires = 1; +- } +- +- ngx_http_lua_shdict_expire(ctx, 0); +- +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- return NGX_OK; +-} +- +- +-static ngx_int_t +-ngx_http_lua_shdict_peek(ngx_shm_zone_t *shm_zone, ngx_uint_t hash, +- u_char *kdata, size_t klen, ngx_http_lua_shdict_node_t **sdp) +-{ +- ngx_int_t rc; +- ngx_rbtree_node_t *node, *sentinel; +- ngx_http_lua_shdict_ctx_t *ctx; +- ngx_http_lua_shdict_node_t *sd; +- +- ctx = shm_zone->data; +- +- node = ctx->sh->rbtree.root; +- sentinel = ctx->sh->rbtree.sentinel; +- +- while (node != sentinel) { +- +- if (hash < node->key) { +- node = node->left; +- continue; +- } +- +- if (hash > node->key) { +- node = node->right; +- continue; +- } +- +- /* hash == node->key */ +- +- sd = (ngx_http_lua_shdict_node_t *) &node->color; +- +- rc = ngx_memn2cmp(kdata, sd->data, klen, (size_t) sd->key_len); +- +- if (rc == 0) { +- *sdp = sd; +- +- return NGX_OK; +- } +- +- node = (rc < 0) ? node->left : node->right; +- } +- +- *sdp = NULL; +- +- return NGX_DECLINED; +-} +- +- +-long +-ngx_http_lua_ffi_shdict_get_ttl(ngx_shm_zone_t *zone, u_char *key, +- size_t key_len) +-{ +- uint32_t hash; +- uint64_t now; +- uint64_t expires; +- ngx_int_t rc; +- ngx_time_t *tp; +- ngx_http_lua_shdict_ctx_t *ctx; +- ngx_http_lua_shdict_node_t *sd; +- +- ctx = zone->data; +- hash = ngx_crc32_short(key, key_len); +- +- ngx_shmtx_lock(&ctx->shpool->mutex); +- +- rc = ngx_http_lua_shdict_peek(zone, hash, key, key_len, &sd); +- +- if (rc == NGX_DECLINED) { +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- return NGX_DECLINED; +- } +- +- /* rc == NGX_OK */ +- +- expires = sd->expires; +- +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- if (expires == 0) { +- return 0; +- } +- +- tp = ngx_timeofday(); +- now = (uint64_t) tp->sec * 1000 + tp->msec; +- +- return expires - now; +-} +- +- +-int +-ngx_http_lua_ffi_shdict_set_expire(ngx_shm_zone_t *zone, u_char *key, +- size_t key_len, long exptime) +-{ +- uint32_t hash; +- ngx_int_t rc; +- ngx_time_t *tp = NULL; +- ngx_http_lua_shdict_ctx_t *ctx; +- ngx_http_lua_shdict_node_t *sd; +- +- if (exptime > 0) { +- tp = ngx_timeofday(); +- } +- +- ctx = zone->data; +- hash = ngx_crc32_short(key, key_len); +- +- ngx_shmtx_lock(&ctx->shpool->mutex); +- +- rc = ngx_http_lua_shdict_peek(zone, hash, key, key_len, &sd); +- +- if (rc == NGX_DECLINED) { +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- return NGX_DECLINED; +- } +- +- /* rc == NGX_OK */ +- +- if (exptime > 0) { +- sd->expires = (uint64_t) tp->sec * 1000 + tp->msec +- + (uint64_t) exptime; +- +- } else { +- sd->expires = 0; +- } +- +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- return NGX_OK; +-} +- +- +-size_t +-ngx_http_lua_ffi_shdict_capacity(ngx_shm_zone_t *zone) +-{ +- return zone->shm.size; +-} +- +- +-#if (nginx_version >= 1011007) +-size_t +-ngx_http_lua_ffi_shdict_free_space(ngx_shm_zone_t *zone) +-{ +- size_t bytes; +- ngx_http_lua_shdict_ctx_t *ctx; +- +- ctx = zone->data; +- +- ngx_shmtx_lock(&ctx->shpool->mutex); +- bytes = ctx->shpool->pfree * ngx_pagesize; +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- return bytes; +-} +-#endif +- +- +-/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ +diff --git src/ngx_http_lua_shdict.h src/ngx_http_lua_shdict.h +deleted file mode 100644 +index 90a0099f..00000000 +--- src/ngx_http_lua_shdict.h ++++ /dev/null +@@ -1,67 +0,0 @@ +- +-/* +- * Copyright (C) Yichun Zhang (agentzh) +- */ +- +- +-#ifndef _NGX_HTTP_LUA_SHDICT_H_INCLUDED_ +-#define _NGX_HTTP_LUA_SHDICT_H_INCLUDED_ +- +- +-#include "ngx_http_lua_common.h" +- +- +-typedef struct { +- u_char color; +- uint8_t value_type; +- u_short key_len; +- uint32_t value_len; +- uint64_t expires; +- ngx_queue_t queue; +- uint32_t user_flags; +- u_char data[1]; +-} ngx_http_lua_shdict_node_t; +- +- +-typedef struct { +- ngx_queue_t queue; +- uint32_t value_len; +- uint8_t value_type; +- u_char data[1]; +-} ngx_http_lua_shdict_list_node_t; +- +- +-typedef struct { +- ngx_rbtree_t rbtree; +- ngx_rbtree_node_t sentinel; +- ngx_queue_t lru_queue; +-} ngx_http_lua_shdict_shctx_t; +- +- +-typedef struct { +- ngx_http_lua_shdict_shctx_t *sh; +- ngx_slab_pool_t *shpool; +- ngx_str_t name; +- ngx_http_lua_main_conf_t *main_conf; +- ngx_log_t *log; +-} ngx_http_lua_shdict_ctx_t; +- +- +-typedef struct { +- ngx_log_t *log; +- ngx_http_lua_main_conf_t *lmcf; +- ngx_cycle_t *cycle; +- ngx_shm_zone_t zone; +-} ngx_http_lua_shm_zone_ctx_t; +- +- +-ngx_int_t ngx_http_lua_shdict_init_zone(ngx_shm_zone_t *shm_zone, void *data); +-void ngx_http_lua_shdict_rbtree_insert_value(ngx_rbtree_node_t *temp, +- ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel); +-void ngx_http_lua_inject_shdict_api(ngx_http_lua_main_conf_t *lmcf, +- lua_State *L); +- +- +-#endif /* _NGX_HTTP_LUA_SHDICT_H_INCLUDED_ */ +- +-/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ +diff --git src/ngx_http_lua_util.c src/ngx_http_lua_util.c +index 5fe9b506..33d6a657 100644 +--- src/ngx_http_lua_util.c ++++ src/ngx_http_lua_util.c +@@ -12,6 +12,7 @@ + + + #include "nginx.h" ++#include "ngx_meta_lua_api.h" + #include "ngx_http_lua_directive.h" + #include "ngx_http_lua_util.h" + #include "ngx_http_lua_exception.h" +@@ -28,7 +29,6 @@ + #include "ngx_http_lua_string.h" + #include "ngx_http_lua_misc.h" + #include "ngx_http_lua_consts.h" +-#include "ngx_http_lua_shdict.h" + #include "ngx_http_lua_coroutine.h" + #include "ngx_http_lua_socket_tcp.h" + #include "ngx_http_lua_socket_udp.h" +@@ -114,7 +114,7 @@ static ngx_int_t ngx_http_lua_handle_rewrite_jump(lua_State *L, + static int ngx_http_lua_thread_traceback(lua_State *L, lua_State *co, + ngx_http_lua_co_ctx_t *coctx); + static void ngx_http_lua_inject_ngx_api(lua_State *L, +- ngx_http_lua_main_conf_t *lmcf, ngx_log_t *log); ++ ngx_cycle_t *cycle, ngx_http_lua_main_conf_t *lmcf, ngx_log_t *log); + static void ngx_http_lua_inject_arg_api(lua_State *L); + static int ngx_http_lua_param_get(lua_State *L); + static int ngx_http_lua_param_set(lua_State *L); +@@ -808,13 +808,13 @@ ngx_http_lua_init_globals(lua_State *L, ngx_cycle_t *cycle, + ngx_http_lua_inject_ndk_api(L); + #endif /* defined(NDK) && NDK */ + +- ngx_http_lua_inject_ngx_api(L, lmcf, log); ++ ngx_http_lua_inject_ngx_api(L, cycle, lmcf, log); + } + + + static void +-ngx_http_lua_inject_ngx_api(lua_State *L, ngx_http_lua_main_conf_t *lmcf, +- ngx_log_t *log) ++ngx_http_lua_inject_ngx_api(lua_State *L, ngx_cycle_t *cycle, ++ ngx_http_lua_main_conf_t *lmcf, ngx_log_t *log) + { + lua_createtable(L, 0 /* narr */, 113 /* nrec */); /* ngx.* */ + +@@ -836,7 +836,7 @@ ngx_http_lua_inject_ngx_api(lua_State *L, ngx_http_lua_main_conf_t *lmcf, + ngx_http_lua_inject_req_api(log, L); + ngx_http_lua_inject_resp_header_api(L); + ngx_http_lua_create_headers_metatable(log, L); +- ngx_http_lua_inject_shdict_api(lmcf, L); ++ ngx_meta_lua_inject_shdict_api(L, cycle, &ngx_http_lua_module); + ngx_http_lua_inject_socket_tcp_api(log, L); + ngx_http_lua_inject_socket_udp_api(log, L); + ngx_http_lua_inject_uthread_api(log, L); +diff --git src/ngx_http_lua_util.h src/ngx_http_lua_util.h +index 1768e5e2..9c5d26de 100644 +--- src/ngx_http_lua_util.h ++++ src/ngx_http_lua_util.h +@@ -327,7 +327,9 @@ ngx_http_lua_create_ctx(ngx_http_request_t *r) + ngx_http_lua_assert(L != NULL); + + if (lmcf->init_handler) { +- if (lmcf->init_handler(r->connection->log, lmcf, L) != NGX_OK) { ++ if (lmcf->init_handler(r->connection->log, lmcf->init_src, L) ++ != NGX_OK) ++ { + /* an error happened */ + return NULL; + } diff --git a/patch/1.21.4.1/ngx_lua-skip_filter.patch b/patch/1.21.4.1/ngx_lua-skip_filter.patch new file mode 100644 index 0000000..e65f72a --- /dev/null +++ b/patch/1.21.4.1/ngx_lua-skip_filter.patch @@ -0,0 +1,54 @@ +diff --git src/ngx_http_lua_bodyfilterby.c src/ngx_http_lua_bodyfilterby.c +index 9024889..88af761 100644 +--- src/ngx_http_lua_bodyfilterby.c ++++ src/ngx_http_lua_bodyfilterby.c +@@ -22,6 +22,9 @@ + #include "ngx_http_lua_misc.h" + #include "ngx_http_lua_consts.h" + #include "ngx_http_lua_output.h" ++#if (NGX_HTTP_APISIX) ++#include "ngx_http_apisix_module.h" ++#endif + + + static void ngx_http_lua_body_filter_by_lua_env(lua_State *L, +@@ -241,6 +244,12 @@ ngx_http_lua_body_filter(ngx_http_request_t *r, ngx_chain_t *in) + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua body filter for user lua code, uri \"%V\"", &r->uri); + ++#if (NGX_HTTP_APISIX) ++ if (ngx_http_apisix_is_body_filter_by_lua_skipped(r)) { ++ return ngx_http_next_body_filter(r, in); ++ } ++#endif ++ + llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); + + if (llcf->body_filter_handler == NULL || r->header_only) { +diff --git src/ngx_http_lua_headerfilterby.c src/ngx_http_lua_headerfilterby.c +index ed0c3a6..5f04992 100644 +--- src/ngx_http_lua_headerfilterby.c ++++ src/ngx_http_lua_headerfilterby.c +@@ -19,6 +19,9 @@ + #include "ngx_http_lua_string.h" + #include "ngx_http_lua_misc.h" + #include "ngx_http_lua_consts.h" ++#if (NGX_HTTP_APISIX) ++#include "ngx_http_apisix_module.h" ++#endif + + + static ngx_http_output_header_filter_pt ngx_http_next_header_filter; +@@ -80,6 +83,12 @@ ngx_http_lua_header_filter_by_chunk(lua_State *L, ngx_http_request_t *r) + #endif + ngx_http_lua_ctx_t *ctx; + ++#if (NGX_HTTP_APISIX) ++ if (ngx_http_apisix_is_header_filter_by_lua_skipped(r)) { ++ return NGX_OK; ++ } ++#endif ++ + ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + if (ctx->exited) { + old_exit_code = ctx->exit_code; diff --git a/patch/1.21.4.1/ngx_lua-tlshandshake.patch b/patch/1.21.4.1/ngx_lua-tlshandshake.patch new file mode 100644 index 0000000..ee17565 --- /dev/null +++ b/patch/1.21.4.1/ngx_lua-tlshandshake.patch @@ -0,0 +1,704 @@ +diff --git src/ngx_http_lua_socket_tcp.c src/ngx_http_lua_socket_tcp.c +index 55bd203..ebb72d9 100644 +--- src/ngx_http_lua_socket_tcp.c ++++ src/ngx_http_lua_socket_tcp.c +@@ -22,7 +22,9 @@ + static int ngx_http_lua_socket_tcp(lua_State *L); + static int ngx_http_lua_socket_tcp_connect(lua_State *L); + #if (NGX_HTTP_SSL) +-static int ngx_http_lua_socket_tcp_sslhandshake(lua_State *L); ++static void ngx_http_lua_tls_handshake_handler(ngx_connection_t *c); ++static int ngx_http_lua_tls_handshake_retval_handler(ngx_http_request_t *r, ++ ngx_http_lua_socket_tcp_upstream_t *u, lua_State *L); + #endif + static int ngx_http_lua_socket_tcp_receive(lua_State *L); + static int ngx_http_lua_socket_tcp_receiveany(lua_State *L); +@@ -151,12 +153,6 @@ static void + ngx_http_lua_socket_empty_resolve_handler(ngx_resolver_ctx_t *ctx); + static int ngx_http_lua_socket_prepare_error_retvals(ngx_http_request_t *r, + ngx_http_lua_socket_tcp_upstream_t *u, lua_State *L, ngx_uint_t ft_type); +-#if (NGX_HTTP_SSL) +-static int ngx_http_lua_ssl_handshake_retval_handler(ngx_http_request_t *r, +- ngx_http_lua_socket_tcp_upstream_t *u, lua_State *L); +-static void ngx_http_lua_ssl_handshake_handler(ngx_connection_t *c); +-static int ngx_http_lua_ssl_free_session(lua_State *L); +-#endif + static void ngx_http_lua_socket_tcp_close_connection(ngx_connection_t *c); + + +@@ -224,9 +220,6 @@ static char ngx_http_lua_upstream_udata_metatable_key; + static char ngx_http_lua_downstream_udata_metatable_key; + static char ngx_http_lua_pool_udata_metatable_key; + static char ngx_http_lua_pattern_udata_metatable_key; +-#if (NGX_HTTP_SSL) +-static char ngx_http_lua_ssl_session_metatable_key; +-#endif + + + #define ngx_http_lua_tcp_socket_metatable_literal_key "__tcp_cosocket_mt" +@@ -326,13 +319,6 @@ ngx_http_lua_inject_socket_tcp_api(ngx_log_t *log, lua_State *L) + lua_pushcfunction(L, ngx_http_lua_socket_tcp_connect); + lua_setfield(L, -2, "connect"); + +-#if (NGX_HTTP_SSL) +- +- lua_pushcfunction(L, ngx_http_lua_socket_tcp_sslhandshake); +- lua_setfield(L, -2, "sslhandshake"); +- +-#endif +- + lua_pushcfunction(L, ngx_http_lua_socket_tcp_receive); + lua_setfield(L, -2, "receive"); + +@@ -406,19 +392,6 @@ ngx_http_lua_inject_socket_tcp_api(ngx_log_t *log, lua_State *L) + lua_setfield(L, -2, "__gc"); + lua_rawset(L, LUA_REGISTRYINDEX); + /* }}} */ +- +-#if (NGX_HTTP_SSL) +- +- /* {{{ssl session userdata metatable */ +- lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( +- ssl_session_metatable_key)); +- lua_createtable(L, 0 /* narr */, 1 /* nrec */); /* metatable */ +- lua_pushcfunction(L, ngx_http_lua_ssl_free_session); +- lua_setfield(L, -2, "__gc"); +- lua_rawset(L, LUA_REGISTRYINDEX); +- /* }}} */ +- +-#endif + } + + +@@ -1568,64 +1541,73 @@ ngx_http_lua_socket_conn_error_retval_handler(ngx_http_request_t *r, + + #if (NGX_HTTP_SSL) + +-static int +-ngx_http_lua_socket_tcp_sslhandshake(lua_State *L) ++static const char * ++ngx_http_lua_socket_tcp_check_busy(ngx_http_request_t *r, ++ ngx_http_lua_socket_tcp_upstream_t *u, unsigned int ops) + { +- int n, top; +- ngx_int_t rc; +- ngx_str_t name = ngx_null_string; +- ngx_connection_t *c; +- ngx_ssl_session_t **psession; +- ngx_http_request_t *r; +- ngx_http_lua_ctx_t *ctx; +- ngx_http_lua_co_ctx_t *coctx; +- +- ngx_http_lua_socket_tcp_upstream_t *u; +- +- /* Lua function arguments: self [,session] [,host] [,verify] +- [,send_status_req] */ ++ if ((ops & SOCKET_OP_CONNECT) && u->conn_waiting) { ++ return "socket busy connecting"; ++ } + +- n = lua_gettop(L); +- if (n < 1 || n > 5) { +- return luaL_error(L, "ngx.socket sslhandshake: expecting 1 ~ 5 " +- "arguments (including the object), but seen %d", n); ++ if ((ops & SOCKET_OP_READ) && u->read_waiting) { ++ return "socket busy reading"; + } + +- r = ngx_http_lua_get_req(L); +- if (r == NULL) { +- return luaL_error(L, "no request found"); ++ if ((ops & SOCKET_OP_WRITE) ++ && (u->write_waiting ++ || (u->raw_downstream ++ && (r->connection->buffered & NGX_HTTP_LOWLEVEL_BUFFERED)))) ++ { ++ return "socket busy writing"; + } + +- ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, +- "lua tcp socket ssl handshake"); ++ return NULL; ++} + +- luaL_checktype(L, 1, LUA_TTABLE); + +- lua_rawgeti(L, 1, SOCKET_CTX_INDEX); +- u = lua_touserdata(L, -1); ++int ++ngx_http_lua_ffi_socket_tcp_tlshandshake(ngx_http_request_t *r, ++ ngx_http_lua_socket_tcp_upstream_t *u, ngx_ssl_session_t *sess, ++ int enable_session_reuse, ngx_str_t *server_name, int verify, ++ int ocsp_status_req, STACK_OF(X509) *chain, EVP_PKEY *pkey, ++ const char **errmsg) ++{ ++ ngx_int_t rc, i; ++ ngx_connection_t *c; ++ ngx_http_lua_ctx_t *ctx; ++ ngx_http_lua_co_ctx_t *coctx; ++ const char *busy_rc; ++ ngx_ssl_conn_t *ssl_conn; ++ X509 *x509; ++ ++ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, ++ "lua tcp socket tls handshake"); + + if (u == NULL + || u->peer.connection == NULL + || u->read_closed + || u->write_closed) + { +- lua_pushnil(L); +- lua_pushliteral(L, "closed"); +- return 2; ++ *errmsg = "closed"; ++ return NGX_ERROR; + } + + if (u->request != r) { +- return luaL_error(L, "bad request"); ++ *errmsg = "bad request"; ++ return NGX_ERROR; + } + +- ngx_http_lua_socket_check_busy_connecting(r, u, L); +- ngx_http_lua_socket_check_busy_reading(r, u, L); +- ngx_http_lua_socket_check_busy_writing(r, u, L); ++ busy_rc = ngx_http_lua_socket_tcp_check_busy(r, u, SOCKET_OP_CONNECT ++ | SOCKET_OP_READ ++ | SOCKET_OP_WRITE); ++ if (busy_rc != NULL) { ++ *errmsg = busy_rc; ++ return NGX_ERROR; ++ } + + if (u->raw_downstream || u->body_downstream) { +- lua_pushnil(L); +- lua_pushliteral(L, "not supported for downstream"); +- return 2; ++ *errmsg = "not supported for downstream sockets"; ++ return NGX_ERROR; + } + + c = u->peer.connection; +@@ -1633,122 +1615,140 @@ ngx_http_lua_socket_tcp_sslhandshake(lua_State *L) + u->ssl_session_reuse = 1; + + if (c->ssl && c->ssl->handshaked) { +- switch (lua_type(L, 2)) { +- case LUA_TUSERDATA: +- lua_pushvalue(L, 2); +- break; ++ if (sess != NULL) { ++ return NGX_DONE; ++ } + +- case LUA_TBOOLEAN: +- if (!lua_toboolean(L, 2)) { +- /* avoid generating the ssl session */ +- lua_pushboolean(L, 1); +- break; +- } +- /* fall through */ ++ u->ssl_session_reuse = enable_session_reuse; + +- default: +- ngx_http_lua_ssl_handshake_retval_handler(r, u, L); +- break; +- } ++ (void) ngx_http_lua_tls_handshake_retval_handler(r, u, NULL); + +- return 1; ++ return NGX_OK; + } + + if (ngx_ssl_create_connection(u->conf->ssl, c, + NGX_SSL_BUFFER|NGX_SSL_CLIENT) + != NGX_OK) + { +- lua_pushnil(L); +- lua_pushliteral(L, "failed to create ssl connection"); +- return 2; ++ *errmsg = "failed to create ssl connection"; ++ return NGX_ERROR; + } + ++ ssl_conn = c->ssl->connection; ++ + ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + if (ctx == NULL) { +- return luaL_error(L, "no ctx found"); ++ return NGX_HTTP_LUA_FFI_NO_REQ_CTX; + } + + coctx = ctx->cur_co_ctx; + + c->sendfile = 0; + +- if (n >= 2) { +- if (lua_type(L, 2) == LUA_TBOOLEAN) { +- u->ssl_session_reuse = lua_toboolean(L, 2); ++ if (sess != NULL) { ++ if (ngx_ssl_set_session(c, sess) != NGX_OK) { ++ *errmsg = "tls set session failed"; ++ return NGX_ERROR; ++ } + +- } else { +- psession = lua_touserdata(L, 2); ++ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, ++ "lua tls set session: %p", sess); + +- if (psession != NULL && *psession != NULL) { +- if (ngx_ssl_set_session(c, *psession) != NGX_OK) { +- lua_pushnil(L); +- lua_pushliteral(L, "lua ssl set session failed"); +- return 2; +- } ++ } else { ++ u->ssl_session_reuse = enable_session_reuse; ++ } + +- ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, +- "lua ssl set session: %p", *psession); +- } ++ if (chain != NULL) { ++ ngx_http_lua_assert(pkey != NULL); /* ensured by resty.core */ ++ ++ if (sk_X509_num(chain) < 1) { ++ ERR_clear_error(); ++ *errmsg = "invalid client certificate chain"; ++ return NGX_ERROR; + } + +- if (n >= 3) { +- name.data = (u_char *) lua_tolstring(L, 3, &name.len); ++ x509 = sk_X509_value(chain, 0); ++ if (x509 == NULL) { ++ ERR_clear_error(); ++ *errmsg = "tls fetch client certificate from chain failed"; ++ return NGX_ERROR; ++ } + +- if (name.data) { +- ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, +- "lua ssl server name: \"%*s\"", name.len, +- name.data); ++ if (SSL_use_certificate(ssl_conn, x509) == 0) { ++ ERR_clear_error(); ++ *errmsg = "tls set client certificate failed"; ++ return NGX_ERROR; ++ } + +-#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME ++ /* read rest of the chain */ + +- if (SSL_set_tlsext_host_name(c->ssl->connection, +- (char *) name.data) +- == 0) +- { +- lua_pushnil(L); +- lua_pushliteral(L, "SSL_set_tlsext_host_name failed"); +- return 2; +- } ++ for (i = 1; i < sk_X509_num(chain); i++) { ++ x509 = sk_X509_value(chain, i); ++ if (x509 == NULL) { ++ ERR_clear_error(); ++ *errmsg = "tls fetch client intermediate certificate from " ++ "chain failed"; ++ return NGX_ERROR; ++ } + +-#else ++ if (SSL_add1_chain_cert(ssl_conn, x509) == 0) { ++ ERR_clear_error(); ++ *errmsg = "tls set client intermediate certificate failed"; ++ return NGX_ERROR; ++ } ++ } + +- ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, +- "lua socket SNI disabled because the current " +- "version of OpenSSL lacks the support"); ++ if (SSL_use_PrivateKey(ssl_conn, pkey) == 0) { ++ ERR_clear_error(); ++ *errmsg = "tls set client private key failed"; ++ return NGX_ERROR; ++ } ++ } ++ ++ if (server_name != NULL && server_name->data != NULL) { ++ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, ++ "lua tls server name: \"%V\"", server_name); + ++#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME ++ if (SSL_set_tlsext_host_name(c->ssl->connection, ++ (char *) server_name->data) ++ == 0) ++ { ++ *errmsg = "SSL_set_tlsext_host_name failed"; ++ return NGX_ERROR; ++ } ++ ++#else ++ *errmsg = "no TLS extension support"; ++ return NGX_ERROR; + #endif +- } ++ } + +- if (n >= 4) { +- u->ssl_verify = lua_toboolean(L, 4); ++ u->ssl_verify = verify; + +- if (n >= 5) { +- if (lua_toboolean(L, 5)) { ++ if (ocsp_status_req) { + #ifdef NGX_HTTP_LUA_USE_OCSP +- SSL_set_tlsext_status_type(c->ssl->connection, +- TLSEXT_STATUSTYPE_ocsp); ++ SSL_set_tlsext_status_type(c->ssl->connection, ++ TLSEXT_STATUSTYPE_ocsp); ++ + #else +- return luaL_error(L, "no OCSP support"); ++ *errmsg = "no OCSP support"; ++ return NGX_ERROR; + #endif +- } +- } +- } +- } + } + +- dd("found sni name: %.*s %p", (int) name.len, name.data, name.data); +- +- if (name.len == 0) { ++ if (server_name->len == 0) { + u->ssl_name.len = 0; + + } else { + if (u->ssl_name.data) { + /* buffer already allocated */ + +- if (u->ssl_name.len >= name.len) { ++ if (u->ssl_name.len >= server_name->len) { + /* reuse it */ +- ngx_memcpy(u->ssl_name.data, name.data, name.len); +- u->ssl_name.len = name.len; ++ ngx_memcpy(u->ssl_name.data, server_name->data, ++ server_name->len); ++ u->ssl_name.len = server_name->len; + + } else { + ngx_free(u->ssl_name.data); +@@ -1759,17 +1759,15 @@ ngx_http_lua_socket_tcp_sslhandshake(lua_State *L) + + new_ssl_name: + +- u->ssl_name.data = ngx_alloc(name.len, ngx_cycle->log); ++ u->ssl_name.data = ngx_alloc(server_name->len, ngx_cycle->log); + if (u->ssl_name.data == NULL) { + u->ssl_name.len = 0; +- +- lua_pushnil(L); +- lua_pushliteral(L, "no memory"); +- return 2; ++ *errmsg = "no memory"; ++ return NGX_ERROR; + } + +- ngx_memcpy(u->ssl_name.data, name.data, name.len); +- u->ssl_name.len = name.len; ++ ngx_memcpy(u->ssl_name.data, server_name->data, server_name->len); ++ u->ssl_name.len = server_name->len; + } + } + +@@ -1783,7 +1781,8 @@ new_ssl_name: + + rc = ngx_ssl_handshake(c); + +- dd("ngx_ssl_handshake returned %d", (int) rc); ++ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, ++ "ngx_ssl_handshake returned: %d", rc); + + if (rc == NGX_AGAIN) { + if (c->write->timer_set) { +@@ -1793,13 +1792,13 @@ new_ssl_name: + ngx_add_timer(c->read, u->connect_timeout); + + u->conn_waiting = 1; +- u->write_prepare_retvals = ngx_http_lua_ssl_handshake_retval_handler; ++ u->write_prepare_retvals = ngx_http_lua_tls_handshake_retval_handler; + + ngx_http_lua_cleanup_pending_operation(coctx); + coctx->cleanup = ngx_http_lua_coctx_cleanup; + coctx->data = u; + +- c->ssl->handler = ngx_http_lua_ssl_handshake_handler; ++ c->ssl->handler = ngx_http_lua_tls_handshake_handler; + + if (ctx->entered_content_phase) { + r->write_event_handler = ngx_http_lua_content_wev_handler; +@@ -1808,21 +1807,24 @@ new_ssl_name: + r->write_event_handler = ngx_http_core_run_phases; + } + +- return lua_yield(L, 0); ++ return NGX_AGAIN; ++ } ++ ++ ngx_http_lua_tls_handshake_handler(c); ++ ++ if (rc == NGX_ERROR) { ++ *errmsg = u->error_ret; ++ return NGX_ERROR; + } + +- top = lua_gettop(L); +- ngx_http_lua_ssl_handshake_handler(c); +- return lua_gettop(L) - top; ++ return NGX_OK; + } + + + static void +-ngx_http_lua_ssl_handshake_handler(ngx_connection_t *c) ++ngx_http_lua_tls_handshake_handler(ngx_connection_t *c) + { +- const char *err; + int waiting; +- lua_State *L; + ngx_int_t rc; + ngx_connection_t *dc; /* downstream connection */ + ngx_http_request_t *r; +@@ -1845,11 +1847,9 @@ ngx_http_lua_ssl_handshake_handler(ngx_connection_t *c) + waiting = u->conn_waiting; + + dc = r->connection; +- L = u->write_co_ctx->co; + + if (c->read->timedout) { +- lua_pushnil(L); +- lua_pushliteral(L, "timeout"); ++ u->error_ret = "timeout"; + goto failed; + } + +@@ -1858,19 +1858,18 @@ ngx_http_lua_ssl_handshake_handler(ngx_connection_t *c) + } + + if (c->ssl->handshaked) { +- + if (u->ssl_verify) { + rc = SSL_get_verify_result(c->ssl->connection); + + if (rc != X509_V_OK) { +- lua_pushnil(L); +- err = lua_pushfstring(L, "%d: %s", (int) rc, +- X509_verify_cert_error_string(rc)); ++ u->error_ret = X509_verify_cert_error_string(rc); ++ u->openssl_error_code_ret = rc; + + llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); + if (llcf->log_socket_errors) { +- ngx_log_error(NGX_LOG_ERR, dc->log, 0, "lua ssl " +- "certificate verify error: (%s)", err); ++ ngx_log_error(NGX_LOG_ERR, dc->log, 0, "lua tls " ++ "certificate verify error: (%d: %s)", ++ rc, u->error_ret); + } + + goto failed; +@@ -1881,12 +1880,11 @@ ngx_http_lua_ssl_handshake_handler(ngx_connection_t *c) + if (u->ssl_name.len + && ngx_ssl_check_host(c, &u->ssl_name) != NGX_OK) + { +- lua_pushnil(L); +- lua_pushliteral(L, "certificate host mismatch"); ++ u->error_ret = "certificate host mismatch"; + + llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); + if (llcf->log_socket_errors) { +- ngx_log_error(NGX_LOG_ERR, dc->log, 0, "lua ssl " ++ ngx_log_error(NGX_LOG_ERR, dc->log, 0, "lua tls " + "certificate does not match host \"%V\"", + &u->ssl_name); + } +@@ -1901,7 +1899,7 @@ ngx_http_lua_ssl_handshake_handler(ngx_connection_t *c) + ngx_http_lua_socket_handle_conn_success(r, u); + + } else { +- (void) ngx_http_lua_ssl_handshake_retval_handler(r, u, L); ++ (void) ngx_http_lua_tls_handshake_retval_handler(r, u, NULL); + } + + if (waiting) { +@@ -1911,60 +1909,83 @@ ngx_http_lua_ssl_handshake_handler(ngx_connection_t *c) + return; + } + +- lua_pushnil(L); +- lua_pushliteral(L, "handshake failed"); ++ u->error_ret = "handshake failed"; + + failed: + + if (waiting) { + u->write_prepare_retvals = +- ngx_http_lua_socket_conn_error_retval_handler; +- ngx_http_lua_socket_handle_conn_error(r, u, +- NGX_HTTP_LUA_SOCKET_FT_SSL); ++ ngx_http_lua_socket_conn_error_retval_handler; ++ ngx_http_lua_socket_handle_conn_error(r, u, NGX_HTTP_LUA_SOCKET_FT_SSL); + ngx_http_run_posted_requests(dc); + + } else { +- (void) ngx_http_lua_socket_conn_error_retval_handler(r, u, L); ++ u->ft_type |= NGX_HTTP_LUA_SOCKET_FT_SSL; ++ ++ (void) ngx_http_lua_socket_conn_error_retval_handler(r, u, NULL); ++ } ++} ++ ++ ++int ++ngx_http_lua_ffi_socket_tcp_get_tlshandshake_result(ngx_http_request_t *r, ++ ngx_http_lua_socket_tcp_upstream_t *u, ngx_ssl_session_t **sess, ++ const char **errmsg, int *openssl_error_code) ++{ ++ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, ++ "lua cosocket get TLS handshake result for upstream: %p", u); ++ ++ if (u->error_ret != NULL) { ++ *errmsg = u->error_ret; ++ *openssl_error_code = u->openssl_error_code_ret; ++ ++ return NGX_ERROR; + } ++ ++ *sess = u->ssl_session_ret; ++ ++ return NGX_OK; + } + + + static int +-ngx_http_lua_ssl_handshake_retval_handler(ngx_http_request_t *r, ++ngx_http_lua_tls_handshake_retval_handler(ngx_http_request_t *r, + ngx_http_lua_socket_tcp_upstream_t *u, lua_State *L) + { + ngx_connection_t *c; +- ngx_ssl_session_t *ssl_session, **ud; ++ ngx_ssl_session_t *ssl_session; + + if (!u->ssl_session_reuse) { +- lua_pushboolean(L, 1); +- return 1; ++ return 0; + } + +- ud = lua_newuserdata(L, sizeof(ngx_ssl_session_t *)); +- + c = u->peer.connection; + + ssl_session = ngx_ssl_get_session(c); + if (ssl_session == NULL) { +- *ud = NULL; ++ u->ssl_session_ret = NULL; + + } else { +- *ud = ssl_session; ++ u->ssl_session_ret = ssl_session; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, +- "lua ssl save session: %p", ssl_session); +- +- /* set up the __gc metamethod */ +- lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( +- ssl_session_metatable_key)); +- lua_rawget(L, LUA_REGISTRYINDEX); +- lua_setmetatable(L, -2); ++ "lua tls save session: %p", ssl_session); + } + +- return 1; ++ return 0; ++} ++ ++ ++void ++ngx_http_lua_ffi_tls_free_session(ngx_ssl_session_t *sess) ++{ ++ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, ++ "lua tls free session: %p", sess); ++ ++ ngx_ssl_free_session(sess); + } + ++ + #endif /* NGX_HTTP_SSL */ + + +@@ -2017,12 +2038,14 @@ ngx_http_lua_socket_prepare_error_retvals(ngx_http_request_t *r, + u_char errstr[NGX_MAX_ERROR_STR]; + u_char *p; + +- if (ft_type & (NGX_HTTP_LUA_SOCKET_FT_RESOLVER +- | NGX_HTTP_LUA_SOCKET_FT_SSL)) +- { ++ if (ft_type & NGX_HTTP_LUA_SOCKET_FT_RESOLVER) { + return 2; + } + ++ if (ft_type & NGX_HTTP_LUA_SOCKET_FT_SSL) { ++ return 0; ++ } ++ + lua_pushnil(L); + + if (ft_type & NGX_HTTP_LUA_SOCKET_FT_TIMEOUT) { +@@ -6112,27 +6135,6 @@ ngx_http_lua_coctx_cleanup(void *data) + } + + +-#if (NGX_HTTP_SSL) +- +-static int +-ngx_http_lua_ssl_free_session(lua_State *L) +-{ +- ngx_ssl_session_t **psession; +- +- psession = lua_touserdata(L, 1); +- if (psession && *psession != NULL) { +- ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, +- "lua ssl free session: %p", *psession); +- +- ngx_ssl_free_session(*psession); +- } +- +- return 0; +-} +- +-#endif /* NGX_HTTP_SSL */ +- +- + void + ngx_http_lua_cleanup_conn_pools(lua_State *L) + { +diff --git src/ngx_http_lua_socket_tcp.h src/ngx_http_lua_socket_tcp.h +index a0a5a51..ee9411b 100644 +--- src/ngx_http_lua_socket_tcp.h ++++ src/ngx_http_lua_socket_tcp.h +@@ -120,6 +120,9 @@ struct ngx_http_lua_socket_tcp_upstream_s { + + #if (NGX_HTTP_SSL) + ngx_str_t ssl_name; ++ ngx_ssl_session_t *ssl_session_ret; ++ const char *error_ret; ++ int openssl_error_code_ret; + #endif + + unsigned ft_type:16; diff --git a/patch/1.21.4.1/ngx_stream_lua-expose_request_struct.patch b/patch/1.21.4.1/ngx_stream_lua-expose_request_struct.patch new file mode 100644 index 0000000..4e5848f --- /dev/null +++ b/patch/1.21.4.1/ngx_stream_lua-expose_request_struct.patch @@ -0,0 +1,15 @@ +diff --git src/api/ngx_stream_lua_api.h src/api/ngx_stream_lua_api.h +index 92f933d..812e0c4 100644 +--- src/api/ngx_stream_lua_api.h ++++ src/api/ngx_stream_lua_api.h +@@ -20,6 +20,10 @@ + #include + + ++#if (NGX_STREAM_APISIX) ++#include ++#include "../ngx_stream_lua_request.h" ++#endif + + + #include diff --git a/patch/1.21.4.1/ngx_stream_lua-reject-in-handshake.patch b/patch/1.21.4.1/ngx_stream_lua-reject-in-handshake.patch new file mode 100644 index 0000000..fee271e --- /dev/null +++ b/patch/1.21.4.1/ngx_stream_lua-reject-in-handshake.patch @@ -0,0 +1,40 @@ +diff --git src/ngx_stream_lua_ssl_certby.c src/ngx_stream_lua_ssl_certby.c +index bc1b156..49fa0d3 100644 +--- src/ngx_stream_lua_ssl_certby.c ++++ src/ngx_stream_lua_ssl_certby.c +@@ -1365,9 +1365,16 @@ ngx_stream_lua_ssl_verify_callback(int ok, X509_STORE_CTX *x509_store) + } + + ++static int ++ngx_stream_lua_ssl_verify_reject_in_handshake_callback(int ok, X509_STORE_CTX *x509_store) ++{ ++ return ok; ++} ++ ++ + int + ngx_stream_lua_ffi_ssl_verify_client(ngx_stream_lua_request_t *r, +- void *ca_certs, int depth, char **err) ++ void *ca_certs, int depth, int reject_in_handshake, char **err) + { + ngx_stream_lua_ctx_t *ctx; + ngx_ssl_conn_t *ssl_conn; +@@ -1407,8 +1414,15 @@ ngx_stream_lua_ffi_ssl_verify_client(ngx_stream_lua_request_t *r, + + /* enable verify */ + +- SSL_set_verify(ssl_conn, SSL_VERIFY_PEER, +- ngx_stream_lua_ssl_verify_callback); ++ if (reject_in_handshake) { ++ SSL_set_verify(ssl_conn, ++ SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT , ++ ngx_stream_lua_ssl_verify_reject_in_handshake_callback); ++ ++ } else { ++ SSL_set_verify(ssl_conn, SSL_VERIFY_PEER, ++ ngx_stream_lua_ssl_verify_callback); ++ } + + /* set depth */ + diff --git a/patch/1.21.4.1/ngx_stream_lua-shared_shdict.patch b/patch/1.21.4.1/ngx_stream_lua-shared_shdict.patch new file mode 100644 index 0000000..bbb0f50 --- /dev/null +++ b/patch/1.21.4.1/ngx_stream_lua-shared_shdict.patch @@ -0,0 +1,2790 @@ +diff --git config config +index 07240ea..536b66b 100644 +--- config ++++ config +@@ -260,7 +260,6 @@ STREAM_LUA_SRCS=" \ + $ngx_addon_dir/src/ngx_stream_lua_ctx.c \ + $ngx_addon_dir/src/ngx_stream_lua_regex.c \ + $ngx_addon_dir/src/ngx_stream_lua_script.c \ +- $ngx_addon_dir/src/ngx_stream_lua_shdict.c \ + $ngx_addon_dir/src/ngx_stream_lua_variable.c \ + $ngx_addon_dir/src/ngx_stream_lua_timer.c \ + $ngx_addon_dir/src/ngx_stream_lua_config.c \ +@@ -304,7 +303,6 @@ STREAM_LUA_DEPS=" \ + $ngx_addon_dir/src/ngx_stream_lua_phase.h \ + $ngx_addon_dir/src/ngx_stream_lua_ctx.h \ + $ngx_addon_dir/src/ngx_stream_lua_script.h \ +- $ngx_addon_dir/src/ngx_stream_lua_shdict.h \ + $ngx_addon_dir/src/ngx_stream_lua_timer.h \ + $ngx_addon_dir/src/ngx_stream_lua_config.h \ + $ngx_addon_dir/src/api/ngx_stream_lua_api.h \ +diff --git src/api/ngx_stream_lua_api.h src/api/ngx_stream_lua_api.h +index 92f933d..e722580 100644 +--- src/api/ngx_stream_lua_api.h ++++ src/api/ngx_stream_lua_api.h +@@ -57,15 +57,6 @@ lua_State *ngx_stream_lua_get_global_state(ngx_conf_t *cf); + ngx_int_t ngx_stream_lua_add_package_preload(ngx_conf_t *cf, + const char *package, lua_CFunction func); + +-ngx_int_t ngx_stream_lua_shared_dict_get(ngx_shm_zone_t *shm_zone, +- u_char *key_data, size_t key_len, ngx_stream_lua_value_t *value); +- +-ngx_shm_zone_t *ngx_stream_lua_find_zone(u_char *name_data, +- size_t name_len); +- +-ngx_shm_zone_t *ngx_stream_lua_shared_memory_add(ngx_conf_t *cf, +- ngx_str_t *name, size_t size, void *tag); +- + + #endif /* _NGX_STREAM_LUA_API_H_INCLUDED_ */ + +diff --git src/ngx_stream_lua_api.c src/ngx_stream_lua_api.c +index cf01b36..fcc685c 100644 +--- src/ngx_stream_lua_api.c ++++ src/ngx_stream_lua_api.c +@@ -20,7 +20,6 @@ + + #include "ngx_stream_lua_common.h" + #include "api/ngx_stream_lua_api.h" +-#include "ngx_stream_lua_shdict.h" + #include "ngx_stream_lua_util.h" + + +@@ -35,12 +34,6 @@ ngx_stream_lua_get_global_state(ngx_conf_t *cf) + } + + +- +- +-static ngx_int_t ngx_stream_lua_shared_memory_init(ngx_shm_zone_t *shm_zone, +- void *data); +- +- + ngx_int_t + ngx_stream_lua_add_package_preload(ngx_conf_t *cf, const char *package, + lua_CFunction func) +@@ -86,136 +79,4 @@ ngx_stream_lua_add_package_preload(ngx_conf_t *cf, const char *package, + return NGX_OK; + } + +- +-ngx_shm_zone_t * +-ngx_stream_lua_shared_memory_add(ngx_conf_t *cf, ngx_str_t *name, +- size_t size, void *tag) +-{ +- ngx_stream_lua_main_conf_t *lmcf; +- ngx_stream_lua_shm_zone_ctx_t *ctx; +- +- ngx_shm_zone_t **zp; +- ngx_shm_zone_t *zone; +- ngx_int_t n; +- +- lmcf = ngx_stream_conf_get_module_main_conf(cf, ngx_stream_lua_module); +- if (lmcf == NULL) { +- return NULL; +- } +- +- if (lmcf->shm_zones == NULL) { +- lmcf->shm_zones = ngx_palloc(cf->pool, sizeof(ngx_array_t)); +- if (lmcf->shm_zones == NULL) { +- return NULL; +- } +- +- if (ngx_array_init(lmcf->shm_zones, cf->pool, 2, +- sizeof(ngx_shm_zone_t *)) +- != NGX_OK) +- { +- return NULL; +- } +- } +- +- zone = ngx_shared_memory_add(cf, name, (size_t) size, tag); +- if (zone == NULL) { +- return NULL; +- } +- +- if (zone->data) { +- ctx = (ngx_stream_lua_shm_zone_ctx_t *) zone->data; +- return &ctx->zone; +- } +- +- n = sizeof(ngx_stream_lua_shm_zone_ctx_t); +- +- ctx = ngx_pcalloc(cf->pool, n); +- if (ctx == NULL) { +- return NULL; +- } +- +- ctx->lmcf = lmcf; +- ctx->log = &cf->cycle->new_log; +- ctx->cycle = cf->cycle; +- +- ngx_memcpy(&ctx->zone, zone, sizeof(ngx_shm_zone_t)); +- +- zp = ngx_array_push(lmcf->shm_zones); +- if (zp == NULL) { +- return NULL; +- } +- +- *zp = zone; +- +- /* set zone init */ +- zone->init = ngx_stream_lua_shared_memory_init; +- zone->data = ctx; +- +- lmcf->requires_shm = 1; +- +- return &ctx->zone; +-} +- +- +-static ngx_int_t +-ngx_stream_lua_shared_memory_init(ngx_shm_zone_t *shm_zone, void *data) +-{ +- ngx_stream_lua_shm_zone_ctx_t *octx = data; +- ngx_stream_lua_main_conf_t *lmcf; +- ngx_stream_lua_shm_zone_ctx_t *ctx; +- +- ngx_shm_zone_t *ozone; +- void *odata; +- ngx_int_t rc; +- volatile ngx_cycle_t *saved_cycle; +- ngx_shm_zone_t *zone; +- +- ctx = (ngx_stream_lua_shm_zone_ctx_t *) shm_zone->data; +- zone = &ctx->zone; +- +- odata = NULL; +- if (octx) { +- ozone = &octx->zone; +- odata = ozone->data; +- } +- +- zone->shm = shm_zone->shm; +-#if defined(nginx_version) && nginx_version >= 1009000 +- zone->noreuse = shm_zone->noreuse; +-#endif +- +- if (zone->init(zone, odata) != NGX_OK) { +- return NGX_ERROR; +- } +- +- dd("get lmcf"); +- +- lmcf = ctx->lmcf; +- if (lmcf == NULL) { +- return NGX_ERROR; +- } +- +- dd("lmcf->lua: %p", lmcf->lua); +- +- lmcf->shm_zones_inited++; +- +- if (lmcf->shm_zones_inited == lmcf->shm_zones->nelts +- && lmcf->init_handler && !ngx_test_config) +- { +- saved_cycle = ngx_cycle; +- ngx_cycle = ctx->cycle; +- +- rc = lmcf->init_handler(ctx->log, lmcf, lmcf->lua); +- +- ngx_cycle = saved_cycle; +- +- if (rc != NGX_OK) { +- /* an error happened */ +- return NGX_ERROR; +- } +- } +- +- return NGX_OK; +-} +- + /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ +diff --git src/ngx_stream_lua_common.h src/ngx_stream_lua_common.h +index 0aa0a5e..28ef2d1 100644 +--- src/ngx_stream_lua_common.h ++++ src/ngx_stream_lua_common.h +@@ -31,6 +31,8 @@ + #include + #include + ++#include "ngx_meta_lua_api.h" ++ + + #include "ngx_stream_lua_request.h" + +@@ -53,6 +55,11 @@ + #endif + + ++#if !defined(ngx_meta_lua_version) || ngx_meta_lua_version < 00001 ++# error ngx_meta_lua_module 0.0.1 or above is required ++#endif ++ ++ + + + #if LUA_VERSION_NUM != 501 +@@ -158,8 +165,6 @@ typedef struct ngx_stream_lua_balancer_peer_data_s + typedef struct ngx_stream_lua_sema_mm_s ngx_stream_lua_sema_mm_t; + + +-typedef ngx_int_t (*ngx_stream_lua_main_conf_handler_pt)(ngx_log_t *log, +- ngx_stream_lua_main_conf_t *lmcf, lua_State *L); + typedef ngx_int_t (*ngx_stream_lua_srv_conf_handler_pt)( + ngx_stream_lua_request_t *r, ngx_stream_lua_srv_conf_t *lscf, lua_State *L); + +@@ -207,10 +212,10 @@ struct ngx_stream_lua_main_conf_s { + + ngx_flag_t postponed_to_preread_phase_end; + +- ngx_stream_lua_main_conf_handler_pt init_handler; ++ ngx_meta_lua_main_conf_handler_pt init_handler; + ngx_str_t init_src; + +- ngx_stream_lua_main_conf_handler_pt init_worker_handler; ++ ngx_meta_lua_main_conf_handler_pt init_worker_handler; + ngx_str_t init_worker_src; + + ngx_stream_lua_balancer_peer_data_t *balancer_peer_data; +@@ -220,8 +225,6 @@ struct ngx_stream_lua_main_conf_s { + * data pointer in the main conf. + */ + +- ngx_uint_t shm_zones_inited; +- + ngx_stream_lua_sema_mm_t *sema_mm; + + ngx_uint_t malloc_trim_cycle; /* a cycle is defined as the number +@@ -234,7 +237,6 @@ struct ngx_stream_lua_main_conf_s { + unsigned requires_preread:1; + + unsigned requires_log:1; +- unsigned requires_shm:1; + unsigned requires_capture_log:1; + }; + +diff --git src/ngx_stream_lua_directive.c src/ngx_stream_lua_directive.c +index 5580106..04fed32 100644 +--- src/ngx_stream_lua_directive.c ++++ src/ngx_stream_lua_directive.c +@@ -27,7 +27,6 @@ + #include "ngx_stream_lua_logby.h" + #include "ngx_stream_lua_initby.h" + #include "ngx_stream_lua_initworkerby.h" +-#include "ngx_stream_lua_shdict.h" + #include "ngx_stream_lua_lex.h" + #include "ngx_stream_lua_log.h" + #include "ngx_stream_lua_log_ringbuf.h" +@@ -69,90 +68,6 @@ enum { + }; + + +-char * +-ngx_stream_lua_shared_dict(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +-{ +- ngx_stream_lua_main_conf_t *lmcf = conf; +- ngx_str_t *value, name; +- ngx_shm_zone_t *zone; +- ngx_shm_zone_t **zp; +- ngx_stream_lua_shdict_ctx_t *ctx; +- ssize_t size; +- +- if (lmcf->shdict_zones == NULL) { +- lmcf->shdict_zones = ngx_palloc(cf->pool, sizeof(ngx_array_t)); +- if (lmcf->shdict_zones == NULL) { +- return NGX_CONF_ERROR; +- } +- +- if (ngx_array_init(lmcf->shdict_zones, cf->pool, 2, +- sizeof(ngx_shm_zone_t *)) +- != NGX_OK) +- { +- return NGX_CONF_ERROR; +- } +- } +- +- value = cf->args->elts; +- +- ctx = NULL; +- +- if (value[1].len == 0) { +- ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, +- "invalid lua shared dict name \"%V\"", &value[1]); +- return NGX_CONF_ERROR; +- } +- +- name = value[1]; +- +- size = ngx_parse_size(&value[2]); +- +- if (size <= 8191) { +- ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, +- "invalid lua shared dict size \"%V\"", &value[2]); +- return NGX_CONF_ERROR; +- } +- +- ctx = ngx_pcalloc(cf->pool, sizeof(ngx_stream_lua_shdict_ctx_t)); +- if (ctx == NULL) { +- return NGX_CONF_ERROR; +- } +- +- ctx->name = name; +- ctx->main_conf = lmcf; +- ctx->log = &cf->cycle->new_log; +- +- zone = ngx_stream_lua_shared_memory_add(cf, &name, (size_t) size, +- &ngx_stream_lua_module); +- if (zone == NULL) { +- return NGX_CONF_ERROR; +- } +- +- if (zone->data) { +- ctx = zone->data; +- +- ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, +- "lua_shared_dict \"%V\" is already defined as " +- "\"%V\"", &name, &ctx->name); +- return NGX_CONF_ERROR; +- } +- +- zone->init = ngx_stream_lua_shdict_init_zone; +- zone->data = ctx; +- +- zp = ngx_array_push(lmcf->shdict_zones); +- if (zp == NULL) { +- return NGX_CONF_ERROR; +- } +- +- *zp = zone; +- +- lmcf->requires_shm = 1; +- +- return NGX_CONF_OK; +-} +- +- + char * + ngx_stream_lua_code_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) + { +@@ -190,6 +105,15 @@ ngx_stream_lua_load_resty_core(ngx_conf_t *cf, ngx_command_t *cmd, + } + + ++char * ++ngx_stream_lua_shdict_directive(ngx_conf_t *cf, ngx_command_t *cmd, ++ void *conf) ++{ ++ return ngx_meta_lua_shdict_directive_helper(cf, ++ &ngx_stream_lua_module); ++} ++ ++ + char * + ngx_stream_lua_package_cpath(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) + { +@@ -646,7 +570,7 @@ ngx_stream_lua_init_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, + return NGX_CONF_ERROR; + } + +- lmcf->init_handler = (ngx_stream_lua_main_conf_handler_pt) cmd->post; ++ lmcf->init_handler = (ngx_meta_lua_main_conf_handler_pt) cmd->post; + + if (cmd->post == ngx_stream_lua_init_by_file) { + name = ngx_stream_lua_rebase_path(cf->pool, value[1].data, +@@ -707,7 +631,7 @@ ngx_stream_lua_init_worker_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, + + value = cf->args->elts; + +- lmcf->init_worker_handler = (ngx_stream_lua_main_conf_handler_pt) cmd->post; ++ lmcf->init_worker_handler = (ngx_meta_lua_main_conf_handler_pt) cmd->post; + + if (cmd->post == ngx_stream_lua_init_worker_by_file) { + name = ngx_stream_lua_rebase_path(cf->pool, value[1].data, +diff --git src/ngx_stream_lua_directive.h src/ngx_stream_lua_directive.h +index 6b36bb1..fa469b6 100644 +--- src/ngx_stream_lua_directive.h ++++ src/ngx_stream_lua_directive.h +@@ -20,7 +20,7 @@ + #include "ngx_stream_lua_common.h" + + +-char *ngx_stream_lua_shared_dict(ngx_conf_t *cf, ngx_command_t *cmd, ++char *ngx_stream_lua_shdict_directive(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); + char *ngx_stream_lua_package_cpath(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +diff --git src/ngx_stream_lua_initby.c src/ngx_stream_lua_initby.c +index c6bbf0d..98e3c6f 100644 +--- src/ngx_stream_lua_initby.c ++++ src/ngx_stream_lua_initby.c +@@ -22,13 +22,13 @@ + + + ngx_int_t +-ngx_stream_lua_init_by_inline(ngx_log_t *log, ngx_stream_lua_main_conf_t *lmcf, ++ngx_stream_lua_init_by_inline(ngx_log_t *log, ngx_str_t init_src, + lua_State *L) + { + int status; + +- status = luaL_loadbuffer(L, (char *) lmcf->init_src.data, +- lmcf->init_src.len, "=init_by_lua") ++ status = luaL_loadbuffer(L, (char *) init_src.data, init_src.len, ++ "=init_by_lua") + || ngx_stream_lua_do_call(log, L); + + return ngx_stream_lua_report(log, L, status, "init_by_lua"); +@@ -36,12 +36,12 @@ ngx_stream_lua_init_by_inline(ngx_log_t *log, ngx_stream_lua_main_conf_t *lmcf, + + + ngx_int_t +-ngx_stream_lua_init_by_file(ngx_log_t *log, ngx_stream_lua_main_conf_t *lmcf, ++ngx_stream_lua_init_by_file(ngx_log_t *log, ngx_str_t init_src, + lua_State *L) + { + int status; + +- status = luaL_loadfile(L, (char *) lmcf->init_src.data) ++ status = luaL_loadfile(L, (char *) init_src.data) + || ngx_stream_lua_do_call(log, L); + + return ngx_stream_lua_report(log, L, status, "init_by_lua_file"); +diff --git src/ngx_stream_lua_initby.h src/ngx_stream_lua_initby.h +index f2e2c40..060ee41 100644 +--- src/ngx_stream_lua_initby.h ++++ src/ngx_stream_lua_initby.h +@@ -20,10 +20,10 @@ + + + ngx_int_t ngx_stream_lua_init_by_inline(ngx_log_t *log, +- ngx_stream_lua_main_conf_t *lmcf, lua_State *L); ++ ngx_str_t init_src, lua_State *L); + + ngx_int_t ngx_stream_lua_init_by_file(ngx_log_t *log, +- ngx_stream_lua_main_conf_t *lmcf, lua_State *L); ++ ngx_str_t init_src, lua_State *L); + + + #endif /* _NGX_STREAM_LUA_INITBY_H_INCLUDED_ */ +diff --git src/ngx_stream_lua_initworkerby.c src/ngx_stream_lua_initworkerby.c +index 0c329a5..151cf19 100644 +--- src/ngx_stream_lua_initworkerby.c ++++ src/ngx_stream_lua_initworkerby.c +@@ -297,7 +297,8 @@ ngx_stream_lua_init_worker(ngx_cycle_t *cycle) + + ngx_stream_lua_set_req(lmcf->lua, r); + +- (void) lmcf->init_worker_handler(cycle->log, lmcf, lmcf->lua); ++ (void) lmcf->init_worker_handler(cycle->log, lmcf->init_worker_src, ++ lmcf->lua); + + ngx_destroy_pool(c->pool); + return NGX_OK; +@@ -318,12 +319,12 @@ failed: + + ngx_int_t + ngx_stream_lua_init_worker_by_inline(ngx_log_t *log, +- ngx_stream_lua_main_conf_t *lmcf, lua_State *L) ++ ngx_str_t init_worker_src, lua_State *L) + { + int status; + +- status = luaL_loadbuffer(L, (char *) lmcf->init_worker_src.data, +- lmcf->init_worker_src.len, "=init_worker_by_lua") ++ status = luaL_loadbuffer(L, (char *) init_worker_src.data, ++ init_worker_src.len, "=init_worker_by_lua") + || ngx_stream_lua_do_call(log, L); + + return ngx_stream_lua_report(log, L, status, "init_worker_by_lua"); +@@ -332,11 +333,11 @@ ngx_stream_lua_init_worker_by_inline(ngx_log_t *log, + + ngx_int_t + ngx_stream_lua_init_worker_by_file(ngx_log_t *log, +- ngx_stream_lua_main_conf_t *lmcf, lua_State *L) ++ ngx_str_t init_worker_src, lua_State *L) + { + int status; + +- status = luaL_loadfile(L, (char *) lmcf->init_worker_src.data) ++ status = luaL_loadfile(L, (char *) init_worker_src.data) + || ngx_stream_lua_do_call(log, L); + + return ngx_stream_lua_report(log, L, status, "init_worker_by_lua_file"); +diff --git src/ngx_stream_lua_initworkerby.h src/ngx_stream_lua_initworkerby.h +index 43f6de3..53a443a 100644 +--- src/ngx_stream_lua_initworkerby.h ++++ src/ngx_stream_lua_initworkerby.h +@@ -20,10 +20,10 @@ + + + ngx_int_t ngx_stream_lua_init_worker_by_inline(ngx_log_t *log, +- ngx_stream_lua_main_conf_t *lmcf, lua_State *L); ++ ngx_str_t init_worker_src, lua_State *L); + + ngx_int_t ngx_stream_lua_init_worker_by_file(ngx_log_t *log, +- ngx_stream_lua_main_conf_t *lmcf, lua_State *L); ++ ngx_str_t init_worker_src, lua_State *L); + + ngx_int_t ngx_stream_lua_init_worker(ngx_cycle_t *cycle); + +diff --git src/ngx_stream_lua_module.c src/ngx_stream_lua_module.c +index 6034add..45e3b89 100644 +--- src/ngx_stream_lua_module.c ++++ src/ngx_stream_lua_module.c +@@ -19,6 +19,7 @@ + #include "ddebug.h" + + ++#include "ngx_meta_lua_api.h" + #include "ngx_stream_lua_directive.h" + #include "ngx_stream_lua_contentby.h" + #include "ngx_stream_lua_util.h" +@@ -103,7 +104,7 @@ static ngx_command_t ngx_stream_lua_cmds[] = { + + { ngx_string("lua_shared_dict"), + NGX_STREAM_MAIN_CONF|NGX_CONF_TAKE2, +- ngx_stream_lua_shared_dict, ++ ngx_stream_lua_shdict_directive, + 0, + 0, + NULL }, +@@ -465,7 +466,6 @@ static ngx_int_t + ngx_stream_lua_init(ngx_conf_t *cf) + { + ngx_int_t rc; +- volatile ngx_cycle_t *saved_cycle; + ngx_array_t *arr; + ngx_pool_cleanup_t *cln; + +@@ -577,18 +577,11 @@ ngx_stream_lua_init(ngx_conf_t *cf) + + ngx_stream_lua_assert(lmcf->lua != NULL); + +- if (!lmcf->requires_shm && lmcf->init_handler) { +- saved_cycle = ngx_cycle; +- ngx_cycle = cf->cycle; +- +- rc = lmcf->init_handler(cf->log, lmcf, lmcf->lua); +- +- ngx_cycle = saved_cycle; +- +- if (rc != NGX_OK) { +- /* an error happened */ +- return NGX_ERROR; +- } ++ if (ngx_meta_lua_post_init_handler(cf, lmcf->init_handler, ++ lmcf->init_src, lmcf->lua) ++ != NGX_OK) ++ { ++ return NGX_ERROR; + } + + dd("Lua VM initialized!"); +@@ -648,11 +641,8 @@ ngx_stream_lua_create_main_conf(ngx_conf_t *cf) + * lmcf->watcher = NULL; + * lmcf->regex_cache_entries = 0; + * lmcf->jit_stack = NULL; +- * lmcf->shm_zones = NULL; + * lmcf->init_handler = NULL; + * lmcf->init_src = { 0, NULL }; +- * lmcf->shm_zones_inited = 0; +- * lmcf->shdict_zones = NULL; + * lmcf->preload_hooks = NULL; + * lmcf->requires_header_filter = 0; + * lmcf->requires_body_filter = 0; +@@ -660,7 +650,6 @@ ngx_stream_lua_create_main_conf(ngx_conf_t *cf) + * lmcf->requires_rewrite = 0; + * lmcf->requires_access = 0; + * lmcf->requires_log = 0; +- * lmcf->requires_shm = 0; + */ + + lmcf->pool = cf->pool; +diff --git src/ngx_stream_lua_shdict.c src/ngx_stream_lua_shdict.c +deleted file mode 100644 +index 6b137f5..0000000 +--- src/ngx_stream_lua_shdict.c ++++ /dev/null +@@ -1,2030 +0,0 @@ +- +-/* +- * !!! DO NOT EDIT DIRECTLY !!! +- * This file was automatically generated from the following template: +- * +- * src/subsys/ngx_subsys_lua_shdict.c.tt2 +- */ +- +- +-/* +- * Copyright (C) Yichun Zhang (agentzh) +- */ +- +- +-#ifndef DDEBUG +-#define DDEBUG 0 +-#endif +-#include "ddebug.h" +- +- +-#include "ngx_stream_lua_shdict.h" +-#include "ngx_stream_lua_util.h" +-#include "ngx_stream_lua_api.h" +- +- +-static int ngx_stream_lua_shdict_expire(ngx_stream_lua_shdict_ctx_t *ctx, +- ngx_uint_t n); +-static ngx_int_t ngx_stream_lua_shdict_lookup(ngx_shm_zone_t *shm_zone, +- ngx_uint_t hash, u_char *kdata, size_t klen, +- ngx_stream_lua_shdict_node_t **sdp); +-static int ngx_stream_lua_shdict_flush_expired(lua_State *L); +-static int ngx_stream_lua_shdict_get_keys(lua_State *L); +-static int ngx_stream_lua_shdict_lpush(lua_State *L); +-static int ngx_stream_lua_shdict_rpush(lua_State *L); +-static int ngx_stream_lua_shdict_push_helper(lua_State *L, int flags); +-static int ngx_stream_lua_shdict_lpop(lua_State *L); +-static int ngx_stream_lua_shdict_rpop(lua_State *L); +-static int ngx_stream_lua_shdict_pop_helper(lua_State *L, int flags); +-static int ngx_stream_lua_shdict_llen(lua_State *L); +- +- +-static ngx_inline ngx_shm_zone_t *ngx_stream_lua_shdict_get_zone(lua_State *L, +- int index); +- +- +-#define NGX_STREAM_LUA_SHDICT_ADD 0x0001 +-#define NGX_STREAM_LUA_SHDICT_REPLACE 0x0002 +-#define NGX_STREAM_LUA_SHDICT_SAFE_STORE 0x0004 +- +- +-#define NGX_STREAM_LUA_SHDICT_LEFT 0x0001 +-#define NGX_STREAM_LUA_SHDICT_RIGHT 0x0002 +- +- +-enum { +- SHDICT_USERDATA_INDEX = 1, +-}; +- +- +-enum { +- SHDICT_TNIL = 0, /* same as LUA_TNIL */ +- SHDICT_TBOOLEAN = 1, /* same as LUA_TBOOLEAN */ +- SHDICT_TNUMBER = 3, /* same as LUA_TNUMBER */ +- SHDICT_TSTRING = 4, /* same as LUA_TSTRING */ +- SHDICT_TLIST = 5, +-}; +- +- +-static ngx_inline ngx_queue_t * +-ngx_stream_lua_shdict_get_list_head(ngx_stream_lua_shdict_node_t *sd, +- size_t len) +-{ +- return (ngx_queue_t *) ngx_align_ptr(((u_char *) &sd->data + len), +- NGX_ALIGNMENT); +-} +- +- +-ngx_int_t +-ngx_stream_lua_shdict_init_zone(ngx_shm_zone_t *shm_zone, void *data) +-{ +- ngx_stream_lua_shdict_ctx_t *octx = data; +- ngx_stream_lua_shdict_ctx_t *ctx; +- +- size_t len; +- +- dd("init zone"); +- +- ctx = shm_zone->data; +- +- if (octx) { +- ctx->sh = octx->sh; +- ctx->shpool = octx->shpool; +- +- return NGX_OK; +- } +- +- ctx->shpool = (ngx_slab_pool_t *) shm_zone->shm.addr; +- +- if (shm_zone->shm.exists) { +- ctx->sh = ctx->shpool->data; +- +- return NGX_OK; +- } +- +- ctx->sh = ngx_slab_alloc(ctx->shpool, +- sizeof(ngx_stream_lua_shdict_shctx_t)); +- if (ctx->sh == NULL) { +- return NGX_ERROR; +- } +- +- ctx->shpool->data = ctx->sh; +- +- ngx_rbtree_init(&ctx->sh->rbtree, &ctx->sh->sentinel, +- ngx_stream_lua_shdict_rbtree_insert_value); +- +- ngx_queue_init(&ctx->sh->lru_queue); +- +- len = sizeof(" in lua_shared_dict zone \"\"") + shm_zone->shm.name.len; +- +- ctx->shpool->log_ctx = ngx_slab_alloc(ctx->shpool, len); +- if (ctx->shpool->log_ctx == NULL) { +- return NGX_ERROR; +- } +- +- ngx_sprintf(ctx->shpool->log_ctx, " in lua_shared_dict zone \"%V\"%Z", +- &shm_zone->shm.name); +- +- ctx->shpool->log_nomem = 0; +- +- return NGX_OK; +-} +- +- +-void +-ngx_stream_lua_shdict_rbtree_insert_value(ngx_rbtree_node_t *temp, +- ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel) +-{ +- ngx_rbtree_node_t **p; +- +- ngx_stream_lua_shdict_node_t *sdn, *sdnt; +- +- for ( ;; ) { +- +- if (node->key < temp->key) { +- +- p = &temp->left; +- +- } else if (node->key > temp->key) { +- +- p = &temp->right; +- +- } else { /* node->key == temp->key */ +- +- sdn = (ngx_stream_lua_shdict_node_t *) &node->color; +- sdnt = (ngx_stream_lua_shdict_node_t *) &temp->color; +- +- p = ngx_memn2cmp(sdn->data, sdnt->data, sdn->key_len, +- sdnt->key_len) < 0 ? &temp->left : &temp->right; +- } +- +- if (*p == sentinel) { +- break; +- } +- +- temp = *p; +- } +- +- *p = node; +- node->parent = temp; +- node->left = sentinel; +- node->right = sentinel; +- ngx_rbt_red(node); +-} +- +- +-static ngx_int_t +-ngx_stream_lua_shdict_lookup(ngx_shm_zone_t *shm_zone, ngx_uint_t hash, +- u_char *kdata, size_t klen, ngx_stream_lua_shdict_node_t **sdp) +-{ +- ngx_int_t rc; +- ngx_time_t *tp; +- uint64_t now; +- int64_t ms; +- ngx_rbtree_node_t *node, *sentinel; +- +- ngx_stream_lua_shdict_ctx_t *ctx; +- ngx_stream_lua_shdict_node_t *sd; +- +- ctx = shm_zone->data; +- +- node = ctx->sh->rbtree.root; +- sentinel = ctx->sh->rbtree.sentinel; +- +- while (node != sentinel) { +- +- if (hash < node->key) { +- node = node->left; +- continue; +- } +- +- if (hash > node->key) { +- node = node->right; +- continue; +- } +- +- /* hash == node->key */ +- +- sd = (ngx_stream_lua_shdict_node_t *) &node->color; +- +- rc = ngx_memn2cmp(kdata, sd->data, klen, (size_t) sd->key_len); +- +- if (rc == 0) { +- ngx_queue_remove(&sd->queue); +- ngx_queue_insert_head(&ctx->sh->lru_queue, &sd->queue); +- +- *sdp = sd; +- +- dd("node expires: %lld", (long long) sd->expires); +- +- if (sd->expires != 0) { +- tp = ngx_timeofday(); +- +- now = (uint64_t) tp->sec * 1000 + tp->msec; +- ms = sd->expires - now; +- +- dd("time to live: %lld", (long long) ms); +- +- if (ms < 0) { +- dd("node already expired"); +- return NGX_DONE; +- } +- } +- +- return NGX_OK; +- } +- +- node = (rc < 0) ? node->left : node->right; +- } +- +- *sdp = NULL; +- +- return NGX_DECLINED; +-} +- +- +-static int +-ngx_stream_lua_shdict_expire(ngx_stream_lua_shdict_ctx_t *ctx, ngx_uint_t n) +-{ +- ngx_time_t *tp; +- uint64_t now; +- ngx_queue_t *q, *list_queue, *lq; +- int64_t ms; +- ngx_rbtree_node_t *node; +- int freed = 0; +- +- ngx_stream_lua_shdict_node_t *sd; +- ngx_stream_lua_shdict_list_node_t *lnode; +- +- tp = ngx_timeofday(); +- +- now = (uint64_t) tp->sec * 1000 + tp->msec; +- +- /* +- * n == 1 deletes one or two expired entries +- * n == 0 deletes oldest entry by force +- * and one or two zero rate entries +- */ +- +- while (n < 3) { +- +- if (ngx_queue_empty(&ctx->sh->lru_queue)) { +- return freed; +- } +- +- q = ngx_queue_last(&ctx->sh->lru_queue); +- +- sd = ngx_queue_data(q, ngx_stream_lua_shdict_node_t, queue); +- +- if (n++ != 0) { +- +- if (sd->expires == 0) { +- return freed; +- } +- +- ms = sd->expires - now; +- if (ms > 0) { +- return freed; +- } +- } +- +- if (sd->value_type == SHDICT_TLIST) { +- list_queue = ngx_stream_lua_shdict_get_list_head(sd, +- sd->key_len); +- +- for (lq = ngx_queue_head(list_queue); +- lq != ngx_queue_sentinel(list_queue); +- lq = ngx_queue_next(lq)) +- { +- lnode = ngx_queue_data(lq, ngx_stream_lua_shdict_list_node_t, +- queue); +- +- ngx_slab_free_locked(ctx->shpool, lnode); +- } +- } +- +- ngx_queue_remove(q); +- +- node = (ngx_rbtree_node_t *) +- ((u_char *) sd - offsetof(ngx_rbtree_node_t, color)); +- +- ngx_rbtree_delete(&ctx->sh->rbtree, node); +- +- ngx_slab_free_locked(ctx->shpool, node); +- +- freed++; +- } +- +- return freed; +-} +- +- +-void +-ngx_stream_lua_inject_shdict_api(ngx_stream_lua_main_conf_t *lmcf, lua_State *L) +-{ +- ngx_stream_lua_shdict_ctx_t *ctx; +- +- ngx_uint_t i; +- ngx_shm_zone_t **zone; +- ngx_shm_zone_t **zone_udata; +- +- if (lmcf->shdict_zones != NULL) { +- lua_createtable(L, 0, lmcf->shdict_zones->nelts /* nrec */); +- /* ngx.shared */ +- +- lua_createtable(L, 0 /* narr */, 22 /* nrec */); /* shared mt */ +- +- lua_pushcfunction(L, ngx_stream_lua_shdict_lpush); +- lua_setfield(L, -2, "lpush"); +- +- lua_pushcfunction(L, ngx_stream_lua_shdict_rpush); +- lua_setfield(L, -2, "rpush"); +- +- lua_pushcfunction(L, ngx_stream_lua_shdict_lpop); +- lua_setfield(L, -2, "lpop"); +- +- lua_pushcfunction(L, ngx_stream_lua_shdict_rpop); +- lua_setfield(L, -2, "rpop"); +- +- lua_pushcfunction(L, ngx_stream_lua_shdict_llen); +- lua_setfield(L, -2, "llen"); +- +- lua_pushcfunction(L, ngx_stream_lua_shdict_flush_expired); +- lua_setfield(L, -2, "flush_expired"); +- +- lua_pushcfunction(L, ngx_stream_lua_shdict_get_keys); +- lua_setfield(L, -2, "get_keys"); +- +- lua_pushvalue(L, -1); /* shared mt mt */ +- lua_setfield(L, -2, "__index"); /* shared mt */ +- +- zone = lmcf->shdict_zones->elts; +- +- for (i = 0; i < lmcf->shdict_zones->nelts; i++) { +- ctx = zone[i]->data; +- +- lua_pushlstring(L, (char *) ctx->name.data, ctx->name.len); +- /* shared mt key */ +- +- lua_createtable(L, 1 /* narr */, 0 /* nrec */); +- /* table of zone[i] */ +- zone_udata = lua_newuserdata(L, sizeof(ngx_shm_zone_t *)); +- /* shared mt key ud */ +- *zone_udata = zone[i]; +- lua_rawseti(L, -2, SHDICT_USERDATA_INDEX); /* {zone[i]} */ +- lua_pushvalue(L, -3); /* shared mt key ud mt */ +- lua_setmetatable(L, -2); /* shared mt key ud */ +- lua_rawset(L, -4); /* shared mt */ +- } +- +- lua_pop(L, 1); /* shared */ +- +- } else { +- lua_newtable(L); /* ngx.shared */ +- } +- +- lua_setfield(L, -2, "shared"); +-} +- +- +-static ngx_inline ngx_shm_zone_t * +-ngx_stream_lua_shdict_get_zone(lua_State *L, int index) +-{ +- ngx_shm_zone_t *zone; +- ngx_shm_zone_t **zone_udata; +- +- lua_rawgeti(L, index, SHDICT_USERDATA_INDEX); +- zone_udata = lua_touserdata(L, -1); +- lua_pop(L, 1); +- +- if (zone_udata == NULL) { +- return NULL; +- } +- +- zone = *zone_udata; +- return zone; +-} +- +- +-static int +-ngx_stream_lua_shdict_flush_expired(lua_State *L) +-{ +- ngx_queue_t *q, *prev, *list_queue, *lq; +- ngx_shm_zone_t *zone; +- ngx_time_t *tp; +- int freed = 0; +- int attempts = 0; +- ngx_rbtree_node_t *node; +- uint64_t now; +- int n; +- +- ngx_stream_lua_shdict_node_t *sd; +- ngx_stream_lua_shdict_ctx_t *ctx; +- ngx_stream_lua_shdict_list_node_t *lnode; +- +- n = lua_gettop(L); +- +- if (n != 1 && n != 2) { +- return luaL_error(L, "expecting 1 or 2 argument(s), but saw %d", n); +- } +- +- luaL_checktype(L, 1, LUA_TTABLE); +- +- zone = ngx_stream_lua_shdict_get_zone(L, 1); +- if (zone == NULL) { +- return luaL_error(L, "bad user data for the ngx_shm_zone_t pointer"); +- } +- +- if (n == 2) { +- attempts = luaL_checkint(L, 2); +- } +- +- ctx = zone->data; +- +- ngx_shmtx_lock(&ctx->shpool->mutex); +- +- if (ngx_queue_empty(&ctx->sh->lru_queue)) { +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- lua_pushnumber(L, 0); +- return 1; +- } +- +- tp = ngx_timeofday(); +- +- now = (uint64_t) tp->sec * 1000 + tp->msec; +- +- q = ngx_queue_last(&ctx->sh->lru_queue); +- +- while (q != ngx_queue_sentinel(&ctx->sh->lru_queue)) { +- prev = ngx_queue_prev(q); +- +- sd = ngx_queue_data(q, ngx_stream_lua_shdict_node_t, queue); +- +- if (sd->expires != 0 && sd->expires <= now) { +- +- if (sd->value_type == SHDICT_TLIST) { +- list_queue = ngx_stream_lua_shdict_get_list_head(sd, +- sd->key_len); +- +- for (lq = ngx_queue_head(list_queue); +- lq != ngx_queue_sentinel(list_queue); +- lq = ngx_queue_next(lq)) +- { +- lnode = ngx_queue_data(lq, +- ngx_stream_lua_shdict_list_node_t, +- queue); +- +- ngx_slab_free_locked(ctx->shpool, lnode); +- } +- } +- +- ngx_queue_remove(q); +- +- node = (ngx_rbtree_node_t *) +- ((u_char *) sd - offsetof(ngx_rbtree_node_t, color)); +- +- ngx_rbtree_delete(&ctx->sh->rbtree, node); +- ngx_slab_free_locked(ctx->shpool, node); +- freed++; +- +- if (attempts && freed == attempts) { +- break; +- } +- } +- +- q = prev; +- } +- +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- lua_pushnumber(L, freed); +- return 1; +-} +- +- +-/* +- * This trades CPU for memory. This is potentially slow. O(2n) +- */ +- +-static int +-ngx_stream_lua_shdict_get_keys(lua_State *L) +-{ +- ngx_queue_t *q, *prev; +- ngx_shm_zone_t *zone; +- ngx_time_t *tp; +- int total = 0; +- int attempts = 1024; +- uint64_t now; +- int n; +- +- ngx_stream_lua_shdict_node_t *sd; +- ngx_stream_lua_shdict_ctx_t *ctx; +- +- n = lua_gettop(L); +- +- if (n != 1 && n != 2) { +- return luaL_error(L, "expecting 1 or 2 argument(s), " +- "but saw %d", n); +- } +- +- luaL_checktype(L, 1, LUA_TTABLE); +- +- zone = ngx_stream_lua_shdict_get_zone(L, 1); +- if (zone == NULL) { +- return luaL_error(L, "bad user data for the ngx_shm_zone_t pointer"); +- } +- +- if (n == 2) { +- attempts = luaL_checkint(L, 2); +- } +- +- ctx = zone->data; +- +- ngx_shmtx_lock(&ctx->shpool->mutex); +- +- if (ngx_queue_empty(&ctx->sh->lru_queue)) { +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- lua_createtable(L, 0, 0); +- return 1; +- } +- +- tp = ngx_timeofday(); +- +- now = (uint64_t) tp->sec * 1000 + tp->msec; +- +- /* first run through: get total number of elements we need to allocate */ +- +- q = ngx_queue_last(&ctx->sh->lru_queue); +- +- while (q != ngx_queue_sentinel(&ctx->sh->lru_queue)) { +- prev = ngx_queue_prev(q); +- +- sd = ngx_queue_data(q, ngx_stream_lua_shdict_node_t, queue); +- +- if (sd->expires == 0 || sd->expires > now) { +- total++; +- if (attempts && total == attempts) { +- break; +- } +- } +- +- q = prev; +- } +- +- lua_createtable(L, total, 0); +- +- /* second run through: add keys to table */ +- +- total = 0; +- q = ngx_queue_last(&ctx->sh->lru_queue); +- +- while (q != ngx_queue_sentinel(&ctx->sh->lru_queue)) { +- prev = ngx_queue_prev(q); +- +- sd = ngx_queue_data(q, ngx_stream_lua_shdict_node_t, queue); +- +- if (sd->expires == 0 || sd->expires > now) { +- lua_pushlstring(L, (char *) sd->data, sd->key_len); +- lua_rawseti(L, -2, ++total); +- if (attempts && total == attempts) { +- break; +- } +- } +- +- q = prev; +- } +- +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- /* table is at top of stack */ +- return 1; +-} +- +- +- +- +-static int +-ngx_stream_lua_shdict_lpush(lua_State *L) +-{ +- return ngx_stream_lua_shdict_push_helper(L, NGX_STREAM_LUA_SHDICT_LEFT); +-} +- +- +-static int +-ngx_stream_lua_shdict_rpush(lua_State *L) +-{ +- return ngx_stream_lua_shdict_push_helper(L, NGX_STREAM_LUA_SHDICT_RIGHT); +-} +- +- +-static int +-ngx_stream_lua_shdict_push_helper(lua_State *L, int flags) +-{ +- int n; +- ngx_str_t key; +- uint32_t hash; +- ngx_int_t rc; +- ngx_str_t value; +- int value_type; +- double num; +- ngx_rbtree_node_t *node; +- ngx_shm_zone_t *zone; +- ngx_queue_t *queue, *q; +- +- ngx_stream_lua_shdict_ctx_t *ctx; +- ngx_stream_lua_shdict_node_t *sd; +- ngx_stream_lua_shdict_list_node_t *lnode; +- +- n = lua_gettop(L); +- +- if (n != 3) { +- return luaL_error(L, "expecting 3 arguments, " +- "but only seen %d", n); +- } +- +- if (lua_type(L, 1) != LUA_TTABLE) { +- return luaL_error(L, "bad \"zone\" argument"); +- } +- +- zone = ngx_stream_lua_shdict_get_zone(L, 1); +- if (zone == NULL) { +- return luaL_error(L, "bad \"zone\" argument"); +- } +- +- ctx = zone->data; +- +- if (lua_isnil(L, 2)) { +- lua_pushnil(L); +- lua_pushliteral(L, "nil key"); +- return 2; +- } +- +- key.data = (u_char *) luaL_checklstring(L, 2, &key.len); +- +- if (key.len == 0) { +- lua_pushnil(L); +- lua_pushliteral(L, "empty key"); +- return 2; +- } +- +- if (key.len > 65535) { +- lua_pushnil(L); +- lua_pushliteral(L, "key too long"); +- return 2; +- } +- +- hash = ngx_crc32_short(key.data, key.len); +- +- value_type = lua_type(L, 3); +- +- switch (value_type) { +- +- case SHDICT_TSTRING: +- value.data = (u_char *) lua_tolstring(L, 3, &value.len); +- break; +- +- case SHDICT_TNUMBER: +- value.len = sizeof(double); +- num = lua_tonumber(L, 3); +- value.data = (u_char *) # +- break; +- +- default: +- lua_pushnil(L); +- lua_pushliteral(L, "bad value type"); +- return 2; +- } +- +- ngx_shmtx_lock(&ctx->shpool->mutex); +- +-#if 1 +- ngx_stream_lua_shdict_expire(ctx, 1); +-#endif +- +- rc = ngx_stream_lua_shdict_lookup(zone, hash, key.data, key.len, &sd); +- +- dd("shdict lookup returned %d", (int) rc); +- +- /* exists but expired */ +- +- if (rc == NGX_DONE) { +- +- if (sd->value_type != SHDICT_TLIST) { +- /* TODO: reuse when length matched */ +- +- ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ctx->log, 0, +- "lua shared dict push: found old entry and value " +- "type not matched, remove it first"); +- +- ngx_queue_remove(&sd->queue); +- +- node = (ngx_rbtree_node_t *) +- ((u_char *) sd - offsetof(ngx_rbtree_node_t, color)); +- +- ngx_rbtree_delete(&ctx->sh->rbtree, node); +- +- ngx_slab_free_locked(ctx->shpool, node); +- +- dd("go to init_list"); +- goto init_list; +- } +- +- ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ctx->log, 0, +- "lua shared dict push: found old entry and value " +- "type matched, reusing it"); +- +- sd->expires = 0; +- sd->value_len = 0; +- /* free list nodes */ +- +- queue = ngx_stream_lua_shdict_get_list_head(sd, key.len); +- +- for (q = ngx_queue_head(queue); +- q != ngx_queue_sentinel(queue); +- q = ngx_queue_next(q)) +- { +- /* TODO: reuse matched size list node */ +- lnode = ngx_queue_data(q, ngx_stream_lua_shdict_list_node_t, queue); +- ngx_slab_free_locked(ctx->shpool, lnode); +- } +- +- ngx_queue_init(queue); +- +- ngx_queue_remove(&sd->queue); +- ngx_queue_insert_head(&ctx->sh->lru_queue, &sd->queue); +- +- dd("go to push_node"); +- goto push_node; +- } +- +- /* exists and not expired */ +- +- if (rc == NGX_OK) { +- +- if (sd->value_type != SHDICT_TLIST) { +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- lua_pushnil(L); +- lua_pushliteral(L, "value not a list"); +- return 2; +- } +- +- queue = ngx_stream_lua_shdict_get_list_head(sd, key.len); +- +- ngx_queue_remove(&sd->queue); +- ngx_queue_insert_head(&ctx->sh->lru_queue, &sd->queue); +- +- dd("go to push_node"); +- goto push_node; +- } +- +- /* rc == NGX_DECLINED, not found */ +- +-init_list: +- +- ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ctx->log, 0, +- "lua shared dict list: creating a new entry"); +- +- /* NOTICE: we assume the begin point aligned in slab, be careful */ +- n = offsetof(ngx_rbtree_node_t, color) +- + offsetof(ngx_stream_lua_shdict_node_t, data) +- + key.len +- + sizeof(ngx_queue_t); +- +- dd("length before aligned: %d", n); +- +- n = (int) (uintptr_t) ngx_align_ptr(n, NGX_ALIGNMENT); +- +- dd("length after aligned: %d", n); +- +- node = ngx_slab_alloc_locked(ctx->shpool, n); +- +- if (node == NULL) { +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- lua_pushboolean(L, 0); +- lua_pushliteral(L, "no memory"); +- return 2; +- } +- +- sd = (ngx_stream_lua_shdict_node_t *) &node->color; +- +- queue = ngx_stream_lua_shdict_get_list_head(sd, key.len); +- +- node->key = hash; +- sd->key_len = (u_short) key.len; +- +- sd->expires = 0; +- +- sd->value_len = 0; +- +- dd("setting value type to %d", (int) SHDICT_TLIST); +- +- sd->value_type = (uint8_t) SHDICT_TLIST; +- +- ngx_memcpy(sd->data, key.data, key.len); +- +- ngx_queue_init(queue); +- +- ngx_rbtree_insert(&ctx->sh->rbtree, node); +- +- ngx_queue_insert_head(&ctx->sh->lru_queue, &sd->queue); +- +-push_node: +- +- ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ctx->log, 0, +- "lua shared dict list: creating a new list node"); +- +- n = offsetof(ngx_stream_lua_shdict_list_node_t, data) +- + value.len; +- +- dd("list node length: %d", n); +- +- lnode = ngx_slab_alloc_locked(ctx->shpool, n); +- +- if (lnode == NULL) { +- +- if (sd->value_len == 0) { +- +- ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ctx->log, 0, +- "lua shared dict list: no memory for create" +- " list node and list empty, remove it"); +- +- ngx_queue_remove(&sd->queue); +- +- node = (ngx_rbtree_node_t *) +- ((u_char *) sd - offsetof(ngx_rbtree_node_t, color)); +- +- ngx_rbtree_delete(&ctx->sh->rbtree, node); +- +- ngx_slab_free_locked(ctx->shpool, node); +- } +- +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- lua_pushboolean(L, 0); +- lua_pushliteral(L, "no memory"); +- return 2; +- } +- +- dd("setting list length to %d", sd->value_len + 1); +- +- sd->value_len = sd->value_len + 1; +- +- dd("setting list node value length to %d", (int) value.len); +- +- lnode->value_len = (uint32_t) value.len; +- +- dd("setting list node value type to %d", value_type); +- +- lnode->value_type = (uint8_t) value_type; +- +- ngx_memcpy(lnode->data, value.data, value.len); +- +- if (flags == NGX_STREAM_LUA_SHDICT_LEFT) { +- ngx_queue_insert_head(queue, &lnode->queue); +- +- } else { +- ngx_queue_insert_tail(queue, &lnode->queue); +- } +- +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- lua_pushnumber(L, sd->value_len); +- return 1; +-} +- +- +-static int +-ngx_stream_lua_shdict_lpop(lua_State *L) +-{ +- return ngx_stream_lua_shdict_pop_helper(L, NGX_STREAM_LUA_SHDICT_LEFT); +-} +- +- +-static int +-ngx_stream_lua_shdict_rpop(lua_State *L) +-{ +- return ngx_stream_lua_shdict_pop_helper(L, NGX_STREAM_LUA_SHDICT_RIGHT); +-} +- +- +-static int +-ngx_stream_lua_shdict_pop_helper(lua_State *L, int flags) +-{ +- int n; +- ngx_str_t name; +- ngx_str_t key; +- uint32_t hash; +- ngx_int_t rc; +- ngx_str_t value; +- int value_type; +- double num; +- ngx_rbtree_node_t *node; +- ngx_shm_zone_t *zone; +- ngx_queue_t *queue; +- +- ngx_stream_lua_shdict_ctx_t *ctx; +- ngx_stream_lua_shdict_node_t *sd; +- ngx_stream_lua_shdict_list_node_t *lnode; +- +- n = lua_gettop(L); +- +- if (n != 2) { +- return luaL_error(L, "expecting 2 arguments, " +- "but only seen %d", n); +- } +- +- if (lua_type(L, 1) != LUA_TTABLE) { +- return luaL_error(L, "bad \"zone\" argument"); +- } +- +- zone = ngx_stream_lua_shdict_get_zone(L, 1); +- if (zone == NULL) { +- return luaL_error(L, "bad \"zone\" argument"); +- } +- +- ctx = zone->data; +- name = ctx->name; +- +- if (lua_isnil(L, 2)) { +- lua_pushnil(L); +- lua_pushliteral(L, "nil key"); +- return 2; +- } +- +- key.data = (u_char *) luaL_checklstring(L, 2, &key.len); +- +- if (key.len == 0) { +- lua_pushnil(L); +- lua_pushliteral(L, "empty key"); +- return 2; +- } +- +- if (key.len > 65535) { +- lua_pushnil(L); +- lua_pushliteral(L, "key too long"); +- return 2; +- } +- +- hash = ngx_crc32_short(key.data, key.len); +- +- ngx_shmtx_lock(&ctx->shpool->mutex); +- +-#if 1 +- ngx_stream_lua_shdict_expire(ctx, 1); +-#endif +- +- rc = ngx_stream_lua_shdict_lookup(zone, hash, key.data, key.len, &sd); +- +- dd("shdict lookup returned %d", (int) rc); +- +- if (rc == NGX_DECLINED || rc == NGX_DONE) { +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- lua_pushnil(L); +- return 1; +- } +- +- /* rc == NGX_OK */ +- +- if (sd->value_type != SHDICT_TLIST) { +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- lua_pushnil(L); +- lua_pushliteral(L, "value not a list"); +- return 2; +- } +- +- if (sd->value_len <= 0) { +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- return luaL_error(L, "bad lua list length found for key %s " +- "in shared_dict %s: %lu", key.data, name.data, +- (unsigned long) sd->value_len); +- } +- +- queue = ngx_stream_lua_shdict_get_list_head(sd, key.len); +- +- if (flags == NGX_STREAM_LUA_SHDICT_LEFT) { +- queue = ngx_queue_head(queue); +- +- } else { +- queue = ngx_queue_last(queue); +- } +- +- lnode = ngx_queue_data(queue, ngx_stream_lua_shdict_list_node_t, queue); +- +- value_type = lnode->value_type; +- +- dd("data: %p", lnode->data); +- dd("value len: %d", (int) sd->value_len); +- +- value.data = lnode->data; +- value.len = (size_t) lnode->value_len; +- +- switch (value_type) { +- +- case SHDICT_TSTRING: +- +- lua_pushlstring(L, (char *) value.data, value.len); +- break; +- +- case SHDICT_TNUMBER: +- +- if (value.len != sizeof(double)) { +- +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- return luaL_error(L, "bad lua list node number value size found " +- "for key %s in shared_dict %s: %lu", key.data, +- name.data, (unsigned long) value.len); +- } +- +- ngx_memcpy(&num, value.data, sizeof(double)); +- +- lua_pushnumber(L, num); +- break; +- +- default: +- +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- return luaL_error(L, "bad list node value type found for key %s in " +- "shared_dict %s: %d", key.data, name.data, +- value_type); +- } +- +- ngx_queue_remove(queue); +- +- ngx_slab_free_locked(ctx->shpool, lnode); +- +- if (sd->value_len == 1) { +- +- ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ctx->log, 0, +- "lua shared dict list: empty node after pop, " +- "remove it"); +- +- ngx_queue_remove(&sd->queue); +- +- node = (ngx_rbtree_node_t *) +- ((u_char *) sd - offsetof(ngx_rbtree_node_t, color)); +- +- ngx_rbtree_delete(&ctx->sh->rbtree, node); +- +- ngx_slab_free_locked(ctx->shpool, node); +- +- } else { +- sd->value_len = sd->value_len - 1; +- +- ngx_queue_remove(&sd->queue); +- ngx_queue_insert_head(&ctx->sh->lru_queue, &sd->queue); +- } +- +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- return 1; +-} +- +- +-static int +-ngx_stream_lua_shdict_llen(lua_State *L) +-{ +- int n; +- ngx_str_t key; +- uint32_t hash; +- ngx_int_t rc; +- ngx_shm_zone_t *zone; +- +- ngx_stream_lua_shdict_ctx_t *ctx; +- ngx_stream_lua_shdict_node_t *sd; +- +- n = lua_gettop(L); +- +- if (n != 2) { +- return luaL_error(L, "expecting 2 arguments, " +- "but only seen %d", n); +- } +- +- if (lua_type(L, 1) != LUA_TTABLE) { +- return luaL_error(L, "bad \"zone\" argument"); +- } +- +- zone = ngx_stream_lua_shdict_get_zone(L, 1); +- if (zone == NULL) { +- return luaL_error(L, "bad \"zone\" argument"); +- } +- +- ctx = zone->data; +- +- if (lua_isnil(L, 2)) { +- lua_pushnil(L); +- lua_pushliteral(L, "nil key"); +- return 2; +- } +- +- key.data = (u_char *) luaL_checklstring(L, 2, &key.len); +- +- if (key.len == 0) { +- lua_pushnil(L); +- lua_pushliteral(L, "empty key"); +- return 2; +- } +- +- if (key.len > 65535) { +- lua_pushnil(L); +- lua_pushliteral(L, "key too long"); +- return 2; +- } +- +- hash = ngx_crc32_short(key.data, key.len); +- +- ngx_shmtx_lock(&ctx->shpool->mutex); +- +-#if 1 +- ngx_stream_lua_shdict_expire(ctx, 1); +-#endif +- +- rc = ngx_stream_lua_shdict_lookup(zone, hash, key.data, key.len, &sd); +- +- dd("shdict lookup returned %d", (int) rc); +- +- if (rc == NGX_OK) { +- +- if (sd->value_type != SHDICT_TLIST) { +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- lua_pushnil(L); +- lua_pushliteral(L, "value not a list"); +- return 2; +- } +- +- ngx_queue_remove(&sd->queue); +- ngx_queue_insert_head(&ctx->sh->lru_queue, &sd->queue); +- +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- lua_pushnumber(L, (lua_Number) sd->value_len); +- return 1; +- } +- +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- lua_pushnumber(L, 0); +- return 1; +-} +- +- +-ngx_shm_zone_t * +-ngx_stream_lua_find_zone(u_char *name_data, size_t name_len) +-{ +- ngx_str_t *name; +- ngx_uint_t i; +- ngx_shm_zone_t *zone; +- volatile ngx_list_part_t *part; +- +- ngx_stream_lua_shm_zone_ctx_t *ctx; +- +- part = &ngx_cycle->shared_memory.part; +- zone = part->elts; +- +- for (i = 0; /* void */ ; i++) { +- +- if (i >= part->nelts) { +- if (part->next == NULL) { +- break; +- } +- +- part = part->next; +- zone = part->elts; +- i = 0; +- } +- +- name = &zone[i].shm.name; +- +- dd("name: [%.*s] %d", (int) name->len, name->data, (int) name->len); +- dd("name2: [%.*s] %d", (int) name_len, name_data, (int) name_len); +- +- if (name->len == name_len +- && ngx_strncmp(name->data, name_data, name_len) == 0) +- { +- ctx = (ngx_stream_lua_shm_zone_ctx_t *) zone[i].data; +- return &ctx->zone; +- } +- } +- +- return NULL; +-} +- +- +-ngx_shm_zone_t * +-ngx_stream_lua_ffi_shdict_udata_to_zone(void *zone_udata) +-{ +- if (zone_udata == NULL) { +- return NULL; +- } +- +- return *(ngx_shm_zone_t **) zone_udata; +-} +- +- +-int +-ngx_stream_lua_ffi_shdict_store(ngx_shm_zone_t *zone, int op, u_char *key, +- size_t key_len, int value_type, u_char *str_value_buf, +- size_t str_value_len, double num_value, long exptime, int user_flags, +- char **errmsg, int *forcible) +-{ +- int i, n; +- u_char c, *p; +- uint32_t hash; +- ngx_int_t rc; +- ngx_time_t *tp; +- ngx_queue_t *queue, *q; +- ngx_rbtree_node_t *node; +- +- ngx_stream_lua_shdict_ctx_t *ctx; +- ngx_stream_lua_shdict_node_t *sd; +- +- dd("exptime: %ld", exptime); +- +- ctx = zone->data; +- +- *forcible = 0; +- +- hash = ngx_crc32_short(key, key_len); +- +- switch (value_type) { +- +- case SHDICT_TSTRING: +- /* do nothing */ +- break; +- +- case SHDICT_TNUMBER: +- dd("num value: %lf", num_value); +- str_value_buf = (u_char *) &num_value; +- str_value_len = sizeof(double); +- break; +- +- case SHDICT_TBOOLEAN: +- c = num_value ? 1 : 0; +- str_value_buf = &c; +- str_value_len = sizeof(u_char); +- break; +- +- case LUA_TNIL: +- if (op & (NGX_STREAM_LUA_SHDICT_ADD|NGX_STREAM_LUA_SHDICT_REPLACE)) { +- *errmsg = "attempt to add or replace nil values"; +- return NGX_ERROR; +- } +- +- str_value_buf = NULL; +- str_value_len = 0; +- break; +- +- default: +- *errmsg = "unsupported value type"; +- return NGX_ERROR; +- } +- +- ngx_shmtx_lock(&ctx->shpool->mutex); +- +-#if 1 +- ngx_stream_lua_shdict_expire(ctx, 1); +-#endif +- +- rc = ngx_stream_lua_shdict_lookup(zone, hash, key, key_len, &sd); +- +- dd("lookup returns %d", (int) rc); +- +- if (op & NGX_STREAM_LUA_SHDICT_REPLACE) { +- +- if (rc == NGX_DECLINED || rc == NGX_DONE) { +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- *errmsg = "not found"; +- return NGX_DECLINED; +- } +- +- /* rc == NGX_OK */ +- +- goto replace; +- } +- +- if (op & NGX_STREAM_LUA_SHDICT_ADD) { +- +- if (rc == NGX_OK) { +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- *errmsg = "exists"; +- return NGX_DECLINED; +- } +- +- if (rc == NGX_DONE) { +- /* exists but expired */ +- +- dd("go to replace"); +- goto replace; +- } +- +- /* rc == NGX_DECLINED */ +- +- dd("go to insert"); +- goto insert; +- } +- +- if (rc == NGX_OK || rc == NGX_DONE) { +- +- if (value_type == LUA_TNIL) { +- goto remove; +- } +- +-replace: +- +- if (str_value_buf +- && str_value_len == (size_t) sd->value_len +- && sd->value_type != SHDICT_TLIST) +- { +- +- ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ctx->log, 0, +- "lua shared dict set: found old entry and value " +- "size matched, reusing it"); +- +- ngx_queue_remove(&sd->queue); +- ngx_queue_insert_head(&ctx->sh->lru_queue, &sd->queue); +- +- sd->key_len = (u_short) key_len; +- +- if (exptime > 0) { +- tp = ngx_timeofday(); +- sd->expires = (uint64_t) tp->sec * 1000 + tp->msec +- + (uint64_t) exptime; +- +- } else { +- sd->expires = 0; +- } +- +- sd->user_flags = user_flags; +- +- sd->value_len = (uint32_t) str_value_len; +- +- dd("setting value type to %d", value_type); +- +- sd->value_type = (uint8_t) value_type; +- +- p = ngx_copy(sd->data, key, key_len); +- ngx_memcpy(p, str_value_buf, str_value_len); +- +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- return NGX_OK; +- } +- +- ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ctx->log, 0, +- "lua shared dict set: found old entry but value size " +- "NOT matched, removing it first"); +- +-remove: +- +- if (sd->value_type == SHDICT_TLIST) { +- queue = ngx_stream_lua_shdict_get_list_head(sd, key_len); +- +- for (q = ngx_queue_head(queue); +- q != ngx_queue_sentinel(queue); +- q = ngx_queue_next(q)) +- { +- p = (u_char *) ngx_queue_data(q, +- ngx_stream_lua_shdict_list_node_t, +- queue); +- +- ngx_slab_free_locked(ctx->shpool, p); +- } +- } +- +- ngx_queue_remove(&sd->queue); +- +- node = (ngx_rbtree_node_t *) +- ((u_char *) sd - offsetof(ngx_rbtree_node_t, color)); +- +- ngx_rbtree_delete(&ctx->sh->rbtree, node); +- +- ngx_slab_free_locked(ctx->shpool, node); +- +- } +- +-insert: +- +- /* rc == NGX_DECLINED or value size unmatch */ +- +- if (str_value_buf == NULL) { +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- return NGX_OK; +- } +- +- ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ctx->log, 0, +- "lua shared dict set: creating a new entry"); +- +- n = offsetof(ngx_rbtree_node_t, color) +- + offsetof(ngx_stream_lua_shdict_node_t, data) +- + key_len +- + str_value_len; +- +- node = ngx_slab_alloc_locked(ctx->shpool, n); +- +- if (node == NULL) { +- +- if (op & NGX_STREAM_LUA_SHDICT_SAFE_STORE) { +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- *errmsg = "no memory"; +- return NGX_ERROR; +- } +- +- ngx_log_debug2(NGX_LOG_DEBUG_STREAM, ctx->log, 0, +- "lua shared dict set: overriding non-expired items " +- "due to memory shortage for entry \"%*s\"", key_len, +- key); +- +- for (i = 0; i < 30; i++) { +- if (ngx_stream_lua_shdict_expire(ctx, 0) == 0) { +- break; +- } +- +- *forcible = 1; +- +- node = ngx_slab_alloc_locked(ctx->shpool, n); +- if (node != NULL) { +- goto allocated; +- } +- } +- +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- *errmsg = "no memory"; +- return NGX_ERROR; +- } +- +-allocated: +- +- sd = (ngx_stream_lua_shdict_node_t *) &node->color; +- +- node->key = hash; +- sd->key_len = (u_short) key_len; +- +- if (exptime > 0) { +- tp = ngx_timeofday(); +- sd->expires = (uint64_t) tp->sec * 1000 + tp->msec +- + (uint64_t) exptime; +- +- } else { +- sd->expires = 0; +- } +- +- sd->user_flags = user_flags; +- sd->value_len = (uint32_t) str_value_len; +- dd("setting value type to %d", value_type); +- sd->value_type = (uint8_t) value_type; +- +- p = ngx_copy(sd->data, key, key_len); +- ngx_memcpy(p, str_value_buf, str_value_len); +- +- ngx_rbtree_insert(&ctx->sh->rbtree, node); +- ngx_queue_insert_head(&ctx->sh->lru_queue, &sd->queue); +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- return NGX_OK; +-} +- +- +-int +-ngx_stream_lua_ffi_shdict_get(ngx_shm_zone_t *zone, u_char *key, +- size_t key_len, int *value_type, u_char **str_value_buf, +- size_t *str_value_len, double *num_value, int *user_flags, +- int get_stale, int *is_stale, char **err) +-{ +- ngx_str_t name; +- uint32_t hash; +- ngx_int_t rc; +- ngx_str_t value; +- +- ngx_stream_lua_shdict_ctx_t *ctx; +- ngx_stream_lua_shdict_node_t *sd; +- +- *err = NULL; +- +- ctx = zone->data; +- name = ctx->name; +- +- hash = ngx_crc32_short(key, key_len); +- +-#if (NGX_DEBUG) +- ngx_log_debug3(NGX_LOG_DEBUG_STREAM, ctx->log, 0, +- "fetching key \"%*s\" in shared dict \"%V\"", key_len, +- key, &name); +-#endif /* NGX_DEBUG */ +- +- ngx_shmtx_lock(&ctx->shpool->mutex); +- +-#if 1 +- if (!get_stale) { +- ngx_stream_lua_shdict_expire(ctx, 1); +- } +-#endif +- +- rc = ngx_stream_lua_shdict_lookup(zone, hash, key, key_len, &sd); +- +- dd("shdict lookup returns %d", (int) rc); +- +- if (rc == NGX_DECLINED || (rc == NGX_DONE && !get_stale)) { +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- *value_type = LUA_TNIL; +- return NGX_OK; +- } +- +- /* rc == NGX_OK || (rc == NGX_DONE && get_stale) */ +- +- *value_type = sd->value_type; +- +- dd("data: %p", sd->data); +- dd("key len: %d", (int) sd->key_len); +- +- value.data = sd->data + sd->key_len; +- value.len = (size_t) sd->value_len; +- +- if (*str_value_len < (size_t) value.len) { +- if (*value_type == SHDICT_TBOOLEAN) { +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- return NGX_ERROR; +- } +- +- if (*value_type == SHDICT_TSTRING) { +- *str_value_buf = malloc(value.len); +- if (*str_value_buf == NULL) { +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- return NGX_ERROR; +- } +- } +- } +- +- switch (*value_type) { +- +- case SHDICT_TSTRING: +- *str_value_len = value.len; +- ngx_memcpy(*str_value_buf, value.data, value.len); +- break; +- +- case SHDICT_TNUMBER: +- +- if (value.len != sizeof(double)) { +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, +- "bad lua number value size found for key %*s " +- "in shared_dict %V: %z", key_len, key, +- &name, value.len); +- return NGX_ERROR; +- } +- +- *str_value_len = value.len; +- ngx_memcpy(num_value, value.data, sizeof(double)); +- break; +- +- case SHDICT_TBOOLEAN: +- +- if (value.len != sizeof(u_char)) { +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, +- "bad lua boolean value size found for key %*s " +- "in shared_dict %V: %z", key_len, key, &name, +- value.len); +- return NGX_ERROR; +- } +- +- ngx_memcpy(*str_value_buf, value.data, value.len); +- break; +- +- case SHDICT_TLIST: +- +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- *err = "value is a list"; +- return NGX_ERROR; +- +- default: +- +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, +- "bad value type found for key %*s in " +- "shared_dict %V: %d", key_len, key, &name, +- *value_type); +- return NGX_ERROR; +- } +- +- *user_flags = sd->user_flags; +- dd("user flags: %d", *user_flags); +- +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- if (get_stale) { +- +- /* always return value, flags, stale */ +- +- *is_stale = (rc == NGX_DONE); +- return NGX_OK; +- } +- +- return NGX_OK; +-} +- +- +-int +-ngx_stream_lua_ffi_shdict_incr(ngx_shm_zone_t *zone, u_char *key, +- size_t key_len, double *value, char **err, int has_init, double init, +- long init_ttl, int *forcible) +-{ +- int i, n; +- uint32_t hash; +- ngx_int_t rc; +- ngx_time_t *tp = NULL; +- double num; +- ngx_rbtree_node_t *node; +- u_char *p; +- ngx_queue_t *queue, *q; +- +- ngx_stream_lua_shdict_ctx_t *ctx; +- ngx_stream_lua_shdict_node_t *sd; +- +- if (init_ttl > 0) { +- tp = ngx_timeofday(); +- } +- +- ctx = zone->data; +- +- *forcible = 0; +- +- hash = ngx_crc32_short(key, key_len); +- +- dd("looking up key %.*s in shared dict %.*s", (int) key_len, key, +- (int) ctx->name.len, ctx->name.data); +- +- ngx_shmtx_lock(&ctx->shpool->mutex); +-#if 1 +- ngx_stream_lua_shdict_expire(ctx, 1); +-#endif +- rc = ngx_stream_lua_shdict_lookup(zone, hash, key, key_len, &sd); +- +- dd("shdict lookup returned %d", (int) rc); +- +- if (rc == NGX_DECLINED || rc == NGX_DONE) { +- if (!has_init) { +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- *err = "not found"; +- return NGX_ERROR; +- } +- +- /* add value */ +- num = *value + init; +- +- if (rc == NGX_DONE) { +- +- /* found an expired item */ +- +- if ((size_t) sd->value_len == sizeof(double) +- && sd->value_type != SHDICT_TLIST) +- { +- ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ctx->log, 0, +- "lua shared dict incr: found old entry and " +- "value size matched, reusing it"); +- +- ngx_queue_remove(&sd->queue); +- ngx_queue_insert_head(&ctx->sh->lru_queue, &sd->queue); +- +- dd("go to setvalue"); +- goto setvalue; +- } +- +- dd("go to remove"); +- goto remove; +- } +- +- dd("go to insert"); +- goto insert; +- } +- +- /* rc == NGX_OK */ +- +- if (sd->value_type != SHDICT_TNUMBER || sd->value_len != sizeof(double)) { +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- *err = "not a number"; +- return NGX_ERROR; +- } +- +- ngx_queue_remove(&sd->queue); +- ngx_queue_insert_head(&ctx->sh->lru_queue, &sd->queue); +- +- dd("setting value type to %d", (int) sd->value_type); +- +- p = sd->data + key_len; +- +- ngx_memcpy(&num, p, sizeof(double)); +- num += *value; +- +- ngx_memcpy(p, (double *) &num, sizeof(double)); +- +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- *value = num; +- return NGX_OK; +- +-remove: +- +- ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ctx->log, 0, +- "lua shared dict incr: found old entry but value size " +- "NOT matched, removing it first"); +- +- if (sd->value_type == SHDICT_TLIST) { +- queue = ngx_stream_lua_shdict_get_list_head(sd, key_len); +- +- for (q = ngx_queue_head(queue); +- q != ngx_queue_sentinel(queue); +- q = ngx_queue_next(q)) +- { +- p = (u_char *) ngx_queue_data(q, ngx_stream_lua_shdict_list_node_t, +- queue); +- +- ngx_slab_free_locked(ctx->shpool, p); +- } +- } +- +- ngx_queue_remove(&sd->queue); +- +- node = (ngx_rbtree_node_t *) +- ((u_char *) sd - offsetof(ngx_rbtree_node_t, color)); +- +- ngx_rbtree_delete(&ctx->sh->rbtree, node); +- +- ngx_slab_free_locked(ctx->shpool, node); +- +-insert: +- +- ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ctx->log, 0, +- "lua shared dict incr: creating a new entry"); +- +- n = offsetof(ngx_rbtree_node_t, color) +- + offsetof(ngx_stream_lua_shdict_node_t, data) +- + key_len +- + sizeof(double); +- +- node = ngx_slab_alloc_locked(ctx->shpool, n); +- +- if (node == NULL) { +- +- ngx_log_debug2(NGX_LOG_DEBUG_STREAM, ctx->log, 0, +- "lua shared dict incr: overriding non-expired items " +- "due to memory shortage for entry \"%*s\"", key_len, +- key); +- +- for (i = 0; i < 30; i++) { +- if (ngx_stream_lua_shdict_expire(ctx, 0) == 0) { +- break; +- } +- +- *forcible = 1; +- +- node = ngx_slab_alloc_locked(ctx->shpool, n); +- if (node != NULL) { +- goto allocated; +- } +- } +- +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- *err = "no memory"; +- return NGX_ERROR; +- } +- +-allocated: +- +- sd = (ngx_stream_lua_shdict_node_t *) &node->color; +- +- node->key = hash; +- +- sd->key_len = (u_short) key_len; +- +- sd->value_len = (uint32_t) sizeof(double); +- +- ngx_rbtree_insert(&ctx->sh->rbtree, node); +- +- ngx_queue_insert_head(&ctx->sh->lru_queue, &sd->queue); +- +-setvalue: +- +- sd->user_flags = 0; +- +- if (init_ttl > 0) { +- sd->expires = (uint64_t) tp->sec * 1000 + tp->msec +- + (uint64_t) init_ttl; +- +- } else { +- sd->expires = 0; +- } +- +- dd("setting value type to %d", LUA_TNUMBER); +- +- sd->value_type = (uint8_t) LUA_TNUMBER; +- +- p = ngx_copy(sd->data, key, key_len); +- ngx_memcpy(p, (double *) &num, sizeof(double)); +- +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- *value = num; +- return NGX_OK; +-} +- +- +-int +-ngx_stream_lua_ffi_shdict_flush_all(ngx_shm_zone_t *zone) +-{ +- ngx_queue_t *q; +- +- ngx_stream_lua_shdict_node_t *sd; +- ngx_stream_lua_shdict_ctx_t *ctx; +- +- ctx = zone->data; +- +- ngx_shmtx_lock(&ctx->shpool->mutex); +- +- for (q = ngx_queue_head(&ctx->sh->lru_queue); +- q != ngx_queue_sentinel(&ctx->sh->lru_queue); +- q = ngx_queue_next(q)) +- { +- sd = ngx_queue_data(q, ngx_stream_lua_shdict_node_t, queue); +- sd->expires = 1; +- } +- +- ngx_stream_lua_shdict_expire(ctx, 0); +- +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- return NGX_OK; +-} +- +- +-static ngx_int_t +-ngx_stream_lua_shdict_peek(ngx_shm_zone_t *shm_zone, ngx_uint_t hash, +- u_char *kdata, size_t klen, ngx_stream_lua_shdict_node_t **sdp) +-{ +- ngx_int_t rc; +- ngx_rbtree_node_t *node, *sentinel; +- +- ngx_stream_lua_shdict_ctx_t *ctx; +- ngx_stream_lua_shdict_node_t *sd; +- +- ctx = shm_zone->data; +- +- node = ctx->sh->rbtree.root; +- sentinel = ctx->sh->rbtree.sentinel; +- +- while (node != sentinel) { +- +- if (hash < node->key) { +- node = node->left; +- continue; +- } +- +- if (hash > node->key) { +- node = node->right; +- continue; +- } +- +- /* hash == node->key */ +- +- sd = (ngx_stream_lua_shdict_node_t *) &node->color; +- +- rc = ngx_memn2cmp(kdata, sd->data, klen, (size_t) sd->key_len); +- +- if (rc == 0) { +- *sdp = sd; +- +- return NGX_OK; +- } +- +- node = (rc < 0) ? node->left : node->right; +- } +- +- *sdp = NULL; +- +- return NGX_DECLINED; +-} +- +- +-long +-ngx_stream_lua_ffi_shdict_get_ttl(ngx_shm_zone_t *zone, u_char *key, +- size_t key_len) +-{ +- uint32_t hash; +- uint64_t now; +- uint64_t expires; +- ngx_int_t rc; +- ngx_time_t *tp; +- +- ngx_stream_lua_shdict_ctx_t *ctx; +- ngx_stream_lua_shdict_node_t *sd; +- +- ctx = zone->data; +- hash = ngx_crc32_short(key, key_len); +- +- ngx_shmtx_lock(&ctx->shpool->mutex); +- +- rc = ngx_stream_lua_shdict_peek(zone, hash, key, key_len, &sd); +- +- if (rc == NGX_DECLINED) { +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- return NGX_DECLINED; +- } +- +- /* rc == NGX_OK */ +- +- expires = sd->expires; +- +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- if (expires == 0) { +- return 0; +- } +- +- tp = ngx_timeofday(); +- now = (uint64_t) tp->sec * 1000 + tp->msec; +- +- return expires - now; +-} +- +- +-int +-ngx_stream_lua_ffi_shdict_set_expire(ngx_shm_zone_t *zone, u_char *key, +- size_t key_len, long exptime) +-{ +- uint32_t hash; +- ngx_int_t rc; +- ngx_time_t *tp = NULL; +- +- ngx_stream_lua_shdict_ctx_t *ctx; +- ngx_stream_lua_shdict_node_t *sd; +- +- if (exptime > 0) { +- tp = ngx_timeofday(); +- } +- +- ctx = zone->data; +- hash = ngx_crc32_short(key, key_len); +- +- ngx_shmtx_lock(&ctx->shpool->mutex); +- +- rc = ngx_stream_lua_shdict_peek(zone, hash, key, key_len, &sd); +- +- if (rc == NGX_DECLINED) { +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- return NGX_DECLINED; +- } +- +- /* rc == NGX_OK */ +- +- if (exptime > 0) { +- sd->expires = (uint64_t) tp->sec * 1000 + tp->msec +- + (uint64_t) exptime; +- +- } else { +- sd->expires = 0; +- } +- +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- return NGX_OK; +-} +- +- +-size_t +-ngx_stream_lua_ffi_shdict_capacity(ngx_shm_zone_t *zone) +-{ +- return zone->shm.size; +-} +- +- +-#if defined(nginx_version) && nginx_version >= 1011007 +-size_t +-ngx_stream_lua_ffi_shdict_free_space(ngx_shm_zone_t *zone) +-{ +- size_t bytes; +- +- ngx_stream_lua_shdict_ctx_t *ctx; +- +- ctx = zone->data; +- +- ngx_shmtx_lock(&ctx->shpool->mutex); +- bytes = ctx->shpool->pfree * ngx_pagesize; +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- return bytes; +-} +-#endif +- +- +-/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ +diff --git src/ngx_stream_lua_shdict.h src/ngx_stream_lua_shdict.h +deleted file mode 100644 +index 630c5b6..0000000 +--- src/ngx_stream_lua_shdict.h ++++ /dev/null +@@ -1,75 +0,0 @@ +- +-/* +- * !!! DO NOT EDIT DIRECTLY !!! +- * This file was automatically generated from the following template: +- * +- * src/subsys/ngx_subsys_lua_shdict.h.tt2 +- */ +- +- +-/* +- * Copyright (C) Yichun Zhang (agentzh) +- */ +- +- +-#ifndef _NGX_STREAM_LUA_SHDICT_H_INCLUDED_ +-#define _NGX_STREAM_LUA_SHDICT_H_INCLUDED_ +- +- +-#include "ngx_stream_lua_common.h" +- +- +-typedef struct { +- u_char color; +- uint8_t value_type; +- u_short key_len; +- uint32_t value_len; +- uint64_t expires; +- ngx_queue_t queue; +- uint32_t user_flags; +- u_char data[1]; +-} ngx_stream_lua_shdict_node_t; +- +- +-typedef struct { +- ngx_queue_t queue; +- uint32_t value_len; +- uint8_t value_type; +- u_char data[1]; +-} ngx_stream_lua_shdict_list_node_t; +- +- +-typedef struct { +- ngx_rbtree_t rbtree; +- ngx_rbtree_node_t sentinel; +- ngx_queue_t lru_queue; +-} ngx_stream_lua_shdict_shctx_t; +- +- +-typedef struct { +- ngx_stream_lua_shdict_shctx_t *sh; +- ngx_slab_pool_t *shpool; +- ngx_str_t name; +- ngx_stream_lua_main_conf_t *main_conf; +- ngx_log_t *log; +-} ngx_stream_lua_shdict_ctx_t; +- +- +-typedef struct { +- ngx_log_t *log; +- ngx_stream_lua_main_conf_t *lmcf; +- ngx_cycle_t *cycle; +- ngx_shm_zone_t zone; +-} ngx_stream_lua_shm_zone_ctx_t; +- +- +-ngx_int_t ngx_stream_lua_shdict_init_zone(ngx_shm_zone_t *shm_zone, void *data); +-void ngx_stream_lua_shdict_rbtree_insert_value(ngx_rbtree_node_t *temp, +- ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel); +-void ngx_stream_lua_inject_shdict_api(ngx_stream_lua_main_conf_t *lmcf, +- lua_State *L); +- +- +-#endif /* _NGX_STREAM_LUA_SHDICT_H_INCLUDED_ */ +- +-/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ +diff --git src/ngx_stream_lua_util.c src/ngx_stream_lua_util.c +index 58061b4..ab52d5a 100644 +--- src/ngx_stream_lua_util.c ++++ src/ngx_stream_lua_util.c +@@ -20,6 +20,7 @@ + + + #include "nginx.h" ++#include "ngx_meta_lua_api.h" + #include "ngx_stream_lua_directive.h" + #include "ngx_stream_lua_util.h" + #include "ngx_stream_lua_exception.h" +@@ -31,7 +32,6 @@ + #include "ngx_stream_lua_string.h" + #include "ngx_stream_lua_misc.h" + #include "ngx_stream_lua_consts.h" +-#include "ngx_stream_lua_shdict.h" + #include "ngx_stream_lua_coroutine.h" + #include "ngx_stream_lua_socket_tcp.h" + #include "ngx_stream_lua_socket_udp.h" +@@ -102,7 +102,7 @@ static ngx_int_t ngx_stream_lua_handle_exit(lua_State *L, + static int ngx_stream_lua_thread_traceback(lua_State *L, lua_State *co, + ngx_stream_lua_co_ctx_t *coctx); + static void ngx_stream_lua_inject_ngx_api(lua_State *L, +- ngx_stream_lua_main_conf_t *lmcf, ngx_log_t *log); ++ ngx_cycle_t *cycle, ngx_stream_lua_main_conf_t *lmcf, ngx_log_t *log); + static ngx_int_t ngx_stream_lua_output_filter(ngx_stream_lua_request_t *r, + ngx_chain_t *in); + static void ngx_stream_lua_finalize_threads(ngx_stream_lua_request_t *r, +@@ -501,13 +501,13 @@ ngx_stream_lua_init_globals(lua_State *L, ngx_cycle_t *cycle, + "lua initializing lua globals"); + + +- ngx_stream_lua_inject_ngx_api(L, lmcf, log); ++ ngx_stream_lua_inject_ngx_api(L, cycle, lmcf, log); + } + + + static void +-ngx_stream_lua_inject_ngx_api(lua_State *L, ngx_stream_lua_main_conf_t *lmcf, +- ngx_log_t *log) ++ngx_stream_lua_inject_ngx_api(lua_State *L, ngx_cycle_t *cycle, ++ ngx_stream_lua_main_conf_t *lmcf, ngx_log_t *log) + { + lua_createtable(L, 0 /* narr */, 113 /* nrec */); /* ngx.* */ + +@@ -529,7 +529,7 @@ ngx_stream_lua_inject_ngx_api(lua_State *L, ngx_stream_lua_main_conf_t *lmcf, + ngx_stream_lua_inject_req_api(log, L); + + +- ngx_stream_lua_inject_shdict_api(lmcf, L); ++ ngx_meta_lua_inject_shdict_api(L, cycle, &ngx_stream_lua_module); + ngx_stream_lua_inject_socket_tcp_api(log, L); + ngx_stream_lua_inject_socket_udp_api(log, L); + ngx_stream_lua_inject_uthread_api(log, L); +diff --git src/ngx_stream_lua_util.h src/ngx_stream_lua_util.h +index deb255f..e1c2f92 100644 +--- src/ngx_stream_lua_util.h ++++ src/ngx_stream_lua_util.h +@@ -344,7 +344,9 @@ ngx_stream_lua_create_ctx(ngx_stream_session_t *r) + ngx_stream_lua_assert(L != NULL); + + if (lmcf->init_handler) { +- if (lmcf->init_handler(r->connection->log, lmcf, L) != NGX_OK) { ++ if (lmcf->init_handler(r->connection->log, lmcf->init_src, L) ++ != NGX_OK) ++ { + /* an error happened */ + return NULL; + } diff --git a/patch/1.21.4.1/ngx_stream_lua-tlshandshake.patch b/patch/1.21.4.1/ngx_stream_lua-tlshandshake.patch new file mode 100644 index 0000000..73557c9 --- /dev/null +++ b/patch/1.21.4.1/ngx_stream_lua-tlshandshake.patch @@ -0,0 +1,718 @@ +diff --git src/ngx_stream_lua_socket_tcp.c src/ngx_stream_lua_socket_tcp.c +index 46e117e..7fcfb45 100644 +--- src/ngx_stream_lua_socket_tcp.c ++++ src/ngx_stream_lua_socket_tcp.c +@@ -30,7 +30,9 @@ + static int ngx_stream_lua_socket_tcp(lua_State *L); + static int ngx_stream_lua_socket_tcp_connect(lua_State *L); + #if (NGX_STREAM_SSL) +-static int ngx_stream_lua_socket_tcp_sslhandshake(lua_State *L); ++static void ngx_stream_lua_tls_handshake_handler(ngx_connection_t *c); ++static int ngx_stream_lua_tls_handshake_retval_handler(ngx_stream_lua_request_t *r, ++ ngx_stream_lua_socket_tcp_upstream_t *u, lua_State *L); + #endif + static int ngx_stream_lua_socket_tcp_receive(lua_State *L); + static int ngx_stream_lua_socket_tcp_receiveany(lua_State *L); +@@ -177,13 +179,6 @@ static void + static int ngx_stream_lua_socket_prepare_error_retvals( + ngx_stream_lua_request_t *r, ngx_stream_lua_socket_tcp_upstream_t *u, + lua_State *L, ngx_uint_t ft_type); +-#if (NGX_STREAM_SSL) +-static int ngx_stream_lua_ssl_handshake_retval_handler( +- ngx_stream_lua_request_t *r, ngx_stream_lua_socket_tcp_upstream_t *u, +- lua_State *L); +-static void ngx_stream_lua_ssl_handshake_handler(ngx_connection_t *c); +-static int ngx_stream_lua_ssl_free_session(lua_State *L); +-#endif + static void ngx_stream_lua_socket_tcp_close_connection(ngx_connection_t *c); + + static int ngx_stream_lua_socket_tcp_peek(lua_State *L); +@@ -246,9 +241,6 @@ static char ngx_stream_lua_upstream_udata_metatable_key; + static char ngx_stream_lua_downstream_udata_metatable_key; + static char ngx_stream_lua_pool_udata_metatable_key; + static char ngx_stream_lua_pattern_udata_metatable_key; +-#if (NGX_STREAM_SSL) +-static char ngx_stream_lua_ssl_session_metatable_key; +-#endif + + + void +@@ -326,13 +318,6 @@ ngx_stream_lua_inject_socket_tcp_api(ngx_log_t *log, lua_State *L) + lua_pushcfunction(L, ngx_stream_lua_socket_tcp_connect); + lua_setfield(L, -2, "connect"); + +-#if (NGX_STREAM_SSL) +- +- lua_pushcfunction(L, ngx_stream_lua_socket_tcp_sslhandshake); +- lua_setfield(L, -2, "sslhandshake"); +- +-#endif +- + lua_pushcfunction(L, ngx_stream_lua_socket_tcp_receive); + lua_setfield(L, -2, "receive"); + +@@ -406,19 +391,6 @@ ngx_stream_lua_inject_socket_tcp_api(ngx_log_t *log, lua_State *L) + lua_setfield(L, -2, "__gc"); + lua_rawset(L, LUA_REGISTRYINDEX); + /* }}} */ +- +-#if (NGX_STREAM_SSL) +- +- /* {{{ssl session userdata metatable */ +- lua_pushlightuserdata(L, ngx_stream_lua_lightudata_mask( +- ssl_session_metatable_key)); +- lua_createtable(L, 0 /* narr */, 1 /* nrec */); /* metatable */ +- lua_pushcfunction(L, ngx_stream_lua_ssl_free_session); +- lua_setfield(L, -2, "__gc"); +- lua_rawset(L, LUA_REGISTRYINDEX); +- /* }}} */ +- +-#endif + } + + +@@ -1556,64 +1528,72 @@ ngx_stream_lua_socket_conn_error_retval_handler(ngx_stream_lua_request_t *r, + + #if (NGX_STREAM_SSL) + +-static int +-ngx_stream_lua_socket_tcp_sslhandshake(lua_State *L) ++static const char * ++ngx_stream_lua_socket_tcp_check_busy(ngx_stream_lua_request_t *r, ++ ngx_stream_lua_socket_tcp_upstream_t *u, unsigned int ops) + { +- int n, top; +- ngx_int_t rc; +- ngx_str_t name = ngx_null_string; +- ngx_connection_t *c; +- ngx_ssl_session_t **psession; +- +- ngx_stream_lua_request_t *r; +- ngx_stream_lua_ctx_t *ctx; +- ngx_stream_lua_co_ctx_t *coctx; +- ngx_stream_lua_socket_tcp_upstream_t *u; +- +- /* Lua function arguments: self [,session] [,host] [,verify] +- [,send_status_req] */ ++ if ((ops & SOCKET_OP_CONNECT) && u->conn_waiting) { ++ return "socket busy connecting"; ++ } + +- n = lua_gettop(L); +- if (n < 1 || n > 5) { +- return luaL_error(L, "ngx.socket sslhandshake: expecting 1 ~ 5 " +- "arguments (including the object), but seen %d", n); ++ if ((ops & SOCKET_OP_READ) && u->read_waiting) { ++ return "socket busy reading"; + } + +- r = ngx_stream_lua_get_req(L); +- if (r == NULL) { +- return luaL_error(L, "no request found"); ++ if ((ops & SOCKET_OP_WRITE) ++ && (u->write_waiting ++ || (u->raw_downstream && r->connection->buffered))) ++ { ++ return "socket busy writing"; + } + +- ngx_log_debug0(NGX_LOG_DEBUG_STREAM, r->connection->log, 0, +- "stream lua tcp socket ssl handshake"); ++ return NULL; ++} + +- luaL_checktype(L, 1, LUA_TTABLE); + +- lua_rawgeti(L, 1, SOCKET_CTX_INDEX); +- u = lua_touserdata(L, -1); ++int ++ngx_stream_lua_ffi_socket_tcp_tlshandshake(ngx_stream_lua_request_t *r, ++ ngx_stream_lua_socket_tcp_upstream_t *u, ngx_ssl_session_t *sess, ++ int enable_session_reuse, ngx_str_t *server_name, int verify, ++ int ocsp_status_req, STACK_OF(X509) *chain, EVP_PKEY *pkey, ++ const char **errmsg) ++{ ++ ngx_int_t rc, i; ++ ngx_connection_t *c; ++ ngx_stream_lua_ctx_t *ctx; ++ ngx_stream_lua_co_ctx_t *coctx; ++ const char *busy_rc; ++ ngx_ssl_conn_t *ssl_conn; ++ X509 *x509; ++ ++ ngx_log_debug0(NGX_LOG_DEBUG_STREAM, r->connection->log, 0, ++ "stream lua tcp socket tls handshake"); + + if (u == NULL + || u->peer.connection == NULL + || u->read_closed + || u->write_closed) + { +- lua_pushnil(L); +- lua_pushliteral(L, "closed"); +- return 2; ++ *errmsg = "closed"; ++ return NGX_ERROR; + } + + if (u->request != r) { +- return luaL_error(L, "bad request"); ++ *errmsg = "bad request"; ++ return NGX_ERROR; + } + +- ngx_stream_lua_socket_check_busy_connecting(r, u, L); +- ngx_stream_lua_socket_check_busy_reading(r, u, L); +- ngx_stream_lua_socket_check_busy_writing(r, u, L); ++ busy_rc = ngx_stream_lua_socket_tcp_check_busy(r, u, SOCKET_OP_CONNECT ++ | SOCKET_OP_READ ++ | SOCKET_OP_WRITE); ++ if (busy_rc != NULL) { ++ *errmsg = busy_rc; ++ return NGX_ERROR; ++ } + + if (u->raw_downstream || u->body_downstream) { +- lua_pushnil(L); +- lua_pushliteral(L, "not supported for downstream"); +- return 2; ++ *errmsg = "not supported for downstream sockets"; ++ return NGX_ERROR; + } + + c = u->peer.connection; +@@ -1621,122 +1601,140 @@ ngx_stream_lua_socket_tcp_sslhandshake(lua_State *L) + u->ssl_session_reuse = 1; + + if (c->ssl && c->ssl->handshaked) { +- switch (lua_type(L, 2)) { +- case LUA_TUSERDATA: +- lua_pushvalue(L, 2); +- break; ++ if (sess != NULL) { ++ return NGX_DONE; ++ } + +- case LUA_TBOOLEAN: +- if (!lua_toboolean(L, 2)) { +- /* avoid generating the ssl session */ +- lua_pushboolean(L, 1); +- break; +- } +- /* fall through */ ++ u->ssl_session_reuse = enable_session_reuse; + +- default: +- ngx_stream_lua_ssl_handshake_retval_handler(r, u, L); +- break; +- } ++ (void) ngx_stream_lua_tls_handshake_retval_handler(r, u, NULL); + +- return 1; ++ return NGX_OK; + } + + if (ngx_ssl_create_connection(u->conf->ssl, c, + NGX_SSL_BUFFER|NGX_SSL_CLIENT) + != NGX_OK) + { +- lua_pushnil(L); +- lua_pushliteral(L, "failed to create ssl connection"); +- return 2; ++ *errmsg = "failed to create ssl connection"; ++ return NGX_ERROR; + } + ++ ssl_conn = c->ssl->connection; ++ + ctx = ngx_stream_lua_get_module_ctx(r, ngx_stream_lua_module); + if (ctx == NULL) { +- return luaL_error(L, "no ctx found"); ++ return NGX_STREAM_LUA_FFI_NO_REQ_CTX; + } + + coctx = ctx->cur_co_ctx; + + c->sendfile = 0; + +- if (n >= 2) { +- if (lua_type(L, 2) == LUA_TBOOLEAN) { +- u->ssl_session_reuse = lua_toboolean(L, 2); ++ if (sess != NULL) { ++ if (ngx_ssl_set_session(c, sess) != NGX_OK) { ++ *errmsg = "tls set session failed"; ++ return NGX_ERROR; ++ } ++ ++ ngx_log_debug1(NGX_LOG_DEBUG_STREAM, c->log, 0, ++ "stream lua tls set session: %p", sess); + +- } else { +- psession = lua_touserdata(L, 2); ++ } else { ++ u->ssl_session_reuse = enable_session_reuse; ++ } + +- if (psession != NULL && *psession != NULL) { +- if (ngx_ssl_set_session(c, *psession) != NGX_OK) { +- lua_pushnil(L); +- lua_pushliteral(L, "lua ssl set session failed"); +- return 2; +- } ++ if (chain != NULL) { ++ ngx_stream_lua_assert(pkey != NULL); /* ensured by resty.core */ + +- ngx_log_debug1(NGX_LOG_DEBUG_STREAM, c->log, 0, +- "stream lua ssl set session: %p", *psession); +- } ++ if (sk_X509_num(chain) < 1) { ++ ERR_clear_error(); ++ *errmsg = "invalid client certificate chain"; ++ return NGX_ERROR; + } + +- if (n >= 3) { +- name.data = (u_char *) lua_tolstring(L, 3, &name.len); ++ x509 = sk_X509_value(chain, 0); ++ if (x509 == NULL) { ++ ERR_clear_error(); ++ *errmsg = "tls fetch client certificate from chain failed"; ++ return NGX_ERROR; ++ } + +- if (name.data) { +- ngx_log_debug2(NGX_LOG_DEBUG_STREAM, r->connection->log, 0, +- "stream lua ssl server name: \"%*s\"", name.len, +- name.data); ++ if (SSL_use_certificate(ssl_conn, x509) == 0) { ++ ERR_clear_error(); ++ *errmsg = "tls set client certificate failed"; ++ return NGX_ERROR; ++ } + +-#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME ++ /* read rest of the chain */ + +- if (SSL_set_tlsext_host_name(c->ssl->connection, +- (char *) name.data) +- == 0) +- { +- lua_pushnil(L); +- lua_pushliteral(L, "SSL_set_tlsext_host_name failed"); +- return 2; +- } ++ for (i = 1; i < sk_X509_num(chain); i++) { ++ x509 = sk_X509_value(chain, i); ++ if (x509 == NULL) { ++ ERR_clear_error(); ++ *errmsg = "tls fetch client intermediate certificate from " ++ "chain failed"; ++ return NGX_ERROR; ++ } + +-#else ++ if (SSL_add1_chain_cert(ssl_conn, x509) == 0) { ++ ERR_clear_error(); ++ *errmsg = "tls set client intermediate certificate failed"; ++ return NGX_ERROR; ++ } ++ } + +- ngx_log_debug0(NGX_LOG_DEBUG_STREAM, c->log, 0, +- "lua socket SNI disabled because the current " +- "version of OpenSSL lacks the support"); ++ if (SSL_use_PrivateKey(ssl_conn, pkey) == 0) { ++ ERR_clear_error(); ++ *errmsg = "tls set client private key failed"; ++ return NGX_ERROR; ++ } ++ } + ++ if (server_name != NULL && server_name->data != NULL) { ++ ngx_log_debug1(NGX_LOG_DEBUG_STREAM, r->connection->log, 0, ++ "stream lua tls server name: \"%V\"", server_name); ++ ++#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME ++ if (SSL_set_tlsext_host_name(c->ssl->connection, ++ (char *) server_name->data) ++ == 0) ++ { ++ *errmsg = "SSL_set_tlsext_host_name failed"; ++ return NGX_ERROR; ++ } ++ ++#else ++ *errmsg = "no TLS extension support"; ++ return NGX_ERROR; + #endif +- } ++ } + +- if (n >= 4) { +- u->ssl_verify = lua_toboolean(L, 4); ++ u->ssl_verify = verify; + +- if (n >= 5) { +- if (lua_toboolean(L, 5)) { ++ if (ocsp_status_req) { + #ifdef NGX_STREAM_LUA_USE_OCSP +- SSL_set_tlsext_status_type(c->ssl->connection, +- TLSEXT_STATUSTYPE_ocsp); ++ SSL_set_tlsext_status_type(c->ssl->connection, ++ TLSEXT_STATUSTYPE_ocsp); ++ + #else +- return luaL_error(L, "no OCSP support"); ++ *errmsg = "no OCSP support"; ++ return NGX_ERROR; + #endif +- } +- } +- } +- } + } + +- dd("found sni name: %.*s %p", (int) name.len, name.data, name.data); +- +- if (name.len == 0) { ++ if (server_name->len == 0) { + u->ssl_name.len = 0; + + } else { + if (u->ssl_name.data) { + /* buffer already allocated */ + +- if (u->ssl_name.len >= name.len) { ++ if (u->ssl_name.len >= server_name->len) { + /* reuse it */ +- ngx_memcpy(u->ssl_name.data, name.data, name.len); +- u->ssl_name.len = name.len; ++ ngx_memcpy(u->ssl_name.data, server_name->data, ++ server_name->len); ++ u->ssl_name.len = server_name->len; + + } else { + ngx_free(u->ssl_name.data); +@@ -1747,17 +1745,15 @@ ngx_stream_lua_socket_tcp_sslhandshake(lua_State *L) + + new_ssl_name: + +- u->ssl_name.data = ngx_alloc(name.len, ngx_cycle->log); ++ u->ssl_name.data = ngx_alloc(server_name->len, ngx_cycle->log); + if (u->ssl_name.data == NULL) { + u->ssl_name.len = 0; +- +- lua_pushnil(L); +- lua_pushliteral(L, "no memory"); +- return 2; ++ *errmsg = "no memory"; ++ return NGX_ERROR; + } + +- ngx_memcpy(u->ssl_name.data, name.data, name.len); +- u->ssl_name.len = name.len; ++ ngx_memcpy(u->ssl_name.data, server_name->data, server_name->len); ++ u->ssl_name.len = server_name->len; + } + } + +@@ -1771,7 +1767,8 @@ new_ssl_name: + + rc = ngx_ssl_handshake(c); + +- dd("ngx_ssl_handshake returned %d", (int) rc); ++ ngx_log_debug1(NGX_LOG_DEBUG_STREAM, r->connection->log, 0, ++ "ngx_ssl_handshake returned: %d", rc); + + if (rc == NGX_AGAIN) { + if (c->write->timer_set) { +@@ -1781,13 +1778,13 @@ new_ssl_name: + ngx_add_timer(c->read, u->connect_timeout); + + u->conn_waiting = 1; +- u->write_prepare_retvals = ngx_stream_lua_ssl_handshake_retval_handler; ++ u->write_prepare_retvals = ngx_stream_lua_tls_handshake_retval_handler; + + ngx_stream_lua_cleanup_pending_operation(coctx); + coctx->cleanup = ngx_stream_lua_coctx_cleanup; + coctx->data = u; + +- c->ssl->handler = ngx_stream_lua_ssl_handshake_handler; ++ c->ssl->handler = ngx_stream_lua_tls_handshake_handler; + + if (ctx->entered_content_phase) { + r->write_event_handler = ngx_stream_lua_content_wev_handler; +@@ -1796,28 +1793,31 @@ new_ssl_name: + r->write_event_handler = ngx_stream_lua_core_run_phases; + } + +- return lua_yield(L, 0); ++ return NGX_AGAIN; + } + +- top = lua_gettop(L); +- ngx_stream_lua_ssl_handshake_handler(c); +- return lua_gettop(L) - top; ++ ngx_stream_lua_tls_handshake_handler(c); ++ ++ if (rc == NGX_ERROR) { ++ *errmsg = u->error_ret; ++ return NGX_ERROR; ++ } ++ ++ return NGX_OK; + } + + + static void +-ngx_stream_lua_ssl_handshake_handler(ngx_connection_t *c) ++ngx_stream_lua_tls_handshake_handler(ngx_connection_t *c) + { +- const char *err; + int waiting; +- lua_State *L; + ngx_int_t rc; + ngx_connection_t *dc; /* downstream connection */ + ngx_stream_lua_request_t *r; ++ ngx_stream_lua_ctx_t *ctx; ++ ngx_stream_lua_loc_conf_t *llcf; + +- ngx_stream_lua_ctx_t *ctx; +- ngx_stream_lua_loc_conf_t *llcf; +- ngx_stream_lua_socket_tcp_upstream_t *u; ++ ngx_stream_lua_socket_tcp_upstream_t *u; + + u = c->data; + r = u->request; +@@ -1833,11 +1833,9 @@ ngx_stream_lua_ssl_handshake_handler(ngx_connection_t *c) + waiting = u->conn_waiting; + + dc = r->connection; +- L = u->write_co_ctx->co; + + if (c->read->timedout) { +- lua_pushnil(L); +- lua_pushliteral(L, "timeout"); ++ u->error_ret = "timeout"; + goto failed; + } + +@@ -1846,37 +1844,33 @@ ngx_stream_lua_ssl_handshake_handler(ngx_connection_t *c) + } + + if (c->ssl->handshaked) { +- + if (u->ssl_verify) { + rc = SSL_get_verify_result(c->ssl->connection); + + if (rc != X509_V_OK) { +- lua_pushnil(L); +- err = lua_pushfstring(L, "%d: %s", (int) rc, +- X509_verify_cert_error_string(rc)); ++ u->error_ret = X509_verify_cert_error_string(rc); ++ u->openssl_error_code_ret = rc; + +- llcf = ngx_stream_lua_get_module_loc_conf(r, +- ngx_stream_lua_module); ++ llcf = ngx_stream_lua_get_module_loc_conf(r, ngx_stream_lua_module); + if (llcf->log_socket_errors) { +- ngx_log_error(NGX_LOG_ERR, dc->log, 0, "stream lua ssl " +- "certificate verify error: (%s)", err); ++ ngx_log_error(NGX_LOG_ERR, dc->log, 0, "stream lua tls " ++ "certificate verify error: (%d: %s)", ++ rc, u->error_ret); + } + + goto failed; + } + +-#if defined(nginx_version) && nginx_version >= 1007000 ++#if (nginx_version >= 1007000) + + if (u->ssl_name.len + && ngx_ssl_check_host(c, &u->ssl_name) != NGX_OK) + { +- lua_pushnil(L); +- lua_pushliteral(L, "certificate host mismatch"); ++ u->error_ret = "certificate host mismatch"; + +- llcf = ngx_stream_lua_get_module_loc_conf(r, +- ngx_stream_lua_module); ++ llcf = ngx_stream_lua_get_module_loc_conf(r, ngx_stream_lua_module); + if (llcf->log_socket_errors) { +- ngx_log_error(NGX_LOG_ERR, dc->log, 0, "stream lua ssl " ++ ngx_log_error(NGX_LOG_ERR, dc->log, 0, "stream lua tls " + "certificate does not match host \"%V\"", + &u->ssl_name); + } +@@ -1891,65 +1885,86 @@ ngx_stream_lua_ssl_handshake_handler(ngx_connection_t *c) + ngx_stream_lua_socket_handle_conn_success(r, u); + + } else { +- (void) ngx_stream_lua_ssl_handshake_retval_handler(r, u, L); ++ (void) ngx_stream_lua_tls_handshake_retval_handler(r, u, NULL); + } + +- + return; + } + +- lua_pushnil(L); +- lua_pushliteral(L, "handshake failed"); ++ u->error_ret = "handshake failed"; + + failed: + + if (waiting) { + u->write_prepare_retvals = +- ngx_stream_lua_socket_conn_error_retval_handler; ++ ngx_stream_lua_socket_conn_error_retval_handler; + ngx_stream_lua_socket_handle_conn_error(r, u, + NGX_STREAM_LUA_SOCKET_FT_SSL); + +- + } else { +- (void) ngx_stream_lua_socket_conn_error_retval_handler(r, u, L); ++ u->ft_type |= NGX_STREAM_LUA_SOCKET_FT_SSL; ++ ++ (void) ngx_stream_lua_socket_conn_error_retval_handler(r, u, NULL); + } + } + + ++int ++ngx_stream_lua_ffi_socket_tcp_get_tlshandshake_result(ngx_stream_lua_request_t *r, ++ ngx_stream_lua_socket_tcp_upstream_t *u, ngx_ssl_session_t **sess, ++ const char **errmsg, int *openssl_error_code) ++{ ++ ngx_log_debug1(NGX_LOG_DEBUG_STREAM, r->connection->log, 0, ++ "stream lua cosocket get TLS handshake result for upstream: %p", u); ++ ++ if (u->error_ret != NULL) { ++ *errmsg = u->error_ret; ++ *openssl_error_code = u->openssl_error_code_ret; ++ ++ return NGX_ERROR; ++ } ++ ++ *sess = u->ssl_session_ret; ++ ++ return NGX_OK; ++} ++ ++ + static int +-ngx_stream_lua_ssl_handshake_retval_handler(ngx_stream_lua_request_t *r, ++ngx_stream_lua_tls_handshake_retval_handler(ngx_stream_lua_request_t *r, + ngx_stream_lua_socket_tcp_upstream_t *u, lua_State *L) + { + ngx_connection_t *c; +- ngx_ssl_session_t *ssl_session, **ud; ++ ngx_ssl_session_t *ssl_session; + + if (!u->ssl_session_reuse) { +- lua_pushboolean(L, 1); +- return 1; ++ return 0; + } + +- ud = lua_newuserdata(L, sizeof(ngx_ssl_session_t *)); +- + c = u->peer.connection; + + ssl_session = ngx_ssl_get_session(c); + if (ssl_session == NULL) { +- *ud = NULL; ++ u->ssl_session_ret = NULL; + + } else { +- *ud = ssl_session; ++ u->ssl_session_ret = ssl_session; + +- ngx_log_debug1(NGX_LOG_DEBUG_STREAM, c->log, 0, +- "stream lua ssl save session: %p", ssl_session); +- +- /* set up the __gc metamethod */ +- lua_pushlightuserdata(L, ngx_stream_lua_lightudata_mask( +- ssl_session_metatable_key)); +- lua_rawget(L, LUA_REGISTRYINDEX); +- lua_setmetatable(L, -2); ++ ngx_log_debug1(NGX_LOG_DEBUG_STREAM, c->log, 0, ++ "stream lua tls save session: %p", ssl_session); + } + +- return 1; ++ return 0; ++} ++ ++ ++void ++ngx_stream_lua_ffi_tls_free_session(ngx_ssl_session_t *sess) ++{ ++ ngx_log_debug1(NGX_LOG_DEBUG_STREAM, ngx_cycle->log, 0, ++ "stream lua tls free session: %p", sess); ++ ++ ngx_ssl_free_session(sess); + } + + #endif /* NGX_STREAM_SSL */ +@@ -2004,12 +2019,14 @@ ngx_stream_lua_socket_prepare_error_retvals(ngx_stream_lua_request_t *r, + u_char errstr[NGX_MAX_ERROR_STR]; + u_char *p; + +- if (ft_type & (NGX_STREAM_LUA_SOCKET_FT_RESOLVER +- | NGX_STREAM_LUA_SOCKET_FT_SSL)) +- { ++ if (ft_type & NGX_STREAM_LUA_SOCKET_FT_RESOLVER) { + return 2; + } + ++ if (ft_type & NGX_STREAM_LUA_SOCKET_FT_SSL) { ++ return 0; ++ } ++ + lua_pushnil(L); + + if (ft_type & NGX_STREAM_LUA_SOCKET_FT_TIMEOUT) { +@@ -6201,27 +6218,6 @@ ngx_stream_lua_coctx_cleanup(void *data) + } + + +-#if (NGX_STREAM_SSL) +- +-static int +-ngx_stream_lua_ssl_free_session(lua_State *L) +-{ +- ngx_ssl_session_t **psession; +- +- psession = lua_touserdata(L, 1); +- if (psession && *psession != NULL) { +- ngx_log_debug1(NGX_LOG_DEBUG_STREAM, ngx_cycle->log, 0, +- "stream lua ssl free session: %p", *psession); +- +- ngx_ssl_free_session(*psession); +- } +- +- return 0; +-} +- +-#endif /* NGX_STREAM_SSL */ +- +- + void + ngx_stream_lua_cleanup_conn_pools(lua_State *L) + { +diff --git src/ngx_stream_lua_socket_tcp.h src/ngx_stream_lua_socket_tcp.h +index 3473250..a8abe83 100644 +--- src/ngx_stream_lua_socket_tcp.h ++++ src/ngx_stream_lua_socket_tcp.h +@@ -123,6 +123,9 @@ struct ngx_stream_lua_socket_tcp_upstream_s { + + #if (NGX_STREAM_SSL) + ngx_str_t ssl_name; ++ ngx_ssl_session_t *ssl_session_ret; ++ const char *error_ret; ++ int openssl_error_code_ret; + #endif + + unsigned ft_type:16; diff --git a/patch/1.21.4.1/ngx_stream_lua-xrpc.patch b/patch/1.21.4.1/ngx_stream_lua-xrpc.patch new file mode 100644 index 0000000..b1a0e11 --- /dev/null +++ b/patch/1.21.4.1/ngx_stream_lua-xrpc.patch @@ -0,0 +1,845 @@ +diff --git src/ngx_stream_lua_input_filters.c src/ngx_stream_lua_input_filters.c +index 159185c..83ff85f 100644 +--- src/ngx_stream_lua_input_filters.c ++++ src/ngx_stream_lua_input_filters.c +@@ -144,3 +144,64 @@ ngx_stream_lua_read_line(ngx_buf_t *src, ngx_chain_t *buf_in, + + return NGX_AGAIN; + } ++ ++ ++ngx_int_t ++ngx_stream_lua_read_line_within_bytes(ngx_buf_t *src, ngx_chain_t *buf_in, ++ size_t *rest, ssize_t bytes, ngx_log_t *log) ++{ ++ u_char *dst; ++ u_char c; ++#if (NGX_DEBUG) ++ u_char *begin; ++#endif ++ ++#if (NGX_DEBUG) ++ begin = src->pos; ++#endif ++ ++ if (bytes == 0) { ++ return NGX_ERROR; ++ } ++ ++ if ((size_t) bytes >= *rest) { ++ bytes = *rest; ++ } ++ ++ dst = buf_in->buf->last; ++ ++ while (bytes--) { ++ ++ (*rest)--; ++ dst++; ++ c = *src->pos++; ++ ++ switch (c) { ++ case '\n': ++ ngx_log_debug2(NGX_LOG_DEBUG_STREAM, log, 0, ++ "stream lua read the final line part: " ++ "\"%*s\"", src->pos - 1 - begin, begin); ++ ++ buf_in->buf->last = dst; ++ ++ return NGX_OK; ++ ++ default: ++ break; ++ } ++ } ++ ++#if (NGX_DEBUG) ++ ngx_log_debug2(NGX_LOG_DEBUG_STREAM, log, 0, ++ "stream lua read partial line data: %*s", ++ dst - begin, begin); ++#endif ++ ++ buf_in->buf->last = dst; ++ ++ if (*rest == 0) { ++ return NGX_DONE; ++ } ++ ++ return NGX_AGAIN; ++} +diff --git src/ngx_stream_lua_input_filters.h src/ngx_stream_lua_input_filters.h +index e65d572..25175a5 100644 +--- src/ngx_stream_lua_input_filters.h ++++ src/ngx_stream_lua_input_filters.h +@@ -31,6 +31,8 @@ ngx_int_t ngx_stream_lua_read_any(ngx_buf_t *src, ngx_chain_t *buf_in, + ngx_int_t ngx_stream_lua_read_line(ngx_buf_t *src, ngx_chain_t *buf_in, + ssize_t bytes, ngx_log_t *log); + ++ngx_int_t ngx_stream_lua_read_line_within_bytes(ngx_buf_t *src, ngx_chain_t *buf_in, ++ size_t *max, ssize_t bytes, ngx_log_t *log); + + #endif /* _NGX_STREAM_LUA_INPUT_FILTERS_H_INCLUDED_ */ + +diff --git src/ngx_stream_lua_socket_tcp.c src/ngx_stream_lua_socket_tcp.c +index 7fcfb45..9981b4b 100644 +--- src/ngx_stream_lua_socket_tcp.c ++++ src/ngx_stream_lua_socket_tcp.c +@@ -234,6 +234,41 @@ enum { + } + + ++#define ngx_stream_lua_ffi_socket_check_busy_connecting(r, u, errbuf, \ ++ errbuf_size) \ ++ if ((u)->conn_waiting) { \ ++ *errbuf_size = ngx_snprintf((errbuf), *(errbuf_size), \ ++ "socket busy connecting") \ ++ - (errbuf); \ ++ return NGX_ERROR; \ ++ } ++ ++ ++#define ngx_stream_lua_ffi_socket_check_busy_reading(r, u, errbuf, \ ++ errbuf_size) \ ++ if ((u)->read_waiting) { \ ++ *errbuf_size = ngx_snprintf((errbuf), *(errbuf_size), \ ++ "socket busy reading") \ ++ - (errbuf); \ ++ return NGX_ERROR; \ ++ } ++ ++ ++#define ngx_stream_lua_ffi_socket_check_busy_writing(r, u, errbuf, \ ++ errbuf_size) \ ++ if ((u)->write_waiting) { \ ++ *errbuf_size = ngx_snprintf((errbuf), *(errbuf_size), \ ++ "socket busy writing") \ ++ - (errbuf); \ ++ } \ ++ if ((u)->raw_downstream \ ++ && ((r)->connection->buffered)) \ ++ { \ ++ *errbuf_size = ngx_snprintf((errbuf), *(errbuf_size), \ ++ "socket busy writing") \ ++ - (errbuf); \ ++ } ++ + + static char ngx_stream_lua_raw_req_socket_metatable_key; + static char ngx_stream_lua_tcp_socket_metatable_key; +@@ -2607,6 +2642,31 @@ ngx_stream_lua_socket_read_any(void *data, ssize_t bytes) + } + + ++static ngx_int_t ++ngx_stream_lua_socket_read_line_within_bytes(void *data, ssize_t bytes) ++{ ++ ngx_int_t rc; ++ ngx_stream_lua_socket_tcp_upstream_t *u = data; ++ ++ ngx_log_debug0(NGX_LOG_DEBUG_STREAM, u->request->connection->log, 0, ++ "stream lua tcp socket read line within bytes"); ++ ++ rc = ngx_stream_lua_read_line_within_bytes(&u->buffer, u->buf_in, &u->rest, bytes, ++ u->request->connection->log); ++ if (rc == NGX_ERROR) { ++ u->ft_type |= NGX_STREAM_LUA_SOCKET_FT_CLOSED; ++ return NGX_ERROR; ++ } ++ ++ if (rc == NGX_DONE) { ++ u->ft_type |= NGX_STREAM_LUA_SOCKET_FT_TRUNCATED; ++ return NGX_ERROR; ++ } ++ ++ return rc; ++} ++ ++ + static ngx_int_t + ngx_stream_lua_socket_tcp_read(ngx_stream_lua_request_t *r, + ngx_stream_lua_socket_tcp_upstream_t *u) +@@ -6005,6 +6065,672 @@ static ngx_int_t ngx_stream_lua_socket_insert_buffer( + } + + ++static void ++ngx_stream_lua_ffi_socket_reset_buf(ngx_stream_lua_ctx_t *ctx, ++ ngx_stream_lua_socket_tcp_upstream_t *u) ++{ ++ ngx_chain_t *cl = u->bufs_in; ++ ngx_chain_t **ll = NULL; ++ ++ if (cl == NULL) { ++ return; ++ } ++ ++ if (cl->next) { ++ ll = &cl->next; ++ } ++ ++ if (ll) { ++ *ll = ctx->free_recv_bufs; ++ ctx->free_recv_bufs = u->bufs_in; ++ u->bufs_in = u->buf_in; ++ } ++ ++ if (u->buffer.pos == u->buffer.last) { ++ u->buffer.pos = u->buffer.start; ++ u->buffer.last = u->buffer.pos; ++ } ++ ++ if (u->bufs_in) { ++ u->buf_in->buf->last = u->buffer.pos; ++ u->buf_in->buf->pos = u->buffer.pos; ++ } ++} ++ ++ ++void ++ngx_stream_lua_ffi_socket_tcp_reset_read_buf(ngx_stream_lua_request_t *r, ++ ngx_stream_lua_socket_tcp_upstream_t *u) ++{ ++ ngx_stream_lua_ctx_t *ctx; ++ ++ ctx = ngx_stream_lua_get_module_ctx(r, ngx_stream_lua_module); ++ ngx_stream_lua_ffi_socket_reset_buf(ctx, u); ++} ++ ++ ++static int ++ngx_stream_lua_socket_tcp_dummy_retval_handler(ngx_stream_lua_request_t *r, ++ ngx_stream_lua_socket_tcp_upstream_t *u, lua_State *L) ++{ ++ return 0; ++} ++ ++ ++static ngx_int_t ++ngx_stream_lua_ffi_socket_push_res(ngx_stream_lua_request_t *r, ++ ngx_stream_lua_ctx_t *ctx, ngx_stream_lua_socket_tcp_upstream_t *u, ++ u_char **buf, size_t len, size_t *actual_len) ++{ ++ dd("bufs_in: %p, buf_in: %p", u->bufs_in, u->buf_in); ++ ++ ngx_log_debug3(NGX_LOG_DEBUG_STREAM, u->request->connection->log, 0, ++ "stream lua tcp socket push res: pos:%p, last:%p, len:%d", ++ u->buffer.pos, u->buffer.last, len); ++ ++ if (actual_len != NULL) { ++ len = u->length - u->rest; ++ *buf = u->buffer.pos - len; ++ ++ if ((*buf)[len - 1] == '\n') { ++ len--; ++ } ++ if ((*buf)[len - 1] == '\r') { ++ len--; ++ } ++ *actual_len = len; ++ ++ } else { ++ *buf = u->buffer.pos - len; ++ } ++ ++ return NGX_OK; ++} ++ ++ ++static void ++ngx_stream_lua_ffi_socket_prepare_error_retvals(ngx_stream_lua_request_t *r, ++ ngx_stream_lua_socket_tcp_upstream_t *u, ngx_uint_t ft_type, ++ u_char *errbuf, size_t *errbuf_size) ++{ ++ u_char *p; ++ ++ if (ft_type & NGX_STREAM_LUA_SOCKET_FT_TIMEOUT) { ++ *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "timeout") - errbuf; ++ ++ } else if (ft_type & NGX_STREAM_LUA_SOCKET_FT_CLOSED) { ++ *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "closed") - errbuf; ++ ++ } else if (ft_type & NGX_STREAM_LUA_SOCKET_FT_TRUNCATED) { ++ *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "truncated") - errbuf; ++ ++ } else if (ft_type & NGX_STREAM_LUA_SOCKET_FT_BUFTOOSMALL) { ++ *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "buffer too small") ++ - errbuf; ++ ++ } else if (ft_type & NGX_STREAM_LUA_SOCKET_FT_NOMEM) { ++ *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "no memory") - errbuf; ++ ++ } else if (ft_type & NGX_STREAM_LUA_SOCKET_FT_CLIENTABORT) { ++ *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "client aborted") ++ - errbuf; ++ ++ } else { ++ ++ if (u->socket_errno) { ++ p = ngx_strerror(u->socket_errno, errbuf, *errbuf_size); ++ /* for compatibility with LuaSocket */ ++ ngx_strlow(errbuf, errbuf, p - errbuf); ++ *errbuf_size = p - errbuf; ++ ++ } else { ++ *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "error") ++ - errbuf; ++ } ++ } ++} ++ ++ ++static void ++ngx_stream_lua_ffi_socket_read_error_retval_handler( ++ ngx_stream_lua_request_t *r, ngx_stream_lua_socket_tcp_upstream_t *u, ++ u_char *errbuf, size_t *errbuf_size) ++{ ++ ngx_uint_t ft_type; ++ ++ if (u->ft_type & NGX_STREAM_LUA_SOCKET_FT_TIMEOUT) { ++ u->no_close = 1; ++ } ++ ++ if (u->read_co_ctx) { ++ u->read_co_ctx->cleanup = NULL; ++ } ++ ++ ft_type = u->ft_type; ++ u->ft_type = 0; ++ ++ if (u->no_close) { ++ u->no_close = 0; ++ ++ } else { ++ ngx_stream_lua_socket_tcp_finalize_read_part(r, u); ++ } ++ ++ ngx_stream_lua_ffi_socket_prepare_error_retvals(r, u, ft_type, ++ errbuf, errbuf_size); ++} ++ ++ ++static ngx_int_t ++ngx_stream_lua_ffi_socket_read_retval_handler(ngx_stream_lua_request_t *r, ++ ngx_stream_lua_socket_tcp_upstream_t *u, u_char **buf, size_t len, ++ size_t *actual_len, u_char *errbuf, size_t *errbuf_size) ++{ ++ ngx_stream_lua_ctx_t *ctx; ++ ngx_event_t *ev; ++ ++ ngx_stream_lua_loc_conf_t *llcf; ++ ++ ctx = ngx_stream_lua_get_module_ctx(r, ngx_stream_lua_module); ++ ++ if (u->raw_downstream || u->body_downstream) { ++ llcf = ngx_stream_lua_get_module_loc_conf(r, ngx_stream_lua_module); ++ ++ if (llcf->check_client_abort) { ++ ++ r->read_event_handler = ngx_stream_lua_rd_check_broken_connection; ++ ++ ev = r->connection->read; ++ ++ dd("rev active: %d", ev->active); ++ ++ if ((ngx_event_flags & NGX_USE_LEVEL_EVENT) && !ev->active) { ++ if (ngx_add_event(ev, NGX_READ_EVENT, 0) != NGX_OK) { ++ *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, ++ "failed to add event") - errbuf; ++ return NGX_ERROR; ++ } ++ } ++ ++ } else { ++ /* llcf->check_client_abort == 0 */ ++ r->read_event_handler = ngx_stream_lua_block_reading; ++ } ++ } ++ ++ if (u->ft_type) { ++ ngx_stream_lua_ffi_socket_read_error_retval_handler(r, u, errbuf, ++ errbuf_size); ++ return NGX_ERROR; ++ } ++ ++ if (buf != NULL) { ++ ngx_stream_lua_ffi_socket_push_res(r, ctx, u, buf, len, actual_len); ++ } ++ ++ return NGX_OK; ++} ++ ++ ++int ++ngx_stream_lua_ffi_socket_tcp_read_buf(ngx_stream_lua_request_t *r, ++ ngx_stream_lua_socket_tcp_upstream_t *u, u_char **buf, size_t len, ++ size_t *actual_len, u_char *errbuf, size_t *errbuf_size) ++{ ++ ngx_int_t rc; ++ ngx_stream_lua_loc_conf_t *llcf; ++ ngx_stream_lua_ctx_t *lctx; ++ ngx_stream_lua_co_ctx_t *coctx; ++ ++ if (u == NULL || u->peer.connection == NULL || u->read_closed) { ++ ++ llcf = ngx_stream_lua_get_module_loc_conf(r, ngx_stream_lua_module); ++ ++ if (llcf->log_socket_errors) { ++ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, ++ "stream attempt to receive data on a closed " ++ "socket: u:%p, c:%p, ft:%d eof:%d", ++ u, u ? u->peer.connection : NULL, ++ u ? (int) u->ft_type : 0, u ? (int) u->eof : 0); ++ } ++ ++ *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "closed") - errbuf; ++ return NGX_ERROR; ++ } ++ ++ if (u->request != r) { ++ *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "bad request") ++ - errbuf; ++ return NGX_DONE; ++ } ++ ++ ngx_stream_lua_ffi_socket_check_busy_connecting(r, u, errbuf, errbuf_size); ++ ngx_stream_lua_ffi_socket_check_busy_reading(r, u, errbuf, errbuf_size); ++ ++ ngx_log_debug1(NGX_LOG_DEBUG_STREAM, r->connection->log, 0, ++ "stream lua tcp socket read timeout: %M", u->read_timeout); ++ ++ if (actual_len != NULL) { ++ u->input_filter = ngx_stream_lua_socket_read_line_within_bytes; ++ } else { ++ u->input_filter = ngx_stream_lua_socket_read_chunk; ++ } ++ ++ u->length = (size_t) len; ++ u->rest = u->length; ++ u->input_filter_ctx = u; ++ ++ lctx = ngx_stream_lua_get_module_ctx(r, ngx_stream_lua_module); ++ ++ if (buf != NULL) { ++ if (u->bufs_in == NULL) { ++ size_t buf_len = len > u->conf->buffer_size ? len : u->conf->buffer_size; ++ ++ ngx_log_debug1(NGX_LOG_DEBUG_STREAM, r->connection->log, 0, ++ "stream lua tcp socket allocate new new buf of size %uz", ++ buf_len); ++ ++ u->bufs_in = ++ ngx_stream_lua_chain_get_free_buf(r->connection->log, ++ r->pool, ++ &lctx->free_recv_bufs, ++ buf_len); ++ ++ if (u->bufs_in == NULL) { ++ *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "no memory") - errbuf; ++ return NGX_DONE; ++ } ++ ++ u->buf_in = u->bufs_in; ++ u->buffer = *u->buf_in->buf; ++ ++ } else { ++ size_t remain_space = u->buffer.end - u->buffer.pos; ++ size_t remain_data = u->buffer.last - u->buffer.pos; ++ size_t buf_len; ++ u_char *pos; ++ ngx_chain_t *cl, *tmp_cl; ++ ++ if (remain_space < len) { ++ buf_len = len > u->conf->buffer_size ? len : u->conf->buffer_size; ++ ++ ngx_log_debug1(NGX_LOG_DEBUG_STREAM, r->connection->log, 0, ++ "stream lua tcp socket allocate new new buf of size %uz", ++ buf_len); ++ ++ cl = ngx_stream_lua_chain_get_free_buf(r->connection->log, ++ r->pool, ++ &lctx->free_recv_bufs, ++ buf_len); ++ if (cl == NULL) { ++ *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "no memory") - errbuf; ++ return NGX_DONE; ++ } ++ ++ for (tmp_cl = u->bufs_in; tmp_cl->next; tmp_cl = tmp_cl->next) {} ++ tmp_cl->next = cl; ++ u->buf_in = cl; ++ ++ u->buffer.last = u->buffer.pos; ++ pos = u->buffer.pos; ++ u->buffer = *cl->buf; ++ ++ if (remain_data > 0) { ++ u->buffer.last = ngx_copy(u->buffer.last, pos, remain_data); ++ } ++ } ++ } ++ ++ } else if (u->bufs_in == NULL) { ++ ngx_log_debug1(NGX_LOG_DEBUG_STREAM, r->connection->log, 0, ++ "stream lua tcp socket allocate new new buf of size %uz", ++ u->conf->buffer_size); ++ ++ u->bufs_in = ++ ngx_stream_lua_chain_get_free_buf(r->connection->log, ++ r->pool, ++ &lctx->free_recv_bufs, ++ u->conf->buffer_size); ++ ++ if (u->bufs_in == NULL) { ++ *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "no memory") - errbuf; ++ return NGX_DONE; ++ } ++ ++ u->buf_in = u->bufs_in; ++ u->buffer = *u->buf_in->buf; ++ } ++ ++ dd("tcp receive: buf_in: %p, bufs_in: %p", u->buf_in, u->bufs_in); ++ ++ ngx_log_debug1(NGX_LOG_DEBUG_STREAM, r->connection->log, 0, ++ "stream lua tcp socket read timeout: %M", u->read_timeout); ++ ++ if (u->raw_downstream || u->body_downstream) { ++ r->read_event_handler = ngx_stream_lua_req_socket_rev_handler; ++ } ++ ++ u->read_waiting = 0; ++ u->read_co_ctx = NULL; ++ ++ rc = ngx_stream_lua_socket_tcp_read(r, u); ++ ++ ngx_log_debug1(NGX_LOG_DEBUG_STREAM, r->connection->log, 0, ++ "stream lua socket tcp read, rc: %d", rc); ++ ++ if (rc == NGX_ERROR) { ++ dd("read failed: %d", (int) u->ft_type); ++ rc = ngx_stream_lua_ffi_socket_read_retval_handler(r, u, buf, len, ++ actual_len, ++ errbuf, errbuf_size); ++ dd("tcp receive retval returned: %d", (int) rc); ++ return rc; ++ } ++ ++ if (rc == NGX_OK) { ++ ++ ngx_log_debug0(NGX_LOG_DEBUG_STREAM, r->connection->log, 0, ++ "stream lua tcp socket receive done in a single run"); ++ ++ return ngx_stream_lua_ffi_socket_read_retval_handler(r, u, buf, len, ++ actual_len, ++ errbuf, errbuf_size); ++ } ++ ++ if (rc == NGX_AGAIN) { ++ u->read_event_handler = ngx_stream_lua_socket_read_handler; ++ ++ coctx = lctx->cur_co_ctx; ++ ++ ngx_stream_lua_cleanup_pending_operation(coctx); ++ coctx->cleanup = ngx_stream_lua_coctx_cleanup; ++ coctx->data = u; ++ ++ if (lctx->entered_content_phase) { ++ r->write_event_handler = ngx_stream_lua_content_wev_handler; ++ ++ } else { ++ r->write_event_handler = ngx_stream_lua_core_run_phases; ++ } ++ ++ u->read_co_ctx = coctx; ++ u->read_waiting = 1; ++ u->read_prepare_retvals = ngx_stream_lua_socket_tcp_dummy_retval_handler; ++ ++ dd("setting data to %p, coctx:%p", u, coctx); ++ ++ if (u->raw_downstream || u->body_downstream) { ++ lctx->downstream = u; ++ } ++ ++ ngx_log_debug1(NGX_LOG_DEBUG_STREAM, r->connection->log, 0, ++ "lua socket receive yield, u: %p", u); ++ ++ return NGX_AGAIN; ++ } ++ ++ return ngx_stream_lua_ffi_socket_read_retval_handler(r, u, buf, len, ++ actual_len, ++ errbuf, errbuf_size); ++} ++ ++ ++int ++ngx_stream_lua_ffi_socket_tcp_get_read_buf_result(ngx_stream_lua_request_t *r, ++ ngx_stream_lua_socket_tcp_upstream_t *u, u_char **buf, size_t len, ++ size_t *actual_len, u_char *errbuf, size_t *errbuf_size) ++{ ++ ngx_log_debug0(NGX_LOG_DEBUG_STREAM, r->connection->log, 0, ++ "lua tcp socket get receive result"); ++ ++ return ngx_stream_lua_ffi_socket_read_retval_handler(r, u, buf, len, ++ actual_len, ++ errbuf, errbuf_size); ++} ++ ++ ++int ++ngx_stream_lua_ffi_socket_tcp_has_pending_data(ngx_stream_lua_request_t *r, ++ ngx_stream_lua_socket_tcp_upstream_t *u, ++ u_char *errbuf, size_t *errbuf_size) ++{ ++ /* skip many input checks as we require glance to be called ++ * after any read methods called successfully */ ++ ++ if (u == NULL || u->bufs_in == NULL) { ++ *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "closed") - errbuf; ++ return NGX_ERROR; ++ } ++ ++ /* no remain data */ ++ if ((u->buffer.last == u->buffer.pos && u->buffer.last != u->buffer.end) ++ || u->eof /* EOF reached */) ++ { ++ return NGX_OK; ++ } ++ ++ return NGX_AGAIN; ++} ++ ++ ++static void ++ngx_stream_lua_ffi_socket_write_error_retval_handler( ++ ngx_stream_lua_request_t *r, ngx_stream_lua_socket_tcp_upstream_t *u, ++ u_char *errbuf, size_t *errbuf_size) ++{ ++ ngx_uint_t ft_type; ++ ++ if (u->write_co_ctx) { ++ u->write_co_ctx->cleanup = NULL; ++ } ++ ++ ngx_stream_lua_socket_tcp_finalize_write_part(r, u, 0); ++ ++ ft_type = u->ft_type; ++ u->ft_type = 0; ++ ++ ngx_stream_lua_ffi_socket_prepare_error_retvals(r, u, ft_type, ++ errbuf, errbuf_size); ++} ++ ++ ++int ++ngx_stream_lua_ffi_socket_tcp_send_from_socket(ngx_stream_lua_request_t *r, ++ ngx_stream_lua_socket_tcp_upstream_t *u, ngx_stream_lua_socket_tcp_upstream_t *src, ++ u_char *errbuf, size_t *errbuf_size) ++{ ++ size_t len = 0; ++ ngx_int_t rc; ++ ngx_chain_t *cl, *in_cl; ++ ngx_stream_lua_ctx_t *ctx; ++ int tcp_nodelay; ++ ngx_buf_t *b; ++ ngx_connection_t *c; ++ ngx_stream_lua_loc_conf_t *llcf; ++ ngx_stream_core_srv_conf_t *clcf; ++ ngx_stream_lua_co_ctx_t *coctx; ++ ++ if (u == NULL || u->peer.connection == NULL || u->write_closed) { ++ llcf = ngx_stream_lua_get_module_loc_conf(r, ngx_stream_lua_module); ++ ++ if (llcf->log_socket_errors) { ++ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, ++ "attempt to send data on a closed socket: u:%p, " ++ "c:%p, ft:%d eof:%d", ++ u, u ? u->peer.connection : NULL, ++ u ? (int) u->ft_type : 0, u ? (int) u->eof : 0); ++ } ++ ++ *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "closed") - errbuf; ++ return NGX_ERROR; ++ } ++ ++ if (u->request != r) { ++ *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "bad request") ++ - errbuf; ++ return NGX_DONE; ++ } ++ ++ ngx_stream_lua_ffi_socket_check_busy_connecting(r, u, errbuf, errbuf_size); ++ ngx_stream_lua_ffi_socket_check_busy_writing(r, u, errbuf, errbuf_size); ++ ++ if (u->body_downstream) { ++ *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, ++ "attempt to write to request sockets") ++ - errbuf; ++ return NGX_DONE; ++ } ++ ++ ngx_log_debug1(NGX_LOG_DEBUG_STREAM, r->connection->log, 0, ++ "lua tcp socket send timeout: %M", u->send_timeout); ++ ++ ctx = ngx_stream_lua_get_module_ctx(r, ngx_stream_lua_module); ++ ++ for (in_cl = src->bufs_in; in_cl; in_cl = in_cl->next) { ++ b = in_cl->buf; ++ ++ len += b->last - b->pos; ++ ++ ngx_log_debug3(NGX_LOG_DEBUG_STREAM, r->connection->log, 0, ++ "lua tcp socket move cl:%p buf %p, len: %d", ++ in_cl, b, b->last - b->pos); ++ ++ } ++ ++ ngx_log_debug2(NGX_LOG_DEBUG_STREAM, r->connection->log, 0, ++ "lua tcp socket move total buf %p, len: %d", ++ src->bufs_in, len); ++ ++ if (len == 0) { ++ return NGX_OK; ++ } ++ ++ cl = ngx_stream_lua_chain_get_free_buf(r->connection->log, r->pool, ++ &ctx->free_bufs, len); ++ ++ if (cl == NULL) { ++ *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "no memory") - errbuf; ++ return NGX_DONE; ++ } ++ ++ if (!src->bufs_in->next) { ++ cl->buf->pos = src->bufs_in->buf->pos; ++ cl->buf->last = src->bufs_in->buf->last; ++ ++ } else { ++ /* TODO: avoid copying (it requires to modify the way cosocket sends data) */ ++ for (in_cl = src->bufs_in; in_cl; in_cl = in_cl->next) { ++ b = in_cl->buf; ++ cl->buf->last = ngx_copy(cl->buf->last, b->pos, b->last - b->pos); ++ } ++ } ++ ++ ngx_stream_lua_ffi_socket_reset_buf(ctx, src); ++ ++ u->request_bufs = cl; ++ ++ u->request_len = len; ++ ++ /* mimic ngx_stream_upstream_init_request here */ ++ ++ clcf = ngx_stream_lua_get_module_loc_conf(r, ngx_stream_core_module); ++ c = u->peer.connection; ++ ++ if (clcf->tcp_nodelay && c->tcp_nodelay == NGX_TCP_NODELAY_UNSET) { ++ ngx_log_debug0(NGX_LOG_DEBUG_STREAM, c->log, 0, ++ "lua socket tcp_nodelay"); ++ ++ tcp_nodelay = 1; ++ ++ if (setsockopt(c->fd, IPPROTO_TCP, TCP_NODELAY, ++ (const void *) &tcp_nodelay, sizeof(int)) ++ == -1) ++ { ++ llcf = ngx_stream_lua_get_module_loc_conf(r, ngx_stream_lua_module); ++ if (llcf->log_socket_errors) { ++ ngx_connection_error(c, ngx_socket_errno, ++ "setsockopt(TCP_NODELAY) " ++ "failed"); ++ } ++ ++ *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, ++ "setsocketopt tcp_nodelay failed") ++ - errbuf; ++ return NGX_ERROR; ++ } ++ ++ c->tcp_nodelay = NGX_TCP_NODELAY_SET; ++ } ++ ++ u->write_waiting = 0; ++ u->write_co_ctx = NULL; ++ ++ ngx_stream_lua_probe_socket_tcp_send_start(r, u, b->pos, len); ++ ++ rc = ngx_stream_lua_socket_send(r, u); ++ ++ dd("socket send returned %d", (int) rc); ++ ++ if (rc == NGX_ERROR) { ++ ngx_stream_lua_ffi_socket_write_error_retval_handler(r, u, errbuf, ++ errbuf_size); ++ return NGX_ERROR; ++ } ++ ++ if (rc == NGX_OK) { ++ return rc; ++ } ++ ++ /* rc == NGX_AGAIN */ ++ ++ coctx = ctx->cur_co_ctx; ++ ++ ngx_stream_lua_cleanup_pending_operation(coctx); ++ coctx->cleanup = ngx_stream_lua_coctx_cleanup; ++ coctx->data = u; ++ ++ if (u->raw_downstream) { ++ ctx->writing_raw_req_socket = 1; ++ } ++ ++ if (ctx->entered_content_phase) { ++ r->write_event_handler = ngx_stream_lua_content_wev_handler; ++ ++ } else { ++ r->write_event_handler = ngx_stream_lua_core_run_phases; ++ } ++ ++ u->write_co_ctx = coctx; ++ u->write_waiting = 1; ++ u->write_prepare_retvals = ngx_stream_lua_socket_tcp_dummy_retval_handler; ++ ++ dd("setting data to %p", u); ++ ++ ngx_log_debug1(NGX_LOG_DEBUG_STREAM, c->log, 0, ++ "lua socket send yield, u: %p", u); ++ ++ return NGX_AGAIN; ++} ++ ++ ++int ++ngx_stream_lua_ffi_socket_tcp_get_send_result(ngx_stream_lua_request_t *r, ++ ngx_stream_lua_socket_tcp_upstream_t *u, u_char *errbuf, ++ size_t *errbuf_size) ++{ ++ ngx_log_debug0(NGX_LOG_DEBUG_STREAM, r->connection->log, 0, ++ "lua tcp socket get send result"); ++ ++ if (u->ft_type) { ++ ngx_stream_lua_ffi_socket_write_error_retval_handler(r, u, errbuf, ++ errbuf_size); ++ return NGX_ERROR; ++ } ++ ++ return NGX_OK; ++} ++ ++ + static ngx_int_t + ngx_stream_lua_socket_tcp_conn_op_resume(ngx_stream_lua_request_t *r) + { +diff --git src/ngx_stream_lua_socket_tcp.h src/ngx_stream_lua_socket_tcp.h +index a8abe83..a7ce31d 100644 +--- src/ngx_stream_lua_socket_tcp.h ++++ src/ngx_stream_lua_socket_tcp.h +@@ -28,6 +28,7 @@ + #define NGX_STREAM_LUA_SOCKET_FT_PARTIALWRITE 0x0040 + #define NGX_STREAM_LUA_SOCKET_FT_CLIENTABORT 0x0080 + #define NGX_STREAM_LUA_SOCKET_FT_SSL 0x0100 ++#define NGX_STREAM_LUA_SOCKET_FT_TRUNCATED 0x1000 + + + typedef struct ngx_stream_lua_socket_tcp_upstream_s