Назад | Перейти на главную страницу

HAProxy кодирует URL-адрес для строки запроса

У меня есть система, которая должна сохранять исходный реферер при нескольких перенаправлениях. Чтобы добиться этого, я пытаюсь написать ссылку на строку запроса URL.
У меня это уже работает (в некоторой степени).

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

Единственная проблема заключается в том, что URL-адреса в строке запроса должны быть закодированы. К сожалению, у HAProxy есть только функция url_dec.

Есть ли простой способ кодирования URL-адреса?

Похоже, что для этого нет встроенной функции, но это легко сделать с помощью интеграции Lua в HAProxy 1.6 и новее.

Создайте файл Lua, скажем /etc/haproxy/lua/url_escape.lua.

Я нашел в Интернете несколько примеров экранирования URL-адресов ("кодирования") в Lua, но ни один из них, который я обнаружил при беглом поиске, не был совместим с 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, измененный запрос никогда не регистрируется - исходный запрос - это то, что попадает в журнал.