Iam building an extension where i catch all the post requests. But in the httpChannel.originalURI.spec there aren't any attributes from the post. How can i get the post's atrtibutes?
myObserver.prototype = {
observe: function(subject, topic, data) {
if("http-on-modify-request"){
var httpChannel = subject.QueryInterface(Components.interfaces.nsIHttpChannel);
if(httpChannel.requestMethod=="POST")
alert(httpChannel.originalURI.spec);
}
}
},
register: function() {
var observerService = Components.classes["#mozilla.org/observer-service;1"]
.getService(Components.interfaces.nsIObserverService);
observerService.addObserver(this, "http-on-modify-request", false);
},
unregister: function() {
var observerService = Components.classes["#mozilla.org/observer-service;1"]
.getService(Components.interfaces.nsIObserverService);
observerService.removeObserver(this, "http-on-modify-request");
}
}
Any ideas?
nsIHttpChannel only provides access to HTTP headers. POST data is sent as part of the request body so you need to change your object interface to nsIUploadChannel and read the binary upload data into a string.
var uploadChannel = httpChannel.QueryInterface(Ci.nsIUploadChannel);
var uploadStream = uploadChannel.uploadStream;
uploadStream.QueryInterface(Ci.nsISeekableStream).
seek(Ci.nsISeekableStream.NS_SEEK_SET, 0);
var binStream = Cc["#mozilla.org/binaryinputstream;1"].
createInstance(Ci.nsIBinaryInputStream);
binStream.setInputStream(uploadStream);
var postBytes = binStream.readByteArray(binStream.available());
var postString = String.fromCharCode.apply(null, postBytes);
The code from Luckyrat did not work properly for me. I had to deal with some requests timing out. Noticing nmaiers comment this code is working correctly (as far as I can tell):
function getPostString(httpChannel) {
var postStr = "";
try {
var uploadChannel = httpChannel.QueryInterface(Ci.nsIUploadChannel);
var uploadChannelStream = uploadChannel.uploadStream;
if (!(uploadChannelStream instanceof Ci.nsIMultiplexInputStream)) {
uploadChannelStream.QueryInterface(Ci.nsISeekableStream).seek(Ci.nsISeekableStream.NS_SEEK_SET, 0);
var stream = Cc["#mozilla.org/binaryinputstream;1"].createInstance(Ci.nsIBinaryInputStream);
stream.setInputStream(uploadChannelStream);
var postBytes = stream.readByteArray(stream.available());
uploadChannelStream.QueryInterface(Ci.nsISeekableStream).seek(0, 0);
postStr = String.fromCharCode.apply(null, postBytes);
}
}
catch (e) {
console.error("Error while reading post string from channel: ", e);
}
finally {
return postStr;
}
}
Related
I am trying to save a key if it doesn't exists and if it does- just read it.
But it always alerts undefined.
var idb = window.indexedDB.open('MyDB', 1);
idb.onupgradeneeded = function(e)
{
var db = e.target.result;
if (!db.objectStoreNames.contains('all'))
{
db.createObjectStore('all');
}
}
idb.onsuccess = function(e)
{
db = e.target.result;
setData();
}
function setData()
{
var store = db.transaction(['all'], 'readwrite').objectStore('all');
var item1 = {theTitle: 'myKey', theValue: 'myValue'};
var op = store.get('myKey');
op.onsuccess = function(event)
{
alert(op.result);
}
op.onerror = function()
{
var req = store.add(item1, 1);
req.onsuccess = function()
{
alert('Saved');
}
}
}
IDBObjectStore will return undefined if it can't find anything, so your op.onsuccess function is actually working correctly.
See here: http://www.w3.org/TR/IndexedDB/#widl-IDBObjectStore-get-IDBRequest-any-key
You can place your "store.add" code in your onsuccess function:
var transaction = db.transaction(['all'], 'readwrite');
var store = transaction.objectStore('all');
var item1 = {
theTitle: 'myKey',
theValue: 'myValue'
};
var op = store.get('myKey');
op.onsuccess = function(event) {
if (op.result) {
alert(op.result);
} else {
var req = store.add(item1, 1);
req.onsuccess = function() {
alert('Saved');
}
}
}
transaction.oncomplete = function(event) {
console.log("Transaction complete. Everything is saved.")
}
Also look at the transaction.complete, onerror and onabort functions - they provide you with a better place to do dump all your error handling.
I would advise you to read the IDB spec: it's seems longwinded at first, but you get used to it and it's the best document there is on IDB.
http://www.w3.org/TR/IndexedDB/
Have fun!
I have an app (questionnaire) that uses indexedDB.
We have one database and several stores in it.
Stores have data already stored in them.
At some point a dashboard html file is loaded. In this file I am calling couple of functions:
function init(){
adjustUsedScreenHeight();
db_init();
setInstitutionInstRow();
loadRecommendations();
loadResultsFromDB();
fillEvaluations();
document.addEventListener("deviceready", onDeviceReady, function(e) {console.log(e);});
}
The init() function is called on body onLoad.
setInstitutionInstRow() looks like these:
function setInstitutionInstRow(localId){
//localId = 10;
if (localId == undefined){
console.log("Localid underfined: ");
//open db, open objectstore;
var request = indexedDB.open("kcapp_db", "1.0");
request.onsuccess = function() {
var db = request.result;
var tx = db.transaction ("LOCALINSTITUTIONS", "readonly");
var store = tx.objectStore("LOCALINSTITUTIONS");
tx.oncomplete = function(){
db.close();
}
tx.onerror = function(){
console.log("Transaction error on setInstInstRow");
}
var cursor = store.openCursor();
cursor.onsuccess= function () {
var match = cursor.result;
console.log ("Retrieved item: " + match.value.instid);
// alert("Added new data");
if (match){
setInstituionInstRow(match.value.instid);
console.log("Got localid: " + math.value.instid);
}
else
console.log("localinsid: it is empty " );
};
cursor.onerror = function () {
console.log("Error: " + item.result.errorCode);
}
}
request.onerror = function () {
console.log("Error: " + request.result.errorCode );
}
request.oncomplete = function (){
console.log("The transaction is done: setInstitutionRow()");
}
request.onupgradeneeded = function (){
console.log("Upgrade needed ...");
}
request.onblocked = function(){
console.log("DB is Blocked ...");
}
} else {
instid = localId;
var now = new Date();
//console.log("["+now.getTime()+"]setInstituionInstRow - instid set to "+localId);
//open db, open objectstore;
var request = indexedDB.open("kcapp_db", "1.0");
request.onsuccess = function() {
var db = this.result;
var tx = db.transaction ("INSTITUTIONS", "readonly");
var store = tx.objectStore("INSTITUTIONS");
var item = store.get(localId);
console.log(item);
item.onsuccess= function () {
console.log ("Retrieved item: ");
if (item.length > 0)
var lInstitution = item.result.value;
kitaDisplayValue = lInstitution.krippe;
};
item.onerror = function () {
console.log("Error: " + item.result.errorCode);
}
}
request.onerror = function () {
console.log("Error: " + request.result.errorCode );
}
}
Now the problem is,
var request = indexedDB.open("kcapp_db", "1.0");
the above request is never getting into any onsuccess, oncomplete, onerror states. I debugged with Chrome tools, it never getting into any above states.
Accordingly I am not getting any data from transactions.
And there are no errors in Chrome console.
And here is the request value from Chrome dev:
From above image the readyState: done , which means it should fire an event (success, error, blocked etc). But it is not going into any of them.
I am looking into it, and still can not figure out why it is not working.
Have to mention that the other functions from init() is behaving the same way.
Looking forward to get some help.
You may be using an invalid version parameter to the open function. Try indexedDB.open('kcapp_db', 1); instead.
Like Josh said, your version parameter should be an integer, not a string.
Your request object can get 4 events in response to the open request: success, error, upgradeneeded, or blocked. Add event listeners for all of those (e.g. request.onblocked = ...) and see which one is getting fired.
I had that problem but only with the "onupgradeneeded" event. I fixed it changing the name of the "open" function. At the begining I had a very long name; I changed it for a short one and start working. I don't know if this is the real problem but it was solved at that moment.
My code:
if (this.isSupported) {
this.openRequest = indexedDB.open("OrdenesMant", 1);
/**
* Creación de la base de datos con tablas y claves primarias
*/
this.openRequest.onupgradeneeded = function(oEvent) {
...
Hope it works for you as well.
I'm basically following the accepted answer to this question (Is it possible to ping a server from Javascript?)
Update
It seems to work as expected when the domain is 15 characters long (actually, http:// + 15, but 16 or more causes it to bomb. More details at the bottom.
The issue I'm seeing is that if you're using something that seems like a valid domain, for example http://thisisdefinitelynotarealdomainname.com, it returns an error but the code mentioned considers errors okay (because most should be). Looking at the error event, I'm not sure I see where I could get the HTTP response code (i.e., if it's a 404, consider it invalid).
Here is a jsFiddle showing the problem -- they all display "responded". If you look in the console, the invalid domain returns a 404 error, and the two valid ones (if in chrome console, not sure about the others) show that they were interpreted as an image but transferred as text/html -- is there any way to read either the 404 error, or the mime type?
var pinger = function () {
var ping = function (ip, callback) {
if (!this.inUse) {
this.status = 'unchecked';
this.inUse = true;
this.callback = callback;
this.ip = ip;
var _that = this;
this.img = new Image();
this.img.onload = function () {
_that.inUse = false;
_that.callback('responded');
};
this.img.onerror = function (e) {
if (_that.inUse) {
_that.inUse = false;
_that.callback('responded', e);
}
console.log(e);
};
this.start = new Date().getTime();
this.img.src = "http://" + ip + "/?now=" + this.start; // add the current time to work around caching
this.time = setTimeout(function () {
if (_that.inUse) {
_that.inUse = false;
_that.callback('timeout');
}
}, 1500);
}
}
return {
ping: ping
};
}();
(function () {
var output = document.getElementById('output');
var servers = [
'localhost',
'google.com',
'okthisreallydoesntmakeanysense',
'okthisreallydoe',
'thisisashortone',
'thisisabitlonger'
];
servers.forEach(function (server) {
new pinger.ping(server, function (status, e) {
output.innerHTML += server + ': ' + status + '<br />';
});
});
})();
Update
What's even more weird is that it seems to be fine up until 15 characters. I've updated the jsFiddle. See below on ones that respond how I'd expect vs ones that don't. What might cause this?
'localhost',
'google.com',
'okthisreallydoesntmakeanysense', // doesn't work
'okthisreallydoe', // works (15 characters)
'thisisashortone', // works (15 characters)
'thisisabitlonger' // doesn't work (16 characters)
This might help.
function Pinger_ping(ip, callback) {
if(!this.inUse) {
this.inUse = true;
this.callback = callback
this.ip = ip;
var _that = this;
this.img = new Image();
this.img.onload = function() {_that.good();};
this.img.onerror = function() {_that.good();};
this.start = new Date().getTime();
this.img.src = "http://" + ip;
this.timer = setTimeout(function() { _that.bad();}, 1500);
}
}
Let me know if it works
After wasting my two days to find out what's going wrong with this script, finally I decide to ask it.
What I am trying to do
I am trying to read a text file from remote server. Then storing all text file updates to an SQLITE database at the time of my Firefox Extension/Addon get loaded.
What I tried
var updatereader = {
start: function () {
//alert('reading update');
var fURL = null;
var ioService = null;
var fURI = null;
var httpChannel = null;
fURL = "http://www.example.com/addon/mlist.txt";
ioService = Components.classes["#mozilla.org/network/io-service;1"].getService(Components.interfaces.nsIIOService);
fURI = ioService.newURI(fURL, null, null);
httpChannel = ioService.newChannelFromURI(fURI).QueryInterface(Components.interfaces.nsIHttpChannel);
httpChannel.asyncOpen(updatereader.StreamReader, null);
},
onUpdateCompleted: function () {
},
StreamReader:
{
fOutputStream: null,
fPointer: null,
tempFile: "mlist.txt",
onStartRequest: function (aRequest, aContext) {
//alert('onStart');
updatereader.StreamReader.fOutputStream = Components.classes["#mozilla.org/network/file-output-stream;1"].createInstance(Components.interfaces.nsIFileOutputStream);
updatereader.StreamReader.fPointer = Components.classes["#mozilla.org/file/directory_service;1"].getService(Components.interfaces.nsIProperties).get("ProfD", Components.interfaces.nsIFile);
updatereader.StreamReader.fPointer.append(updatereader.StreamReader.tempFile);
updatereader.StreamReader.fOutputStream.init(updatereader.StreamReader.fPointer, 0x02 | 0x20 | 0x08, 0644, 0);
},
onDataAvailable: function (aRequest, aContext, aInputStream, aOffset, aCount) {
//control flow is not entering here - may be here is somehting missing
var sStream = null;
var tempBuffer = null;
sStream = Components.classes["#mozilla.org/scriptableinputstream;1"].createInstance(Components.interfaces.nsIScriptableInputStream);
sStream.init(aInputStream);
tempBuffer = sStream.read(aCount);
updatereader.StreamReader.fOutputStream.write(tempBuffer, aCount);
},
onStopRequest: function (aRequest, aContext, aStatusCode) {
//alert('onStop');
var currentDate = new Date();
if (aStatusCode == 0) {
fileInputStream = Components.classes["#mozilla.org/network/file-input-stream;1"].createInstance(Components.interfaces.nsIFileInputStream);
updatereader.StreamReader.fOutputStream.close();
fileInputStream.init(updatereader.StreamReader.fPointer, 0x01, 0, 0);
lineInputStream = fileInputStream.QueryInterface(Components.interfaces.nsILineInputStream);
//pass data to somewhere
var dbH = new dbstore();
dbH.updateData(lineInputStream);
lineInputStream.close();
updatereader.StreamReader.fPointer.remove(false);
updatereader.onUpdateCompleted();
} else {
}
}
}
}
Problem:
Getting nothing in lineInputStream which passes the read data to somewhere else for storing it.
Area of problem:
Program control flow is not entring to this section
onDataAvailable:
Not getting any error.
First of all, there doesn't really seem to be any need to read the file to the disk first (unless it is really, really big).
I'd just use XMLHttpRequest to get the file, which when run from a privileged context (e.g. add-on code, but not a website) can access any and every valid URI.
XMLHttpRequest will simplify almost everything, e.g. no more onDataAvailable, (usually) no more manual text converting, etc.
Also, no need to ever hit the disk during the transfer.
Code would look something like this:
var req = new XMLHttpRequest();
req.open("GET", "http://www.example.com/addon/mlist.txt"); // file:/// would work too, BTW
req.overrideMimeType("text/plain");
req.addEventListener("load", function() {
// Do something with req.responseText
}, false);
req.addEventListener("error", function() {
// Handle error
}, false);
req.send();
If you want to use XMLHttpRequest in a non-window, e.g. js code module or js components, then you need to first initialize a constructor. This is not required for windows, including XUL windows and by that XUL overlays.
// Add XMLHttpRequest constructor, if not already present
if (!('XMLHttpRequest' in this)) {
this.XMLHttpRequest = Components.Constructor("#mozilla.org/xmlextras/xmlhttprequest;1", "nsIXMLHttpRequest");
}
SDK users should use the request module, or net/xhr if a lower-level API is required.
PS: If you're still interested in using raw channels, here is a minimal example I coded up in a Scratchpad (to run, open a Scratchpad for a privileged location, e.g. about:newtab).
You shouldn't alert from your own implementation: alert() will spin the event loop and causes reentrant code, which is not supported in this context.
var {
classes: Cc,
interfaces: Ci,
results: Cr,
utils: Cu
} = Components;
Cu.import("resource://gre/modules/XPCOMUtils.jsm")
Cu.import("resource://gre/modules/Services.jsm");
var ConverterStream = Components.Constructor(
"#mozilla.org/intl/converter-input-stream;1",
"nsIConverterInputStream",
"init");
var RC = Ci.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER;
function Listener() {
this.content = "";
}
Listener.prototype = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIStreamListener]),
onStartRequest: function(req, ctx) {
console.log("start");
},
onDataAvailable: function(req, ctx, stream, offset, count) {
console.log("data", count);
try {
var cs = new ConverterStream(stream, null /* utf-8 */, 4096, RC);
try {
var str = {};
while (cs.readString(4096, str)) {
this.content += str.value;
}
}
finally {
cs.close();
}
}
catch (ex) {
console.error("data", ex.message, ex);
}
},
onStopRequest: function(req, ctx, status) {
console.log("stop", status,
this.content.substr(0, 20), this.content.length);
}
};
var uri = Services.io.newURI("http://example.org", null, null);
Services.io.newChannelFromURI(uri).asyncOpen(new Listener(), null);
I'm created this class to fetch a file from web to check for new version using Ajax.
This code run on a Windows gadget, on IE8. But I'm having trouble because of the cache.
Is there a way to fix this Ajax class to disable cache?
PS: I don't use any library or frameworks.
var ClassAjax = function() {
this.data = null;
var that = this;
this.get = function(url, send) {
var ajax = new function ObjAjax() {
try{ return new XMLHttpRequest(); }
catch(e){try{ return new ActiveXObject("Msxml2.XMLHTTP"); }
catch(e){ return new ActiveXObject("Microsoft.XMLHTTP"); }}
return null;
}
ajax.onreadystatechange = function() {
if(ajax.readyState == 1) { that.onLoading(); }
if(ajax.readyState == 4) { that.data=ajax.responseText; that.onCompleted(that.data); }
}
ajax.open("GET", url, true);
ajax.send(send);
};
this.onLoading = function() {
//function called when connection was opened
};
this.onCompleted = function(data) {
//function called when download was completed
};
}
var request = new ClassAjax();
request.onCompleted = function(data) { alert(data); }
request.get('http://exemple.com/lastversion.html', null);
You can pass the current timestamp as a variable in the url, like this :
var timestamp = new Date().getTime();
ajax.open("GET", url+'?ts='+timestamp, true);
Also, you can force the page to be reloaded on server-side, using the proper headers