2010-02-10 70 views
42

我一直在尝试这个很长一段时间,并没有很好的结果。重定向请求(nsiHttpChannel?)在Firefox扩展中

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,找出哪些窗口(如果有的话)与相关联,和一堆其他的东西。我无法弄清楚的是如何重定向请求,我知道这是可能的,因为我可以在发送任何请求之前获得nsIHttpChannel。

任何人都知道该怎么办? :/我已经尝试了几个星期的开关,并且没有任何进展。

+0

重定向请求是什么意思?将浏览器位置重定向到另一个URL? – 2010-02-20 05:48:40

+3

是的,但在我正在做的事情。我明白了,如果我能够解决问题,我会在稍后发布解决方案。 – 2010-02-22 21:36:04

+2

该解决方案可能有帮助。 – 2010-03-15 10:56:54

回答

1

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

我会推荐的是,如果你想要重定向,请联系频道的所有者窗口(99%的时间),并指示它重定向。我知道它不会有相同的表现,但由于我不确切知道你为什么要这样做,所以这将在外部(对用户)看起来与你所要求的做同样的事情。

这里是什么,我想最基础的:

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

我们可以用一个新的重载nsiHttpChannel这样做,这样做是稍微复杂,但幸运的是,附加https-everywhere实现此强制https连接。

https-everywhere的源代码可here

最需要这个代码是在文件

[IO Util.js] [ChannelReplacement.js]

我们也可以只使用上述文件工作前提是我们有基本变量,如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(); 

该代码将取代请求不重定向。

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

P.S.我曾见过一个SO帖子,其中提出了这种方法。

+0

可以请你提供一些缺失的功能,如isToBeReplace和ChannelReplacement – Noitidart 2014-02-26 08:34:03

+0

isToBeReplace是你的逻辑,应该决定是否重定向。 ChannelReplacement在ChannelReplacement.js中定义 – mdprasadeng 2014-02-27 07:01:05

+0

非常感谢@mdprasadeng的回复,我担心这个消息不会给你。 isToBeReplace我可以理解这一点,但你可以请链接到ChannelReplacement.js上述链接是打破 – Noitidart 2014-02-27 07:12:19

0

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

这段代码似乎不是按照预期工作当我将这段代码应用到一个包含图像的网站时,这个调用将会在图像上进行,因此当前加载的页面将被替换为URL generateNewUrl(“image.jpg”),而不是generateNewUrl(“index.html”)。我认为'channel.redirectTo(nsUrl)'是一个更好的方法。 – 2014-06-19 22:27:21

0

在测试的东西我创建在其他的答案中提到的信道更换逻辑的压缩版本(见this gist)。

总的想法似乎是将所有关键属性转移到新通道,从旧通道中删除回调,以便操作不会使页面加载跳动,然后关闭旧通道。

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

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