97 lines
2.7 KiB
JavaScript
97 lines
2.7 KiB
JavaScript
'use strict';
|
|
|
|
const utils = require('./utils');
|
|
const {StripeError} = require('./Error');
|
|
|
|
class StreamProcessingError extends StripeError {}
|
|
|
|
// Method for formatting HTTP body for the multipart/form-data specification
|
|
// Mostly taken from Fermata.js
|
|
// https://github.com/natevw/fermata/blob/5d9732a33d776ce925013a265935facd1626cc88/fermata.js#L315-L343
|
|
const multipartDataGenerator = (method, data, headers) => {
|
|
const segno = (
|
|
Math.round(Math.random() * 1e16) + Math.round(Math.random() * 1e16)
|
|
).toString();
|
|
headers['Content-Type'] = `multipart/form-data; boundary=${segno}`;
|
|
let buffer = Buffer.alloc(0);
|
|
|
|
function push(l) {
|
|
const prevBuffer = buffer;
|
|
const newBuffer = l instanceof Buffer ? l : Buffer.from(l);
|
|
buffer = Buffer.alloc(prevBuffer.length + newBuffer.length + 2);
|
|
prevBuffer.copy(buffer);
|
|
newBuffer.copy(buffer, prevBuffer.length);
|
|
buffer.write('\r\n', buffer.length - 2);
|
|
}
|
|
|
|
function q(s) {
|
|
return `"${s.replace(/"|"/g, '%22').replace(/\r\n|\r|\n/g, ' ')}"`;
|
|
}
|
|
|
|
const flattenedData = utils.flattenAndStringify(data);
|
|
|
|
for (const k in flattenedData) {
|
|
const v = flattenedData[k];
|
|
push(`--${segno}`);
|
|
if (v.hasOwnProperty('data')) {
|
|
push(
|
|
`Content-Disposition: form-data; name=${q(k)}; filename=${q(
|
|
v.name || 'blob'
|
|
)}`
|
|
);
|
|
push(`Content-Type: ${v.type || 'application/octet-stream'}`);
|
|
push('');
|
|
push(v.data);
|
|
} else {
|
|
push(`Content-Disposition: form-data; name=${q(k)}`);
|
|
push('');
|
|
push(v);
|
|
}
|
|
}
|
|
push(`--${segno}--`);
|
|
|
|
return buffer;
|
|
};
|
|
|
|
const streamProcessor = (method, data, headers, callback) => {
|
|
const bufferArray = [];
|
|
data.file.data
|
|
.on('data', (line) => {
|
|
bufferArray.push(line);
|
|
})
|
|
.once('end', () => {
|
|
const bufferData = Object.assign({}, data);
|
|
bufferData.file.data = Buffer.concat(bufferArray);
|
|
const buffer = multipartDataGenerator(method, bufferData, headers);
|
|
callback(null, buffer);
|
|
})
|
|
.on('error', (err) => {
|
|
callback(
|
|
new StreamProcessingError({
|
|
message:
|
|
'An error occurred while attempting to process the file for upload.',
|
|
detail: err,
|
|
}),
|
|
null
|
|
);
|
|
});
|
|
};
|
|
|
|
const multipartRequestDataProcessor = (method, data, headers, callback) => {
|
|
data = data || {};
|
|
|
|
if (method !== 'POST') {
|
|
return callback(null, utils.stringifyRequestData(data));
|
|
}
|
|
|
|
const isStream = utils.checkForStream(data);
|
|
if (isStream) {
|
|
return streamProcessor(method, data, headers, callback);
|
|
}
|
|
|
|
const buffer = multipartDataGenerator(method, data, headers);
|
|
return callback(null, buffer);
|
|
};
|
|
|
|
module.exports.multipartRequestDataProcessor = multipartRequestDataProcessor;
|