在Firefox扩展中redirect请求(nsiHttpChannel?)

我已经在这个很长一段时间尝试了,没有好的结果。

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); 

基本上,在http-on-modify-request ,我知道如何检查URI,找出与哪个窗口(如果有)关联,以及其他一些东西。 我无法弄清楚的是如何redirect一个请求,我知道这是可能的,因为在发送请求之前,我可以得到一个nsIHttpChannel。

任何人都知道该怎么办? :/我已经尝试了几个星期的closures,并没有得到任何好处。

我们可以通过用新的覆盖nsiHttpChannel来做到这一点,这样做有点复杂,但幸运的是,附加的https-everywhere实现这个强制https连接。

https-everywhere的源代码在这里可用

大部分所需的代码都在文件中

[ IO Util.js ] [ ChannelReplacement.js ]

我们可以单独使用上面的文件,只要我们有基本的variables如Cc,Ci设置和函数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(); 

代码将取代不redirect的请求。

虽然我已经很好的testing了上面的代码,但我不确定它的实现。 据我所知,它复制了所请求通道的所有属性,并将它们设置为要覆盖的通道。 之后以某种方式,原始请求所请求的输出将使用新的通道提供。

PS我曾看过一个SOpost,其中提出了这种方法。

我的印象是,你不能在这个层面上做到这一点 – 我尝试了各种各样的外部“欺骗”代码,要求创build一个nsIHttpChannel的方法(例如在post的末尾)。

我会build议如果你想要redirect,请联系频道的所有者窗口(99%的时间),并指示它redirect。 我知道这不会有相同的performance,但是因为我不知道你为什么要这样做,所以这对外部(对用户)似乎和你所要求的一样。

以下是我正在尝试的基础知识:

 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() {}); } 

我这样做了:在"http-on-modify-request"事件"http-on-modify-request"停止nsIHttpChannel ,获取当前窗口的浏览器对象,调用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); 

在testing某些东西时,我创build了其他答案中提到的通道replace逻辑的精简版本(请参阅此要点 )。

总的想法似乎是将所有关键属性转移到新频道,从旧频道中删除callback,以便操纵不会跳过页面加载,然后closures旧频道。

通过一些修改,可以更改文档加载的页面URI或保持原样。

警告:这只是一个简单的方法来加载几个页面,我没有深入的testing,它可能会打破一些情况。 我怀疑为什么HTTPS Everywhere更复杂。