-->

Asynchronous webRequest.onBeforeRequest URL inspec

2019-03-04 00:13发布

问题:

I'm trying to create URL inspector using Firefox native messages. The problem is, when native application sends a verdict, onBeforeRequest listener already released request, thus redirection doesn't happen. Can you please help to make my extension wait for reply for up to 2 seconds and redirect the request if answer is "0"?

var port = browser.runtime.connectNative("ping_pong");

function inspectURL(requestDetails) {
    console.log("Loading: <" + requestDetails.url + ">");
    port.postMessage(requestDetails.url);
    console.log("Posting complete <" + requestDetails.url + ">");
}

port.onMessage.addListener((response) = > {
    console.log("Received: <" + response + ">");
    if (response == "1")
    {
        console.log("Good url!!!");
    }
    else
    {
        console.log("BAD url - redirecting!!!");
        return {
        redirectUrl: "https://38.media.tumblr.com/tumblr_ldbj01lZiP1qe0eclo1_500.gif"
        };
    }
});

browser.webRequest.onBeforeRequest.addListener(
    inspectURL,
    { urls: ["<all_urls>"] },
    ["blocking"]
);

回答1:

Firefox

Firefox supports asynchronous webRequest blocking/modification listeners from Firefox 52 onward. To do so (MDN: webRequest: Modifying requests (and multiple other pages)):

From Firefox 52 onwards, instead of returning BlockingResponse, the listener can return a Promise which is resolved with a BlockingResponse. This enables the listener to process the request asynchronously.

So, in your wrbRequest.onBeforeRequest listener, you return a Promise which you resolve with the BlockingResponse.

You will need to store a list of requests for which you have asked for information from your port. The response from your port needs to uniquely identify the request to which it's responding. Keep in mind that this is all asynchronous, so you can have multiple requests in flight at the same time. You must appropriately track these and only resolve the appropriate Promise. Assuming your responses from your port don't rapidly change, you should store a list of URLs which have been checked (both good and bad), so you can respond immediately to URLs which have already been checked.

Chrome

What you desire is not possible in Chrome. You will need to resolve you issue in some other way.



回答2:

There's no way at all. It's possible since Firefox 52, see this answer. It's still not possible on Chrome.

Native Messaging is an asynchronous API. After posting a message, you will not receive a reply until you go back to the event loop (e.g. current code terminates).

However, blocking WebRequest API requires a synchronous reply. This is a core limitation, because asynchronous reply may never come or come after an uncertain delay, and the network stack won't wait for that to happen. I mean, it could, but the design of the API deliberately forbids it.

Basically: even if the reply is ready, your code will not receive it until inspectURL terminates, at which point WebRequest already carries on with the request. There is no way in JavaScript to make it synchronous.