fix(backend): serve PDF/Markdown manuals inline so the viewer can render them#3714
Conversation
…der them Uploaded manual files (RomFile with category="manual") were served from the content endpoint as application/octet-stream + attachment, so the in-page manual viewer showed a blank area while nav buttons and download still worked. Include .pdf and .md in is_allowed_media_file (with explicit MIME overrides) so they are served inline, and set X-Content-Type-Options: nosniff on inline responses so a Markdown manual can't be sniffed into HTML. Fixes #3712 Generated-By: PostHog Code Task-Id: 73be371c-908a-4f9f-9748-7ddba2df71e2
There was a problem hiding this comment.
Pull request overview
This PR fixes rendering of uploaded ROM manuals in the in-page manual viewer by serving PDF/Markdown files inline (with trusted MIME types) from the existing ROM file content endpoint, rather than forcing them to download as attachments.
Changes:
- Extend the inline-media allowlist to include
.pdfand.md, with explicit MIME overrides (application/pdf,text/markdown). - Add
X-Content-Type-Options: nosnifffor inline responses (both devFileResponseand nginxX-Accel-Redirectresponses). - Add endpoint tests asserting inline disposition, correct Content-Type, and
nosnifffor PDF/Markdown manuals.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| backend/utils/media_types.py | Adds document extensions and MIME overrides so PDFs/Markdown can be served inline with consistent Content-Type. |
| backend/endpoints/roms/files.py | Applies nosniff to inline responses and forwards headers through both FileResponse and FileRedirectResponse. |
| backend/tests/endpoints/roms/test_files.py | Adds regression tests for serving PDF/Markdown manual files inline with expected headers. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Greptile SummaryThis PR lets uploaded manuals render inline from the ROM file content endpoint. The main changes are:
Confidence Score: 5/5The changed flow looks mergeable after a small cleanup to the document inline scope.
backend/utils/media_types.py Important Files Changed
Reviews (1): Last reviewed commit: "fix(backend): serve PDF/Markdown manuals..." | Re-trigger Greptile |
Serving any .pdf/.md file inline by extension also flipped game/extra files from downloads to inline. Gate the document check on RomFileCategory.MANUAL so only manuals render inline; other files keep the attachment behavior. Generated-By: PostHog Code Task-Id: 73be371c-908a-4f9f-9748-7ddba2df71e2
Dismissed because a newer commit was pushed; Greptile will re-review the current head.
Description
Explain the changes or enhancements you are proposing with this pull request.
Uploaded manuals (a
RomFilewithcategory="manual") are served fromGET /api/roms/{id}/files/content/{file_name}. That endpoint only treated soundtracks and image/video files as inline media, so manuals fell through toapplication/octet-stream+Content-Disposition: attachment. The same URL is used for both viewing and downloading, so downloads and the nav chrome kept working while the in-page PDF/Markdown viewer got an octet-stream/attachment response and rendered a blank area.This only affected manuals uploaded as extra files. Scraped/primary manuals (
rom.has_manual+rom.path_manual) load from the static-asset path and were unaffected, which is why the bug reproduced for some libraries but not others.Changes:
.pdfand.mdtois_allowed_media_file(via a newALLOWED_DOCUMENT_EXTENSIONS/is_allowed_document_file), with explicit MIME overrides (application/pdf,text/markdown) so the content type is trustworthy across platforms. Manuals are now served inline.X-Content-Type-Options: nosniffon inline responses (both the devFileResponseand the nginxFileRedirectResponse). SVG is deliberately kept out of the inline allowlist because it can carry script, so serving Markdown inline warrants the same care:nosniffprevents the browser from sniffing a.mdmanual into HTML.Fixes #3712
AI assistance disclosure
Per CONTRIBUTING.md.
This change was written with AI assistance (PostHog Code / Claude): investigation, code changes, and tests were AI-generated and human-reviewed.
Checklist
Please check all that apply.
Screenshots (if applicable)
Created with PostHog Code