Filename can be a nested path#355
Conversation
|
😱 What's wrong with CI tests?! Worked fine for me. 🤔 |
|
All unit tests pass now. The CodeFactor issues seem to be unrelated to this patch, AFAICT. |
|
Thanks for the PR @sebdeckers. Do you mind to add a test for the use case? Thanks. PS. I'll check what's wrong with CodeFactor. |
|
I removed CodeFactor (it was weird and inconsistent) – it should be better now. |
|
Ooh, that's a great idea! 💡 How did I not think of just adding a new property. 😅 Will refactor this PR and add testing. |
|
All right. Took me a few tries to get Windows support working but this should do the trick. 😅 Appveyor is very useful. |
|
|
||
| if (filename) { | ||
| contentDisposition = 'filename="' + path.basename(filename) + '"'; | ||
| filename = options.filepath ? normalize(filename) : path.basename(filename); |
There was a problem hiding this comment.
How about using path.normalize?
There was a problem hiding this comment.
Different purpose:
path.normalisecleans up..and de-dupes path separators, but retains platform-specific path separators.normalize-pathconverts Windows\path separator to forward slash.
TBH I didn't check if the spec calls for forward slashes but seems consistent with all web-related paths.
There was a problem hiding this comment.
I see.
Probably we still want to clean up don't, './photos/toys/unicycle.jpg' -> 'photos/toys/unicycle.jpg', as for win -> unix, we could do something like:
filename = filename.replace('\\', '/');
| // 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 = options.filepath || options.filename || value.name || value.path; |
There was a problem hiding this comment.
What do you think doing it in "one-stroke" fashion?
Something like:
var filename = options.filepath ? path.normalize(options.filepath) : path.basename(options.filename || value.name || value.path);
And add basename call to the streams.
The main reason is to handle options here and don't "leak" them further into the function.
There was a problem hiding this comment.
Totally agree. Will clean this up.
|
Thanks for the update. Looks good in general, just want to discuss implementation details. |
|
(Sorry for the coveralls spam ... It seems to leave a comment on every rebase.) Fixed as per review:
Also fixed:
Edit: Oops, broke again in Windows. Hang on. |
|
Don't worry about coveralls :) With greenkeeper gone from this repo, it's all nice and quiet :) |
| filename = value.client._httpMessage.path; | ||
| if (typeof options.filepath === 'string') { | ||
| // custom filepath for relative paths | ||
| filename = path.normalize(options.filepath.replace(/\\/g, '/')); |
2 similar comments
3 similar comments
| 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'); |
There was a problem hiding this comment.
I remember struggles like that, with no local access to windows :)
You could try something like:
assert.strictEqual(files['custom_filepath'].name, relativeFile.replace(/\\/g, '/'), 'Expects custom filename:' + files['custom_filepath'].name + ' -vs- ' + relativeFile.replace(/\\/g, '/') + ' -from- ' + relativeFile + ' -end-');
:)
There was a problem hiding this comment.
Hah this is too funny. 😂
Anyway I think it's because I did path.resolve after the backslash replace. Seems on Windows path.resolve expects to still see the native OS separator. Makes sense, I suppose.
Should be fixed now. Also cleaned up some path concatenation in text/common.js, just to be on the safe side.
There was a problem hiding this comment.
I see. Native nodejs methods do convert slashes for windows, so it should be fine.
There was a problem hiding this comment.
Oh, do you mind to change 'Expects custom filename' to 'Expects custom filepath', it will be more clear which line is failed.
92096d4 to
517081a
Compare
| 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(__dirname, '..'), knownFile); |
There was a problem hiding this comment.
Oops this should have been relative to knownFile, not __dirname. One more patch incoming...
| tmp: path.join(rootDir, '/test/tmp') | ||
| lib: path.join(rootDir, 'lib'), | ||
| fixture: path.join(rootDir, 'test', 'fixture'), | ||
| tmp: path.join(rootDir, 'test', 'tmp') |
There was a problem hiding this comment.
path.join updates all the slashes on windows.
There was a problem hiding this comment.
Okay, will roll this back.
| 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(__dirname, '..'), knownFile); |
There was a problem hiding this comment.
Do you want to pass rootDir to the common.dir.root, so we stay more DRY here?
There was a problem hiding this comment.
Changed this to be a relative path to knownFile. So it will have the OS-specific separator. This makes the test more meaningful than a hardcoded string. LMK if you prefer a change.
|
🤞 |
|
Looks like it's in good working state. I invited you as a Collaborator, you can merge when it's passes. Thank you. |
|
@alexindigo Thanks! It's an honour. Appreciate your guidance & patience. 🤝 |
|
Thank you. I'll publish it shortly. |
|
Published |
TL;DR This patch allows setting of arbitrary filename to support uploads of directories. This matches current spec and behaviour of Chrome.
Example
Edit: Updated to reflect latest patch.
Description
The FormData
.appendspec defers to the File API spec which states:However, the
HTMLInputElement.webkitdirectoryspec supports relative paths, and Chrome sets them as thefilename=...in the form field.This is also supported by Multer, for example.
Caveat Emptor
Breaking change for anyone manually specifying filename as a full path. Does not change behaviour on auto-detecting of filename from stream, http, etc.Edit: The
filepathoption overridesfilename. This PR is no longer a breaking change.See also