在Firefox扩展中重定向请求(nsiHttpChannel?)

时间:2010-02-10 13:35:30

标签: javascript firefox-addon httprequest

我现在已经在这方面努力了很长时间,并没有很好的结果。

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。

任何人都知道该怎么办? :/我一直试着打了几个星期,然后无处可去。

4 个答案:

答案 0 :(得分: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帖子,其中提出了这种方法。

答案 1 :(得分: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() {});                          
            } 

答案 2 :(得分:0)

我这样做了:在nsIHttpChannel事件上停止"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);

答案 3 :(得分:0)

在测试某些内容时,我创建了其他答案中提到的频道替换逻辑的精简版本(参见this gist)。

一般的想法似乎是将所有关键属性转移到新频道,从旧频道中删除回调,这样操作就不会使页面加载绊倒,然后关闭旧频道。

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

警告:这只是一个加载几页的快速入侵,我没有深入测试它,它可能会在某些情况下中断。我怀疑为什么HTTPS Everywhere更复杂。