From 49493d035cd6c1bb020ab4fc065165113f519ef2 Mon Sep 17 00:00:00 2001 From: Thibault Charbonnier Date: Fri, 30 Jun 2017 02:32:32 +0200 Subject: [PATCH] fix(router) do not match another API with a longer URI When matching URIs, we iterate over a list of APIs, and not a list of URIs (for various, performance reasons, although a refactor of the router is scheduled with some performance improvements later on). This list of APIs is sorted per URI length. But an API can have more than one URI. As such, the router can potentially evaluate an API with a very long URI, and a much shorter one that matches the request URI, instead of a following API which would be an exact match for that API. To fix this, we sort our deserialized list of URIs to iterate on in the select method, and if we do have a match, we conserve the URI that was matched, to check if it belongs to the right API at API match time. Fix #2662 --- kong/core/router.lua | 5 +++++ spec/01-unit/010-router_spec.lua | 19 +++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/kong/core/router.lua b/kong/core/router.lua index a08fd815c363..e5ac8fe5b9f5 100644 --- a/kong/core/router.lua +++ b/kong/core/router.lua @@ -467,6 +467,9 @@ function _M.new(apis) return max_uri_a > max_uri_b end + table.sort(uris_prefixes, function(a, b) + return #a > #b + end) for category_bit, category in pairs(categories) do table.sort(category.apis, function(a, b) @@ -572,6 +575,8 @@ function _M.new(apis) end if from then + -- strip \Q...\E tokens + uri = sub(uris_prefixes[i], 3, -3) req_category = bor(req_category, MATCH_RULES.URI) break end diff --git a/spec/01-unit/010-router_spec.lua b/spec/01-unit/010-router_spec.lua index 9a854ba1c17f..1a3107410231 100644 --- a/spec/01-unit/010-router_spec.lua +++ b/spec/01-unit/010-router_spec.lua @@ -605,6 +605,25 @@ describe("Router", function() assert.same(use_case[#use_case], api_t.api) end) end) + + it("does not incorrectly match another API which has a longer [uri]", function() + local use_case = { + { + name = "api-1", + uris = { "/a", "/bbbbbbb" } + }, + { + name = "api-2", + uris = { "/a/bb" } + }, + } + + local router = assert(Router.new(use_case)) + + local api_t = router.select("GET", "/a/bb/foobar") + assert.truthy(api_t) + assert.same(use_case[2], api_t.api) + end) end) describe("misses", function()