HTTP file upload with node.js is changing the file - node.js

I have a problem uploading an jpg file with node.js to my tomcat server - somewhere in the upload the file content is changed. I think, it is something with the encoding, but I hav no idea what I'm missing.
The node.js code is:
var agentOptions;
var agent;
agentOptions = {
host: 'this.is.my.server'
, port: '8443'
, path: '/'
, rejectUnauthorized: false
};
agent = new https.Agent(agentOptions);
var binaryFilename = "image.jpg";
var fContent = fs.readFileSync( binaryFilename );
console.log( "file size = " + fContent.length );
var boundary = '69b2c2b9c464731d'
var content = "--"+boundary+"\r\n"
+ "Content-Disposition: form-data; name=\"file\"; filename=\"image.jpg\"\r\n"
+ "Content-Type: application/octet-stream\r\n"
+ "Content-Transfer-Encoding: BINARY\r\n"
+ "\r\n"
+ fContent + "\r\n"
+ "--"+boundary+"--\r\n"
postOptions = {
headers: {
'Content-Type': 'multipart/form-data; boundary='+boundary ,
'Content-Length': Buffer.byteLength(content) ,
'Authorization': 'Basic ABCEDFE..'
} ,
host: 'this.is.my.server' ,
port: '8443' ,
path: '/restservices/uploadimage?data=value&data2=value2' ,
method: 'POST' ,
strictSSL: false ,
agent: agent
} ;
// Set up the request
post_req = https.request(
postOptions,
function(res) {
//
res.setEncoding('utf8') ;
res.on('data', function (chunk) {
console.log('Response: ' + chunk) ;
}) ;
}) ;
// post the data
post_req.write(content) ;
post_req.end() ;
Java code on the server starts with
#RequestMapping(value = "/uploadimage", method = RequestMethod.POST )
public #ResponseBody String uploadpreview(#RequestParam String data, #RequestParam String data1, #RequestParam("file") MultipartFile file) {
if (!file.isEmpty()) {
....
Start of the image before upload:
Start of the image after upload:
(source: dataplan.de)
Every byte with the highest bit set is converted to three bytes EF BF BD
I tried several things, maybe I'm missing something simple - at the moment I have no idea what I'm doing wrong.
Thanks for any ideas and tipps
Klaus

Here's another attempt:
const https = require('https');
const formData = require('form-data')();
var binaryFilename = process.argv[2] || 'image.jpg';
let request = https.request({
host: 'this.is.my.server'
port: '8443',
path: '/',
method: 'POST',
headers: formData.getHeaders()
}, (res) => {
res.on('data', (data) => {
console.log('Data received: ', data.toString());
});
});
request.on("error", (e) => {
console.error(e);
});
formData.append('image_file', require("fs").createReadStream(binaryFilename));
formData.pipe(request);

Related

gibberish instead of html response as body in node.request

I'm making a HTTP request to a password protected site using the request module in npm, putting in a password, storing a cookie, then making the request once the cookie is stored and verified. I am able to get the same headers as I would on a normal browser request, but hte body itself, instead of being the HTML document I get in a browser, just looks like this:
� �Z�r�H��c��䞙��pT���Ī$3�ƾ�~Y�#�MK8���>*��?�z)�?U���ݨ�J�혳��섯tB��x��c��?�����������0�H�����V��O'�7����}���L�"˖}/ta�xn�g#�ݱ�O�����
Any ideas what might be causing this or how I can fix it?
In addition, when I run this from the command prompt, the computer "dings"
Here is the full node.js code I am running (minus the URLs/passwords/etc.)
var parsedurl1 = url.parse( urlstring1 );
var options1 = {
hostname: parsedurl1.hostname,
port: ( parsedurl1.port || 80 ), // 80 by default
method: 'POST',
path: parsedurl1.path,
headers: {
'Host': hostname
,'User-Agent': myuseragent
,'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8'
,'Accept-Language':"en-US,en;q=0.5"
,'Accept-Encoding': "gzip, deflate"
,'Referer': hostname
,'Content-Type': "text/html; charset=utf-8"
,'Content-Length': Buffer.byteLength(postData)
,'Connection': "keep-alive"
,'Upgrade-Insecure-Requests': "1"},
};
var cookiefile ;
var postData=querystring.stringify({
'email': myemail
,'password':mypassword
,'action': 'login'
,'go.x': 0
,'go.y': 0
})
var cookiefile;
var callback = function ( response ) {
// display returned cookies in header
var setcookie = response.headers["set-cookie"];
if ( setcookie ) {
setcookie.forEach(
function ( cookiestr ) {
cookiefile = cookiestr;
fs.writeFile(cookiefilelocation, cookiestr);
console.log( "COOKIE:" + cookiestr );
}
);
}
var data = "";
response.on(
"data",
function ( chunk ) { data += chunk; }
);
response.on(
"end",
function () {
newcookiefile = cookiefile.substr(0, cookiefile.indexOf(";"));
var parsedurl2 = url.parse( urlstring2 );
var options2 = {
url: urlstring2,
// port: ( parsedurl2.port || 80 ), // 80 by default
method: 'GET',
// path: parsedurl2.path,
headers: {
"Host": hostname
,"User-Agent": myuseragent
,'Accept': "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
,'Accept-Language':"en-US,en;q=0.5"
,'Accept-Encoding': "gzip, deflate"
,'Referer':hostname
,'Cookie': newcookiefile
,'Connection': "keep-alive"
,'Upgrade-Insecure-Requests': "1"},
};
function callback3(error, response, body){
console.log('error:', error); // Print the error if one occurred
console.log('statusCode:', response.headers ); // Print the response status code if a response was received
console.log('body:', body.substr(1,1000));
fs.writeFile('./config/pullfiles/mostrecent.txt', body);
}
requestlib(options2, callback3);
}
);
};
var request = http.request(options1, callback);
request.on(
"error",
function( err ) {
console.error( "RERROR:" + err );
}
);
request.write(postData);
request.end(); // let request know it is finished sending
I figured it out! This gibberish was caused by my lack of the 'gzip: true' option is my request(). Now the second request reads:
url: urlstring2
,gzip: true
,headers:{...

nodejs requestify.request() crashes when the method is given in the options

Why does requestify.request() crash because it doesn't think it was given the method POST
var postBody = querystring.stringify(dat);
var postOptions = {
host: 'https://www.example.com'
, path: '/admin'
, method: 'post' // POST, 'POST', post
, headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(postBody) }
};
var postReq = requestify.request(postOptions, function (err, resp, respBody) {
resp.setEncoding('utf8');
resp.on('data', function (chunk) {
console.log('Response: ' + chunk);
});
});
It looks like you are using an old version of the documentation for the newer version of requestify
Read the API reference section of https://github.com/ranm8/requestify
And read just a little lower down it see a requestify.request() example.
Options doesn't have host, path, ...

How to upload assets to a github release from node.js

I am trying to automatically post some assets on a Github release I programmatically create.
Here is my upload function:
function uploadFile(fileName, uploadUrl, callback){
var uploadEndPoint = url.parse(uploadUrl.substring(0,uploadUrl.indexOf('{')));
options.host = uploadEndPoint.hostname;
options.path = uploadEndPoint.pathname+'?name=' + fileName;
options.method = 'POST';
options.headers['content-type'] = 'application/zip';
var uploadRequest = https.request(options, callback);
uploadRequest.on('error', function(e) {
console.log('release.js - problem with uploadRequest request: ' + e.message);
});
var readStream = fs.ReadStream(path.resolve(__dirname,'builds',fileName));
readStream.pipe(uploadRequest);
readStream.on('close', function () {
req.end();
console.log('release.js - ' + fileName + ' sent to the server');
});
}
At the end of this I get a 404 not found
I tried auth from token and user/password
I checked the url
I though it might be because of SNI, but I don't know how to check that.
Any clue ? Thanks !
I found a solution to that problem by NOT using the low level node.js modules and using instead restler which is a library that handles SNI.
Here is how is used it:
rest = require('restler'),
path = require('path'),
fs = require('fs');
fs.stat(path.resolve(__dirname,'builds',fileName), function(err, stats){
rest.post(uploadEndPoint.href+'?name=' + fileName, {
multipart: true,
username: GITHUB_OAUTH_TOKEN,
password: '',
data: rest.file(path.resolve(__dirname,'builds',fileName), null, stats.size, null, 'application/zip')
}).on('complete', callback);
});
Hope that will help someone :)
EDIT on 27/02/2015: We recently switched from restler to request.
var
request = require('request'),
fs = require('fs');
var stats = fs.statSync(filePath);
var options = {
url: upload_url.replace('{?name}', ''),
port: 443,
auth: {
pass: 'x-oauth-basic',
user: GITHUB_OAUTH_TOKEN
},
json:true,
headers: {
'User-Agent': 'Release-Agent',
'Accept': 'application/vnd.github.v3+json',
'Content-Type': 'application/zip',
'Content-Length': stats.size
},
qs: {
name: assetName
}
};
// Better as a stream
fs.createReadStream(filePath).pipe(request.post(options, function(err, res){
// Do whatever you will like with the result
}));
The upload_uri can be retrieved through a get request on an existing release or in the response directly after the release creation.

Posting images to twitter in Node.js using Oauth

I'm trying to post images to Twitter using the Oauth module. Here is what I have:
It throws a 403 error, I know im doing something wrong with how I add the media to the post but Im just not sure where to go from here.
var https = require('https');
var OAuth= require('oauth').OAuth;
var keys = require('./twitterkeys');
var twitterer = new OAuth(
"https://api.twitter.com/oauth/request_token",
"https://api.twitter.com/oauth/access_token",
keys.consumerKey,
keys.consumerSecret,
"1.0",
null,
"HMAC-SHA1"
);
var params = {
status : "Tiger!",
media : [("data:" + mimeType + ";base64,") + fs.readFileSync(path,'base64')]
};
//function(url, oauth_token, oauth_token_secret, post_body, post_content_type, callback)
twitterer.post("https://upload.twitter.com/1/statuses/update_with_media.json",
keys.token, keys.secret, params, "multipart/form-data",
function (error, data, response2) {
if(error){
console.log('Error: Something is wrong.\n'+JSON.stringify(error)+'\n');
}else{
console.log('Twitter status updated.\n');
console.log(response2+'\n');
}
});
Here is what I belive im supose to be doing but I don't know how to do that in the Node.js Oauth module.
Posting image to twitter using Twitter+OAuth
Reviewing the code, it looks like there's no multipart/form-data handling at all in the node-oauth package right now. You can still use the node-oauth function to create the authorization header, but you'll have to do the multipart stuff on your own.
There are probably third-party libraries that can help out with that, but here's how I got it to work constructed by hand.
var data = fs.readFileSync(fileName);
var oauth = new OAuth(
'https://api.twitter.com/oauth/request_token',
'https://api.twitter.com/oauth/access_token',
twitterKey, twitterSecret,
'1.0', null, 'HMAC-SHA1');
var crlf = "\r\n";
var boundary = '---------------------------10102754414578508781458777923';
var separator = '--' + boundary;
var footer = crlf + separator + '--' + crlf;
var fileHeader = 'Content-Disposition: file; name="media"; filename="' + photoName + '"';
var contents = separator + crlf
+ 'Content-Disposition: form-data; name="status"' + crlf
+ crlf
+ tweet + crlf
+ separator + crlf
+ fileHeader + crlf
+ 'Content-Type: image/jpeg' + crlf
+ crlf;
var multipartBody = Buffer.concat([
new Buffer(contents),
data,
new Buffer(footer)]);
var hostname = 'upload.twitter.com';
var authorization = oauth.authHeader(
'https://upload.twitter.com/1/statuses/update_with_media.json',
accessToken, tokenSecret, 'POST');
var headers = {
'Authorization': authorization,
'Content-Type': 'multipart/form-data; boundary=' + boundary,
'Host': hostname,
'Content-Length': multipartBody.length,
'Connection': 'Keep-Alive'
};
var options = {
host: hostname,
port: 443,
path: '/1/statuses/update_with_media.json',
method: 'POST',
headers: headers
};
var request = https.request(options);
request.write(multipartBody);
request.end();
request.on('error', function (err) {
console.log('Error: Something is wrong.\n'+JSON.stringify(err)+'\n');
});
request.on('response', function (response) {
response.setEncoding('utf8');
response.on('data', function (chunk) {
console.log(chunk.toString());
});
response.on('end', function () {
console.log(response.statusCode +'\n');
});
});

node.js paypal https request

first question here, so apologies if it turns out to be something very obvious
I am trying to call the paypal adaptive payments api via node.js and am getting a 580001 invalid request error. I can make a successfull call via curl with the below message and headers, but not through node.
any help would be much appreciated.
var API_endpoint = "svcs.sandbox.paypal.com";
var API_user = '';
var API_pass = '';
var API_sig = '';
message='requestEnvelope.errorLanguage=en_US&actionType=PAY&senderEmail=test_1320882990_per#gmail.com&receiverList.receiver(0).email=test2_1320887729_biz#gmail.com& receiverList.receiver(0).amount=100.00&currencyCode=USD&cancelUrl=http://your_cancel_url& returnUrl=http://your_return_url'
//var params = qs.parse(message);
//params = qs.stringify(params);
var req_options = {
host: API_endpoint,
method: 'POST',
path: '/AdaptivePayments/Pay',
headers: {
'Host': API_endpoint,
'Content-Type': 'application/x-www-form-urlencoded',
//'Content-Type': 'text/namevalue',
'Content-Length': message.length,
'X-PAYPAL-REQUEST-DATA-FORMAT:':'NV',
'X-PAYPAL-RESPONSE-DATA-FORMAT':'NV',
'X-PAYPAL-SECURITY-USERID':API_user,
'X-PAYPAL-SECURITY-PASSWORD':API_pass,
'X-PAYPAL-SECURITY-SIGNATURE':API_sig,
'X-PAYPAL-APPLICATION-ID':'APP-80W284485P519543T'
}
}
fs.readFile('/home/dev/.ssh/sandbox-paypal-private.pem', 'ascii', function(err, key){
fs.readFile('/home/dev/.ssh/sandbox-paypal-public.pem', 'ascii', function(err, cert){
req_options.key=key
req_options.cert=cert
var req = https.request(req_options, function(res){
console.log('STATUS: ' + res.statusCode);
console.log('HEADERS: ' + JSON.stringify(res.headers));
res.on('data', function(d){
var response = d.toString();
console.log(response)
});
});
req.write(message);
req.end();
req.on('error', function request_error(e) {
console.log(e);
});
});
});
I'm not sure if it's only a copy paste problem, but your message variable does not seem to contain properly formatted string. It has white spaces and the special characters are not encoded.
requestEnvelope.errorLanguage=en_US&actionType=PAY&senderEmail=test_1320882990_per#gmail.com&receiverList.receiver(0).email=test2_1320887729_biz#gmail.com&receiverList.receiver(0).amount=100.00&currencyCode=USD&cancelUrl=http://your_cancel_url& returnUrl=http://your_return_url'.
It should look like this:
requestEnvelope.errorLanguage=en_US&actionType=PAY&senderEmail=test_1320882990_per%40gmail.com&receiverList.receiver(0).email=test2_1320887729_biz%40gmail.com& receiverList.receiver(0).amount=100.00&currencyCode=USD&cancelUrl=http%3A%2F%2Fyour_cancel_url&returnUrl=http%3A%2F%2Fyour_return_url
There's a trailing colon in one of your header fields; Rather than:
'X-PAYPAL-REQUEST-DATA-FORMAT:'
You should have:
'X-PAYPAL-REQUEST-DATA-FORMAT'

Resources