I'm trying to implement a feature that will give me the response text and (all the) response headers of each http request in the browser,
I've read a bit here: http://www.softwareishard.com/blog/firebug/nsitraceablechannel-intercept-http-traffic/
I had no idea how to extract the response from the TracingListener object. Anyone dealt with that before?? thanks!
My code:
const Cc = Components.classes;
const Ci = Components.interfaces;
// Helper function for XPCOM instanciation (from Firebug)
function CCIN(cName, ifaceName) {
return Cc[cName].createInstance(Ci[ifaceName]);
}
// get the observer service and register for the two coookie topics.
var observerService = Components.classes["#mozilla.org/observer-service;1"]
.getService(Components.interfaces.nsIObserverService);
// Copy response listener implementation.
function TracingListener() {
this.originalListener = null;
this.receivedData = []; // array for incoming data.
}
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);
this.receivedData.push(data);
binaryOutputStream.writeBytes(data, count);
this.originalListener.onDataAvailable(request, context,storageStream.newInputStream(0), offset, count);
},
onStartRequest: function(request, context) {
this.originalListener.onStartRequest(request, context);
},
onStopRequest: function(request, context, statusCode)
{
try {
if (request.originalURI && piratequesting.baseURL == request.originalURI.prePath && request.originalURI.path.indexOf("/index.php?ajax=") == 0) {
dump("\nProcessing: " + request.originalURI.spec + "\n");
var date = request.getResponseHeader("Date");
var responseSource = this.receivedData.join();
dump("\nResponse: " + responseSource + "\n");
piratequesting.ProcessRawResponse(request.originalURI.spec, responseSource, date);
}
} 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;
}
}
// create an nsIObserver implementor
var listener = {
observe : function(aSubject, aTopic, aData) {
// Make sure it is our connection first.
//if (aSubject == gChannel) {
var httpChannel = aSubject.QueryInterface(Components.interfaces.nsIHttpChannel);
if (aTopic == "http-on-modify-request") {
// ...
httpChannel.setRequestHeader("X-Hello", "World", false);
} else if (aTopic == "http-on-examine-response") {
// ...
//alert(JSON.stringify(aData));
var newListener = new TracingListener();
aSubject.QueryInterface(Ci.nsITraceableChannel);
newListener.originalListener = aSubject.setNewListener(newListener);
alert(httpChannel.getResponseHeader("Location"));
//alert(httpChannel.getAllResponseHeaders());
}
//}
},
QueryInterface : function(aIID) {
if (aIID.equals(Components.interfaces.nsISupports) ||
aIID.equals(Components.interfaces.nsIObserver))
return this;
throw Components.results.NS_NOINTERFACE;
}
};
observerService.addObserver(listener, "http-on-modify-request", false);
observerService.addObserver(listener, "http-on-examine-response", false);
Related
My Code
I want to make a multiple connection to a telnet console. This project is for Teamspeak and Teamspeak just communicate with telnet. I´ve a object that create a telnet connection as socket with the net lib. If we have just one instance to connect all works fine and I get the serverlist over the telnet connection back. But if I´ve two instance he says invalid loginname or password. That login informations are correct and he also try just to connect to one server.
My Class:
/*
Teamspeak query client class
#instance: Instance object of the teamspeak query client
*/
function TeamspeakQueryClient(instance) {
events.EventEmitter.call(this);
var $this = this,
socket = net.connect(instance.port, instance.ip),
reader = null,
skipLines = -2,
queue = [ ],
executing = null,
server = null;
this.Type = 'Unknown';
this.Id = null;
this.Connected = false;
this.Banned = false;
/*
Socket settings
*/
socket.setKeepAlive(true, 60000);
/*
Socket connect to the teamspeak instance
*/
socket.on("connect", function() {
reader = LineInputStream(socket);
reader.on("line", function(line) {
var s = line.trim();
console.log(line);
// Skipp the first lines
if(skipLines < 0){
if(line === 'TS3') {
this.Type = 'Teamspeak';
};
skipLines++;
if(skipLines === 0) {
checkQueue();
if(server === null) {
$this.SendCommand("login", {client_login_name: instance.client, client_login_password: instance.password}, function(err, response, rawResponse) {
console.log(err);
if(err === null) {
if(err.id === 3329) {
$this.Banned = true;
};
$this.CloseSocket();
} else {
$this.SendCommand("serverlist", null, function(err, response, rawResponse){
console.log(response);
if(response[0] === undefined) {
console.log('1 server');
} else {
console.log('mehrere server');
};
//console.log(rawResponse);
/*cl.send("clientlist", function(err, response, rawResponse){
console.log(util.inspect(response));
});*/
});
};
});
} else {
console.log(server);
};
};
return;
};
// Parse server request
var response = undefined;
if(s.indexOf("error") === 0){
response = parseResponse(s.substr("error ".length).trim());
executing.error = response;
if(executing.error.id === 0) delete executing.error;
if(executing.cb) executing.cb.call(executing, executing.error, executing.response,
executing.rawResponse);
executing = null;
checkQueue();
} else if(s.indexOf("notify") === 0){
s = s.substr("notify".length);
response = parseResponse(s);
$this.emit(s.substr(0, s.indexOf(" ")), response);
} else if(executing) {
response = parseResponse(s);
executing.rawResponse = s;
executing.response = response;
};
});
$this.emit("connect");
});
/*
Socket error
*/
socket.on("error", function(err){
log.LogLine(1, 'TeamspeakQueryClient: We got a error');
log.LogLine(1, 'Message: '+err);
$this.emit("error", err);
});
/*
Socket close
*/
socket.on("close", function(){
log.LogLine(3, 'TeamspeakQueryClient: Socket from '+instance.alias+' closeing...');
$this.emit("close", queue);
});
/*
Function to send a custom command to the telnet console
*/
TeamspeakQueryClient.prototype.SendCommand = function SendCommand() {
var args = Array.prototype.slice.call(arguments);
//console.log(args);
var options = [], params = {};
var callback = undefined;
var cmd = args.shift();
args.forEach(function(v){
if(util.isArray(v)){
options = v;
} else if(typeof v === "function"){
callback = v;
} else {
params = v;
}
});
var tosend = tsescape(cmd);
options.forEach(function(v){
tosend += " -" + tsescape(v);
});
for(var k in params){
var v = params[k];
if(util.isArray(v)){ // Multiple values for the same key - concatenate all
var doptions = v.map(function(val){
return tsescape(k) + "=" + tsescape(val);
});
tosend += " " + doptions.join("|");
} else {
tosend += " " + tsescape(k.toString()) + "=" + tsescape(v.toString());
}
}
queue.push({cmd: cmd, options: options, parameters: params, text: tosend, cb: callback});
if(skipLines === 0) checkQueue();
};
/*
Function to close the socket
*/
TeamspeakQueryClient.prototype.CloseSocket = function CloseSocket() {
socket.destroy();
$this.emit("close");
};
/*
Function to parse a string to a object
#s: String of the object that will be parsed
#return: Object of the parsed string
*/
function parseResponse(s){
var response = [];
var records = s.split("|");
response = records.map(function(k){
var args = k.split(" ");
var thisrec = { };
args.forEach(function(v) {
if(v.indexOf("=") > -1) {
var key = tsunescape(v.substr(0, v.indexOf("=")));
var value = tsunescape(v.substr(v.indexOf("=")+1));
if(parseInt(value, 10) == value) value = parseInt(value, 10);
thisrec[key] = value;
} else {
thisrec[v] = "";
};
});
return thisrec;
});
if(response.length === 0) {
response = null;
} else if(response.length === 1) {
response = response.shift();
};
return response;
};
/*
Function to write commands into the socket
*/
function checkQueue() {
if(!executing && queue.length >= 1){
executing = queue.shift();
socket.write(executing.text + "\n");
};
};
/*
Function to escape a telnet string
#s: String that want to be escaped
#return: The escaped string
*/
function tsescape(s) {
return s
.replace(/\\/g, "\\\\")
.replace(/\//g, "\\/")
.replace(/\|/g, "\\p")
.replace(/\n/g, "\\n")
.replace(/\r/g, "\\r")
.replace(/\t/g, "\\t")
.replace(/\v/g, "\\v")
.replace(/\f/g, "\\f")
.replace(/ /g, "\\s");
};
/*
Function to unescape a telnet string
#s: String that want to be unescaped
#return: The unescaped string
*/
function tsunescape(s) {
return s
.replace(/\\s/g, " ")
.replace(/\\p/g, "|")
.replace(/\\n/g, "\n")
.replace(/\\f/g, "\f")
.replace(/\\r/g, "\r")
.replace(/\\t/g, "\t")
.replace(/\\v/g, "\v")
.replace(/\\\//g, "\/")
.replace(/\\\\/g, "\\");
};
};
util.inherits(TeamspeakQueryClient, events.EventEmitter);
How I open the class
if I call example one all works fine but example two has the descriped error.
Example 1:
test1 = new TeamspeakQueryClient({
"alias": "First-Coder Testinsance",
"ip": "first-coder.de",
"port": 10011,
"client": "serveradmin",
"password": "SECURE"
});
Example 2:
test1 = new TeamspeakQueryClient({
"alias": "First Insance",
"ip": "HIDDEN",
"port": HIDDEN,
"client": "serveradmin",
"password": "SECURE"
});
test2 = new TeamspeakQueryClient({
"alias": "Second Instance",
"ip": "HIDDEN",
"port": HIDDEN,
"client": "serveradmin",
"password": "SECURE"
});
Screenshots
Picture of the error in the console
According to your error, your second instance is not sending the correct login:
error id=520 msg=invalid\sloginname\sor\spassword
The additional errors displayed are due to your code not handling errors correctly.
For example:
socket.on("connect", function() {
...
if(err === null) {
if(err.id === 3329) {
If err === null, why would err have an element id?
Most likely this is code error, and you actually meant err !== null
$this.SendCommand("serverlist", null, function(err, response, rawResponse){
console.log(response);
if(response[0] === undefined) {
This error triggers because the (above) previous error was not caught.
At this point, the client is not logged in (authorized).
So when the serverlist command is sent, it riggers another error.
This additional error is also no handled, instead response is immediately used.
I'm using csrfMagic as an automatic CSRF protection for my project. when I include the script in my project XMLHTTPRequest events don't work.
for example 'onprogress' event is not triggered.
my code:
var xhr = new XMLHttpRequest()
xhr.open("POST", "./");
xhr.onreadystatechange = function (e) {
//some code
}
xhr.upload.onprogress = function (e) {
//this event is not triggered
console.log('xhr.upload.onprogress was triggerd');
}
csrfMagic script:
/**
* #file
*
* Rewrites XMLHttpRequest to automatically send CSRF token with it. In theory
* plays nice with other JavaScript libraries, needs testing though.
*/
// Here are the basic overloaded method definitions
// The wrapper must be set BEFORE onreadystatechange is written to, since
// a bug in ActiveXObject prevents us from properly testing for it.
CsrfMagic = function(real) {
// try to make it ourselves, if you didn't pass it
if (!real) try { real = new XMLHttpRequest; } catch (e) {;}
if (!real) try { real = new ActiveXObject('Msxml2.XMLHTTP'); } catch (e) {;}
if (!real) try { real = new ActiveXObject('Microsoft.XMLHTTP'); } catch (e) {;}
if (!real) try { real = new ActiveXObject('Msxml2.XMLHTTP.4.0'); } catch (e) {;}
this.csrf = real;
// properties
var csrfMagic = this;
real.onreadystatechange = function() {
csrfMagic._updateProps();
return csrfMagic.onreadystatechange ? csrfMagic.onreadystatechange() : null;
};
csrfMagic._updateProps();
}
CsrfMagic.prototype = {
open: function(method, url, async, username, password) {
if (method == 'POST') this.csrf_isPost = true;
// deal with Opera bug, thanks jQuery
if (username) return this.csrf_open(method, url, async, username, password);
else return this.csrf_open(method, url, async);
},
csrf_open: function(method, url, async, username, password) {
if (username) return this.csrf.open(method, url, async, username, password);
else return this.csrf.open(method, url, async);
},
send: function(data) {
if (!this.csrf_isPost) return this.csrf_send(data);
prepend = csrfMagicName + '=' + csrfMagicToken + '&';
if (this.csrf_purportedLength === undefined) {
this.csrf_setRequestHeader("Content-length", this.csrf_purportedLength + prepend.length);
delete this.csrf_purportedLength;
}
delete this.csrf_isPost;
return this.csrf_send(prepend + data);
},
csrf_send: function(data) {
return this.csrf.send(data);
},
setRequestHeader: function(header, value) {
// We have to auto-set this at the end, since we don't know how long the
// nonce is when added to the data.
if (this.csrf_isPost && header == "Content-length") {
this.csrf_purportedLength = value;
return;
}
return this.csrf_setRequestHeader(header, value);
},
csrf_setRequestHeader: function(header, value) {
return this.csrf.setRequestHeader(header, value);
},
abort: function() {
return this.csrf.abort();
},
getAllResponseHeaders: function() {
return this.csrf.getAllResponseHeaders();
},
getResponseHeader: function(header) {
return this.csrf.getResponseHeader(header);
} // ,
}
// proprietary
CsrfMagic.prototype._updateProps = function() {
this.readyState = this.csrf.readyState;
if (this.readyState == 4) {
this.responseText = this.csrf.responseText;
this.responseXML = this.csrf.responseXML;
this.status = this.csrf.status;
this.statusText = this.csrf.statusText;
}
}
CsrfMagic.process = function(base) {
var prepend = csrfMagicName + '=' + csrfMagicToken;
if (base) return prepend + '&' + base;
return prepend;
}
// callback function for when everything on the page has loaded
CsrfMagic.end = function() {
// This rewrites forms AGAIN, so in case buffering didn't work this
// certainly will.
forms = document.getElementsByTagName('form');
for (var i = 0; i < forms.length; i++) {
form = forms[i];
if (form.method.toUpperCase() !== 'POST') continue;
if (form.elements[csrfMagicName]) continue;
var input = document.createElement('input');
input.setAttribute('name', csrfMagicName);
input.setAttribute('value', csrfMagicToken);
input.setAttribute('type', 'hidden');
form.appendChild(input);
}
}
// Sets things up for Mozilla/Opera/nice browsers
// We very specifically match against Internet Explorer, since they haven't
// implemented prototypes correctly yet.
if (window.XMLHttpRequest && window.XMLHttpRequest.prototype && '\v' != 'v') {
var x = XMLHttpRequest.prototype;
var c = CsrfMagic.prototype;
// Save the original functions
x.csrf_open = x.open;
x.csrf_send = x.send;
x.csrf_setRequestHeader = x.setRequestHeader;
// Notice that CsrfMagic is itself an instantiatable object, but only
// open, send and setRequestHeader are necessary as decorators.
x.open = c.open;
x.send = c.send;
x.setRequestHeader = c.setRequestHeader;
} else {
// The only way we can do this is by modifying a library you have been
// using. We support YUI, script.aculo.us, prototype, MooTools,
// jQuery, Ext and Dojo.
if (window.jQuery) {
// jQuery didn't implement a new XMLHttpRequest function, so we have
// to do this the hard way.
jQuery.csrf_ajax = jQuery.ajax;
jQuery.ajax = function( s ) {
if (s.type && s.type.toUpperCase() == 'POST') {
s = jQuery.extend(true, s, jQuery.extend(true, {}, jQuery.ajaxSettings, s));
if ( s.data && s.processData && typeof s.data != "string" ) {
s.data = jQuery.param(s.data);
}
s.data = CsrfMagic.process(s.data);
}
return jQuery.csrf_ajax( s );
}
}
if (window.Prototype) {
// This works for script.aculo.us too
Ajax.csrf_getTransport = Ajax.getTransport;
Ajax.getTransport = function() {
return new CsrfMagic(Ajax.csrf_getTransport());
}
}
if (window.MooTools) {
Browser.csrf_Request = Browser.Request;
Browser.Request = function () {
return new CsrfMagic(Browser.csrf_Request());
}
}
if (window.YAHOO) {
// old YUI API
YAHOO.util.Connect.csrf_createXhrObject = YAHOO.util.Connect.createXhrObject;
YAHOO.util.Connect.createXhrObject = function (transaction) {
obj = YAHOO.util.Connect.csrf_createXhrObject(transaction);
obj.conn = new CsrfMagic(obj.conn);
return obj;
}
}
if (window.Ext) {
// Ext can use other js libraries as loaders, so it has to come last
// Ext's implementation is pretty identical to Yahoo's, but we duplicate
// it for comprehensiveness's sake.
Ext.lib.Ajax.csrf_createXhrObject = Ext.lib.Ajax.createXhrObject;
Ext.lib.Ajax.createXhrObject = function (transaction) {
obj = Ext.lib.Ajax.csrf_createXhrObject(transaction);
obj.conn = new CsrfMagic(obj.conn);
return obj;
}
}
if (window.dojo) {
// NOTE: this doesn't work with latest dojo
dojo.csrf__xhrObj = dojo._xhrObj;
dojo._xhrObj = function () {
return new CsrfMagic(dojo.csrf__xhrObj());
}
}
}
Your code does not contain a call of send method of XMLHttpRequest. So csrf_magic can't add csrf token to HTTP-request.
Example of a correct upload function:
function upload(file) {
var xhr = new XMLHttpRequest();
xhr.upload.onprogress = function(event) {
log(event.loaded + ' / ' + event.total);
}
xhr.onload = xhr.onerror = function() {
if (this.status == 200) {
log("success");
} else {
log("error " + this.status);
}
};
xhr.open("POST", "upload", true);
xhr.send(file);
}
Links:
https://developer.mozilla.org/ru/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest
(function () {
var db;
function openDB(dbname, dbtable, keypath) {
var version = 1;
// open the database
var indexeddb_request = indexedDB.open( dbname, version ); // connect + open database
// if error
indexeddb_request.onerror = function ( event ) {
console.log( event.target );
console.trace();
}
// if success
indexeddb_request.onsuccess = function ( event ) {
console.log( event.target );
console.trace();
db = event.target.result;
}
// if onupgradeneeded
indexeddb_request.onupgradeneeded = function( event ) {
console.log( event.target );
console.trace();
db = event.target.result;
var objectStore = db.createObjectStore( dbtable, { keyPath: 'url' } );
}
}
function getObjectStore(store_name, mode) {
var tx = db.transaction(store_name, mode);
return tx.objectStore(store_name);
}
function addPublication(dbtable, data) {
console.log("addPublication arguments:", arguments);
var store = getObjectStore(dbtable, 'readwrite');
var req;
try {
for (var i in data) {
req = store.add(data[i]);
}
//req = store.add(data);
} catch (e) {
if (e.name == 'DataCloneError')
displayActionFailure("This engine doesn't know how to clone a Blob, " +
"use Firefox");
throw e;
}
req.onsuccess = function (evt) {
console.log("Insertion in DB successful");
};
req.onerror = function() {
console.error("addPublication error", this.error);
};
}
function displayPubList(store, store_name) {
console.log("displayPubList");
if (typeof store == 'undefined')
store = getObjectStore(store_name, 'readonly');
var req;
req = store.count();
// Requests are executed in the order in which they were made against the
// transaction, and their results are returned in the same order.
// Thus the count text below will be displayed before the actual pub list
// (not that it is algorithmically important in this case).
req.onsuccess = function(evt) {
console.log("Count of records " + evt.target.result +
' record(s) in the object store.');
};
req.onerror = function(evt) {
console.error("add error", this.error);
};
var i = 0;
req = store.openCursor();
req.onsuccess = function(evt) {
var cursor = evt.target.result;
// If the cursor is pointing at something, ask for the data
if (cursor) {
console.log("displayPubList cursor:", cursor);
req = store.get(cursor.key);
req.onsuccess = function (evt) {
var value = evt.target.result;
console.log("Key :" + cursor.key + 'value :' + value.ssn );
};
// Move on to the next object in store
cursor.continue();
// This counter serves only to create distinct ids
i++;
} else {
console.log("No more entries");
}
};
}
openDB("abc","names","ssn");
const customerData = [
{ ssn: "444-44-4444", name: "Bill", age: 35, email: "bill#company.com" },
{ ssn: "555-55-5555", name: "Donna", age: 32, email: "donna#home.org" }
];
addPublication("names",customerData);
displayPubList("abc","names");
})();
I'm trying to test the above code from chrome developer tools. But looks like some cases the call goes into sucess or upgradeneeded. And many times its always null. Please let me know if i'm doing something wrong here.
I'm trying to send HTTP requests via StreamSocket, but response is truncated with
"failedWinRTError: The object has been closed."
Here is my code:
var count, hostName, raw_request, raw_response, reader, socketProtection, startReader, streamSocket, writer;
streamSocket = new Windows.Networking.Sockets.StreamSocket();
hostName = new Windows.Networking.HostName("www.reddit.com", "80");
raw_response = "";
count = 0;
startReader = function() {
return reader.loadAsync(8 * 1000).done(function(bytesRead) {
raw_response += reader.readString(reader.unconsumedBufferLength);
if (raw_response.indexOf("</html>") > 0) {
return;
} else {
startReader();
}
}, function(error) {
raw_response += reader.readString(reader.unconsumedBufferLength);
window.raw_response = raw_response;
return;
});
};
streamSocket.connectAsync(hostName, "80", 0).done(function(response) {
var string;
reader = new Windows.Storage.Streams.DataReader(streamSocket.inputStream);
reader.inputStreamOptions = 1;
writer = new Windows.Storage.Streams.DataWriter(streamSocket.outputStream);
string = "Hello world";
writer.writeString(raw_request);
return writer.storeAsync().done(function() {
writer.flushAsync();
writer.detachStream();
return startReader();
});
});
I noticed that the beginning of the response is truncated as well.
This is what I get at the beginning of HTTP responses.
/1.1 200 OK
Also strangely... HTTPS requests work perfectly.
Any idea what I'm doing wrong? Thanks :)
Remove http:// from the host name and the second parameter is not needed:
var hostName = new Windows.Networking.HostName("www.reddit.com");
Use this object in ConnectAsync, just hostname and service name parameters are needed:
streamSocket.connectAsync(hostName, "80").done(function (response) {
// ....
}, function (error) {
console.log(error);
});
UPDATE: Ok, if the connection is being closed, probably the server closes it. Are you sending a well formed request? Here is an example:
var raw_request, raw_response, reader, writer;
var streamSocket = new Windows.Networking.Sockets.StreamSocket();
function doRequest() {
var hostName = new Windows.Networking.HostName("www.reddit.com");
streamSocket.connectAsync(hostName, "808").then(function () {
reader = new Windows.Storage.Streams.DataReader(streamSocket.inputStream);
reader.inputStreamOptions = Windows.Storage.Streams.InputStreamOptions.partial;
writer = new Windows.Storage.Streams.DataWriter(streamSocket.outputStream);
raw_request = "GET / HTTP/1.1\r\nHost: www.reddit.com/\r\nConnection: close\r\n\r\n";
writer.writeString(raw_request);
return writer.storeAsync();
}).then(function () {
raw_response = "";
return startReader();
}, function (error) {
console.log(error);
});
}
function startReader() {
return reader.loadAsync(99999999).then(function (bytesRead) {
raw_response += reader.readString(reader.unconsumedBufferLength);
if (bytesRead === 0) {
window.raw_response.value = raw_response;
return;
}
return startReader();
});
};
I'm trying to implement the basic XHR listener as described on "Ashita" however, when loading firefox with the extension I recieve this error on whenever a page tries to load which prevents anything from loading: Error: uncaught exception: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsIBinaryInputStream.readBytes]" nsresult: "0x80004005 (NS_ERROR_FAILURE)" location: "JS frame :: chrome://xhrlogger/content/overlay.js :: anonymous :: line 68" data: no]
My overlay.js is:
if (typeof Cc == "undefined") {
var Cc = Components.classes;
}
if (typeof Ci == "undefined") {
var Ci = Components.interfaces;
}
if (typeof CCIN == "undefined") {
function CCIN(cName, ifaceName){
return Cc[cName].createInstance(Ci[ifaceName]);
}
}
if (typeof CCSV == "undefined") {
function CCSV(cName, ifaceName){
if (Cc[cName])
// if fbs fails to load, the error can be _CC[cName] has no properties
return Cc[cName].getService(Ci[ifaceName]);
else
dump("CCSV fails for cName:" + cName);
};
}
var httpRequestObserver = {
observe: function(request, aTopic, aData){
if (aTopic == "http-on-examine-response") {
var newListener = new TracingListener();
request.QueryInterface(Ci.nsITraceableChannel);
newListener.originalListener = request.setNewListener(newListener);
}
},
QueryInterface: function(aIID){
if (aIID.equals(Ci.nsIObserver) ||
aIID.equals(Ci.nsISupports)) {
return this;
}
throw Components.results.NS_NOINTERFACE;
},
};
function TracingListener() {
this.receivedData = []; //initialize the array
}
TracingListener.prototype =
{
originalListener: null,
receivedData: null, //will be an array for incoming data.
onDataAvailable: function(request, context, inputStream, offset, count) {
var binaryInputStream = CCIN("#mozilla.org/binaryinputstream;1",
"nsIBinaryInputStream");
binaryInputStream.setInputStream(inputStream);
var storageStream = CCIN("#mozilla.org/storagestream;1",
"nsIStorageStream");
//8192 is the segment size in bytes, count is the maximum size of the stream in bytes
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);
this.receivedData.push(data);
binaryOutputStream.writeBytes(data, count);
//Pass it on down the chain
this.originalListener.onDataAvailable(request, context, inputStream, offset, count);
},
onStartRequest: function(request, context) {
this.originalListener.onStartRequest(request, context);
},
onStopRequest: function(request, context, statusCode) {
try
{
//QueryInterface into HttpChannel to access originalURI and requestMethod properties
request.QueryInterface(Ci.nsIHttpChannel);
var data = null;
if (request.requestMethod.toLowerCase() == "post")
{
var postText = this.readPostTextFromRequest(request, context);
if (postText)
data = ((String)(postText)).parseQuery();
}
//Combine the response into a single string
var responseSource = this.receivedData.join('');
//fix leading spaces bug
//(FM occasionally adds spaces to the beginning of their ajax responses...
//which breaks the XML)
responseSource = responseSource.replace(/^\s+(\S[\s\S]+)/, "$1");
//gets the date from the response headers on the request.
//For PirateQuesting this was preferred over the date on the user's machine
var date = Date.parse(request.getResponseHeader("Date"));
//Again a PQ specific function call, but left as an example.
//This just passes a string URL, the text of the response,
//the date, and the data in the POST request (if applicable)
/* piratequesting.ProcessRawResponse(request.originalURI.spec,
responseSource,
date,
data); */
dump(date);
dump(data);
dump(responseSource);
}
catch (e)
{
//standard function to dump a formatted version of the error to console
dump(e);
}
this.originalListener.onStopRequest(request, context, statusCode);
},
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);
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)
{
dump(exc);
}
return null;
},
QueryInterface: function (aIID) {
if (aIID.equals(Ci.nsIStreamListener) ||
aIID.equals(Ci.nsISupports)) {
return this;
}
throw Components.results.NS_NOINTERFACE;
},
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;
}
}
var observerService = Cc["#mozilla.org/observer-service;1"]
.getService(Ci.nsIObserverService);
observerService.addObserver(httpRequestObserver,
"http-on-examine-response", false);
dump("WTFBBQ");
Any help would be most appreciated.
Mine seems to work fine with less code. Try replacing your onDataAvailable function code with:
var binaryInputStream = Components.classes["#mozilla.org/binaryinputstream;1"].createInstance(Components.interfaces.nsIBinaryInputStream);
binaryInputStream.setInputStream(inputStream);
this.receivedData.push(binaryInputStream.readBytes(count));