Skip to content

Commit

Permalink
Merge pull request #355 from sebdeckers/patch-1
Browse files Browse the repository at this point in the history
Filename can be a nested path
  • Loading branch information
sebdeckers committed Jun 11, 2017
2 parents d7398c3 + 9512d0c commit 561dece
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 16 deletions.
5 changes: 4 additions & 1 deletion Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,8 @@ someModule.stream(function(err, stdout, stderr) {
var form = new FormData();

form.append('file', stdout, {
filename: 'unicycle.jpg',
filename: 'unicycle.jpg', // ... or:
filepath: 'photos/toys/unicycle.jpg',
contentType: 'image/jpg',
knownLength: 19806
});
Expand All @@ -144,6 +145,8 @@ someModule.stream(function(err, stdout, stderr) {
});
```

The `filepath` property overrides `filename` and may contain a relative path. This is typically used when uploading [multiple files from a directory](https://wicg.github.io/entries-api/#dom-htmlinputelement-webkitdirectory).

For edge cases, like POST request to URL with query string or to pass HTTP auth credentials, object can be passed to `form.submit()` as first parameter:

``` javascript
Expand Down
31 changes: 18 additions & 13 deletions lib/form_data.js
Original file line number Diff line number Diff line change
Expand Up @@ -209,20 +209,25 @@ FormData.prototype._multiPartHeader = function(field, value, options) {

FormData.prototype._getContentDisposition = function(value, options) {

var contentDisposition;

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

// or try http response
if (!filename && value.readable && value.hasOwnProperty('httpVersion')) {
filename = value.client._httpMessage.path;
if (typeof options.filepath === 'string') {
// custom filepath for relative paths
filename = path.normalize(options.filepath).replace(/\\/g, '/');
} else if (options.filename || value.name || value.path) {
// custom filename take precedence
// formidable and the browser add a name property
// fs- and request- streams have path property
filename = path.basename(options.filename || value.name || value.path);
} else if (value.readable && value.hasOwnProperty('httpVersion')) {
// or try http response
filename = path.basename(value.client._httpMessage.path);
}

if (filename) {
contentDisposition = 'filename="' + path.basename(filename) + '"';
contentDisposition = 'filename="' + filename + '"';
}

return contentDisposition;
Expand All @@ -248,9 +253,9 @@ FormData.prototype._getContentType = function(value, options) {
contentType = value.headers['content-type'];
}

// or guess it from the filename
if (!contentType && options.filename) {
contentType = mime.lookup(options.filename);
// or guess it from the filepath or filename
if (!contentType && (options.filepath || options.filename)) {
contentType = mime.lookup(options.filepath || options.filename);
}

// fallback to the default content type if `value` is not simple value
Expand Down
12 changes: 10 additions & 2 deletions test/integration/test-custom-filename.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,14 @@ var assert = common.assert;
var mime = require('mime-types');
var http = require('http');
var fs = require('fs');
var path = require('path');

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

var knownFile = common.dir.fixture + '/unicycle.jpg';
var unknownFile = common.dir.fixture + '/unknown_file_type';
var knownFile = path.join(common.dir.fixture, 'unicycle.jpg');
var unknownFile = path.join(common.dir.fixture, 'unknown_file_type');
var relativeFile = path.relative(path.join(knownFile, '..', '..'), knownFile);

var options = {
filename: 'test.png',
Expand All @@ -35,6 +37,10 @@ var server = http.createServer(function(req, res) {
assert.strictEqual(files['custom_filename'].name, options.filename, 'Expects custom filename');
assert.strictEqual(files['custom_filename'].type, mime.lookup(knownFile), 'Expects original content-type');

assert('custom_filepath' in files);
assert.strictEqual(files['custom_filepath'].name, relativeFile.replace(/\\/g, '/'), 'Expects custom filename');
assert.strictEqual(files['custom_filepath'].type, mime.lookup(knownFile), 'Expects original content-type');

assert('unknown_with_filename' in files);
assert.strictEqual(files['unknown_with_filename'].name, options.filename, 'Expects custom filename');
assert.strictEqual(files['unknown_with_filename'].type, mime.lookup(options.filename), 'Expects filename-derived content-type');
Expand Down Expand Up @@ -67,6 +73,8 @@ 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});
// Filename with relative path
form.append('custom_filepath', fs.createReadStream(knownFile), {filepath: relativeFile});
// No options or implicit file type from extension on name property.
var customNameStream = fs.createReadStream(unknownFile);
customNameStream.name = options.filename;
Expand Down

0 comments on commit 561dece

Please sign in to comment.