webRequest API重定向使用父请求的{http}方法

时间:2017-11-19 16:54:56

标签: firefox redirect google-chrome-extension firefox-webextensions chrome-webrequest

我正在使用WebExtension中的webRequest-API来监控客户端发出的请求。这非常有效,但是在重定向的情况下API不会按预期运行:

在这种情况下,会发出POST,并以302 FOUND和新位置回答。我的浏览器(Firefox 57,其他版本和其他浏览器 - 例如Chrome - 以相同的方式行事)遵循此重定向,现在向新位置发出GET

enter image description here

不幸的是,webRequest-API的行为有所不同:它跟踪第一个POST(这是正确的)但是将第二个请求作为POST处理,而它应该是GET }。这是一个严重的问题,因为API跟踪了我的浏览器应该做的事情,它实际上以另一种方式做了......

可以通过以下this link to surfnet.nl并从列表中选择IDP(例如Academisch Medisch Centrum)来复制此场景(浏览器部分)。

所以,长话短说:为什么webRequest-API的行为与浏览器的行为方式不同?有没有办法让它完全跟踪浏览器的行为?

有趣的是,webRequest-API可能会正确执行,regarding the documentation

  

即使规范要求方法和正文,不要改变执行重定向时,并非所有用户代理都符合此处 [浏览器显然改变了方法!],你仍然可以在那里找到有缺陷的软件。因此,建议仅将302代码设置为GET或HEAD方法的响应,并使用307临时重定向,因为在这种情况下明确禁止方法更改。   如果您希望将方法更改为GET,请使用303请参阅其他。

修改 由于历史原因,似乎浏览器会更改302上的方法,即使它与RFC 2616相矛盾......

无论如何......问题仍然存在:我如何诱导webRequest-API采取相同的行动?

1 个答案:

答案 0 :(得分:0)

对于任何有兴趣的人,我最终得到以下内容:

文档让我thisredirectUrl):

  

[...]由重定向操作启动的重定向使用原始请求方法进行重定向,但有一个例外:如果重定向是在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将相同的requestId传递给它(2640)。
  5. 代码检查此请求是否有父级,在这种情况下,它是真的。
  6. 然后将该方法(仍为POST)修改为GET。
  7. 对于请求生命周期,请查看插图in the docs