Перенаправление API webRequest использует метод http родительского запроса

Я использую webRequest-API в WebExtension для отслеживания запросов, сделанных клиентом. Это работает довольно хорошо, однако API ведет себя не так, как ожидалось, в случае перенаправления:

В этом случае выдается POST, на который отвечает 302 FOUND и новое местоположение. Мой браузер (Firefox 57, другие версии и другие браузеры — например, Chrome — действуют таким же образом) следует этому перенаправлению и теперь выдает GET на новое место.

введите здесь описание изображения

К сожалению, webRequest-API ведет себя иначе: он отслеживает первый POST (что правильно), но затем обрабатывает второй запрос также как POST, тогда как он должен быть GET. Это серьезная проблема, поскольку API отслеживает то, что предположительно сделал мой браузер, что на самом деле он сделал другим способом...

Этот сценарий (часть браузера) можно воспроизвести, следуя ссылка на веб-сайт surfnet.nl и выбор IDP из списка (например, Academisch Medisch Centrum).

Итак, короче говоря: почему поведение webRequest-API отличается от того, как ведут себя браузеры? И есть ли способ позволить ему точно отслеживать действия браузера?

Интересно, что webRequest-API может сделать это правильно, относительно документации< /а>:

Даже если спецификация требует, чтобы метод и тело не изменялись при выполнении перенаправления, не все пользовательские агенты соответствуют этому [браузеры, очевидно, меняются метод!], и вы все еще можете найти там программное обеспечение с ошибками. Поэтому рекомендуется устанавливать код 302 только в качестве ответа для методов GET или HEAD и вместо этого использовать временное перенаправление 307, так как изменение метода в этом случае явно запрещено. В тех случаях, когда вы хотите, чтобы используемый метод был изменен на GET, вместо этого используйте 303 See Other.


EDIT: кажется, что браузер изменил метод на 302 по историческим причинам, хотя это противоречит RFC 2616...

В любом случае... остается вопрос: как я могу заставить webRequest-API действовать таким же образом?


comment
Откройте сообщение об ошибке на странице bugzilla.mozilla.org.   -  person Smile4ever    schedule 20.11.2017
comment
@Smile4ever спасибо за ваш комментарий, но я не думаю, что это ошибка.   -  person khlr    schedule 20.11.2017
comment
Если вы хотите получить ответ на свой вопрос, это, вероятно, лучшее место, где можно спросить, даже если вы думаете, что это не ошибка.   -  person Smile4ever    schedule 20.11.2017


Ответы (1)


Кому интересно, у меня получилось следующее:

Документы позволяют мне это (redirectUrl):

[...] Перенаправления, инициированные действием перенаправления, используют исходный метод запроса для перенаправления, за одним исключением: если перенаправление инициировано на этапе onHeadersReceived, то перенаправление будет выполнено с использованием метода GET. [...]

Хотя приведенное выше утверждение дало мне некоторую надежду, method этого перенаправленного запроса по-прежнему было помечено как POST...

Поэтому я обновил код примерно так:

// Keep track of all requests issued so far and their responses
var httpRequests = [];

// Redirected requests come in with their originating parents' ID
browser.webRequest.onBeforeRequest.addListener(request => {
    // Check if the request is a redirect
    var isRedirected = function(requestId) {
        var parentRequest = httpRequests.find(r => r.req.requestId === requestId);
        if (parentRequest != null && parentRequest.res != null && parentRequest.res.statusCode === 302) {
            return true;
        }
        return false;
    };

    // The webRequest-API seems to keep the HTTP verbs which is correct in resepct to RFC 2616 but
    // differs from a typical browser behaviour which will usually change the POST to a GET. So do we here...
    if (request.method === 'POST' && isRedirected(request.requestId)) {
        console.log(`Redirected 302-request '${request.requestId}' is a POST but is here changed to a GET to conform to browser behaviour...`);
        request.method = 'GET';
    }

    // Store the request
    var entry = {
        id: id,
        req: request
    };
    httpRequests.push(entry);
});

browser.webRequest.onHeadersReceived.addListener(response => {
    // Store the response alongside the request
    var entry = httpRequests.find(req => req.id === response.requestId);
    entry.res = response;

    // If it turns out that a request should be redirected...
    if (response.statusCode === 302) {
        var location = response.responseHeaders.find(header => header.name.toLowerCase() === "location");
        console.log(`Redirecting request '${id}' to new location '${location.value}'...`);

        // The new location is set as redirectUrl, which results in a new invocation of onBeforeRequest with
        // the current requestId
        return {
            redirectUrl: location.value
        };
    }
});

Что случается?

  1. Скажем, onBeforeRequest получает новый запрос 2640, который является POST.
  2. onHeadersReceived получает ответ, в котором говорится, что этот запрос должен быть перенаправлен в новое место (302).
  3. Приведенный выше код делает это, устанавливая redirectUrl в это новое место.
  4. Затем снова срабатывает onBeforeRequest. WebRequest-API передает ему тот же идентификатор запроса (2640).
  5. Код проверяет, есть ли родитель для этого запроса, и в данном случае это правда.
  6. Затем метод (по-прежнему POST) изменяется на GET.

Жизненный цикл запроса показан на иллюстрации в документации.

person khlr    schedule 24.02.2018