Запрос на перенаправление (nsiHttpChannel?) В расширениях Firefox - PullRequest
43 голосов
/ 10 февраля 2010

Я давно пытаюсь это сделать, но безрезультатно.

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 ]

3 голосов
/ 26 сентября 2012

Мы можем сделать это, переопределив nsiHttpChannel новым, сделать это немного сложно, но, к счастью, дополнение https-everywhere реализует это, чтобы установить соединение https.

Исходный код

https-everywhere доступен здесь

Большая часть кода, необходимого для этого, находится в файлах

[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 голос
/ 26 мая 2012

У меня сложилось впечатление, что вы не можете сделать это на этом уровне - я попробовал различные методы внешнего "обмана" кода, который требует создания 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() {});                          
            } 
0 голосов
/ 17 декабря 2015

Во время тестирования чего-то я создал сокращенную версию (см. эту суть ) логики замены канала, упомянутой в других ответах.

Общая идея, по-видимому, заключается в том, чтобы перенести все критические свойства на новый канал, удалить обратные вызовы со старого канала, чтобы манипуляции не приводили к отключению загрузки страницы, а затем отключить старый канал.

С некоторыми изменениями можно изменить URI страницы для загрузки документа или оставить его как есть.

Предупреждение: это был быстрый взлом, чтобы загрузить несколько страниц, я не проверил его подробно, и в некоторых случаях он может сломаться. Я подозреваю, что есть причины, по которым HTTPS Everywhere более сложный.

0 голосов
/ 27 ноября 2013

Я сделал это следующим образом: остановите 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);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...