Skip to content

Commit 3efd448

Browse files
authored
feature: add FFI implementation for ngx.arg getter (#386)
1 parent 9980264 commit 3efd448

File tree

4 files changed

+177
-0
lines changed

4 files changed

+177
-0
lines changed

README.markdown

+7
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ Table of Contents
2929
* [resty.core.phase](#restycorephase)
3030
* [resty.core.ndk](#restycorendk)
3131
* [resty.core.socket](#restycoresocket)
32+
* [resty.core.param](#restycoreparam)
3233
* [ngx.semaphore](#ngxsemaphore)
3334
* [ngx.balancer](#ngxbalancer)
3435
* [ngx.ssl](#ngxssl)
@@ -273,6 +274,12 @@ in the current request before you reusing the `ctx` table in some other place.
273274

274275
[Back to TOC](#table-of-contents)
275276

277+
## resty.core.param
278+
279+
* [ngx.arg](https://github.com/openresty/lua-nginx-module#ngxarg) (getter only)
280+
281+
[Back to TOC](#table-of-contents)
282+
276283
## ngx.semaphore
277284

278285
This Lua module implements a semaphore API for efficient "light thread" synchronization,

lib/resty/core.lua

+1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ if subsystem == 'http' then
2121
require "resty.core.ndk"
2222
require "resty.core.socket"
2323
require "resty.core.coroutine"
24+
require "resty.core.param"
2425
end
2526

2627

lib/resty/core/param.lua

+103
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
-- Copyright (C) Yichun Zhang (agentzh)
2+
3+
4+
local ffi = require 'ffi'
5+
local base = require "resty.core.base"
6+
require "resty.core.phase" -- for ngx.get_phase
7+
8+
9+
local C = ffi.C
10+
local ffi_str = ffi.string
11+
local FFI_AGAIN = base.FFI_AGAIN
12+
local FFI_OK = base.FFI_OK
13+
local get_request = base.get_request
14+
local get_string_buf = base.get_string_buf
15+
local getmetatable = getmetatable
16+
local ngx = ngx
17+
local ngx_phase = ngx.get_phase
18+
19+
20+
local _M = {
21+
version = base.version
22+
}
23+
24+
25+
ffi.cdef[[
26+
typedef unsigned char u_char;
27+
28+
void ngx_http_lua_ffi_get_setby_param(ngx_http_request_t *r, int idx,
29+
u_char **data, size_t *len);
30+
int ngx_http_lua_ffi_get_body_filter_param_eof(ngx_http_request_t *r);
31+
int ngx_http_lua_ffi_get_body_filter_param_body(ngx_http_request_t *r,
32+
u_char **data_p, size_t *len_p);
33+
int ngx_http_lua_ffi_copy_body_filter_param_body(ngx_http_request_t *r,
34+
u_char *data);
35+
]]
36+
local data_p = ffi.new("unsigned char*[1]")
37+
local len_p = ffi.new("size_t[1]")
38+
39+
40+
local function get_setby_param(r, idx)
41+
C.ngx_http_lua_ffi_get_setby_param(r, idx, data_p, len_p)
42+
if len_p[0] == 0 then
43+
return nil
44+
end
45+
46+
return ffi_str(data_p[0], len_p[0])
47+
end
48+
49+
50+
local function get_body_filter_param(r, idx)
51+
if idx == 1 then
52+
data_p[0] = nil
53+
local rc = C.ngx_http_lua_ffi_get_body_filter_param_body(r, data_p,
54+
len_p)
55+
if rc == FFI_AGAIN then
56+
local buf = get_string_buf(len_p[0])
57+
assert(C.ngx_http_lua_ffi_copy_body_filter_param_body(r, buf)
58+
== FFI_OK)
59+
return ffi_str(buf, len_p[0])
60+
end
61+
62+
if len_p[0] == 0 then
63+
return ""
64+
end
65+
66+
return ffi_str(data_p[0], len_p[0])
67+
68+
elseif idx == 2 then
69+
local rc = C.ngx_http_lua_ffi_get_body_filter_param_eof(r)
70+
return rc == 1
71+
72+
else
73+
return nil
74+
end
75+
end
76+
77+
78+
local function get_param(tb, idx)
79+
local r = get_request()
80+
if not r then
81+
error("no request found")
82+
end
83+
84+
local phase = ngx_phase()
85+
if phase == "set" then
86+
return get_setby_param(r, idx)
87+
end
88+
89+
if phase == "body_filter" then
90+
return get_body_filter_param(r, idx)
91+
end
92+
93+
error("API disabled in the current context")
94+
end
95+
96+
97+
do
98+
local mt = getmetatable(ngx.arg)
99+
mt.__index = get_param
100+
end
101+
102+
103+
return _M

t/param.t

+66
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
# vim:set ft= ts=4 sw=4 et fdm=marker:
2+
use lib '.';
3+
use t::TestCore;
4+
5+
#worker_connections(1014);
6+
#master_process_enabled(1);
7+
#log_level('warn');
8+
9+
repeat_each(2);
10+
11+
plan tests => repeat_each() * (blocks() * 4 + 1);
12+
13+
#no_diff();
14+
#no_long_string();
15+
check_accum_error_log();
16+
run_tests();
17+
18+
__DATA__
19+
20+
=== TEST 1: ngx.arg getter in set_by_lua
21+
--- config
22+
location = /t {
23+
# set_by_lua_block doesn't support arguments
24+
set_by_lua $res '
25+
local arg = ngx.arg
26+
local val
27+
for i = 1, 30 do
28+
val = arg[1] + arg[2]
29+
end
30+
return val
31+
' $arg_a $arg_b;
32+
echo $res;
33+
}
34+
--- request
35+
GET /t?a=1&b=2
36+
--- response_body
37+
3
38+
--- error_log eval
39+
qr/\[TRACE\s+\d+ set_by_lua\(nginx\.conf:\d+\):4 loop\]/
40+
--- no_error_log
41+
[error]
42+
-- NYI: (?!return to lower frame)
43+
44+
45+
46+
=== TEST 2: ngx.arg getter in body_filter_by_lua
47+
--- config
48+
location = /t {
49+
echo hello;
50+
body_filter_by_lua_block {
51+
local arg = ngx.arg
52+
local eof
53+
local body = ""
54+
for i = 1, 30 do
55+
body = body .. arg[1]
56+
eof = arg[2]
57+
end
58+
}
59+
}
60+
--- request
61+
GET /t
62+
--- error_log eval
63+
qr/\[TRACE\s+\d+ body_filter_by_lua\(nginx\.conf:\d+\):5 loop\]/
64+
--- no_error_log
65+
[error]
66+
-- NYI: (?!return to lower frame)

0 commit comments

Comments
 (0)