From 480802c401fcad9aac13e53cb8d647ca16c4610a Mon Sep 17 00:00:00 2001 From: Sam Decrock Date: Fri, 18 Jul 2014 15:41:02 +0200 Subject: [PATCH] added upload function to main function so you can use PUT to upload files too --- lib/httpreq.js | 208 +++++++++++++++++++++---------------------------- 1 file changed, 88 insertions(+), 120 deletions(-) diff --git a/lib/httpreq.js b/lib/httpreq.js index ce3b3fc..7e06dc3 100644 --- a/lib/httpreq.js +++ b/lib/httpreq.js @@ -92,6 +92,14 @@ exports.download = function (url, downloadlocation, progressCallback, callback) doRequest(options, callback); } +// old function, can still be used: +exports.uploadFiles = function(options, callback){ + var moreOptions = options; + moreOptions.method = 'POST'; + doRequest(moreOptions, callback); +} + + function doRequest(o, callback){ if(!callback){ callback = function (err) { @@ -105,7 +113,8 @@ function doRequest(o, callback){ var hasTimedout = false; var chunks = []; - var body; + var body; // Buffer + var contentType; var port; var host; @@ -131,18 +140,76 @@ function doRequest(o, callback){ } } - if(o.method == 'POST' && o.parameters){ - body = querystring.stringify(o.parameters); - }else if(o.method == 'GET' && o.parameters){ - path += "?" + querystring.stringify(o.parameters); + if(o.files && o.files.length > 0 && o.method == 'GET'){ + var err = new Error("Can't send files using GET"); + err.code = 'CANT_SEND_FILES_USING_GET'; + return callback(err); + } + + if(o.parameters){ + if(o.method == 'GET'){ + path += "?" + querystring.stringify(o.parameters); + }else{ + body = new Buffer( querystring.stringify(o.parameters), 'utf8' ); + contentType = 'application/x-www-form-urlencoded; charset=UTF-8'; + } } if(o.json){ - body = JSON.stringify(o.json); + body = new Buffer( JSON.stringify(o.json), 'utf8' ); + contentType = 'application/json'; + } + + if(o.files){ + var crlf = "\r\n"; + var boundary = generateBoundary(); + var separator = '--' + boundary; + var bodyArray = new Array(); // temporary body array + + // if the user want's to POST/PUT files, other parameters need to be encoded using 'Content-Disposition' + for(var key in o.parameters){ + var encodedParameter = separator + crlf + + 'Content-Disposition: form-data; name="'+encodeURIComponent(key)+'"' + crlf + + crlf + + encodeURIComponent(o.parameters[key]) + crlf; + bodyArray.push(new Buffer(encodedParameter)); + } + + // now for the files: + var haveAlreadyAddedAFile = false; + + for(var file in o.files){ + var filepath = o.files[file]; + var filename = filepath.replace(/\\/g,'/').replace( /.*\//, '' ); + + var encodedFile = separator + crlf + + 'Content-Disposition: file; name="' + file + '"; filename="' + filename + '"' + crlf + + 'Content-Type: application/octet-stream' + crlf + + crlf; + + // add crlf before separator if we have already added a file + if(haveAlreadyAddedAFile) + encodedFile = crlf + encodedFile; + + bodyArray.push(new Buffer(encodedFile)); + + // add binary file: + bodyArray.push(require("fs").readFileSync(filepath)); + + haveAlreadyAddedAFile = true; + } + + var footer = crlf + separator + '--' + crlf; + bodyArray.push(new Buffer(footer)); + + // set body and contentType: + body = Buffer.concat(bodyArray); + contentType = 'multipart/form-data; boundary=' + boundary; } + // overwrites the body if the user passes a body: if(o.body){ - body = o.body; + body = new Buffer( o.body, 'utf8' ); } var requestoptions = { @@ -157,22 +224,19 @@ function doRequest(o, callback){ o.redirectCount = 0; } - if(o.method == 'POST' && o.parameters){ - requestoptions['headers']['Content-Type'] = 'application/x-www-form-urlencoded; charset=UTF-8'; - } - - if(o.json){ - requestoptions['headers']['Content-Type'] = 'application/json'; + if(body){ + requestoptions['headers']['Content-Length'] = body.length; } - if(body){ - requestoptions['headers']['Content-Length'] = (new Buffer(body, 'utf8')).length; + if(contentType){ + requestoptions['headers']['Content-Type'] = contentType; } if(o.cookies){ requestoptions['headers']['Cookie'] = o.cookies.join("; "); } + // add custom headers: if(o.headers){ for(var headerkey in o.headers){ requestoptions['headers'][headerkey] = o.headers[headerkey]; @@ -275,118 +339,21 @@ function doRequest(o, callback){ }); if(body) - request.write(body, 'utf8'); + request.write(body); + request.end(); }; +function generateBoundary() { + var boundary = '---------------------------'; + var charset = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; -exports.uploadFiles = function(o, callback){ - var chunks = []; - - var reqUrl = url.parse(o.url); - - var port; - - if(reqUrl.port){ - port = reqUrl.port; - }else if(reqUrl.protocol == 'https:'){ - port = 443; - }else{ - port = 80; - } - - var crlf = "\r\n"; - var boundary = '---------------------------10102754414578508781458777923'; - var separator = '--' + boundary; - - var bufferArray = new Array(); - - for(var key in o.parameters){ - var parametersData = separator + crlf - + 'Content-Disposition: form-data; name="'+encodeURIComponent(key)+'"' + crlf - + crlf - + encodeURIComponent(o.parameters[key]) + crlf; - - bufferArray.push(new Buffer(parametersData)); - } - - for(var file in o.files){ - var filepath = o.files[file]; - var filename = filepath.replace(/\\/g,'/').replace( /.*\//, '' ); - - var fileData = separator + crlf - + 'Content-Disposition: file; name="' + file + '"; filename="' + filename + '"' + crlf - + 'Content-Type: application/octet-stream' + crlf - + crlf; - - bufferArray.push(new Buffer(fileData)); - bufferArray.push(require("fs").readFileSync(filepath)); - } - - var footer = crlf + separator + '--' + crlf; - bufferArray.push(new Buffer(footer)); + for(var i=0; i < 29; i++) + boundary += charset.charAt(Math.floor(Math.random() * charset.length)); - var multipartBody = Buffer.concat(bufferArray); - - var requestoptions = { - host: reqUrl.hostname, - port: port, - path: reqUrl.path, - method: 'POST', - headers: {} - }; - - requestoptions['headers']['Content-Type'] = 'multipart/form-data; boundary=' + boundary; - requestoptions['headers']['Content-Length'] = multipartBody.length; - - if(o.cookies){ - requestoptions['headers']['Cookie'] = o.cookies.join("; "); - } - - if(o.headers){ - for(var headerkey in o.headers){ - requestoptions['headers'][headerkey] = o.headers[headerkey]; - } - } - - function requestResponse(res){ - var ended = false; - - res.on('data', function (chunk) { - chunks.push(chunk); - }); - - res.on('end', function (err) { - ended = true; - var responsebody = Buffer.concat(chunks); - if(!o.binary) - responsebody = responsebody.toString('utf8'); - - callback(null, {headers: res.headers, statusCode: res.statusCode, body: responsebody}); - }); - - res.on('close', function () { - (!ended) - callback(new Error("Request aborted")); - }); - } - - var request; - - if(reqUrl.protocol == 'https:') - request = https.request(requestoptions, requestResponse); - else - request = http.request(requestoptions, requestResponse); - - request.on('error', function (err) { - callback(err); - }); - - request.write(multipartBody); - - request.end(); + return boundary; } function extractCookies (headers) { @@ -404,3 +371,4 @@ function extractCookies (headers) { } exports.doRequest = doRequest; +