diff --git a/CHANGELOG.md b/CHANGELOG.md index 38864293e79..7edc720dda9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -82,6 +82,8 @@ - **ACME**: acme plugin now supports configuring an `account_key` in `keys` and `key_sets` [#9746](https://github.com/Kong/kong/pull/9746) +- **Proxy-Cache**: add `ignore_uri_case` to configuring cache-key uri to be handled as lowercase + [#10453](https://github.com/Kong/kong/pull/10453) ### Fixes diff --git a/kong/clustering/compat/removed_fields.lua b/kong/clustering/compat/removed_fields.lua index dcdca39cd1b..f68912597f1 100644 --- a/kong/clustering/compat/removed_fields.lua +++ b/kong/clustering/compat/removed_fields.lua @@ -59,6 +59,9 @@ return { [3003000000] = { acme = { "account_key", + }, + proxy_cache = { + "ignore_uri_case", } }, } diff --git a/kong/plugins/proxy-cache/handler.lua b/kong/plugins/proxy-cache/handler.lua index af99c394caa..51f057057e8 100644 --- a/kong/plugins/proxy-cache/handler.lua +++ b/kong/plugins/proxy-cache/handler.lua @@ -287,6 +287,12 @@ function ProxyCacheHandler:access(conf) local consumer = kong.client.get_consumer() local route = kong.router.get_route() local uri = ngx_re_sub(ngx.var.request, "\\?.*", "", "oj") + + -- if we want the cache-key uri only to be lowercase + if conf.ignore_uri_case then + uri = lower(uri) + end + local cache_key, err = cache_key.build_cache_key(consumer and consumer.id, route and route.id, kong.request.get_method(), diff --git a/kong/plugins/proxy-cache/schema.lua b/kong/plugins/proxy-cache/schema.lua index 69416012218..56a645a4dad 100644 --- a/kong/plugins/proxy-cache/schema.lua +++ b/kong/plugins/proxy-cache/schema.lua @@ -58,6 +58,11 @@ return { default = false, required = true, }}, + { ignore_uri_case = { + type = "boolean", + default = false, + required = false, + }}, { storage_ttl = { type = "integer", }}, diff --git a/spec/03-plugins/31-proxy-cache/02-access_spec.lua b/spec/03-plugins/31-proxy-cache/02-access_spec.lua index e0e7f27ac78..5716a6ea458 100644 --- a/spec/03-plugins/31-proxy-cache/02-access_spec.lua +++ b/spec/03-plugins/31-proxy-cache/02-access_spec.lua @@ -71,21 +71,27 @@ do local route14 = assert(bp.routes:insert { hosts = { "route-14.com" }, }) - local route15 = assert(bp.routes:insert({ + local route15 = assert(bp.routes:insert { hosts = { "route-15.com" }, - })) - local route16 = assert(bp.routes:insert({ + }) + local route16 = assert(bp.routes:insert { hosts = { "route-16.com" }, - })) - local route17 = assert(bp.routes:insert({ + }) + local route17 = assert(bp.routes:insert { hosts = { "route-17.com" }, - })) - local route18 = assert(bp.routes:insert({ + }) + local route18 = assert(bp.routes:insert { hosts = { "route-18.com" }, - })) - local route19 = assert(bp.routes:insert({ + }) + local route19 = assert(bp.routes:insert { hosts = { "route-19.com" }, - })) + }) + local route20 = assert(bp.routes:insert { + hosts = { "route-20.com" }, + }) + local route21 = assert(bp.routes:insert { + hosts = { "route-21.com" }, + }) local consumer1 = assert(bp.consumers:insert { @@ -282,6 +288,30 @@ do }, }) + assert(bp.plugins:insert { + name = "proxy-cache", + route = { id = route20.id }, + config = { + strategy = policy, + response_code = {404}, + ignore_uri_case = true, + content_type = { "text/plain", "application/json" }, + [policy] = policy_config, + }, + }) + + assert(bp.plugins:insert { + name = "proxy-cache", + route = { id = route21.id }, + config = { + strategy = policy, + response_code = {404}, + ignore_uri_case = false, + content_type = { "text/plain", "application/json" }, + [policy] = policy_config, + }, + }) + assert(helpers.start_kong({ plugins = "bundled", nginx_conf = "spec/fixtures/custom_nginx.template", @@ -1346,5 +1376,69 @@ do assert.same("Bypass", res.headers["X-Cache-Status"]) end) end) + + it("ignore uri case in cache_key", function() + local res = assert(client:send { + method = "GET", + path = "/ignore-case/kong", + headers = { + host = "route-20.com", + }, + }) + + local body1 = assert.res_status(404, res) + assert.same("Miss", res.headers["X-Cache-Status"]) + + local cache_key1 = res.headers["X-Cache-Key"] + assert.matches("^[%w%d]+$", cache_key1) + assert.equals(64, #cache_key1) + + local res = client:send { + method = "GET", + path = "/ignore-case/KONG", + headers = { + host = "route-20.com", + }, + } + + local body2 = assert.res_status(404, res) + assert.same("Hit", res.headers["X-Cache-Status"]) + local cache_key2 = res.headers["X-Cache-Key"] + assert.same(cache_key1, cache_key2) + + assert.same(body1, body2) + end) + + it("acknowledge uri case in cache_key", function() + local res = assert(client:send { + method = "GET", + path = "/acknowledge-case/kong", + headers = { + host = "route-21.com", + }, + }) + + assert.res_status(404, res) + local x_cache_status = assert.response(res).has_header("X-Cache-Status") + assert.same("Miss", x_cache_status) + + local cache_key1 = res.headers["X-Cache-Key"] + assert.matches("^[%w%d]+$", cache_key1) + assert.equals(64, #cache_key1) + + res = assert(client:send { + method = "GET", + path = "/acknowledge-case/KONG", + headers = { + host = "route-21.com", + }, + }) + + x_cache_status = assert.response(res).has_header("X-Cache-Status") + local cache_key2 = assert.response(res).has_header("X-Cache-Key") + assert.same("Miss", x_cache_status) + assert.not_same(cache_key1, cache_key2) + end) + end) end