Problems serving a binary image passed through stdout with Node - image

I'm attempting to create a node server that serves up a png image generated using the node-wkhtml module (basically just a wrapper for the wkhtmltoimage/wkhtmltopdf command line utility). Here's what I have so far:
var http = require('http');
var Image = require("node-wkhtml").image();
http.createServer(function (request, response) {
new Image({ url: "www.google.com" }).convert (function (err, stdout) {
//var theImage = new Buffer (stdout, 'binary');
response.writeHead(200, {'Content-Type' : 'image/png',
'Content-Length' : stdout.length
});
response.write (stdout, 'binary');
response.end ();
//write out an error, if there is one
if (err)
console.log (err);
});
}).listen(8124);
Basically, the module calls the command:
wkhtmltoimage www.google.com -
which then generates a png image and writes it to the stdout. The amount of data served seems to be correct, but I can't get the browser to display it (nor does it work if I download it as a file). I tried the following command:
wkhtmltoimage www.google.com - > download.png
and sure enough, download.png was created and contained a snapshot of the google homepage, meaning that the wkhtmltoimage utility is working correctly, and the command works. I'm a beginner at node, so I'm not super familiar how to serve up a binary file like this, can anyone see any glaring issues? Here's the node module code that works the magic:
Image.prototype.convert = function(callback) {
exec(util.buildCommand(this), {encoding: 'binary', maxBuffer: 10*1024*1024}, callback);
}
(the buildCommand function just generates the "wkhtmltoimage www.google.com -" command, and I've verified it does this correctly, using node inspector.
UPDATE:
In case anyone finds this later and is interested, I found the solution. The plugin I was using (node-wkhtml) was not properly handling large buffers, due to the choice of using child-process.exec I changed the plugin code to use child-process.spawn instead, and it worked as desired.

Related

Nativescript send camera capture to server

In my Nativescript application I would like to capture an image using the camera module and then send the bytes directly to the server via http call.
Here is my code (incomplete for brevity):
var cameraModule = require("camera");
var http = require("http");
...
cameraModule.takePicture().then(function (img) {
// how to extract the actual bytes from img???
http.request({
url: some_url,
method: "POST",
headers: { "Content-Type": "application/octet-stream" },
content: ???
});
});
Is there a way to do that?
I was looking at nativescript-background-http and it seems to fit my requirements exactly, but the example shows the file being loaded from a path only. I did not have any luck making this to work on iOS.
Any help is greatly appreciated.
Thank you.
A couple things;
"img" is actually a image source.
At this point the built in HTTP module does not support direct binary transfers, so we need to convert it to something that can be sent over the wire. So base64 is a text representation that can support binary, and it is a common encoding/decoding method.
Since we already have it as a image source we just use the cool toBase64String ability which give us the Base 64 data.
So here is basically is how I would do it (tested under android).
var cameraModule = require('camera');
var some_url="http://somesite";
// img is a image source
cameraModule.takePicture().then(function (img) {
// You can use "jpeg" or "png". Apparently "png" doesn't work in some
// cases on iOS.
var imageData = img.toBase64String("jpeg");
http.request({
url: some_url,
method: "POST",
headers: { "Content-Type": "application/base64" },
content: imageData
}).then(function() {
console.log("Woo Hoo, we sent our image up to the server!");
}).catch(function(e) {
console.log("Uh oh, something went wrong", e);
});
});
There are a few ways to do this. If your backend can take a base64 string you can use the image-source class and manipulate the data. I'm on my phone or I'd mock up a sample. It really depends what you expect on the server to be honest but most options are possible with NativeScript using the image-source and ui/image component.
http://docs.nativescript.org/api-reference/classes/_image_source_.imagesource.html#tobase64string
Going from memory here but try this when you get the (IMG) back.
var data = img.tobase64string(); that should give you a base 64 string of the image.
Just found this awesome sample from another question https://stackoverflow.com/a/37815237/1893557
This will work to send the file after you save it locally and uses the background-http plugin.

Cloud Code: Creating a Parse.File from URL

I'm working on a Cloud Code function that uses facebook graph API to retrieve users profile picture. So I have access to the proper picture URL but I'm not being able to acreate a Parse.File from this URL.
This is pretty much what I'm trying:
Parse.Cloud.httpRequest({
url: httpResponse.data["attending"]["data"][key]["picture"]["data"]["url"],
success: function(httpImgFile)
{
var imgFile = new Parse.File("file", httpImgFile);
fbPerson.set("profilePicture", imgFile);
},
error: function(httpResponse)
{
console.log("unsuccessful http request");
}
});
And its returning the following:
Result: TypeError: Cannot create a Parse.File with that data.
at new e (Parse.js:13:25175)
at Object.Parse.Cloud.httpRequest.success (main.js:57:26)
at Object.<anonymous> (<anonymous>:842:19)
Ideas?
I was having trouble with this exact same problem right now. For some reason this question is already top on Google results for parsefile from httprequest buffer!
The Parse.File documentation says
The data for the file, as 1. an Array of byte value Numbers, or 2. an Object like { base64: "..." } with a base64-encoded String. 3. a File object selected with a file upload control. (3) only works in Firefox 3.6+, Safari 6.0.2+, Chrome 7+, and IE 10+.
I believe for CloudCode the easiest solution is 2. The thing that was tripping me earlier is that I didn't notice it expects an Object with the format { base64: {{your base64 encoded data here}} }.
Also Parse.Files can only be set to a Parse.Object after being saved (this behaviour is also present on all client SDKs). I strongly recommend using the Promise version of the API as it makes much easier to compose such asynchronous operations.
So the following code will solve your problem:
Parse.Cloud.httpRequest({...}).then(function (httpImgFile) {
var data = {
base64: httpImgFile.buffer.toString('base64')
};
var file = new Parse.File("file", data);
return file.save();
}).then(function (file) {
fbPerson.set("profilePicture", file);
return fbPerson.save();
}).then(function (fbPerson) {
// fbPerson is saved with the image
});

Creating a Nodejs local reverse shell over Ajax?

I'm attempting to make a small node executable which has the ability to open a local shell and send and receive commands to a HTTP server.
Seems simple enough logically but what would be the best practice in implementing this?
Open a command line using Node API
Listen for commands from server URL /xmlrpc-urlhere/
When a command is received via Ajax or WebRTC? Execute it in command line
POST the command line response back to the user
This shell will be for administrative purposes.
I can't think of a good way of doing this, I've checked npm and it would seem there are some basic command line modules for node js but nothing that has this functionality.
The npm modules commander and request ought to do the trick. To get you started, here's a simple command line tool that issues a search to google and dumps the raw HTML into the console.
Eg:
./search.js puppies
#!/usr/bin/env node
var program = require('commander');
var request = require('request');
var search;
program
.version('0.0.1')
.arguments('<query>')
.action(function(query) {
search = query;
});
program.parse(process.argv);
if (typeof search === 'undefined') {
console.error('no query given!');
process.exit(1);
}
var url = 'http://google.com/search?q=' + encodeURIComponent(search);
request(url, function(err, res, body) {
if (err) {
console.error(err);
process.exit(1);
}
console.log('Search result:');
console.log(body);
process.exit(0);
});

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

Meteor.http.call Client-side Results Undefined

Consuming Mashape Airbnb API:
The following sits inside the Clients->airbnb.js file.
My Results are undefined. But using the same API, http://jsfiddle.net/ismaelc/FZ5vG/
works just fine.
function getListings(place) {
alert(place);
Meteor.http.call("GET", "https://airbnb.p.mashape.com/s",
{params : {location:place},
headers : {"X-Mashape-Authorization":"ffnGO1suGtJEjqgz4n7ykeuCbDP1hexv"}},
function (error, result) {
$('#listings').html(EJSON.stringify(result.data));
console.log("Status: "+result.statusCode);
console.log("Content: "+result.statusCode);
console.log("data: "+EJSON.stringify(result.data));
console.log("error: "+error.message);
}
);
}
Template.where.events ({
'click #find': function(event){
var place = $('#location').val();
getListings(place);
}
});
My Google Chrome Web Developers Tool is giving me odd HTTP Response.
IMG: Here http://imgur.com/f5u2C7X
Also, I momentarily see my console.log and then it just disappears. Why is this?
You can use the network tab in the chrome dev kit, make sure its already open before you do the request and it should just add on and you can view its text content to find where its all going wrong.
The response tab should have the text it gets back:
Of note is just check your api you might need to use params (HTTP POST params) instead of data (JSON post in the body), e.g {params : {location:place}.

Resources