Erlang: функции работают в оболочке, но не в YAWS - PullRequest
1 голос
/ 12 апреля 2020

Мой единственный метод отладки (io:format/2) не работает в Y AWS. Я в недоумении. Мой руководитель запускает три процесса: ETS Manager, Y AWS Init и Ratelimiter. Это успешно. Я могу поиграть с ограничителем скорости в оболочке ... вызывая те же функции, Y AWS должно быть. Разница в том, что оболочка ведет себя так, как я ожидал, и я понятия не имею, что происходит в Y AWS.

Я знаю, если я спамю команду в оболочке: ratelimiter:limit(IP) она вернет true в конце концов. Я могу выполнить следующее, и он также вернет true: ratelimiter:lockout(IP), ratelimiter:blacklist(IP). Ограничителем является gen_server.

Функции выполняют следующее:

  • limit/1: проверьте таблицу ETS, если счетчик> порог; счетчик обновлений. Если счетчик> порог черного списка, сделайте запись в таблице мнезий
  • blacklist/1: проверьте таблицу мнезий, если запись существует; Да: сброс таймера
  • lockout/1: немедленно вводит ID в таблицу мнезийных сообщений

В моем модуле arg_rewrite_mod я делаю некоторые проверки, чтобы убедиться, что я получаю запросы HTTP Я ожидаю, а именно GET, POST и HEAD. Я думал, что это было бы хорошим местом, чтобы также сделать ограничение скорости. Сделайте это как можно скорее в цепочке событий веб-сервера.

Кажется, что все изменения, которые я внес в модуль arg_rewrite, работают, за исключением использования "printf" и ограничителя. Я плохо знаком с языком, поэтому я не уверен, что моя ошибка очевидна или нет.

Скелет моего arg_rewrite_mod:

-module(arg_preproc).
-export([arg_rewrite/1]).

-include("limiter_def.hrl").
-include_lib("/usr/lib/yaws/include/yaws_api.hrl").


is_blacklisted(ID) ->
    case ratelimiter:blacklist(ID) of
    false ->    continue;
    true ->     throw(blacklist)
    end.

is_limited(ID) ->
    case ratelimiter:limit(ID) of
    false ->    continue;
    true ->     throw(limit)
    end.


arg_rewrite(A) ->
    Allow = ['GET','POST', 'HEAD'],

    try
        {IP, _} = A#arg.client_ip_port,

        ID = IP,
        is_blacklisted(ID),

io:format("~p ~p ~n",[ID, is_blacklisted(ID)]),         

        %% === Allow expected HTTP requests
        HttpReq = (A#arg.req)#http_request.method,

        case lists:member(HttpReq, Allow) of
            true ->
                {_,ReqTgt} = (A#arg.req)#http_request.path,
                PassThru = [".css",".jpg",".jpeg",".png",".js"],
                %% ... much more ...
            false ->
                is_limited(ID),
                throw(http_method_denied)
        end
    catch
        throw:blacklist -> %% Send back a 429;
        throw:limit -> %% Same but no Retry-After;
        throw:http_method_denied ->
        %%Only thrown experienced
            AllowedReq = string:join([atom_to_list(M) || M <- Allow], ","),
            A#arg{state=#rewrite_response{status=405,
                        headers=[{header, {"Allow", AllowedReq}},{header, {connection, "close"}}]
            }};
        Type:Reason -> {error, {unhandled,{Type, Reason}}}
    end.

Я могу спамить curl -I -X HEAD <<any page>> так быстро как я могу в bash оболочке, и все, что я получаю, это HTTP 200. Таблица ETS также имеет нулевые записи. Используя PUT, я получаю HTTP 405, как и предполагалось. Я могу ratelimiter:lockout({MY_IP}) и получить веб-страницу для загрузки в моем браузере и HTTP 200 с curl.

Я в замешательстве. Я так начал Y AWS?

start() ->
    os:putenv("YAWSHOME", ?HOMEPATH_YAWS),
    code:add_patha(?MODPATH_YAWS),

    ok = case (R = application:start(yaws)) of
        {error, {already_started, _}} -> ok;
        _ -> R
    end,

    {ok,self()}. %% Tell supervisor everything okay in a manner it expects.

Я сделал это, потому что думал, что это будет "проще".

1 Ответ

0 голосов
/ 13 апреля 2020

При запуске Y aws как части другого приложения важно использовать поддержку встраивания . Одна важная вещь, которую делает встраиваемый код запуска Y aws, - это установка переменной среды приложения embedded в true:

application:set_env(yaws, embedded, true),

Y aws проверка этой переменной в нескольких путях кода, особенно во время инициализации, чтобы не предполагать, что он работает как автономный процесс демона.

Что касается ограничения скорости, а не использования переписывающего устройства arg, вы можете рассмотреть возможность использования shaper . Модуль yaws_shaper обеспечивает поведение, которое предполагает, что его модуль обратного вызова реализует две функции:

  • check/1: yaws_shaper вызывает это, чтобы позволить модулю обратного вызова решить, разрешить ли запрос от клиента. Он передает информацию о хосте клиента в качестве аргумента обратного вызова. Модуль обратного вызова формирователя возвращает либо атом allow, чтобы разрешить выполнение запроса, либо кортеж {deny, Status, Message}, где Status - это код состояния HTTP для возврата клиенту, например 429, чтобы указать, что клиент делает слишком много запросы, а Message - это любые дополнительные HTML, которые должны быть возвращены клиенту. (Было бы неплохо, если бы Message мог также включать заголовок ответа, такой как Retry-After; это то, что я рассмотрю, добавив к Y aws.)

  • update/3: yaws_shaper вызывает это, когда ответ для клиента готов к возвращению. Первый аргумент - это информация о хосте клиента, второй аргумент - это число «обращений» (значение 1 для каждого запроса), а третий аргумент - это количество байтов, доставляемых в ответ на запрос клиента. Ваш модуль обратного вызова формирователя может вернуть ok из update/3 (Y aws не использует возвращаемое значение).

Формирователь может использовать эту платформу для отслеживания количества запросов на каждый клиент делает и сколько данных Y aws доставляет каждому клиенту, и использует эту информацию для ограничения или запрета определенных клиентов.

И, наконец, хотя "отладка printf" работает, это далеко не идеально, особенно в Erlang, который имеет встроенную трассировку. Вам следует изучить модуль dbg , чтобы вы могли отследить любую функцию, которую вы хотите, увидеть, кто ее вызвал, посмотреть, какие аргументы передаются ей, посмотреть, что она возвращает, и так далее. c.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...