nsITraceableChannel è davvero il modo di andare qui. i post del blog di Jan Odvarko (softwareishard.com) e io (ashita.org) mostrano come farlo. Si potrebbe anche voler vedere http://www.ashita.org/implementing-an-xpcom-firefox-interface-and-creating-observers/, tuttavia non è davvero necessario farlo in un componente XPCOM.
I passi sono fondamentalmente:
- Creare prototipo oggetto che implementa nsITraceableChannel; e creare osservatore ad ascoltare la http-on-modifica-richiesta e http-on-esame-risposta
- registro osservatore
- osservatore ad ascoltare i due tipi di richiesta aggiunge nostri nsITraceableChannel oggetto nella catena di ascoltatori e assicurarsi che il nostro nsITC sa che è successivo della catena
oggetto
- nsITC fornisce tre callback e ognuno sarà chiamato al momento opportuno: onStartRequest, OnDataAvailable e onStopRequest
- in ciascuna delle callback sopra, il nostro oggetto nsITC deve trasmettere dati al prossimo articolo della catena
Di seguito è riportato il codice effettivo da un componente aggiuntivo specifico del sito che ho scritto che si comporta in modo molto simile al tuo da quello che posso dire.
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);
Nel codice precedente, originalListener
è l'ascoltatore stiamo inserendo stessi prima della catena. È fondamentale conservare tali informazioni durante la creazione del listener di tracciamento e inoltrare i dati in tutte e tre le callback. Altrimenti nulla funzionerà (le pagine non verranno nemmeno caricate. Firefox stesso è l'ultimo della catena).
Nota: ci sono alcune funzioni chiamate nel codice qui sopra, che fanno parte della piratequesting add-on, per es .: parseQuery()
e dumpError()
Il soggetto che si ha un'idea sbagliata, forse. Non sto cercando una soluzione esistente. Si prega di leggere il problema completo. Grazie :) – Jumper
@Jumper, Tamper Data sarebbe probabilmente una buona base per iniziare a costruire il tuo componente aggiuntivo. Dovresti strappare la maggior parte del codice dell'interfaccia utente, ma il codice che devi monitorare e modificare le richieste XHR sarà lì. –
Sì, ha avuto un aspetto superficiale in passato. Sembrava utilizzare il servizio Observer. I link nella domanda (che parlano di nsITraceableChannel) usano anche Observer. Guarderà ancora il codice TamperData oggi. – Jumper