Redirect Request (nsiHttpChannel?) In Firefox Extensions

I tried this for a long time, and there were no good results.

var myObserver = { observe: function(subject, topic, data) { if (topic == "http-on-examine-response") { // implement later } else if(topic == "http-on-modify-request") { // implement later } }, QueryInterface : function (id) { if (id.equals(Components.interfaces["nsIObserver"]) || id.equals(Components.interfaces["nsISupports"])) { return this; } throw Components.results.NS_NOINTERFACE; } }; var obs = new Service("observer-service", "ObserverService"); obs.addObserver(myObserver, "http-on-modify-request", false); 

Basically, on http-on-modify-request , I know how to examine the URI, find out which window (if any) is associated with it, and many other things. I cannot figure out how to redirect a request, which I know is possible from here, because I can get nsIHttpChannel before any request is sent.

Does anyone know what to do?: / I tried a couple of weeks on / off, and didn’t get anywhere else.

+42
javascript firefox-addon
Feb 10 '10 at 13:35
source share
4 answers

We can do this by overriding nsiHttpChannel new one, making it a bit tricky, but fortunately the https-everywhere add https-everywhere implements this to force an https connection.

https-everywhere source code is available here

Most of the code needed for this is in the files

[ IO Util.js ] [ ChannelReplacement.js ]

We can only work with the above files if we have basic variables, such as Cc, Ci, and the xpcom_generateQI function is xpcom_generateQI .

 var httpRequestObserver = { observe: function(subject, topic, data) { if (topic == "http-on-modify-request") { var httpChannel = subject.QueryInterface(Components.interfaces.nsIHttpChannel); var requestURL = subject.URI.spec; if(isToBeReplaced(requestURL)) { var newURL = getURL(requestURL); ChannelReplacement.runWhenPending(subject, function() { var cr = new ChannelReplacement(subject, ch); cr.replace(true,null); cr.open(); }); } } }, get observerService() { return Components.classes["@mozilla.org/observer-service;1"] .getService(Components.interfaces.nsIObserverService); }, register: function() { this.observerService.addObserver(this, "http-on-modify-request", false); }, unregister: function() { this.observerService.removeObserver(this, "http-on-modify-request"); } }; httpRequestObserver.register(); 

In the replace code, the request is not redirected.

Although I checked the code above pretty well, I'm not sure about its implementation. While I can parse, it copies all the attributes of the requested channel and sets them to the redefined channel. After that, some output requested by the initial request is supplied using the new channel.

PS I saw a SO post that suggested this approach.

+3
Sep 26
source

I get the impression that you cannot do this at this level - I tried various methods to “cheat” the code externally, which requires the creation of nsIHttpChannel (example at the end of the post).

I would recommend that if you want to redirect, go to the channel owner’s window (which works 99% of the time) and ask him to redirect. I know that this will not behave the same, but since I don’t know exactly why you are doing this, it will be externally (for the user), it seems to do the same thing as you.

Here are the basics of what I tried:

 if(aTopic == "http-on-examine-response") { var request = aSubject.QueryInterface(Components.interfaces.nsIHttpChannel); if(!request.URI.spec.match("^http://www.apple.com/")) { var ios = Components.classes["@mozilla.org/network/io-service;1"] .getService(Components.interfaces.nsIIOService); var ch = ios.newChannel("http://www.apple.com/", null, null); var listener = { QueryInterface : XPCOMUtils.generateQI([Ci.nsIChannelEventSink]), onDataAvailable: function() {}, onStopRequest: function() {}, onStartRequest: function() {} }; ch.asyncOpen(listener,null); var eventSink = request.notificationCallbacks.getInterface(Ci.nsIChannelEventSink); eventSink.asyncOnChannelRedirect(request,ch,Ci.nsIChannelEventSink.REDIRECT_INTERNAL,function() {}); } 
+1
May 26 '12 at 1:13
source

I did it this way: stop nsIHttpChannel on the "http-on-modify-request" event, get the browser object for the current window, call browser.loadURI .

 var utils = require("sdk/window/utils"); function needsRedirect(url) { // to be implemented return true; } function generateNewUrl(url) { // to be implemented return "http://www.example.com/"; } Cc["@mozilla.org/observer-service;1"] .getService(Ci.nsIObserverService) .addObserver({ observe: function(subject, topic, data) { var channel = subject.QueryInterface(Ci.nsIHttpChannel); var url = channel.originalURI.spec; if (needsRedirect(url)) { //stop channel.cancel(Cr.NS_BINDING_ABORTED); //redirect var gBrowser = utils.getMostRecentBrowserWindow().gBrowser; var domWin = channel.notificationCallbacks.getInterface(Ci.nsIDOMWindow); var browser = gBrowser.getBrowserForDocument(domWin.top.document); browser.loadURI(generateNewUrl(url)); } } }, "http-on-modify-request", false); 
0
Nov 27 '13 at 9:47 on
source

During testing of something, I created a compressed version (see this meaning ) of the channel replacement logic mentioned in other answers.

The general idea is to transfer all critical properties to the new channel, remove callbacks from the old channel so that manipulations do not interrupt page loading, and then close the old channel.

With some changes, you can change the page URI for downloading documents or leave it as is.

Warning: it was just a quick hack to load multiple pages, I did not test it in depth and it will probably break for some cases. I suspect there are reasons why HTTPS Everywhere is more complex.

0
Dec 17 '15 at 8:45
source



All Articles