Skip to content

Commit

Permalink
Allow custom header fields to be set as an object.
Browse files Browse the repository at this point in the history
  • Loading branch information
DylanPiercey committed Apr 2, 2016
1 parent ddb3762 commit a587eac
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 4 deletions.
33 changes: 29 additions & 4 deletions lib/form_data.js
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ FormData.prototype._multiPartHeader = function(field, value, options) {
// custom header specified (as string)?
// it becomes responsible for boundary
// (e.g. to handle extra CRLFs on .NET servers)
if (options.header) {
if (typeof options.header == 'string') {
return options.header;
}

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

// allow custom headers.
if (typeof options.header == 'object') {
populate(headers, options.header);
}

var header;
for (var prop in headers) {
if (headers[prop].length) {
contents += prop + ': ' + headers[prop].join('; ') + FormData.LINE_BREAK;
header = headers[prop];

// skip nullish headers.
if (header == null) {
continue;
}

// convert all headers to arrays.
if (!Array.isArray(header)) {
header = [header];
}

// add non-empty headers.
if (header.length) {
contents += prop + ': ' + header.join('; ') + FormData.LINE_BREAK;
}
}

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

// custom filename takes precedence
// fs- and request- streams have path property
var filename = options.filename || value.path;
// formidable and the browser add a name property.
var filename = options.filename || value.name || value.path;

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

// or try `name` from formidable, browser
if (!contentType && value.name) {
contentType = mime.lookup(value.name);
}

// or try `path` from fs-, request- streams
if (!contentType && value.path) {
contentType = mime.lookup(value.path);
Expand Down
8 changes: 8 additions & 0 deletions test/integration/test-custom-filename.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ var server = http.createServer(function(req, res) {
assert.strictEqual(files['unknown_with_filename_as_object'].name, options.filename, 'Expects custom filename');
assert.strictEqual(files['unknown_with_filename_as_object'].type, mime.lookup(options.filename), 'Expects filename-derived content-type');

assert('unknown_with_name_prop' in files);
assert.strictEqual(files['unknown_with_name_prop'].name, options.filename, 'Expects custom filename');
assert.strictEqual(files['unknown_with_name_prop'].type, mime.lookup(options.filename), 'Expects filename-derived content-type');

assert('unknown_everything' in files);
assert.strictEqual(files['unknown_everything'].type, FormData.DEFAULT_CONTENT_TYPE, 'Expects default content-type');

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

Expand Down
56 changes: 56 additions & 0 deletions test/integration/test-custom-headers-object.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
test custom headers object.
https://github.com/form-data/form-data/issues/133
*/

var common = require('../common');
var assert = common.assert;
var http = require('http');

var FormData = require(common.dir.lib + '/form_data');

var testHeader = { 'X-Test-Fake': 123 };

var expectedLength;


var server = http.createServer(function(req, res) {
assert.ok( typeof req.headers['content-length'] !== 'undefined' );
assert.equal(req.headers['content-length'], expectedLength);

req.on('data', function (data) {
assert.equal(
data.toString('utf8').split('\n')[3],
'X-Test-Fake: 123\r'
);
});

res.writeHead(200);
res.end('done');
});


server.listen(common.port, function() {
var form = new FormData();

var options = {
header: testHeader,

// override content-length,
// much lower than actual buffer size (1000)
knownLength: 1
};

var bufferData = [];
for (var z = 0; z < 1000; z++) {
bufferData.push(1);
}
var buffer = new Buffer(bufferData);

form.append('my_buffer', buffer, options);

// (available to req handler)
expectedLength = form._lastBoundary().length + form._overheadLength + options.knownLength;

common.actions.submit(form, server);
});
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,13 @@ var server = http.createServer(function(req, res) {
assert.ok( typeof req.headers['content-length'] !== 'undefined' );
assert.equal(req.headers['content-length'], expectedLength);

req.on('data', function (data) {
assert.equal(
data.toString('utf8').split('\n')[2],
'X-Test-Fake: 123\r'
);
});

res.writeHead(200);
res.end('done');
});
Expand Down

0 comments on commit a587eac

Please sign in to comment.