Removing a single header amongst others with the same name

719 views
Skip to first unread message

Marcus Bointon

unread,
Apr 2, 2021, 5:17:06 AM4/2/21
to openresty-en
I'm trying to use lua in nginx config using a header_filter_by_lua_block directive to unset some headers, specifically I want to strip all Set-Cookie response headers that contain an Expires value.

I can use

    local h = ngx.resp.get_headers()["Set-Cookie"]

to get hold of all the cookie headers, but then I need to inspect their value to see if I need to remove them (i.e. whether the value contains "Expires").

Having found one, I can't see how to clear only that single header with a given name, when there may be multiple instances with different values. If I say

    ngx.header["Set-Cookie"] = nil

It will clear *all* set-cookie headers. So how can I clear just one of them? In other languages I'd do something like get the header array indexed by integer, then iterate over it backwards (so removing values doesn't mess up indexing), deleting values as I go – how would I do that in Lua?

Kshitij Joshi

unread,
Apr 2, 2021, 3:08:07 PM4/2/21
to openre...@googlegroups.com
You can do it by following in your header_filter_by_lua_block

local function setCookies(cookieValue)
local val = cookieValue:lower()
if string.match(val, "expires") then
return nil
else
return cookieValue
end
end

local rh = ngx.resp.get_headers()
for k, v in pairs(rh) do
if k:lower() == "set-cookie" then
if (type(v) == "table") then
-- checks if there are multiple Set-Cookie Headers
for key, value in pairs(v) do
ngx.header["Set-Cookie"] = setCookies(value)
end
else
ngx.header["Set-Cookie"] = setCookies(v)
end
end
end


--
You received this message because you are subscribed to the Google Groups "openresty-en" group.
To unsubscribe from this group and stop receiving emails from it, send an email to openresty-en...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/openresty-en/53097b39-8b0a-457e-859a-801e1f27ab34n%40googlegroups.com.


--
Regards,
Kshitij Joshi.

Kshitij Joshi

unread,
Apr 2, 2021, 3:22:19 PM4/2/21
to openre...@googlegroups.com
Sorry, I see what you meant before.

Found an answer here

You can use something like

local cookieHelper = require "resty.cookie"
local rh = ngx.resp.get_headers()

for k, v in pairs(rh) do
if k:lower() == "set-cookie" then
        local cookie, err = cookieHelper:new()

if (type(v) == "table") then
-- checks if there are multiple Set-Cookie Headers
for key, value in pairs(v) do
                if string.match(value, "expires") then
ngx.header["Set-Cookie"] = nil
else
cookie:set({key = value:match("([^=]+)"), value = value, path = "/"})
end
end
else
if string.match(v, "expires") then
ngx.header["Set-Cookie"] = nil
else
cookie:set({key = value:match("([^=]+)"), value = v, path = "/"})
end
end
end
end
--
Regards,
Kshitij Joshi.

Marcus Bointon

unread,
Apr 3, 2021, 4:11:44 AM4/3/21
to openre...@googlegroups.com


Sent from my iPhone

On 2 Apr 2021, at 21:22, Kshitij Joshi <kshiti...@gmail.com> wrote:

ngx.header["Set-Cookie"] = nil

Why would that line not delete all set-cookie headers, as it would outside the loop?

Kshitij Joshi

unread,
Apr 3, 2021, 6:45:29 AM4/3/21
to openre...@googlegroups.com
I believe it deletes all the headers. You don't need to keep it in the loop.
The Cookie module is seeing the headers as expected though

--
You received this message because you are subscribed to the Google Groups "openresty-en" group.
To unsubscribe from this group and stop receiving emails from it, send an email to openresty-en...@googlegroups.com.

Marcus Bointon

unread,
Apr 3, 2021, 6:22:08 PM4/3/21
to openresty-en
Thanks. I can see that this module has lots of useful cookie-related things. I managed to install it (it's in Ubuntu as `lua-resty-cookie`), and figure out how to set the path to the package, and it's loading and running, however, it's logging this error and the site is dead:

2021/04/03 21:59:44 [error] 3346854#3346854: *16906 failed to run header_filter_by_lua*: header_filter_by_lua:7: attempt to index local 'cookieHelper' (a boolean value)

I'm guessing this is some kind of instantiation issue, but I have no idea beyond that.

Kshitij Joshi

unread,
Apr 3, 2021, 6:29:14 PM4/3/21
to openre...@googlegroups.com
I had just copied the lua file in my library and imported it as cookie helper.

If you have installed the module you don't need the initial import statement. 

Marcus Bointon

unread,
Apr 3, 2021, 6:42:13 PM4/3/21
to openresty-en
I'm confused by that. Without the cookie.lua in my lua_package_path, it failed – isn't putting a file in that location the same thing as installing it? If I delete that `require` line, cookieHelper is undefined.

Can you say exactly what you mean when you say you copied it into your library – where is that usually? There seems to be some convention where some (not all!) dots in a filename are converted to path separators, so "resty.cookie" will be looked for as `resty/cookie.lua`.

I don't know that I have an installed modules folder. I found one thing that looks like a library called `re.lua` in /usr/share/lua/5.1 and 5.3 (I don't know which version I'm using), but I've no idea how to tell whether that location is were things will be looked for by default - given that it doesn't work without a lua_package_path set in nginx, I assume not. nginx is bad about giving feedback on its own config – there's no equivalent of `apache2ctl -S` or `phpinfo()`.

Kshitij Joshi

unread,
Apr 3, 2021, 10:02:38 PM4/3/21
to openre...@googlegroups.com
So I'm running OpenResty as Docker Container based on 

On top of this Dockerfile, I have 

COPY conf /usr/local/openresty/nginx/conf -> my .conf files
COPY lib/ /usr/local/openresty/lualib/ -> my internal lua files
COPY externals /usr/local/openresty/lualib/resty/ -> my external lua files (modules)
CMD ["/usr/bin/openresty", "-g", "daemon off;"]
So any external Lua module I need to import I can just copy it in my "externals" folder.
And when my Docker image builds, it copies them to the resty folder.
And I can import it using 

local cookieHelper = require "resty.cookie"

So this import statement you might have to tweak based on your OpenResty Setup.
If you can show your setup, maybe I can help you.



--
Regards,
Kshitij Joshi.

Marcus Bointon

unread,
Apr 4, 2021, 10:07:31 AM4/4/21
to openresty-en
I don't really have any setup to speak of. I'm not running openresty specifically, I just enabled the lua extension for nginx. There seems to be some system default location set up in /usr/share/lua, and when I installed lua-nginx-cookie it installed the file in /usr/share/lua/5.1/nginx/cookie.lua. nginx doesn't appear to be configured to look in there by default, so I needed to add a lua_package_path directive to my nginx config pointing there.

I changed the `require` to point at "nginx.cookie", and it seems to be finding the file in /usr/share/lua/5.1/nginx/cookie.lua. I assume that the error about the boolean was due to the require failing and it returning a boolean false instead of loading the file. Is thre no way to make this a fatal error, like the difference between include and require in PHP? This loading pattern seems very random – is there no established standard for package paths in lua?

It now seems to be partly working in that it appears to strip cookies, but that includes session ones too. I've found that WordPress does set an expiry on login cookies, so a better approach might be to remove the "expires" from the cookies, turning them all into session cookies.

I think I've got enough to go on now, so thanks for your help.
Reply all
Reply to author
Forward
0 new messages