2010-02-10 37 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更復雜。