Skip to content

Commit

Permalink
fix(core): header regex for compat mode
Browse files Browse the repository at this point in the history
2 condtions:
1. only 1 header value presents
2. it starts with "~*"

Fixup #12365
Fix KAG-4788

Co-authored-by: Qi <[email protected]>
  • Loading branch information
StarlightIbuki and ADD-SP committed Jul 2, 2024
1 parent 1afd6c6 commit 619feef
Show file tree
Hide file tree
Showing 5 changed files with 43 additions and 27 deletions.
5 changes: 1 addition & 4 deletions kong/db/schema/entities/routes.lua
Original file line number Diff line number Diff line change
Expand Up @@ -196,10 +196,7 @@ local routes = {
},
},
},
values = {
type = "array",
elements = typedefs.regex_or_plain_pattern,
}
values = typedefs.header_regex_or_plain_pattern,
} },

{ regex_priority = { description = "A number used to choose which route resolves a given request when several routes match it using regexes simultaneously.", type = "integer", default = 0 }, },
Expand Down
25 changes: 15 additions & 10 deletions kong/db/schema/typedefs.lua
Original file line number Diff line number Diff line change
Expand Up @@ -504,14 +504,13 @@ end


local function is_valid_regex_pattern(pattern)
local regex = pattern:sub(2) -- remove the leading "~"
-- the value will be interpreted as a regex by the router; but is it a
-- valid one? Let's dry-run it with the same options as our router.
local _, _, err = ngx.re.find("", regex, "aj")
local _, _, err = ngx.re.find("", pattern, "a")
if err then
return nil,
string.format("invalid regex: '%s' (PCRE returned: %s)",
regex, err)
pattern, err)
end

return true
Expand All @@ -525,8 +524,9 @@ local function validate_path_with_regexes(path)
return ok, err, err_code
end

-- starts with `~`
if is_regex_pattern(path) then
return is_valid_regex_pattern(path)
return is_valid_regex_pattern(path:sub(2))
end

-- prefix matching. let's check if it's normalized form
Expand All @@ -539,12 +539,14 @@ local function validate_path_with_regexes(path)
end


local function validate_regex_or_plain_pattern(pattern)
if not is_regex_pattern(pattern) then
local function validate_header_regex_or_plain_pattern(patterns)
-- when there's only 1 pattern and it starts with "~*", it's a regex pattern
if #patterns ~= 1 or patterns[1]:sub(1, 2) ~= "~*" then
return true
end

return is_valid_regex_pattern(pattern)
-- starts with "~*"
return is_valid_regex_pattern(patterns[1]:sub(3))
end


Expand Down Expand Up @@ -646,9 +648,12 @@ typedefs.headers = Schema.define {
description = "A map of header names to arrays of header values."
}

typedefs.regex_or_plain_pattern = Schema.define {
type = "string",
custom_validator = validate_regex_or_plain_pattern,
typedefs.header_regex_or_plain_pattern = Schema.define {
type = "array",
elements = {
type = "string",
},
custom_validator = validate_header_regex_or_plain_pattern,
description = "A string representing a regex or plain pattern."
}

Expand Down
6 changes: 3 additions & 3 deletions kong/router/transform.lua
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,6 @@ local OP_IN = "in"


local DOT = byte(".")
local TILDE = byte("~")
local ASTERISK = byte("*")


Expand Down Expand Up @@ -424,12 +423,13 @@ local function get_expression(route)
for h, v in pairs(headers) do
single_header_buf:reset():put("(")

local num_v = #v
for i, value in ipairs(v) do
local name = "any(lower(http.headers." .. replace_dashes_lower(h) .. "))"
local op = OP_EQUAL

-- value starts with "~*"
if byte(value, 1) == TILDE and byte(value, 2) == ASTERISK then
-- the condition: only 1 value and it starts with `~*`
if num_v == 1 and is_regex_magic(value) then
value = value:sub(3)
op = OP_REGEX
end
Expand Down
3 changes: 2 additions & 1 deletion kong/router/utils.lua
Original file line number Diff line number Diff line change
Expand Up @@ -262,8 +262,9 @@ do
local get_phase = ngx.get_phase

local TILDE = byte("~")
local ASTERISK = byte("*")
is_regex_magic = function(path)
return byte(path) == TILDE
return byte(path) == TILDE and byte(path, 2) == ASTERISK
end

local empty_table = {}
Expand Down
31 changes: 22 additions & 9 deletions spec/01-unit/01-db/01-schema/06-routes_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -622,16 +622,29 @@ describe("routes schema (flavor = " .. flavor .. ")", function()
assert.equal("length must be at least 1", err.headers[1])
end)

it("value must be a plain pattern or a valid regex pattern", function()
local route = {
headers = { location = { "~[" } },
protocols = { "http" },
}
if flavor == "traditional_compatible" then
it("value must be a plain pattern or a valid regex pattern", function()
local route = {
headers = { location = { "~*[" } },
protocols = { "http" },
}

local ok, err = Routes:validate(route)
assert.falsy(ok)
assert.match("invalid regex", err.headers[1])
end)
local ok, err = Routes:validate(route)
assert.falsy(ok)
assert.match("invalid regex", err.headers)
end)

it("multiple patterns are treated as plain patterns", function()
local route = {
headers = { location = { "~*[", "~*" } },
protocols = { "http" },
}

local ok, err = Routes:validate(route)
assert.is_nil(err)
assert.truthy(ok)
end)
end
end)

describe("methods attribute", function()
Expand Down

0 comments on commit 619feef

Please sign in to comment.