Skip to content

Commit

Permalink
feat(router) add header regex matching method (#6079)
Browse files Browse the repository at this point in the history
Co-authored-by: Enrique García Cota <kikito@gmail.com>
  • Loading branch information
vanhtuan0409 and kikito authored Feb 10, 2022
1 parent a2d249e commit d12991f
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 1 deletion.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,9 @@
- Customizable transparent dynamic TLS SNI name.
Thanks, [@zhangshuaiNB](https://github.com/zhangshuaiNB)!
[#8196](https://github.com/Kong/kong/pull/8196)
- Routes now support matching headers with regular expressions
Thanks, [@vanhtuan0409](https://github.com/vanhtuan0409)!
[#6079](https://github.com/Kong/kong/pull/6079)

#### Performance

Expand Down
22 changes: 21 additions & 1 deletion kong/router.lua
Original file line number Diff line number Diff line change
Expand Up @@ -462,13 +462,22 @@ local function marshall_route(r)

if header_name ~= "host" then
local header_values_map = {}
for i = 1, #header_values do
local header_values_count = #header_values
for i = 1, header_values_count do
header_values_map[lower(header_values[i])] = true
end
local header_pattern
if header_values_count == 1 then
local first_header = header_values[1]
if sub(first_header, 1, 2) == "~*" then
header_pattern = sub(first_header, 3)
end
end

append(headers_t, {
name = header_name,
values_map = header_values_map,
header_pattern = header_pattern,
})
end
end
Expand Down Expand Up @@ -1033,6 +1042,12 @@ do
matches_headers[header_t.name] = req_header_val
break
end
-- fallback to regex check if exact match failed
if header_t.header_pattern and re_find(req_header_val, header_t.header_pattern) then
found_in_req = true
ctx.matches.headers[header_t.name] = req_header_val
break
end
end

elseif req_header then -- string
Expand All @@ -1041,6 +1056,11 @@ do
found_in_req = true
matches_headers[header_t.name] = req_header
end
-- fallback to regex check if exact match failed
if header_t.header_pattern and re_find(req_header, header_t.header_pattern) then
found_in_req = true
ctx.matches.headers[header_t.name] = req_header
end
end

if not found_in_req then
Expand Down
21 changes: 21 additions & 0 deletions spec/01-unit/08-router_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,17 @@ local use_case = {
},
},
},
-- 15. headers (regex)
{
service = service,
route = {
headers = {
user_agent = {
"~*windows|linux|os\\s+x\\s*[\\d\\._]+|solaris|bsd",
},
},
},
},
}

describe("Router", function()
Expand Down Expand Up @@ -451,6 +462,16 @@ describe("Router", function()
location = { "my-location-3", "foo" }
})
assert.is_nil(match_t)

local match_t = router.select("GET", "/", nil, "http", nil, nil, nil, nil, nil, {
user_agent = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36"
})
assert.truthy(match_t)
assert.same(use_case[15].route, match_t.route)
assert.same(nil, match_t.matches.method)
assert.same(nil, match_t.matches.uri)
assert.same(nil, match_t.matches.uri_captures)
assert.same({ user_agent = "mozilla/5.0 (x11; linux x86_64) applewebkit/537.36 (khtml, like gecko) chrome/83.0.4103.116 safari/537.36" }, match_t.matches.headers)
end)

it("multiple [headers] values", function()
Expand Down

0 comments on commit d12991f

Please sign in to comment.