Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support advanced matching based on post form #5409

Merged
merged 11 commits into from
Nov 9, 2021
14 changes: 14 additions & 0 deletions apisix/core/ctx.lua
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,20 @@ do
end
end

elseif core_str.has_prefix(key, "post_arg_") then
-- only match default post form
if request.header(nil, "Content-Type") == "application/x-www-form-urlencoded" then
bzp2010 marked this conversation as resolved.
Show resolved Hide resolved
local arg_key = sub_str(key, 10)
local args = request.get_post_args()[arg_key]
if args then
if type(args) == "table" then
val = args[1]
else
val = args
end
end
end

elseif core_str.has_prefix(key, "http_") then
key = key:lower()
key = re_gsub(key, "-", "_", "jo")
Expand Down
19 changes: 19 additions & 0 deletions apisix/core/request.lua
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ local io_open = io.open
local req_read_body = ngx.req.read_body
local req_get_body_data = ngx.req.get_body_data
local req_get_body_file = ngx.req.get_body_file
local req_get_post_args = ngx.req.get_post_args
local req_get_uri_args = ngx.req.get_uri_args
local req_set_uri_args = ngx.req.set_uri_args

Expand Down Expand Up @@ -150,6 +151,24 @@ function _M.set_uri_args(ctx, args)
end


function _M.get_post_args(ctx)
if not ctx then
ctx = ngx.ctx.api_ctx
end

if not ctx.req_post_args then
req_read_body()

-- use 0 to avoid truncated result and keep the behavior as the
-- same as other platforms
local args = req_get_post_args(0)
ctx.req_post_args = args
end

return ctx.req_post_args
end


local function get_file(file_name)
local f, err = io_open(file_name, 'r')
if not f then
Expand Down
5 changes: 3 additions & 2 deletions docs/en/latest/router-radixtree.md
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,8 @@ $ curl http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f
["cookie_device_id", "==", "a66f0cdc4ba2df8c096f74c9110163a9"],
["arg_name", "==", "json"],
["arg_age", ">", "18"],
["arg_address", "~~", "China.*"]
["arg_address", "~~", "China.*"],
["post_arg_name", "==", "json"]
],
"upstream": {
"type": "roundrobin",
Expand All @@ -216,7 +217,7 @@ $ curl http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f
}'
```

This route will require the request header `host` equal `iresty.com`, request cookie key `_device_id` equal `a66f0cdc4ba2df8c096f74c9110163a9` etc.
This route will require the request header `host` equal `iresty.com`, request cookie key `_device_id` equal `a66f0cdc4ba2df8c096f74c9110163a9` etc. And the POST form property match requires you to use `Content-Type: application/x-www-form-urlencoded` for the request to work properly.
bzp2010 marked this conversation as resolved.
Show resolved Hide resolved

### How to filter route by GraphQL attributes

Expand Down
5 changes: 3 additions & 2 deletions docs/zh/latest/router-radixtree.md
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,8 @@ $ curl http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f
["cookie_device_id", "==", "a66f0cdc4ba2df8c096f74c9110163a9"],
["arg_name", "==", "json"],
["arg_age", ">", "18"],
["arg_address", "~~", "China.*"]
["arg_address", "~~", "China.*"],
["post_arg_name", "==", "json"]
],
"upstream": {
"type": "roundrobin",
Expand All @@ -218,7 +219,7 @@ $ curl http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f
```

这个路由需要请求头 `host` 等于 `iresty.com` ,
请求 cookie `_device_id` 等于 `a66f0cdc4ba2df8c096f74c9110163a9` 等。
请求 cookie `_device_id` 等于 `a66f0cdc4ba2df8c096f74c9110163a9` 等。其中POST表单属性匹配需要您使用 Content-Type 为`application/x-www-form-urlencoded`的请求才可正常使用。

### 如何通过 GraphQL 属性过滤路由

Expand Down
76 changes: 76 additions & 0 deletions t/core/ctx2.t
Original file line number Diff line number Diff line change
Expand Up @@ -240,3 +240,79 @@ GET /hello
--- error_code: 404
--- response_body
{"error_msg":"404 Route Not Found"}



=== TEST 11: parsed post args is cached under ctx
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/routes/1',
ngx.HTTP_PUT,
[=[{
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
},
"plugins": {
"serverless-pre-function": {
"phase": "rewrite",
"functions" : ["return function(conf, ctx) ngx.log(ngx.WARN, 'find ctx.req_post_args.test: ', ctx.req_post_args.test ~= nil) end"]
}
},
"uri": "/hello",
"vars": [["post_arg_test", "==", "test"]]
}]=]
)

if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
--- no_error_log
[error]



=== TEST 12: hit
--- request
POST /hello
test=test
--- more_headers
Content-Type: application/x-www-form-urlencoded
--- response_body
hello world
--- error_log
find ctx.req_post_args.test: true



=== TEST 13: missed (post_arg_test is missing)
--- request
POST /hello
--- more_headers
Content-Type: application/x-www-form-urlencoded
--- error_code: 404
--- response_body
{"error_msg":"404 Route Not Found"}



=== TEST 14: missed (post_arg_test is mismatch)
--- request
POST /hello
test=tesy
--- more_headers
Content-Type: application/x-www-form-urlencoded
--- error_code: 404
--- response_body
{"error_msg":"404 Route Not Found"}
30 changes: 30 additions & 0 deletions t/core/request.t
Original file line number Diff line number Diff line change
Expand Up @@ -378,3 +378,33 @@ nil
t
--- no_error_log
[error]



=== TEST 11: get_post_args
--- config
location = /hello {
content_by_lua_block {
local core = require("apisix.core")
local ngx_ctx = ngx.ctx
local api_ctx = ngx_ctx.api_ctx
if api_ctx == nil then
api_ctx = core.tablepool.fetch("api_ctx", 0, 32)
ngx_ctx.api_ctx = api_ctx
end

core.ctx.set_vars_meta(api_ctx)

local args = core.request.get_post_args(ngx.ctx.api_ctx)
ngx.say(args["c"])
ngx.say(args["v"])
}
}
--- request
POST /hello
c=z_z&v=x%20x
--- response_body
z_z
x x
--- no_error_log
[error]
84 changes: 84 additions & 0 deletions t/node/vars.t
Original file line number Diff line number Diff line change
Expand Up @@ -299,3 +299,87 @@ GET /hello?k=uri_arg
hello world
--- no_error_log
[error]



=== TEST 17: set route(only post arg)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/routes/1',
ngx.HTTP_PUT,
[=[{
"uri": "/hello",
"vars": [["post_arg_k", "==", "post_form"]],
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
}
}]=]
)

if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
--- no_error_log
[error]



=== TEST 18: not_found (GET request)
--- request
GET /hello
--- error_code: 404
--- response_body
{"error_msg":"404 Route Not Found"}
--- no_error_log
[error]



=== TEST 19: not_found (wrong request body)
--- request
POST /hello
123
--- error_code: 404
--- response_body
{"error_msg":"404 Route Not Found"}
--- no_error_log
[error]



=== TEST 20: not_found (wrong content type)
--- request
POST /hello
k=post_form
--- more_headers
Content-Type: multipart/form-data
--- error_code: 404
--- response_body
{"error_msg":"404 Route Not Found"}
--- no_error_log
[error]



=== TEST 21: hit routes
--- request
POST /hello
k=post_form
--- more_headers
Content-Type: application/x-www-form-urlencoded
--- response_body
hello world
--- no_error_log
[error]