forked from micnews/apple-news
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathencode-form-data.js
More file actions
128 lines (105 loc) · 3.13 KB
/
encode-form-data.js
File metadata and controls
128 lines (105 loc) · 3.13 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
'use strict';
const FormData = require('form-data');
const stream = require('stream');
const url = require('url');
const http = require('http');
const https = require('https');
const seriesEach = require('eachy');
const FileType = require('file-type');
const CRLF = '\r\n';
const validContentTypes = [
'application/octet-stream', // should be first in this list
'image/jpeg',
'image/png',
'image/gif'
];
function append (form, item, data, contentType) {
const options = item.options;
const len = typeof data === 'string' ? Buffer.byteLength(data) : data.length;
const header = '--' + form.getBoundary() + CRLF +
'Content-Type: ' + contentType + CRLF +
'Content-Disposition: form-data' +
(item.filename ? '; filename=' + encodeURIComponent(options.filename) : '') +
(item.name ? '; name=' + encodeURIComponent(item.name) : '') +
'; size=' + len + CRLF + CRLF;
form.append(item.name || item.filename, data,
Object.assign({ header: header, knownLength: len }, options));
}
module.exports = function encodeFormData (formData, cb) {
const form = new FormData();
seriesEach(formData, function (item, callback) {
const value = item.value;
const options = item.options;
if (options.contentType === 'application/json') {
append(form, item, value, 'application/json');
callback();
return;
}
request(value, function (err, body) {
if (err) {
return callback(err);
}
if (!body || !body.length) {
return callback(new Error('file not found: ' + value));
}
const contentObj = FileType.fromBuffer(body);
if (!contentObj) {
return callback(new Error('filetype error: ' + value));
}
let contentType = contentObj.mime;
if (validContentTypes.indexOf(contentType) === -1) {
contentType = validContentTypes[0];
}
append(form, item, body, contentType);
callback();
});
}, function (err) {
if (err) {
return cb(err);
}
const converter = new stream.Writable();
const chunks = [];
converter._write = function (chunk, enc, cb) {
chunks.push(chunk);
cb();
};
converter.on('finish', function () {
const headers = form.getHeaders();
const buffer = Buffer.concat(chunks);
headers['content-length'] = String(buffer.length);
return cb(null, {
headers: headers,
buffer: buffer
});
});
form.pipe(converter);
});
};
function request (fileUrl, callback) {
const options = url.parse(fileUrl);
const httpModule = options.protocol === 'https:' ? https : http;
options.timeout = 5000;
options.rejectUnauthorized = process.env.NODE_ENV !== 'test';
let done = false;
let cb = function (err, body) {
if (!done) {
done = true;
callback(err, body);
}
};
let req = httpModule.request(options, function (res) {
let bufs = [];
res.on('data', function (data) {
bufs.push(data);
});
res.on('error', cb);
res.on('end', function () {
cb(null, Buffer.concat(bufs));
});
});
req.on('error', cb);
req.on('timeout', function () {
req.abort();
});
req.end();
}