Skip to content

Commit dd46552

Browse files
authored
Merge pull request #190 from DylanPiercey/master
Allow custom header fields to be set as an object.
2 parents ddb3762 + a587eac commit dd46552

4 files changed

Lines changed: 100 additions & 4 deletions

File tree

lib/form_data.js

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ FormData.prototype._multiPartHeader = function(field, value, options) {
162162
// custom header specified (as string)?
163163
// it becomes responsible for boundary
164164
// (e.g. to handle extra CRLFs on .NET servers)
165-
if (options.header) {
165+
if (typeof options.header == 'string') {
166166
return options.header;
167167
}
168168

@@ -177,9 +177,28 @@ FormData.prototype._multiPartHeader = function(field, value, options) {
177177
'Content-Type': [].concat(contentType || [])
178178
};
179179

180+
// allow custom headers.
181+
if (typeof options.header == 'object') {
182+
populate(headers, options.header);
183+
}
184+
185+
var header;
180186
for (var prop in headers) {
181-
if (headers[prop].length) {
182-
contents += prop + ': ' + headers[prop].join('; ') + FormData.LINE_BREAK;
187+
header = headers[prop];
188+
189+
// skip nullish headers.
190+
if (header == null) {
191+
continue;
192+
}
193+
194+
// convert all headers to arrays.
195+
if (!Array.isArray(header)) {
196+
header = [header];
197+
}
198+
199+
// add non-empty headers.
200+
if (header.length) {
201+
contents += prop + ': ' + header.join('; ') + FormData.LINE_BREAK;
183202
}
184203
}
185204

@@ -192,7 +211,8 @@ FormData.prototype._getContentDisposition = function(value, options) {
192211

193212
// custom filename takes precedence
194213
// fs- and request- streams have path property
195-
var filename = options.filename || value.path;
214+
// formidable and the browser add a name property.
215+
var filename = options.filename || value.name || value.path;
196216

197217
// or try http response
198218
if (!filename && value.readable && value.hasOwnProperty('httpVersion')) {
@@ -211,6 +231,11 @@ FormData.prototype._getContentType = function(value, options) {
211231
// use custom content-type above all
212232
var contentType = options.contentType;
213233

234+
// or try `name` from formidable, browser
235+
if (!contentType && value.name) {
236+
contentType = mime.lookup(value.name);
237+
}
238+
214239
// or try `path` from fs-, request- streams
215240
if (!contentType && value.path) {
216241
contentType = mime.lookup(value.path);

test/integration/test-custom-filename.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,10 @@ var server = http.createServer(function(req, res) {
4343
assert.strictEqual(files['unknown_with_filename_as_object'].name, options.filename, 'Expects custom filename');
4444
assert.strictEqual(files['unknown_with_filename_as_object'].type, mime.lookup(options.filename), 'Expects filename-derived content-type');
4545

46+
assert('unknown_with_name_prop' in files);
47+
assert.strictEqual(files['unknown_with_name_prop'].name, options.filename, 'Expects custom filename');
48+
assert.strictEqual(files['unknown_with_name_prop'].type, mime.lookup(options.filename), 'Expects filename-derived content-type');
49+
4650
assert('unknown_everything' in files);
4751
assert.strictEqual(files['unknown_everything'].type, FormData.DEFAULT_CONTENT_TYPE, 'Expects default content-type');
4852

@@ -63,6 +67,10 @@ server.listen(common.port, function() {
6367
form.append('unknown_with_filename', fs.createReadStream(unknownFile), options.filename);
6468
// Filename only with unknown file
6569
form.append('unknown_with_filename_as_object', fs.createReadStream(unknownFile), {filename: options.filename});
70+
// No options or implicit file type from extension on name property.
71+
var customNameStream = fs.createReadStream(unknownFile);
72+
customNameStream.name = options.filename;
73+
form.append('unknown_with_name_prop', customNameStream);
6674
// No options or implicit file type from extension.
6775
form.append('unknown_everything', fs.createReadStream(unknownFile));
6876

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/*
2+
test custom headers object.
3+
https://github.com/form-data/form-data/issues/133
4+
*/
5+
6+
var common = require('../common');
7+
var assert = common.assert;
8+
var http = require('http');
9+
10+
var FormData = require(common.dir.lib + '/form_data');
11+
12+
var testHeader = { 'X-Test-Fake': 123 };
13+
14+
var expectedLength;
15+
16+
17+
var server = http.createServer(function(req, res) {
18+
assert.ok( typeof req.headers['content-length'] !== 'undefined' );
19+
assert.equal(req.headers['content-length'], expectedLength);
20+
21+
req.on('data', function (data) {
22+
assert.equal(
23+
data.toString('utf8').split('\n')[3],
24+
'X-Test-Fake: 123\r'
25+
);
26+
});
27+
28+
res.writeHead(200);
29+
res.end('done');
30+
});
31+
32+
33+
server.listen(common.port, function() {
34+
var form = new FormData();
35+
36+
var options = {
37+
header: testHeader,
38+
39+
// override content-length,
40+
// much lower than actual buffer size (1000)
41+
knownLength: 1
42+
};
43+
44+
var bufferData = [];
45+
for (var z = 0; z < 1000; z++) {
46+
bufferData.push(1);
47+
}
48+
var buffer = new Buffer(bufferData);
49+
50+
form.append('my_buffer', buffer, options);
51+
52+
// (available to req handler)
53+
expectedLength = form._lastBoundary().length + form._overheadLength + options.knownLength;
54+
55+
common.actions.submit(form, server);
56+
});

test/integration/test-custom-headers.js renamed to test/integration/test-custom-headers-string.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,13 @@ var server = http.createServer(function(req, res) {
2020
assert.ok( typeof req.headers['content-length'] !== 'undefined' );
2121
assert.equal(req.headers['content-length'], expectedLength);
2222

23+
req.on('data', function (data) {
24+
assert.equal(
25+
data.toString('utf8').split('\n')[2],
26+
'X-Test-Fake: 123\r'
27+
);
28+
});
29+
2330
res.writeHead(200);
2431
res.end('done');
2532
});

0 commit comments

Comments
 (0)