Запрос перенаправления (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 до того, как какой-либо запрос будет отправлен.

Кто-нибудь знает, что делать? :/ Я пробовал пару недель с перерывами, но ничего не вышло.


person Avindra Goolcharan    schedule 10.02.2010    source источник
comment
Что вы подразумеваете под перенаправлением запроса? Перенаправление местоположения браузера на другой URL?   -  person Sam Ingrassia    schedule 20.02.2010
comment
Да, но в контексте того, что я делаю. Я понял это, я опубликую решение для других позже, если я доберусь до него.   -  person Avindra Goolcharan    schedule 23.02.2010
comment
Это решение, вероятно, будет полезно.   -  person Tim Matthews    schedule 15.03.2010
comment
У вас случайно не завалялось это решение? Приятно иметь здесь ответы, помеченные как полные и все такое, а также очень полезно для людей, которые находят этот вопрос через поисковые системы.   -  person SeriousSamP    schedule 10.11.2011
comment
не могли бы вы опубликовать свое решение?   -  person nonchip    schedule 11.12.2011
comment
Используя setRequestHeader, вы можете сделать это просто: setRequestHeader('Location', 'newsite.com', true) developer.mozilla.org/en/Creating_Sandboxed_HTTP_Connections developer.mozilla.org/en/XPCOM_Interface_Reference/   -  person StiveKnx    schedule 08.03.2012
comment
@AvindraGoolcharan, если у вас есть решение этой проблемы, вам, вероятно, следует опубликовать его. Похоже, некоторые другие пользователи хотели бы увидеть, как это делается. Спасибо!   -  person thomallen    schedule 02.05.2012


Ответы (4)


Мы можем сделать это, переопределив 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, в котором был предложен этот подход.

person mdprasadeng    schedule 26.09.2012
comment
не могли бы вы предоставить некоторые недостающие функции, такие как isToBeReplace и ChannelReplacement - person Noitidart; 26.02.2014
comment
isToBeReplace — это ваша логика, которая должна решать, перенаправлять или нет. ChannelReplacement определяется в ChannelReplacement.js - person mdprasadeng; 27.02.2014
comment
Большое спасибо @mdprasadeng за ответ, я волновался, что сообщение не дойдет до вас. isToBeReplace Я многое понимаю, но не могли бы вы дать ссылку на ChannelReplacement.js, ссылки выше не работают - person Noitidart; 27.02.2014
comment
вы заметили, что ссылки не работают. Я не могу разместить весь свой проект, поэтому вот ссылки на эти два файла ChannelReplacement.js IOUtil.js - person mdprasadeng; 27.02.2014
comment
Еще раз спасибо мужик! Если у вас есть гитхаб, это было бы еще круче, поэтому я могу пометить его и все такое, но это не важно :) - person Noitidart; 27.02.2014
comment
К сожалению, мой проект предназначен для бывшего работодателя и, следовательно, не может разместить весь проект в Интернете. Если у вас возникли проблемы, дайте мне знать, и я создам мини-версию. - person mdprasadeng; 28.02.2014
comment
Ах да, пожалуйста, не могли бы вы сделать это. Мне бы это супер помогло. Я могу сделать перенаправление канала, но только с redirectTo, но это совместимо только с FF20+. Искреннее спасибо за эту помощь. Мне тоже нравится помогать людям, создавая мини-демо! +1 за это :) - person Noitidart; 01.03.2014
comment
@mdprasdeng привет, чувак, я просто хотел узнать, когда ты сможешь показать мне это демо :) - person Noitidart; 05.03.2014
comment
Бамп, пожалуйста, все еще очень пытаюсь понять этот выход :( - person Noitidart; 23.05.2014

У меня сложилось впечатление, что вы не можете сделать это на этом уровне - я пробовал различные методы внешнего «обмана» кода, который требует создания 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() {});                          
            } 
person Daniel    schedule 26.05.2012

Я сделал это так: остановить 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);
person vadimrostok    schedule 27.11.2013
comment
Этот код, похоже, работает не так, как ожидалось. Когда я применяю этот код к веб-сайту, на котором есть изображения, этот вызов будет сделан для изображения, и поэтому текущая загруженная страница будет заменена URL-адресом generateNewUrl(image.jpg) вместо generateNewUrl(index.html) . Я думаю, что channel.redirectTo(nsUrl) лучше. - person Daniel Marschall; 20.06.2014

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

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

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

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

person the8472    schedule 17.12.2015