HAProxy 对查询字符串的 URL 进行编码

HAProxy 对查询字符串的 URL 进行编码

我有一个系统需要在多次重定向中保留原始引用者。为了实现这一点,我尝试将引用者写入 URL 查询字符串。
我已经让它工作了(某种程度上)。

http-request set-query ref=%[req.hdr(Referer)]&%[query]

唯一的问题是查询字符串中的 URL 必须进行编码。不幸的是,HAProxy 只有一个 url_dec 函数。

有没有什么简单的方法可以对 URL 进行编码?

答案1

似乎没有内置此功能,但可以通过 HAProxy 1.6 及更高版本中的 Lua 集成轻松完成。

创建一个 Lua 文件,假设/etc/haproxy/lua/url_escape.lua

我在网上找到了一些 Lua 中 url 转义(“编码”)的示例,但粗略搜索后我发现它们似乎都不支持 UTF-8。因此,我写了以下内容:

function url_escape(str)
    local escape_next = 0;
    local escaped = str:gsub('.',function(char)
        local ord = char:byte(1);
        if(escape_next > 0) then
            escape_next = escape_next - 1;
        elseif(ord <= 127) then               -- single-byte utf-8
            if(char:match("[0-9a-zA-Z%-%._~]")) then -- only these do not get escaped
                return char;
            elseif char == ' ' then           -- also space, becomes '+'
                return '+';
            end;
        elseif(ord >= 192 and ord < 224) then -- utf-8 2-byte
            escape_next = 1;
        elseif(ord >= 224 and ord < 240) then -- utf-8 3-byte
            escape_next = 2;
        elseif(ord >= 240 and ord < 248) then -- utf-8 4-byte
            escape_next = 3;
        end;
        return string.format('%%%02X',ord);
    end);
    return escaped;
end;

core.register_converters('url_escape',url_escape);

配置 HAProxy 来加载此项,在以下global部分/etc/haproxy.cfg

global
    lua-load /etc/haproxy/lua/url_escape.lua

现在,您有一个名为的转换器,其工​​作方式与其他转换器一样——它在提供其输入的表达式的末尾lua.url_escape添加了一个。,

http-request set-query ref=%[req.hdr(Referer),lua.url_escape]&%[query]

测试:

curl -v http://example.com/my-page.html?lol=cat -H 'Referer: http://example.org/cats/Shrödinger.html'

后端看到的请求:

GET /my-page.html?ref=http%3A%2F%2Fexample.org%2Fcats%2FShr%C3%B6dinger.html&lol=cat HTTP/1.1
User-Agent: curl/7.35.0
Host: example.com
Accept: */*
Referer: http://example.org/cats/Shrödinger.html

Shrödinger此处正确转义,ö (U+00D6) 有两个字节Shr%C3%B6dinger。3 字节和 4 字节字符似乎也得到正确处理。高位开启的字节序列与有效的 UTF-8 字符不对应,也将被转义。

请注意,如果您使用 HAProxy 记录查询字符串,则修改后的查询永远不会被记录 - 原始请求才是真正进入日志输出的内容。

答案2

更新:

现在有一个内置转换器:https://www.haproxy.com/documentation/hapee/2-2r1/onepage/#url_enc

http-request您可以在如下指令中使用它:

http-request redirect location https://example.com/login?r=%[url,url_enc()] if !{ req.hdr(x-consumer-username) -m found }

在此示例中,最初请求的 URL 经过 URL 编码并添加到查询字符串中的 key 处r

原始答案:

HAProxy 的工作人员专门为这个用例写了一篇博客文章:

https://www.haproxy.com/blog/5-ways-to-extend-haproxy-with-lua/#converters

然而,在我看来这似乎是应该内置的东西。

相关内容