Receiving binary data using request module in Firefox Add-on SDK - ajax

I am using the Add-on builder and I need to receive binary data (image). I would like to do this using the request module but as you can see from the documentation:
https://addons.mozilla.org/en-US/developers/docs/sdk/latest/packages/addon-kit/docs/request.html
There are only text and json properties and raw is absent.
How should I receive binary data in the add-on script?

You cannot do this using the request module, you will have to use the regular XMLHttpRequest via chrome authority. Something like this should work:
var {Cc, Ci} = require("chrome");
var request = Cc["#mozilla.org/xmlextras/xmlhttprequest;1"]
.createInstance(Ci.nsIJSXMLHttpRequest);
request.open("GET", "...");
request.onload = function()
{
onUnload.unload();
var arrayBuffer = request.response;
if (arrayBuffer)
{
var byteArray = new Uint8Array(arrayBuffer);
...
}
};
request.onerror = function()
{
onUnload.unload();
}
request.send(null);
var onUnload = {
unload: function()
{
// Make sure to abort the request if the extension is disabled
try
{
request.abort();
}
catch (e) {}
}
};
require("unload").ensure(onUnload);
The mechanism to ensure that the request is aborted if your extension is suddenly disabled is rather awkward, that's the main reason the request module exists rather than simply giving you XMLHttpRequest. Note that it is important to call onUnload.unload() once the request finishes, otherwise the Add-on SDK will keep it in the list of methods to be called on unload (a memory leak). See documentation of unload module.

Related

Asynchronous form-data POST request with xmlhhtprequest

I am trying to upload a file to the REST Api of Octoprint, which should be done by sending a POST request with Content-Type: multipart/form-data
(http://docs.octoprint.org/en/master/api/fileops.html#upload-file)
I am using NodeJS and two libraries, XmlHttpRequest and form-data. When trying:
var xhr = new xmlhttprequest() ;
var form = new formData() ;
form.append('exampleKey', 'exampleValue');
xhr.open("POST","octopi.local/api/local", true) ;
xhr.setRequestHeader("Content-Type","multipart/form-data") ;
xhr.send(form) ;
I get an error at the xhr.send line :
TypeError: first argument must be a string or Buffer
If I make a synchronous request by using xhr.open("POST",url,false), this error disappears.
Why is it so ? Is there a way to turn it into an asynchronous request ?
EDIT Actually, I don't really understand the documentation. I suppose that I should set the file I want to upload by using form.append("filename", filepath, "exampleName"), but I am not sure about that. The fact is that I noticed that I get the TypeError even if I try a simplified request, without sending any file.
EDIT2 This is the modified code, which returns the same error :
var XMLHttpRequest=require('xmlhttprequest').XMLHttpRequest ;
var FormData = require('form-data');
var data = new FormData();
data.append("key","value" );
var xhr = new XMLHttpRequest();
xhr.open('POST', "octopi.local/api/files/");
xhr.send(data);
After a long time working on this, I finally managed to upload a file. If you use NodeJS, don't rely on the MDN documentation: it tells what the libraries should do, not what they can actually do on the node platform. You should only focus on the docs available on GitHub.
It seems that it is not currently possible to send a form with XMLHttpRequest : I tried using JSON.stringify(form) but then wireshark tells me that the request is not a multipart/formdata request.
If you want to upload a file, you should rather use the 'request' module. The following has worked for me :
exports.unwrappeduploadToOctoprint = function(){
"use strict" ;
var form ={
file: {
value: fs.readFileSync(__dirname+'/test2.gcode'),
options: { filename: 'test2.gcode'}
}
};
var options = {
method: 'POST',
url: 'http://192.168.1.24/api/files/local',
headers: { 'x-api-key': 'E0A2518FB11B40F595FC0068192A1AB3'},
formData: form
};
var req = request(options, function (error, response, body) {
if (error) throw new Error(error);
console.log(body);
});
};
Seems that you have some typos in your code. Use code snippet below instead. Replace the relevant parts according to your needs
var fileToUpload = document.getElementById('input').files[0];
var data = new FormData();
data.append("myfile", fileToUpload);
var xhr = new XMLHttpRequest();
xhr.open('POST', "upload_endpoint");
xhr.send(data);

Dart Language: Authentication and session control (shelf_auth)

I'm developing a Dart application that will need authentication and session control. I'm trying shelf_auth to do that, but the examples doesn't seem to work or, more likely, I'm not implementing them the right way.
In short, this is what I want to happen:
An user opens the application on the browser.
The user enters the login information (login and password), which are POSTED to the server.
If the provided information is valid, the application generates a session code that is passed to the client and stored on the DB (server-side). This code will be sent with every transaction to the server-side.
The package shelf_auth has some examples, but I don't know which one to follow. So my question is: how could I do that with shelf_auth? I'm not asking for anyone to code this for me, but just to point me to the right direction.
EDIT: The example that I was trying out was this: example_with_login_and_jwt_session.dart. Seems that it's lacking CORS headers (this question helped me fixing it) and, even providing valid information, it responds "Unauthorized".
This is how I'm POSTING the information:
import "dart:html";
void main() {
Map _queryParameters = {
"username": "fred",
"password": "blah"
};
var _button = querySelector("#login_button");
_button.onClick.listen((MouseEvent e) {
e.preventDefault();
var requisition = new HttpRequest();
Uri uri = new Uri(path: "http://localhost:8080/login", queryParameters: _queryParameters);
requisition.open("POST", uri.toString());
requisition.setRequestHeader("content-type", "application/x-www-form-urlencoded");
requisition.onLoadEnd.listen((_) {
print(requisition.response.toString());
});
requisition.send();
});
}
I got it working with this client code
import "dart:html";
void main() {
Map _queryParameters = {"username": "fred", "password": "blah"};
var _button = querySelector("#login_button");
_button.onClick.listen((MouseEvent e) async {
e.preventDefault();
var requisition = new HttpRequest();
Uri uri = new Uri(
path: "http://localhost:8080/login/");
requisition.onLoadEnd.listen((_) {
print(requisition.response.toString());
});
HttpRequest request = await HttpRequest.postFormData(
"http://localhost:8080/login/", _queryParameters
//,withCredentials: true
);
print(request.response);
});
}
The example server expects the credentials in the body instead of query parameters and I set withCredentials: true so authentication cookies are sent with the request. Worked without withCredentials.

firefox OS app,CORS in Firefox os app

I have been developing web-app(not hosted app) in firefox OS .
I want to access the websites xml/JSON data using XMLHttp request. but it gives error as CORS not allowed to access the data . I know about to add 'Access-Control-Allow-Origin' header in website and enabling CORS may cause security issues.
But is their any alternate way to access the data feed via XMLHttp request?
First change your manifest to have the following fields (the type one gets forgotten by people):
"type": "privileged",
"permissions": {
"systemXHR" : {}
}
Second, move all your JavaScript code to a separate JS file. Because it's not allowed to have inline tags in a privileged application.
Third use the mozSystem constructor like raidendev said:
var xhr = new XMLHttpRequest({ mozSystem: true });
To perform cross-domain http request from Firefox OS app you need to set permission systemXHR in app's manifest:
"permissions": {
"systemXHR" : {}
}
and create XMLHttpRequest with property mozSystem set to true:
var xhr = new XMLHttpRequest({ mozSystem: true });
Also, for any cases where XMLHttpRequest is not applicable, you can use TCP Socket API.
var socket = navigator.mozTCPSocket.open('localhost', 80);
socket.ondata = function (event) {
if (typeof event.data === 'string') {
console.log('Get a string: ' + event.data);
} else {
console.log('Get a Uint8Array');
}
}

a file upload progress bar with node (socket.io and formidable) and ajax

I was in the middle of teaching myself some Ajax, and this lesson required building a simple file upload form locally. I'm running XAMPP on windows 7, with a virtual host set up for http://test. The solution in the book was to use node and an almost unknown package called "multipart" which was supposed to parse the form data but was crapping out on me.
I looked for the best package for the job, and that seems to be formidable. It does the trick and my file will upload locally and I get all the details back through Ajax. BUT, it won't play nice with the simple JS code from the book which was to display the upload progress in a progress element. SO, I looked around and people suggested using socket.io to emit the progress info back to the client page.
I've managed to get formidable working locally, and I've managed to get socket.io working with some basic tutorials. Now, I can't for the life of me get them to work together. I can't even get a simple console log message to be sent back to my page from socket.io while formidable does its thing.
First, here is the file upload form by itself. The script inside the upload.html page:
document.getElementById("submit").onclick = handleButtonPress;
var httpRequest;
function handleResponse() {
if (httpRequest.readyState == 4 && httpRequest.status == 200) {
document.getElementById("results").innerHTML = httpRequest.responseText;
}
}
function handleButtonPress(e) {
e.preventDefault();
var form = document.getElementById("myform");
var formData = new FormData(form);
httpRequest = new XMLHttpRequest();
httpRequest.onreadystatechange = handleResponse;
httpRequest.open("POST", form.action);
httpRequest.send(formData);
}
And here's the corresponding node script (the important part being form.on('progress')
var http = require('http'),
util = require('util'),
formidable = require('formidable');
http.createServer(function(req, res) {
if (req.url == '/upload' && req.method.toLowerCase() == 'post') {
var form = new formidable.IncomingForm(),
files = [],
fields = [];
form.uploadDir = './files/';
form.keepExtensions = true;
form
.on('progress', function(bytesReceived, bytesExpected) {
console.log('Progress so far: '+(bytesReceived / bytesExpected * 100).toFixed(0)+"%");
})
.on('file', function(name, file) {
files.push([name, file]);
})
.on('error', function(err) {
console.log('ERROR!');
res.end();
})
.on('end', function() {
console.log('-> upload done');
res.writeHead(200, "OK", {
"Content-Type": "text/html", "Access-Control-Allow-Origin": "http://test"
});
res.end('received files: '+util.inspect(files));
});
form.parse(req);
} else {
res.writeHead(404, {'content-type': 'text/plain'});
res.end('404');
}
return;
}).listen(8080);
console.log('listening');
Ok, so that all works as expected. Now here's the simplest socket.io script which I'm hoping to infuse into the previous two to emit the progress info back to my page. Here's the client-side code:
var socket = io.connect('http://test:8080');
socket.on('news', function(data){
console.log('server sent news:', data);
});
And here's the server-side node script:
var http = require('http'),
fs = require('fs');
var server = http.createServer(function(req, res) {
fs.createReadStream('./socket.html').pipe(res);
});
var io = require('socket.io').listen(server);
io.sockets.on('connection', function(socket) {
socket.emit('news', {hello: "world"});
});
server.listen(8080);
So this works fine by itself, but my problem comes when I try to place the socket.io code inside my form.... I've tried placing it anywhere it might remotely make sense, i've tried the asynchronous mode of fs.readFile too, but it just wont send anything back to the client - meanwhile the file upload portion still works fine. Do I need to establish some sort of handshake between the two packages? Help me out here. I'm a front-end guy so I'm not too familiar with this back-end stuff. I'll put this aside for now and move onto other lessons.
Maybe you can create a room for one single client and then broadcast the percentage to this room.
I explained it here: How to connect formidable file upload to socket.io in Node.js

XMPP and Same origin policy problem

I'm building a chat application using OpenFire server and JSJaC client library.
The page loads from http://staging.mysite.com and XMPP runs on http://xmpp.mysite.com. As you can see they both share the same domain. So I use the following code on page load.
function OnPageLoad (){
document.domain = "mysite.com";
DoLogin();
}
Anyway it throws me exception saying that I violate the security. Why document.domain doesn't work? Should it work or is it done just for a "beauty"? If yes, what can be done in this specific situation?
I don't have access to the XMLHttpRequest object inside the library and do not control it.
Anyway. I had to dig a little bit deeper the JSJaC library and made some injections to the code. But first I've done some workaround. Basically I added the following headers to the response
Access-Control-Allow-Methods: GET, POST, OPTIONS
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: Content-Type, *
Generally this allowed to make crossdomain requests using a native xhr. However it proved to work in only modern browsers. For instance it didn't work in IE8 and any version of Opera simply rejected this header.
Then I used flash based solution. I used flXHR and modified jsjac.uncompressed.js like this.
XmlHttp.create = function () {
// try {
// if (window.XMLHttpRequest) {
// var req = new XMLHttpRequest();
//
// // some versions of Moz do not support the readyState property
// // and the onreadystate event so we patch it!
// if (req.readyState == null) {
// req.readyState = 1;
// req.addEventListener("load", function () {
// req.readyState = 4;
// if (typeof req.onreadystatechange == "function")
// req.onreadystatechange();
// }, false);
// }
//
// return req;
// }
// if (window.ActiveXObject) {
// return new ActiveXObject(XmlHttp.getPrefix() + ".XmlHttp");
// }
// }
// catch (ex) {}
// // fell through
// throw new Error("Your browser does not support XmlHttp objects");
var AsyncClient = new flensed.flXHR({
"autoUpdatePlayer": true,
"instanceId": "myproxy" + _xhrpf.toString(),
// This is important because the library uses the response xml of the object to manipulate the data
"xmlResponseText": true,
"onreadystatechange": function () { }
});
// counter for giving a unique id for the flash xhr object.
_xhrpf++;
return AsyncClient;
};
var _xhrpf = 1;
Then I just added a crossdomain.xml in the root of the target domain. Now it works perfectly if the browser has the flash plugin. Further I want to make some detection mechanism if there is no flash plugin, just make a native xhr and hope for that the browser supports the headers for cross domain requests.

Resources