strip leading separators in all content-disposition filename forms#13206
strip leading separators in all content-disposition filename forms#13206arshsmith1 wants to merge 2 commits into
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #13206 +/- ##
=======================================
Coverage 98.98% 98.98%
=======================================
Files 131 131
Lines 48955 48969 +14
Branches 2550 2550
=======================================
+ Hits 48458 48472 +14
Misses 373 373
Partials 124 124
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. |
Merging this PR will not alter performance
Comparing Footnotes
|
|
@aiolibsbot review |
PR Review — strip leading separators in all content-disposition filename formsCorrect, well-tested consistency fix — merge-ready. The divergence is real and the fix is minimal and right: quoted
Tests are thorough — updates the previously-divergent
🟢 Suggestions
1. Plain (unencoded) continuation reassembly still returns without lstrip
|
| elif is_continuous_param(key): | ||
| if is_quoted(value): | ||
| value = unescape(value[1:-1]) | ||
| value = unescape(value[1:-1].lstrip("\\/")) |
There was a problem hiding this comment.
lstrip runs on every continuation chunk here, so filename*0="dir"; filename*1="/file.txt" becomes dirfile.txt instead of dir/file.txt. Can this be deferred until after content_disposition_filename() joins the parts, as the encoded path does?
There was a problem hiding this comment.
Good catch, that was wrong. Stripping each quoted continuation part in isolation eats a separator that belongs in the middle of the joined value.
Moved it: the quoted branch in parse_content_disposition is back to what it was, and content_disposition_filename now strips the reassembled value on the plain path too, so it matches how the encoded path already worked. filename*0="dir"; filename*1="/file.txt" gives dir/file.txt again, and filename*0="/foo."; filename*1="html" still gives foo.html. Added a test for each.
That also covers the review bot's note about the plain reassembly path returning unstripped.
What do these changes do?
parse_content_dispositionstrips leading path separators when the filename arrives as a quoted-string, but the RFC 5987filename*and the RFC 2231filename*0/filename*0*continuation forms skip that step, so the sender picks whether the normalisation runs at all:filename*=UTF-8''%2Fetc%2Fcron.d%2Fevilcomes back as/etc/cron.d/evilwherefilename="/etc/cron.d/evil"comes back asetc/cron.d/evil.content_disposition_filenamealso prefersfilename*overfilenameand reassembles continuation parts on its own, so the unnormalised spelling is the oneBodyPartReader.filenameandFileField.filenamehand to applications. The samelstripnow runs in the continuation and extended-parameter branches and on the reassembled continuation value, so every spelling of the header lands the same way.The divergence is already visible in the test file:
test_attabspath/test_attabspathwinassert the strip on the quoted form, whiletest_attwithfn2231abspathdisguisedasserted the raw\foo.htmlfor the 2231 form of the same greenbytes case. That expectation is updated here, and the other three forms get coverage alongside it.Are there changes in behavior for the user?
A leading
/or\is now removed fromfilename*and fromfilename*Ncontinuation values, matching what a quotedfilenamehas always done. Nothing else about the value changes.Is it a substantial burden for the maintainers to support this?
No. It reuses the existing
lstrip("\\/")at three more spots in the same two functions; no new helpers or API.Related issue number
None.
Checklist
CONTRIBUTORS.txt— already listedCHANGES/folderLocal run