Сценарии
Общие сведения о Сценариях
Сценарии – это Lua-файлы, являющиеся дополнением к основным параметрам конфигурации Виртуальных Серверов.
Сценарии предназначены для:
-
выбора Сервера Балансировки: распределения клиентских запросов по нескольким Серверам Балансировки на основе данных в запросе;
-
изменения содержимого запросов (HTTPS/HTTPS);
-
ответа на запрос (HTTP/HTTPS);
-
прерывания нежелательного соединения.
В Сценариях можно определять условия выполнения того или иного действия логическими выражениями:
-
if; -
elseif; -
else; -
end.
Условиями для логических выражений могут быть любые данные, полученные из запроса, а также комбинация эти данных, например:
-
выражение для сравнения имени хоста из запроса с именем abc.ru для выполнения какого-либо действия:
if client.http_req.host == "abc.ru” then
-
выражение для сравнения имени хоста из запроса с именем abc.ru и принадлежностью к определенному IP-адресу:
if (client.http_req.host == "abc.ru” and client.remote_p.ip == "192.0.2.1")
Для работы с полученными данными можно использовать возможности языка программирования Lua. Примеры выражений для обработки запроса вида qwe.123.ru/abczxc:
-
выражение сравнения. Результатом будет
true:
if client.http_req.path == "/abcZxc"
-
выражение содержания определенного значения. Результатом будет
true:
if (client.http_req.path:find(”zx"))
-
выражение для получения определенной части строки. Результатом будет
qwe:
(client.http_req.host:match(”(.*).123.ru")
Обработка правил Сценария осуществляется через глобальную переменную client, которая содержит в себе ряд полей. Описание полей приведено в таблице (см. Описание полей структуры client).
Обработка правил Сценария останавливается после выражения: client.action = “xxx”.
|
| Поле | Тип поля | Описание | ||
|---|---|---|---|---|
|
Структура |
Содержит поля удаленной точки подключения, где:
|
||
|
Структура |
Содержит поля локальной точки подключения, аналогично |
||
|
Структура или |
Содержит поля HTTP-запроса или возвращает значение |
||
|
Структура |
Содержит поля для работы с HTTP-ответом (используется в Сценариях модификации ответов). Пример:
|
||
|
Строка |
Определяет имя Сервера Балансировки. Пример:
|
||
|
Целое |
Возвращает код ответа |
||
|
Строка |
Определяет действие:
|
||
|
Строка |
Возвращает статус Сервера Балансировки: |
||
|
Строка |
Возвращает данные Реального Сервера. Пример:
|
| Поле | Тип поля | Описание |
|---|---|---|
|
Целое |
Возвращает версию протокола HTTP: целое число, в котором младший десяток соответствует значению после точки, старший десяток - перед точкой. Поддерживаются версии: 1.0, 1.1. Пример: для HTTP/1.0 будет возвращен ответ: |
|
Строка |
Возвращает метод запроса (GET, POST, HEAD, DELETE, PATCH, PUT, OPTIONS, CONNECT, TRACE и др.). В примере ниже: |
|
Строка |
Возвращает путь запроса. В примере ниже: |
|
Строка |
Возвращает запрос. В примере ниже: |
|
Строка |
Возвращает полный путь запроса. В примере ниже: |
|
Строка |
Возвращает значение заголовка В примере ниже: |
|
Таблица (словарь) |
Возвращает все заголовки со значениями. В примере ниже:
|
|
Строка |
Возвращает тело HTTP-запроса |
Примеры из таблицы отражены в этом ответе на запрос к узлу termideskconnect по протоколу HTTP:
GET /termideskconnect?test=query HTTP/1.0
Host: connect.termidesk.ru
User-Agent: Mozilla Firefox/3.0.3
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Cookie: sessionid=100TC
Добавление Сценария
Добавление Сценария выполняется одним из способов:
-
из интерфейса командной строки Termidesk Connect;
-
из веб-интерфейса Termidesk Connect (см. подраздел Веб. Сценарии).
Пример команды с указанием порядка исполнения и имени файла Сценария:
set vs HTTP <имя> luarules 5 script test.lua
|
Файлы должны располагаться:
Порядковый номер определяет очередность выполнения файла Сценария: например, Сценарий с порядковым номером 10 будет исполнен раньше, чем Сценарий с порядковым номером 15. При этом правила в файлах Сценариев также обрабатываются по порядку:
Правила Сценария могут располагаться как в одном файле, так и в нескольких. |
Примеры Сценариев для изменения содержимого запросов
Пример 1. Если имя хоста содержит текст «abc» и запрос пришел из сети 192.0.2.0/24, то добавить заголовок «XFF: <IP-адрес_пользователя_при_подключении>», и перенаправить запрос на Сервер Балансировки «lb1».
Код:
if (client.http_req.host:find("abc") and client.remote_p:is_network("192.0.2.0/24")) then
client.http_req.header:field_set("XFF", client.remote_p.ip)
client.bs = "lb1"
client.action = "bs"
end
Результат:
WEB -- 03<p>Method GET</p><p>URL on server: /</p><p>REQ
Headers: </p>Host: abc.domain.ru
User-Agent: curl/7.81.0
Accept: */*
XFF: 192.0.2.5
Пример 2. Если имя хоста начинается с «abc», то добавить заголовок «XFF: <IP-адрес_пользователя_при_подключении>» и «Remote-port: <порт-источник_на_клиенте>», и перенаправить запрос на Сервер Балансировки «lb1».
Код:
function startswith(text, prefix)
return text:find(prefix, 1, true) == 1
end
if startswith(client.http_req.host, "abc") then
client.http_req.header:field_set("Remote-port", client.remote_p.port)
client.http_req.header:field_set("XFF", client.remote_p.ip)
client.bs = "lb1"
client.action = "bs"
end
Пример 3. Если путь запроса содержит «app», то при наличии заголовка X-Forwarded-For добавить IP-адрес клиента в конец запроса. Если заголовка не было в запросе, то добавить новый. Перенаправить запрос на Сервер Балансировки «lb1».
Код:
if client.http_req.path:find("abc") then
if client.http_req.header:field_count("X-Forwarded-For") > 0 then
xff, xffip = client.http_req.header:field_get("X-Forwarded-For")
client.http_req.header:field_set("X-Forwarded-For", xffip ..", "..client.remote_p.ip)
else
client.http_req.header:field_set("X-Forwarded-For", client.remote_p.ip)
end
client.bs = "lb1"
client.action = "bs"
end
Пример 4. Подменить домен «ru» на домен «local» (например, если запрос идет к app.domain.ru, то в сторону Реального Сервера должен прийти app.domain.local). В начале пути запроса добавить «/external» и перенаправить запрос на Сервер Балансировки «lb1».
Код:
client.http_req.host = client.http_req.host:match("(.*).ru") .. ".local"
client.http_req.path = "/external" .. client.http_req.path
client.bs = "lb1"
client.action = "bs"
Примеры Сценариев для ответа на запрос
Пример 1. Если метод не GET или не HEAD, то сбросить соединение.
Код:
if (client.http_req.method ~= "GET" and client.http_req.method ~= "HEAD") then
client.action = "drop"
end
Пример 2. Перенаправить соединение с HTTP на HTTPS.
Код:
client.respond.status = 302
client.respond.header["Location"] = "https://" .. client.http_req.host .. client.http_req.path
client.respond.header["Connection"] = "close"
client.action = "respond"
Пример 3. Если запрос из сети 192.0.2.0/24, то ответить HTML-страницей и параметрами запроса.
Код:
if client.remote_p:is_network("192.0.2.0/24") then
client.respond.header["Connection"] = "close"
client.respond.header["Content-type"] = 'text/html
client.respond.body = [[<html>
<body>
<meta charset="UTF-8">
<h1>Lets goodbye!</h1>
<p>Доступ запрещен</p>
</body>
</html>]] .. "IP: " .. client.remote_p.ip .. "\n TRY: " .. client.http_req.host .. client.http_req.path .. "\n" .. " Vserver: " .. client.local_p.ip .. ":" .. client.local_p.port
client.action = 'respond'
Примеры Сценариев для выбора Сервера Балансировки
Пример 1. Передача любого запроса на Сервер Балансировки «lb1».
Код:
client.bs = "lb1"
client.action = "bs"
Пример 2. Если имя хоста в запросе точно соответствует «abc.domain.ru», то направить запрос на Сервер Балансировки «lb1». В противном случае вернуть код ответа 403 (по умолчанию вернется ошибка 503).
Код:
if client.http_req.host == "abc.domain.ru" then
client.bs = "lb1"
client.action = "bs"
else
client.respond.status = 403
client.action = "respond"
end
Пример 3. Если имя хоста содержит текст «abc» и запрос пришел из сети 192.0.2.0/24, то вернуть Сервер Балансировки «lb1». В противном случае вернуть код ответа 403 (по умолчанию вернется ошибка 503).
Код:
if (client.http_req.host:find("abc") and client.remote_p:is_network("192.0.2.0/24"))
then
client.bs = "lb1"
client.action = "bs"
else
client.respond.status = 403
client.action = "respond"
end
Пример 4. Если путь содержит:
-
«red», то вернуть Сервер Балансировки «lb1»;
-
«green», то вернуть Сервер Балансировки «lb2».
Если не сработало ни одно из условий выше, то вернуть Сервер Балансировки «lb-default».
Код:
if client.http_req.path:find("red") then
client.bs = "lb1"
client.action = "bs"
elseif client.http_req.path:find("green") then
client.bs = "lb2"
client.action = "bs"
else
client.bs = "lb-default"
client.action = "bs"
end