ZCU-DATA/fix: RFC 5987 Content-Disposition for single-file download (backport #1368) - #1370
Conversation
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Backport of the single-file half of #1368 (dtq-dev) to customer/zcu-data. allzip was already fixed here by #1267, but single-file download was not: HttpHeadersInitializer encoded the name with MimeUtility.encodeText, i.e. RFC 2047 encoded-words, which RFC 6266 Appendix C.1 forbids in HTTP. Safari shows the raw =?UTF-8?Q?...?= string; Chrome and Firefox decode it anyway, which is why this looked intermittent. Also aligns the private buildContentDisposition added by #1267 with vanilla's createFallbackAsciiName / createEncodedUtf8Name, so allzip and single-file render the same way and both track upstream. The fallback now transliterates rather than blanking out, so it reads "Prilis zlutoucky kun.zip" instead of "P__li_ _lu_ou_k_ k__.zip"; the IT from #1267 is updated accordingly. Only clients that ignore filename* ever see that value. The escaping of \ and " that #1267 added is kept, and marked in the code as a deliberate deviation — vanilla omits it and still has that bug. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
ca3a368 to
7a7c1e2
Compare
There was a problem hiding this comment.
Pull request overview
Backports upstream-aligned RFC 5987 Content-Disposition handling so single-file downloads (and the allzip endpoint) provide a standards-compliant filename* value while retaining an ASCII filename fallback for legacy clients.
Changes:
- Update
HttpHeadersInitializerto generateContent-Disposition: <disposition>; filename="..."; filename*=UTF-8''...(RFC 5987) instead of RFC 2047 encoded-words. - Align allzip’s
Content-Dispositionbuilding with the same fallback/encoding approach (diacritics stripped in fallback; UTF-8 percent-encoded infilename*). - Update integration tests to assert the new header format and updated ASCII fallback behavior.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| dspace-server-webapp/src/main/java/org/dspace/app/rest/utils/HttpHeadersInitializer.java | Switch single-file Content-Disposition generation to RFC 5987 filename* + ASCII fallback. |
| dspace-server-webapp/src/main/java/org/dspace/app/rest/MetadataBitstreamController.java | Update allzip Content-Disposition builder to match the RFC 5987 approach used elsewhere. |
| dspace-server-webapp/src/test/java/org/dspace/app/rest/MetadataBitstreamControllerIT.java | Adjust expected Content-Disposition for diacritics item-name allzip scenario. |
| dspace-server-webapp/src/test/java/org/dspace/app/rest/BitstreamRestControllerIT.java | Update single-bitstream Content-Disposition assertion to RFC 5987 filename* + ASCII fallback. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Restrict createFallbackAsciiName to printable ASCII ([\x20-\x7E]) in both HttpHeadersInitializer (single-file) and MetadataBitstreamController (allzip), so control chars — notably CR/LF — can no longer reach the quoted-string filename= value and inject a header. HttpHeadersInitializer additionally now escapes \ and ", matching MetadataBitstreamController; previously the two paths were inconsistent. MetadataBitstreamController had regressed from [\x20-\x7E] to [\x00-\x7F] while aligning with vanilla; this restores the printable-only filter while keeping the NFD transliteration. Existing IT assertions are unaffected (all use printable names). Addresses Copilot review comments on #1370. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Backport of #1368 to
customer/zcu-data. Fixes the wrong filename when downloading a single file.allzip was already fixed here by #1267 — this covers the other half, which was never fixed on any branch.
What's fixed
HttpHeadersInitializerencoded the name withMimeUtility.encodeText, i.e. an RFC 2047 encoded-word (=?UTF-8?Q?...?=) — an email header format that RFC 6266 App. C.1 does not allow in HTTP.Be aware what this does and does not change in practice. Chrome and Firefox decode RFC 2047 anyway, so for them nothing changes — measured, not assumed (see the middle block of the screenshot in #1368). It bites clients that follow the spec: Safari, and
curl -OJ, which saved the encoded-word verbatim with the extension buried mid-name. That is why this looked intermittent depending on who reported it.Cherry-pick of vanilla
fe4077acee(#11269 → 7.6.6). The cherry-pick conflicted — this branch's copy predates vanilla'sisNullOrEmpty(disposition)guard and has its ownMETHOD_HEADearly-return. I kept this branch's structure and swapped only the encoding, so the backport stays surgical.Alignment with vanilla
The private
buildContentDisposition()added by #1267 now uses vanilla'screateFallbackAsciiName/createEncodedUtf8Name, so allzip and single-file render the same way and both track upstream. No shared fork helper —MetadataBitstreamControlleris fork-only, so it keeps its own copy, exactly as vanilla'sHttpHeadersInitializerdoes.The escaping of
\and"that #1267 added is kept and marked as a deliberate deviation: vanilla omits it and still has that bug, so copying verbatim would have regressed #1267.Behaviour change to note in review
The fallback now transliterates instead of blanking out, so allzip yields
"Prilis zlutoucky kun.zip"where #1267 produced"P__li_ _lu_ou_k_ k__.zip". The IT from #1267 is updated to match. Only clients that ignorefilename*ever see this value.Verified
mvn test-compileondspace-api+dspace-server-webapp— passdtq-devpair, not on this branch🤖 Generated with Claude Code