Skip to content

Commit 6ba726c

Browse files
authored
feature: add a priority field to match routes with the same path in t… (#35)
* feature: add a priority field to match routes with the same path in the order of priority. Fix #31. * feature: supported priority for prefix matching. * doc.
1 parent daa22b9 commit 6ba726c

File tree

4 files changed

+132
-2
lines changed

4 files changed

+132
-2
lines changed

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ This is Lua-Openresty implementation library base on FFI for [rax](https://githu
77

88
This project depends on [lua-resty-ipmatcher](https://github.com/iresty/lua-resty-ipmatcher).
99

10-
This project has been working in projects microservices API gateway [Apache APISIX](https://github.com/apache/incubator-apisix).
10+
This project has been working in microservices API gateway [Apache APISIX](https://github.com/apache/incubator-apisix).
1111

1212
The project is open sourced by Shenzhen [ZhiLiu](https://www.iresty.com/) Technology Company. In addition to this open source version, our company also provides a more powerful and performing commercial version, and provides technical support. If you are interested in our commercial version, please contact us. email: [[email protected]]([email protected]) .
1313

@@ -83,6 +83,7 @@ The attributes of each element may contain these:
8383
|methods |option |A list of method name. Here is full valid method list: "GET", "POST", "PUT", "DELETE", "PATCH", "HEAD", "OPTIONS", "CONNECT" and "TRACE".|{"GET", "POST"}|
8484
|vars |option |A list of `{var, operator, val}`. For example: {{var, operator, val}, {var, operator, val}, ...}, `{"arg_name", "==", "json"}` means the value of argument `name` expect to `json`. Here is the full [Operator List](#operator-list).|{{"arg_name", "==", "json"}, {"arg_age", ">", 18}}|
8585
|filter_fun |option |User defined filter function, We can use it to achieve matching logic for special scenes. `radixtree` will pass `vars` and other arguments when matching route.|function(vars) return vars["arg_name"] == "json" end|
86+
|priority |option |Routing priority, default is 0.|priority = 100|
8687
|metadata |option |Will return this field if using `rx:match` to match route.||
8788
|handler |option |Will call this function using `rx:dispatch` to match route.||
8889

lib/resty/radixtree.lua

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ local cur_level = ngx.config.subsystem == "http" and
2525
require("ngx.errlog").get_sys_filter_level()
2626
local ngx_var = ngx.var
2727
local re_find = ngx.re.find
28+
local sort_tab = table.sort
2829
local empty_table = {}
2930

3031

@@ -98,7 +99,7 @@ for i, name in ipairs({"GET", "POST", "PUT", "DELETE", "PATCH", "HEAD",
9899
end
99100

100101

101-
local _M = { _VERSION = 0.02 }
102+
local _M = { _VERSION = 1.7 }
102103

103104

104105
-- only work under lua51 or luajit
@@ -133,6 +134,11 @@ end
133134
local mt = { __index = _M, __gc = gc_free }
134135

135136

137+
local function sort_route(route_a, route_b)
138+
return (route_a.priority or 0) > (route_b.priority or 0)
139+
end
140+
141+
136142
local function insert_route(self, opts)
137143
local path = opts.path
138144
opts = clone_tab(opts)
@@ -146,6 +152,7 @@ local function insert_route(self, opts)
146152
insert_tab(self.hash_path[path], opts)
147153
end
148154

155+
sort_tab(self.hash_path[path], sort_route)
149156
return true
150157
end
151158

@@ -156,6 +163,7 @@ local function insert_route(self, opts)
156163
local routes = self.match_data[idx]
157164
if routes and routes[1].path == path then
158165
insert_tab(routes, opts)
166+
sort_tab(routes, sort_route)
159167
return true
160168
end
161169
end
@@ -286,6 +294,7 @@ function pre_insert_route(self, path, route)
286294
route_opts.method = bit_methods
287295
route_opts.vars = route.vars
288296
route_opts.filter_fun = route.filter_fun
297+
route_opts.priority = route.priority or 0
289298

290299
local err
291300
local remote_addrs = route.remote_addrs

t/path.t

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ nil
6969
nil
7070
7171
72+
7273
=== TEST 3: multiple path with overlap
7374
--- config
7475
location /t {

t/priority.t

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
use t::RX 'no_plan';
2+
3+
repeat_each(1);
4+
run_tests();
5+
6+
__DATA__
7+
8+
=== TEST 1: multiple route (same priority)
9+
--- config
10+
location /t {
11+
content_by_lua_block {
12+
local radix = require("resty.radixtree")
13+
local rx = radix.new({
14+
{
15+
paths = {"/aa"},
16+
metadata = "metadata 1",
17+
},
18+
{
19+
paths = {"/aa"},
20+
metadata = "metadata 2",
21+
},
22+
})
23+
24+
ngx.say(rx:match("/aa"))
25+
}
26+
}
27+
--- request
28+
GET /t
29+
--- no_error_log
30+
[error]
31+
--- response_body
32+
metadata 1
33+
34+
35+
36+
=== TEST 2: multiple route (different priority)
37+
--- config
38+
location /t {
39+
content_by_lua_block {
40+
local radix = require("resty.radixtree")
41+
local rx = radix.new({
42+
{
43+
paths = {"/aa"},
44+
metadata = "metadata 1",
45+
priority = 1,
46+
},
47+
{
48+
paths = {"/aa"},
49+
metadata = "metadata 2",
50+
priority = 2,
51+
},
52+
})
53+
54+
ngx.say(rx:match("/aa"))
55+
}
56+
}
57+
--- request
58+
GET /t
59+
--- no_error_log
60+
[error]
61+
--- response_body
62+
metadata 2
63+
64+
65+
66+
=== TEST 3: multiple route (same priority)
67+
--- config
68+
location /t {
69+
content_by_lua_block {
70+
local radix = require("resty.radixtree")
71+
local rx = radix.new({
72+
{
73+
paths = {"/aa*"},
74+
metadata = "metadata 1",
75+
},
76+
{
77+
paths = {"/aa*"},
78+
metadata = "metadata 2",
79+
},
80+
})
81+
82+
ngx.say(rx:match("/aa/bb"))
83+
}
84+
}
85+
--- request
86+
GET /t
87+
--- no_error_log
88+
[error]
89+
--- response_body
90+
metadata 1
91+
92+
93+
94+
=== TEST 4: multiple route (different priority)
95+
--- config
96+
location /t {
97+
content_by_lua_block {
98+
local radix = require("resty.radixtree")
99+
local rx = radix.new({
100+
{
101+
paths = {"/aa*"},
102+
metadata = "metadata 1",
103+
},
104+
{
105+
paths = {"/aa*"},
106+
metadata = "metadata 2",
107+
priority = 1,
108+
},
109+
})
110+
111+
ngx.say(rx:match("/aa/bb"))
112+
}
113+
}
114+
--- request
115+
GET /t
116+
--- no_error_log
117+
[error]
118+
--- response_body
119+
metadata 2

0 commit comments

Comments
 (0)