2010-02-10 8 views
42

Ora ci provo da molto tempo e non ci sono risultati positivi.Richiesta di reindirizzamento (nsiHttpChannel?) Nelle estensioni di 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); 

In sostanza, il http-on-modify-request, so come esaminare l'URI, capire quale finestra (se presente) è associata a, e un mucchio di altre cose. Quello che non riesco a capire è come reindirizzare una richiesta, che so è possibile da qui, perché posso ottenere un nsIHttpChannel prima che qualsiasi richiesta venga mai inviata.

Qualcuno sa cosa fare? :/Ho provato per un paio di settimane, e non ho ottenuto nulla.

+0

Cosa intendi per reindirizzare una richiesta? Reindirizzare la posizione del browser a un altro URL? –

+3

Sì, ma nel contesto di ciò che sto facendo. L'ho capito, pubblicherò la soluzione per gli altri più tardi se riuscirò a farcela. –

+2

Questa soluzione sarebbe probabilmente utile. –

risposta

1

Ho l'impressione che non si possa fare questo a questo livello - Ho provato una varietà di metodi di "ingannare" esternamente il codice che richiede la creazione di un nsIHttpChannel (esempio alla fine del post).

Quello che vorrei raccomandare è se si desidera un reindirizzamento, contattare la finestra del proprietario del canale (che funziona il 99% delle volte) e istruirlo a reindirizzare. So che non si comporta allo stesso modo, ma poiché non so esattamente perché lo stai facendo, questo esternamente (all'utente) sembra fare la stessa cosa di quello che chiedi.

Ecco le basi di quello che stavo cercando:

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

possiamo farlo sovrascrivendo il nsiHttpChannel con uno nuovo, fare questo è un po 'complicato, ma per fortuna l'add-on https-everywhere implementa questo per forzare un connessione https.

s' https-everywhere codice sorgente è disponibile here

La maggior parte del codice necessario per questo è nei file

[IO Util.js] [ChannelReplacement.js]

possiamo lavorare solo con i file di cui sopra a condizione che abbiamo le variabili di base come Cc, Ci set e la funzione xpcom_generateQI definita.

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(); 

Il codice verrà sostituirà la richiesta non reindirizzamento.

Mentre ho testato il codice sopra abbastanza bene, non sono sicuro della sua implementazione. Per quanto posso capire, copia tutti gli attributi del canale richiesto e li imposta sul canale da sovrascrivere. Dopodiché, in qualche modo, l'output richiesto dalla richiesta originale viene fornito utilizzando il nuovo canale.

P.S. Avevo visto un post SO in cui questo approccio è stato suggerito.

+0

puoi fornire alcune funzioni mancanti come isToBeReplace e ChannelReplace – Noitidart

+0

isToBeReplace è la tua logica che dovrebbe decidere se reindirizzare o meno. ChannelReplacement è definito in ChannelReplacement.js – mdprasadeng

+0

Grazie mille @mdprasadeng per la risposta ero preoccupato che il messaggio non ti arrivasse. isToBeReplace Posso capirlo molto, ma puoi per favore collegarti a ChannelReplacement.js i link qui sopra sono rotti – Noitidart

0

Ho fatto in questo modo: interrompere nsIHttpChannel su "http-on-modify-request" evento, ottenere oggetto browser per la finestra corrente, chiamare 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

Questo codice sembra non per funzionare come previsto. Quando applico questo codice a un sito Web che contiene immagini, questa chiamata verrà effettuata sull'immagine, quindi la pagina caricata corrente verrà sostituita dall'URL generateNewUrl ("image.jpg") invece di generateNewUrl ("index.html"). Penso che "channel.redirectTo (nsUrl)" sia un modo migliore. –

0

Durante il test qualcosa che ho creato una versione condensata (vedi this gist) della logica di sostituzione del canale detto in altre risposte.

L'idea generale sembra essere quella di trasferire tutte le proprietà critiche sul nuovo canale, rimuovere i callback dal vecchio canale in modo che le manipolazioni non inciamperanno sul caricamento della pagina e quindi chiuderanno il vecchio canale.

Con alcune modifiche è possibile modificare l'URI della pagina per i carichi del documento o lasciarlo così com'è.

Attenzione: questo è stato solo un rapido trucco per caricare alcune pagine, non l'ho testato in profondità e probabilmente si romperà per alcuni casi. Sospetto che ci siano dei motivi per cui l'HTTPS Everywhere è più complesso.

Problemi correlati