Skip to content

Commit 8387ad5

Browse files
feature: ctxdump.lua: added support for stash and restore ngx.ctx. (#50)
1 parent b987e29 commit 8387ad5

File tree

4 files changed

+190
-1
lines changed

4 files changed

+190
-1
lines changed

README.markdown

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ Table of Contents
2020
* [resty.core.shdict](#restycoreshdict)
2121
* [resty.core.var](#restycorevar)
2222
* [resty.core.ctx](#restycorectx)
23+
* [resty.core.ctxdump](#restycorectxdump)
2324
* [get_ctx_table](#get_ctx_table)
2425
* [resty.core.request](#restycorerequest)
2526
* [resty.core.response](#restycoreresponse)
@@ -189,6 +190,60 @@ API Implemented
189190

190191
* [ngx.ctx](https://github.com/openresty/lua-nginx-module#ngxctx)
191192

193+
[Back to TOC](#table-of-contents)
194+
195+
## resty.core.ctxdump
196+
197+
nginx core clears all modules' ctx data upon internal redirects. If we want to
198+
share ngx.ctx between main request and subrequests, we need to stash ngx.ctx in
199+
main request and then restore ngx.ctx in the subrequest.
200+
201+
Synopsis
202+
========
203+
204+
```lua
205+
206+
location /t1 {
207+
set $ctx_ref "";
208+
content_by_lua_block {
209+
local ctxdump = require "resty.core.ctxdump"
210+
ngx.ctx = {
211+
Date = "Wed May 3 15:18:04 CST 2017",
212+
Site = "unknown"
213+
}
214+
ctxdump.stash_ref()
215+
ngx.exec("/t2")
216+
}
217+
}
218+
219+
location /t2 {
220+
internal;
221+
content_by_lua_block {
222+
local ctxdump = require "resty.core.ctxdump"
223+
ctxdump.apply_ref()
224+
ngx.say("Date: " .. ngx.ctx["Date"] .. " Site: " .. ngx.ctx["Site"])
225+
}
226+
}
227+
228+
```
229+
230+
**syntax:** *ctx = resty.core.ctx.stash_ref()*
231+
232+
**phase:** *init_worker_by_lua\*, set_by_lua\*, rewrite_by_lua\*, access_by_lua\*,
233+
content_by_lua\*, header_filter_by_lua\*, body_filter_by_lua\*, log_by_lua\*,
234+
ngx.timer.\*, balancer_by_lua\*
235+
236+
stash ngx.ctx reference index in ngx.var.ctx_ref.
237+
238+
**syntax:** *ctx = resty.core.ctx.apply_ref()*
239+
240+
**phase:** *init_worker_by_lua\*, set_by_lua\*, rewrite_by_lua\*, access_by_lua\*,
241+
content_by_lua\*, header_filter_by_lua\*, body_filter_by_lua\*, log_by_lua\*,
242+
ngx.timer.\*, balancer_by_lua\*
243+
244+
restore ngx.ctx by reference index saved in the ngx.var.ctx_ref.
245+
246+
192247
[Back to TOC](#table-of-contents)
193248

194249
## get_ctx_table

lib/resty/core.lua

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ end
2525

2626
require "resty.core.misc"
2727
require "resty.core.ctx"
28+
require "resty.core.ctxdump"
2829

2930

3031
local base = require "resty.core.base"

lib/resty/core/ctxdump.lua

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
-- A module for sharing ngx.ctx between subrequests.
2+
-- Original work by Alex Zhang (openresty/lua-nginx-module/issues/1057)
3+
-- updated by 3scale/apicast.
4+
--
5+
-- Copyright (c) 2016 3scale Inc.
6+
-- Licensed under the Apache License, Version 2.0.
7+
-- License text: See LICENSE
8+
--
9+
-- Modifications by Kong Inc.
10+
-- * updated module functions signatures
11+
-- * made module function idempotent
12+
-- * replaced thrown errors with warn logs
13+
-- * allow passing of context
14+
-- * updated to work with new 1.19.x apis
15+
16+
local ffi = require "ffi"
17+
local base = require "resty.core.base"
18+
19+
20+
local C = ffi.C
21+
local ngx = ngx
22+
local debug = require "debug"
23+
local tonumber = tonumber
24+
local registry = debug.getregistry()
25+
local subsystem = ngx.config.subsystem
26+
27+
28+
local ngx_lua_ffi_get_ctx_ref
29+
if subsystem == "http" then
30+
ngx_lua_ffi_get_ctx_ref = C.ngx_http_lua_ffi_get_ctx_ref
31+
elseif subsystem == "stream" then
32+
ngx_lua_ffi_get_ctx_ref = C.ngx_stream_lua_ffi_get_ctx_ref
33+
end
34+
35+
36+
local in_ssl_phase = ffi.new("int[1]")
37+
local ssl_ctx_ref = ffi.new("int[1]")
38+
39+
40+
local FFI_NO_REQ_CTX = base.FFI_NO_REQ_CTX
41+
42+
43+
local _M = {
44+
_VERSION = base.version
45+
}
46+
47+
function _M.stash_ref(ctx)
48+
local r = base.get_request()
49+
if not r then
50+
ngx.log(ngx.WARN, "could not stash ngx.ctx ref: no request found")
51+
return
52+
end
53+
54+
do
55+
local ctx_ref = ngx.var.ctx_ref
56+
if not ctx_ref or ctx_ref ~= "" then
57+
return
58+
end
59+
60+
if not ctx then
61+
local _ = ngx.ctx -- load context if not previously loaded
62+
end
63+
end
64+
local ctx_ref = ngx_lua_ffi_get_ctx_ref(r, in_ssl_phase, ssl_ctx_ref)
65+
if ctx_ref == FFI_NO_REQ_CTX then
66+
ngx.log(ngx.WARN, "could not stash ngx.ctx ref: no ctx found")
67+
return
68+
end
69+
70+
ngx.var.ctx_ref = ctx_ref
71+
end
72+
73+
74+
function _M.apply_ref()
75+
local r = base.get_request()
76+
if not r then
77+
ngx.log(ngx.WARN, "could not apply ngx.ctx: no request found")
78+
return
79+
end
80+
81+
local ctx_ref = ngx.var.ctx_ref
82+
if not ctx_ref or ctx_ref == "" then
83+
return
84+
end
85+
86+
ctx_ref = tonumber(ctx_ref)
87+
if not ctx_ref then
88+
return
89+
end
90+
91+
local orig_ctx = registry.ngx_lua_ctx_tables[ctx_ref]
92+
if not orig_ctx then
93+
ngx.log(ngx.WARN, "could not apply ngx.ctx: no ctx found")
94+
return
95+
end
96+
97+
ngx.ctx = orig_ctx
98+
ngx.var.ctx_ref = ""
99+
end
100+
101+
102+
return _M

t/ctx.t

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ log_level('debug');
1010
#repeat_each(120);
1111
repeat_each(2);
1212

13-
plan tests => repeat_each() * (blocks() * 4 - 1);
13+
plan tests => repeat_each() * (blocks() * 4 - 2);
1414

1515
#no_diff();
1616
#no_long_string();
@@ -1015,3 +1015,34 @@ reused
10151015
reused again
10161016
--- no_error_log
10171017
[error]
1018+
1019+
1020+
1021+
=== TEST 14: stash_ctx
1022+
--- config
1023+
location = /t {
1024+
set $ctx_ref "";
1025+
content_by_lua_block {
1026+
ngx.ctx.num = 999
1027+
1028+
local ctxdump = require "resty.core.ctxdump"
1029+
ctxdump.stash_ref()
1030+
ngx.exec("/t2")
1031+
}
1032+
}
1033+
1034+
location /t2 {
1035+
internal;
1036+
content_by_lua_block {
1037+
local ctxdump = require "resty.core.ctxdump"
1038+
ctxdump.apply_ref()
1039+
1040+
ngx.say("num: ", ngx.ctx.num)
1041+
}
1042+
}
1043+
--- request
1044+
GET /t
1045+
--- response_body
1046+
num: 999
1047+
--- no_error_log
1048+
[error]

0 commit comments

Comments
 (0)