So I need to send two images and an api key as part of a multipart/form-data http request to an api. I'm receiving the images from an aws s3 bucket and that's working perfectly, but whenever I try to send the image as part of the form-data I get an EPIPE http error. Somehow, the request gets canceled before all the data was received by the api. I tried the same using postman and everything works well, it's just my node program that doesn't seem able to achieve this. Please find below the code snippet:
const http = require('http')
const https = require('https')
const AWS = require('aws-sdk')
const s3 = new AWS.S3({apiVersion: '2006-03-01'});
//simple http post request, there doesn't seem to be anything wrong with it
const httpPromise = (protocol, params, postData) => {
return new Promise((resolve, reject) => {
const requestModule = protocol === 'http' ? http : https;
const req = requestModule.request(params, res => {
// grab request status
const statusCode = res.statusCode;
if(statusCode < 200 || statusCode > 299) {
throw new Error(`Request Failed with Status Code: ${status}`);
}
let body = '';
// continuosly update data with incoming data
res.setEncoding('utf8');
res.on('data', data => body += data);
// once all data was received
res.on('end', () => {
console.log(body)
resolve(body)
});
})
// write data to a post request
if(typeof(params.method) === 'string' && params.method === 'POST' && postData) {
req.write(postData)
}
// bind to the error event
req.on('error', err => reject(err));
// end the request
req.end();
})
}
const handler = async (event) => {
// requestOption parameters
const apiKey = '000000';
const protocol = 'http';
const path = '/verify';
// set to the defined port, if the port is not defined set to default for either http or https
const port = Port ? Port : protocol === 'http' ? 80 : 443;
const hostname ='www.example.com';
const method = "POST";
const boundary = '__X_PAW_BOUNDARY__';
// get correct keys for the relevant images
const image1Key = 'image1Key';
const image2Key = 'image2Key';
const imageKeys = [image1, image2];
try {
// get the images, this works all as intended
const s3GetObjectPromises = [];
imageKeys.forEach(key => s3GetObjectPromises.push(
s3.getObject({Bucket: BucketName, Key: key})
.promise()
.then(res => res.Body)
))
const [image1, image2] = await Promise.all(s3GetObjectPromises);
//========== ALL GOOD TILL HERE ============
// THIS IS WHERE IT GETS PROBLEMATIC:
// create the postData formData string
const postData = "--" + boundary + "\r\nContent-Disposition: form-data; name=\"key\"\r\n\r\n" + apiKey + "\r\n--" + boundary + "Content-Disposition: form-data; name=\"image1\"; filename=\"IMG_7264.JPG\"\r\nContent-Type: image/jpeg \r\n\r\n" + image1 + "\r\n--" + boundary + "\r\nContent-Disposition: form-data; name=\"image1\"; filename=\"IMG_7264.JPG\"\r\nContent-Type: image/jpeg\r\n\r\n" + image2 + "\r\n--" + boundary + "--";
// the formData headers
const headers = {
"Content-Type":`multipart/form-data; charset=utf-8; boundary=${boundary}`,
"Content-Length": `${postData.length}`,
"User-Agent": "Paw/3.1.7 (Macintosh; OS X/10.14.0) GCDHTTPRequest"
}
// the options object
const options = {hostname, port, path, method, headers};
let result = await httpPromise(protocol, options, postData)
console.log(result)
return result;
} catch(err) {
console.log(err)
//this either throws an EPIPE error or it simply states that no key was available
throw err;
}
//execute the handler
handler()
.then(res => console.log(res))
.catch(err => console.log(err))