Skip to content

Commit

Permalink
refactor(plugin): abstruct proxy cache related function to kong.tools (
Browse files Browse the repository at this point in the history
…#13458)

move proxy-cache plugin parse_directive_header and resource_ttl functions to kong tools for reuse in another plugin.

AG-91
  • Loading branch information
oowl authored Aug 7, 2024
1 parent f21fdb6 commit dd37fac
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 63 deletions.
67 changes: 4 additions & 63 deletions kong/plugins/proxy-cache/handler.lua
Original file line number Diff line number Diff line change
Expand Up @@ -10,22 +10,17 @@ local ngx = ngx
local kong = kong
local type = type
local pairs = pairs
local tostring = tostring
local tonumber = tonumber
local max = math.max
local floor = math.floor
local lower = string.lower
local concat = table.concat
local time = ngx.time
local resp_get_headers = ngx.resp and ngx.resp.get_headers
local ngx_re_gmatch = ngx.re.gmatch
local ngx_re_sub = ngx.re.gsub
local ngx_re_match = ngx.re.match
local parse_http_time = ngx.parse_http_time
local parse_mime_type = mime_type.parse_mime_type
local parse_directive_header = require("kong.tools.http").parse_directive_header
local calculate_resource_ttl = require("kong.tools.http").calculate_resource_ttl


local tab_new = require("table.new")


local STRATEGY_PATH = "kong.plugins.proxy-cache.strategies"
Expand Down Expand Up @@ -74,39 +69,6 @@ local function set_res_header(res, header, value, conf)
end
end

local function parse_directive_header(h)
if not h then
return EMPTY
end

if type(h) == "table" then
h = concat(h, ", ")
end

local t = {}
local res = tab_new(3, 0)
local iter = ngx_re_gmatch(h, "([^,]+)", "oj")

local m = iter()
while m do
local _, err = ngx_re_match(m[0], [[^\s*([^=]+)(?:=(.+))?]],
"oj", nil, res)
if err then
kong.log.err(err)
end

-- store the directive token as a numeric value if it looks like a number;
-- otherwise, store the string value. for directives without token, we just
-- set the key to true
t[lower(res[1])] = tonumber(res[2]) or res[2] or true

m = iter()
end

return t
end


local function req_cc()
return parse_directive_header(ngx.var.http_cache_control)
end
Expand All @@ -117,27 +79,6 @@ local function res_cc()
end


local function resource_ttl(res_cc)
local max_age = res_cc["s-maxage"] or res_cc["max-age"]

if not max_age then
local expires = ngx.var.sent_http_expires

-- if multiple Expires headers are present, last one wins
if type(expires) == "table" then
expires = expires[#expires]
end

local exp_time = parse_http_time(tostring(expires))
if exp_time then
max_age = exp_time - time()
end
end

return max_age and max(max_age, 0) or 0
end


local function cacheable_request(conf, cc)
-- TODO refactor these searches to O(1)
do
Expand Down Expand Up @@ -227,7 +168,7 @@ local function cacheable_response(conf, cc)
return false
end

if conf.cache_control and resource_ttl(cc) <= 0 then
if conf.cache_control and calculate_resource_ttl(cc) <= 0 then
return false
end

Expand Down Expand Up @@ -425,7 +366,7 @@ function ProxyCacheHandler:header_filter(conf)
if cacheable_response(conf, cc) then
-- TODO: should this use the kong.conf configured limit?
proxy_cache.res_headers = resp_get_headers(0, true)
proxy_cache.res_ttl = conf.cache_control and resource_ttl(cc) or conf.cache_ttl
proxy_cache.res_ttl = conf.cache_control and calculate_resource_ttl(cc) or conf.cache_ttl

else
set_header(conf, "X-Cache-Status", "Bypass")
Expand Down
67 changes: 67 additions & 0 deletions kong/tools/http.lua
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,15 @@ local re_match = ngx.re.match
local join = require("kong.tools.string").join
local split = require("kong.tools.string").split
local strip = require("kong.tools.string").strip
local parse_http_time = ngx.parse_http_time
local time = ngx.time
local ngx_re_gmatch = ngx.re.gmatch
local ngx_re_match = ngx.re.match
local lower = string.lower
local max = math.max
local tab_new = require("table.new")

local EMPTY = {}

local _M = {}

Expand Down Expand Up @@ -555,4 +563,63 @@ do
end
end

-- Parses a HTTP header value into a table of directives
-- eg: Cache-Control: public, max-age=3600
-- => { public = true, ["max-age"] = 3600 }
-- @param h (string) the header value to parse
-- @return table a table of directives
function _M.parse_directive_header(h)
if not h then
return EMPTY
end

if type(h) == "table" then
h = concat(h, ", ")
end

local t = {}
local res = tab_new(3, 0)
local iter = ngx_re_gmatch(h, "([^,]+)", "oj")

local m = iter()
while m do
local _, err = ngx_re_match(m[0], [[^\s*([^=]+)(?:=(.+))?]], "oj", nil, res)
if err then
kong.log.err(err)
end

-- store the directive token as a numeric value if it looks like a number;
-- otherwise, store the string value. for directives without token, we just
-- set the key to true
t[lower(res[1])] = tonumber(res[2]) or res[2] or true

m = iter()
end

return t
end

-- Calculates resource Time-To-Live (TTL) based on Cache-Control headers
-- @param res_cc (table) the Cache-Control headers, as parsed by `parse_directive_header`
-- @return number the TTL in seconds
function _M.calculate_resource_ttl(res_cc)
local max_age = res_cc and (res_cc["s-maxage"] or res_cc["max-age"])

if not max_age then
local expires = ngx.var.sent_http_expires

if type(expires) == "table" then
expires = expires[#expires]
end

local exp_time = parse_http_time(tostring(expires))
if exp_time then
max_age = exp_time - time()
end
end

return max_age and max(max_age, 0) or 0
end


return _M

1 comment on commit dd37fac

@github-actions
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bazel Build

Docker image available kong/kong:dd37facfa1682a443d0e2404ec63fadde816fcb3
Artifacts available https://github.com/Kong/kong/actions/runs/10280150323

Please sign in to comment.