Заявка за пренасочване (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
Благодаря отново човече! Ако имате github, това би било още по-готино, за да мога да го звездя и други неща, но това не е голямо :) - 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