local rawget, rawset, setmetatable = rawget, rawset, setmetatable local str_find, str_lower, str_sub = string.find, string.lower, string.sub local _M = { _VERSION = '0.10', } local function hyphenate(k) local k_hyphened = "" local match = false local prev_pos = 0 repeat local pos = str_find(k, "_", prev_pos, true) if pos then match = true k_hyphened = k_hyphened .. str_sub(k, prev_pos, pos - 1) .. "-" elseif match == false then -- Didn't find an underscore and first check return k else -- No more underscores, append the rest of the key k_hyphened = k_hyphened .. str_sub(k, prev_pos) break end prev_pos = pos + 1 until not pos return k_hyphened end -- Returns an empty headers table with internalised case normalisation. -- Supports the same cases as in ngx_lua: -- -- headers.content_length -- headers["content-length"] -- headers["Content-Length"] function _M.new(self) local mt = { normalised = {}, } mt.__index = function(t, k) local k_hyphened = hyphenate(k) local k_normalised = str_lower(k_hyphened) return rawget(t, mt.normalised[k_normalised]) end -- First check the normalised table. If there's no match (first time) add an entry for -- our current case in the normalised table. This is to preserve the human (prettier) case -- instead of outputting lowercased header names. -- -- If there's a match, we're being updated, just with a different case for the key. We use -- the normalised table to give us the original key, and perorm a rawset(). mt.__newindex = function(t, k, v) -- we support underscore syntax, so always hyphenate. local k_hyphened = hyphenate(k) -- lowercase hyphenated is "normalised" local k_normalised = str_lower(k_hyphened) if not mt.normalised[k_normalised] then mt.normalised[k_normalised] = k_hyphened rawset(t, k_hyphened, v) else rawset(t, mt.normalised[k_normalised], v) end end return setmetatable({}, mt) end return _M