2010-01-26 23 views
6

Actualización: Supongo que el sujeto dio una idea equivocada de que estoy buscando un complemento existente. Este es un problema personalizado y NO quiero una solución existente.
Deseo ESCRIBIR (o más apropiadamente, modificar y existente) Complemento.Crear complemento de Firefox para ver y modificar las solicitudes y respuestas de XHR

Aquí es mi requisito:

  • Quiero que mi complemento para trabajar por un sitio en particular sólo
  • Los datos de las páginas se codifican usando un hash de 2 vías
  • Una buena cantidad de información se carga por las peticiones XHR, ya veces mostradas en las burbujas animadas, etc.
  • la versión actual de mi complemento analiza la página a través de XPath expresiones, decodifica los datos, y los reemplaza

  • El problema llega con esas cajas bubblified que se muestran en el evento del ratón sobre

  • Por lo tanto, me di cuenta de que podría ser una buena idea para crear un puente XHR que podría escuchar a todos los datos y decodificar/codificar sobre la marcha
  • Después de un par de búsquedas, me encontré con nsITraceableInterface [1] [2] [3]

sólo quería saber si yo estoy en el camino correcto. Si la respuesta es "sí", amablemente proporciona cualquier sugerencia y sugerencias adicionales que puedan ser apropiadas; y si es "No", entonces ... bueno, ayúdenos con los punteros correctos :)

Gracias,
Bipin.

[1]. https://developer.mozilla.org/en/NsITraceableChannel
[2]. http://www.softwareishard.com/blog/firebug/nsitraceablechannel-intercept-http-traffic/
[3]. http://www.ashita.org/howto-xhr-listening-by-a-firefox-addon/

Respuesta

8

nsITraceableChannel es de hecho el camino a seguir aquí. las publicaciones del blog de Jan Odvarko (softwareishard.com) y de mí (ashita.org) muestran cómo hacerlo. También es posible que desee ver http://www.ashita.org/implementing-an-xpcom-firefox-interface-and-creating-observers/, sin embargo, no es realmente necesario hacer esto en un componente XPCOM.

Los pasos son básicamente:

  1. Crear prototipo objeto que implementa nsITraceableChannel; y crear observador para escuchar http-en-modificación-petición y http-a-examinar-respuesta
  2. observador registro
  3. observador escuchar los dos tipos de peticiones añade nuestros nsITraceableChannel objeto en la cadena de oyentes y asegurarse de que nuestra nsITC sabe quién es el siguiente en la cadena
  4. objeto
  5. nsITC ofrece tres devoluciones de llamada y cada uno se llama en la etapa apropiada: onStartRequest, OnDataAvailable y onStopRequest
  6. en cada una de las devoluciones de llamada anteriores, nuestro objeto nsITC debe transmitir los datos para el siguiente artículo en la cadena

A continuación se muestra el código real de un complemento específico del sitio que escribí que se comporta de forma muy similar a la suya por lo que puedo decir.

function TracingListener() { 
    //this.receivedData = []; 
} 

TracingListener.prototype = 
{ 
    originalListener: null, 
    receivedData: null, // array for incoming data. 

    onDataAvailable: function(request, context, inputStream, offset, count) 
    { 
     var binaryInputStream = CCIN("@mozilla.org/binaryinputstream;1", "nsIBinaryInputStream"); 
     var storageStream = CCIN("@mozilla.org/storagestream;1", "nsIStorageStream"); 
     binaryInputStream.setInputStream(inputStream); 
     storageStream.init(8192, count, null); 

     var binaryOutputStream = CCIN("@mozilla.org/binaryoutputstream;1", 
       "nsIBinaryOutputStream"); 

     binaryOutputStream.setOutputStream(storageStream.getOutputStream(0)); 

     // Copy received data as they come. 
     var data = binaryInputStream.readBytes(count); 
     //var data = inputStream.readBytes(count); 

     this.receivedData.push(data); 

     binaryOutputStream.writeBytes(data, count); 
     this.originalListener.onDataAvailable(request, context,storageStream.newInputStream(0), offset, count); 
    }, 

    onStartRequest: function(request, context) { 
     this.receivedData = []; 
     this.originalListener.onStartRequest(request, context); 
    }, 

    onStopRequest: function(request, context, statusCode) 
    { 
     try 
     { 
      request.QueryInterface(Ci.nsIHttpChannel); 

      if (request.originalURI && piratequesting.baseURL == request.originalURI.prePath && request.originalURI.path.indexOf("/index.php?ajax=") == 0) 
      { 

       var data = null; 
       if (request.requestMethod.toLowerCase() == "post") 
       { 
        var postText = this.readPostTextFromRequest(request, context); 
        if (postText) 
         data = ((String)(postText)).parseQuery(); 

       } 
       var date = Date.parse(request.getResponseHeader("Date")); 
       var responseSource = this.receivedData.join(''); 

       //fix leading spaces bug 
       responseSource = responseSource.replace(/^\s+(\S[\s\S]+)/, "$1"); 

       piratequesting.ProcessRawResponse(request.originalURI.spec, responseSource, date, data); 
      } 
     } 
     catch (e) 
     { 
      dumpError(e); 
     } 
     this.originalListener.onStopRequest(request, context, statusCode); 
    }, 

    QueryInterface: function (aIID) { 
     if (aIID.equals(Ci.nsIStreamListener) || 
      aIID.equals(Ci.nsISupports)) { 
      return this; 
     } 
     throw Components.results.NS_NOINTERFACE; 
    }, 
    readPostTextFromRequest : function(request, context) { 
     try 
     { 
      var is = request.QueryInterface(Ci.nsIUploadChannel).uploadStream; 
      if (is) 
      { 
       var ss = is.QueryInterface(Ci.nsISeekableStream); 
       var prevOffset; 
       if (ss) 
       { 
        prevOffset = ss.tell(); 
        ss.seek(Ci.nsISeekableStream.NS_SEEK_SET, 0); 
       } 

       // Read data from the stream.. 
       var charset = "UTF-8"; 
       var text = this.readFromStream(is, charset, true); 

       // Seek locks the file so, seek to the beginning only if necko hasn't read it yet, 
       // since necko doesn't seek to 0 before reading (at lest not till 459384 is fixed). 
       if (ss && prevOffset == 0) 
        ss.seek(Ci.nsISeekableStream.NS_SEEK_SET, 0); 

       return text; 
      } 
      else { 
       dump("Failed to Query Interface for upload stream.\n"); 
      } 
     } 
     catch(exc) 
     { 
      dumpError(exc); 
     } 

     return null; 
    }, 
    readFromStream : function(stream, charset, noClose) { 

     var sis = CCSV("@mozilla.org/binaryinputstream;1", "nsIBinaryInputStream"); 
     sis.setInputStream(stream); 

     var segments = []; 
     for (var count = stream.available(); count; count = stream.available()) 
      segments.push(sis.readBytes(count)); 

     if (!noClose) 
      sis.close(); 

     var text = segments.join(""); 
     return text; 
    } 

} 


hRO = { 

    observe: function(request, aTopic, aData){ 
     try { 
      if (typeof Cc == "undefined") { 
       var Cc = Components.classes; 
      } 
      if (typeof Ci == "undefined") { 
       var Ci = Components.interfaces; 
      } 
      if (aTopic == "http-on-examine-response") { 
       request.QueryInterface(Ci.nsIHttpChannel); 

       if (request.originalURI && piratequesting.baseURL == request.originalURI.prePath && request.originalURI.path.indexOf("/index.php?ajax=") == 0) { 
        var newListener = new TracingListener(); 
        request.QueryInterface(Ci.nsITraceableChannel); 
        newListener.originalListener = request.setNewListener(newListener); 
       } 
      } 
     } catch (e) { 
      dump("\nhRO error: \n\tMessage: " + e.message + "\n\tFile: " + e.fileName + " line: " + e.lineNumber + "\n"); 
     } 
    }, 

    QueryInterface: function(aIID){ 
     if (typeof Cc == "undefined") { 
      var Cc = Components.classes; 
     } 
     if (typeof Ci == "undefined") { 
      var Ci = Components.interfaces; 
     } 
     if (aIID.equals(Ci.nsIObserver) || 
     aIID.equals(Ci.nsISupports)) { 
      return this; 
     } 

     throw Components.results.NS_NOINTERFACE; 

    }, 
}; 


var observerService = Cc["@mozilla.org/observer-service;1"] 
    .getService(Ci.nsIObserverService); 

observerService.addObserver(hRO, 
    "http-on-examine-response", false); 

En el código anterior, originalListener es el oyente que estamos insertando a nosotros mismos antes de la cadena. Es vital que guarde esa información al crear el Escuchador de seguimiento y transmita los datos en las tres devoluciones de llamada. De lo contrario, nada funcionará (las páginas ni siquiera se cargarán. Firefox es el último en la cadena).

Nota: hay algunas funciones llamadas en el código anterior que son parte de la piratequesting complemento, por ejemplo .: parseQuery() y dumpError()

0

Tamper Data Add-on. Consulte también la página How to Use it

+0

El sujeto que dio una idea equivocada, tal vez. No estoy buscando una solución existente. Amablemente lea el problema completo. Gracias :) – Jumper

+0

@Jumper, Tamper Data probablemente sea una buena base para comenzar a construir su complemento. Tendría que arrancar la mayor parte del código UI, pero el código que necesita para supervisar y modificar las solicitudes XHR estará allí. –

+0

Sí, tenía una mirada superficial en el pasado. Parecía usar el servicio Observer. Los enlaces en la pregunta (que hablan de nsITraceableChannel) también usan Observer. Veremos el código tamperData nuevamente hoy. – Jumper

0

Puede intentar hacer una secuencia de comandos greasemonkey y sobrescribir XMLHttpRequest.
El código sería algo como:

 
function request() { 
}; 
request.prototype.open = function (type, path, block) { 
GM_xmlhttpRequest({ 
    method: type, 
    url: path, 
    onload: function (response) { 
    // some code here 
    } 
}); 
}; 
unsafeWindow.XMLHttpRequest = request; 

también en cuenta que puede convertir una secuencia de comandos de GM en un complemento para Firefox

+0

Lo había considerado pero decidí evitar debido a inseguroWindow considerado inseguro. ¿Alguna idea sobre el canal nsITraceable? – Jumper

+0

unsafeWindow es solo un problema si tiene un código deficiente. Basado en el sonido de tu pregunta, creo que deberías estar bien usando inseguroVentana. La única razón para no usarlo sería si creyese que el sitio en el que se utilizaría intentaría piratear tu sistema de alguna manera (esto no sucederá si no lo liberas, e incluso si lo haces, lo haría). tiene que usar mucho antes de que lo más probable es que les importe), incluso si te hackearon de alguna forma, tu código debería ser lo suficientemente seguro como para manejarlo. Si le preocupa esto, un complemento de FF sería peor. –

Cuestiones relacionadas