Transparent redirect

Is there any way to redirect requests without record the original URL in history? Consider that the original URL is pasted into the address bar, so it’s not about DOM manipulation.

I’ve always used redirector_ui.uc.js, but now that I’ve activated e10s, the original URL is recorded on history as well as the redirected one. The redirection still works, there is no connection to the original URL, but somehow it’s recorded in history.

I’ve tested several redirection extensions, even WebExtensions, and all of them also record the original URL.

If I disable e10s, this problem disappears. Is this a bug?

Code to reproduce using WebRequest (but this way the original URL is recorded even without e10s; for transparent redirect you run redirector_ui.uc.js):

var {WebRequest} = Cu.import("resource://gre/modules/WebRequest.jsm", {});

function redirectAsync (requestDetails) {
  if (/utm/.test(requestDetails.url)) {
    console.log("Redirecting: " + requestDetails.url);
    return new Promise((resolve, reject) => {
      resolve({redirectUrl: 'http://www.example.com/'});
    });
  }
}

WebRequest.onBeforeRequest.addListener(redirectAsync, {urls: new MatchPatternSet(["http://www.example.com/*"])}, ["blocking"]);

Test link:
http://www.example.com/test?utm_source=track&utm_medium=track&utm_campaign=track

Solved implementing nsIContentPolicy (shouldLoad) in content process (Services.ppmm.loadProcessScript). With e10s this is no longer handled in chrome process, except for internal pages (chrome://, about:).

Bug 1331740 broke it.

The code I was using:

      shouldLoad: function (contentType, contentLocation, requestOrigin, node) {
        let redirectUrl = this.getRedirectUrl(contentLocation.spec);
        if (contentType == Ci.nsIContentPolicy.TYPE_DOCUMENT && redirectUrl && node) {
          node.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIWebNavigation).loadURI(redirectUrl, Ci.nsIWebNavigation.LOAD_FLAGS_NONE, requestOrigin, null, null);
          return Ci.nsIContentPolicy.REJECT_REQUEST;
        }
        return Ci.nsIContentPolicy.ACCEPT;
      }

The original URL request is rejected by Ci.nsIContentPolicy.REJECT_REQUEST, then the loadURI function creates a new request on the same channel with the redirected URL.

But after bug 1331740 patch, node.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIWebNavigation) doesn’t work anymore.

So now how could I get some reference of the tab/channel where the original request was made to then be able to call loadURI function?

Given that we now live in a WebExtensions world I doubt many people could help you here.

If WebExtensions didn’t have this “bug” of recording pre-redirected URLs in history, maybe I wouldn’t have to resort to that. :anguished:

A workaround would be to use loadFrameScript instead of loadProcessScript, then content.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIWebNavigation).loadURI, but this is not recommended:

For example, in multiprocess Firefox, if you need to use nsIContentPolicy to register a content policy, you must do this in the content process. But if you register it in a frame script, and the frame script is loaded more than once, you’ll register the content policy more than once, which probably isn’t what you intend.

So I would like to continue using loadProcessScript, but I need a way to shouldLoad(context) {context.[what,please?].loadURI()}.

Solved using

node.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsITabChild).messageManager.sendAsyncMessage('Redirector', redirectUrl);

in content process, and

 Services.mm.addMessageListener('Redirector', function (m) {
   m.target.loadURI(m.data, null, null, null, null);
 });

in chrome process.

I’ll use this solution, but I don’t know which is best:
(1) comunicate between chrome and content processes (the solution in this post)
(2) inject the content script much more times using loadFrameScript instead of loadProcessScript (the solution in previous post).

I guess I chose it right, but not sure. Nor if there is a better solution than both.