Skip to content

Add optional charset parameter to web.FileResponse - #13151

Open
pctablet505 wants to merge 1 commit into
aio-libs:masterfrom
pctablet505:fix-4559-fileresponse-charset
Open

Add optional charset parameter to web.FileResponse#13151
pctablet505 wants to merge 1 commit into
aio-libs:masterfrom
pctablet505:fix-4559-fileresponse-charset

Conversation

@pctablet505

Copy link
Copy Markdown

Fixes #4559

Adds an optional charset parameter to web.FileResponse so callers can set an explicit charset on the response content-type.

@psf-chronographer psf-chronographer Bot added the bot:chronographer:provided There is a change note present in this PR label Jul 15, 2026
@codspeed-hq

codspeed-hq Bot commented Jul 15, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 84 untouched benchmarks
⏩ 83 skipped benchmarks1


Comparing pctablet505:fix-4559-fileresponse-charset (8997395) with master (c207cad)2

Open in CodSpeed

Footnotes

  1. 83 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

  2. No successful run was found on master (2e64b0f) during the generation of this report, so c207cad was used instead as the comparison base. There might be some changes unrelated to this pull request in this report.

@pctablet505
pctablet505 marked this pull request as ready for review July 17, 2026 12:48
@codecov

codecov Bot commented Jul 17, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 99.01%. Comparing base (c207cad) to head (8997395).
⚠️ Report is 1 commits behind head on master.
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@           Coverage Diff           @@
##           master   #13151   +/-   ##
=======================================
  Coverage   99.01%   99.01%           
=======================================
  Files         132      132           
  Lines       49813    49845   +32     
  Branches     2587     2588    +1     
=======================================
+ Hits        49323    49355   +32     
  Misses        368      368           
  Partials      122      122           
Flag Coverage Δ
Autobahn 21.98% <9.37%> (-0.01%) ⬇️
CI-GHA 98.92% <100.00%> (+<0.01%) ⬆️
OS-Linux 98.69% <100.00%> (-0.01%) ⬇️
OS-Windows 97.03% <100.00%> (+<0.01%) ⬆️
OS-macOS 97.95% <100.00%> (+<0.01%) ⬆️
Py-3.10 98.14% <100.00%> (+<0.01%) ⬆️
Py-3.11 98.38% <100.00%> (-0.01%) ⬇️
Py-3.12 98.46% <100.00%> (-0.01%) ⬇️
Py-3.13 98.45% <100.00%> (+<0.01%) ⬆️
Py-3.14 98.46% <100.00%> (-0.01%) ⬇️
Py-3.14t 97.56% <100.00%> (+<0.01%) ⬆️
Py-pypy-3.11 97.43% <100.00%> (+<0.01%) ⬆️
VM-macos 97.95% <100.00%> (+<0.01%) ⬆️
VM-ubuntu 98.69% <100.00%> (-0.01%) ⬇️
VM-windows 97.03% <100.00%> (+<0.01%) ⬆️
cython-coverage 83.03% <33.33%> (-0.02%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

@Dreamsorcerer

Copy link
Copy Markdown
Member

@aiolibsbot review

@aiolibsbot

Copy link
Copy Markdown
Contributor

PR Review — Add optional charset parameter to web.FileResponse

Clean, well-scoped addition of an optional charset parameter to FileResponse. Merge-ready; one design nit to consider.

Strengths:

  • The startswith("text/") guard correctly sidesteps the charset setter's RuntimeError on application/octet-stream (web_response.py:239), so binary files won't crash.

  • Charset block is placed outside the CONTENT_TYPE not in headers branch, so it also applies when the content-type is user-supplied via headers — sensible.

  • Good test coverage: parametrized text cases plus an explicit non-text "ignored" case; changelog fragment and docs param both included.

  • Suggestion: the text/ prefix restriction silently ignores charset for application/json/xml/javascript and +xml/+json types, which is narrower than an explicitly-passed parameter suggests — documented, so a maintainer call rather than a blocker.


🟢 Suggestions

1. `charset` silently ignored for non-`text/` text-based media types
aiohttp/web_fileresponse.py:388-389

The guard self.content_type.startswith("text/") means an explicitly-passed charset is silently dropped for media types that are genuinely text and legitimately carry a charset but do not live under the text/ tree — notably application/json, application/xml, application/javascript, and image/svg+xml.

Why it matters: a caller serving a .json static file with charset="utf-8" will get back application/json with no charset and no error, which is surprising for an explicitly-supplied parameter. Since static JSON/XML/JS files are a common FileResponse use case, the restriction is narrower than users may expect.

The startswith("text/") check does serve a real purpose — it protects against the charset setter raising RuntimeError on application/octet-stream (see web_response.py:239). So you can't just drop the guard.

Options:

  • Broaden the predicate to cover known text-based types (e.g. also allow application/json, application/xml, +xml/+json suffixes, application/javascript).
  • Or keep the narrow scope but the docs already say "text-like MIME types (e.g. text/plain)", so this is defensible as-is — worth a maintainer decision.

Non-blocking; the current behavior is documented and internally consistent.

if self._charset is not None and self.content_type.startswith("text/"):
    self.charset = self._charset

Checklist

  • New behavior covered by tests
  • Charset setter RuntimeError avoided for binary types
  • Docs and changelog updated for public API change
  • API scope matches user expectations — suggestion #1

Automated review by Kōan (Claude) HEAD=093f651 1 min 47s

@Dreamsorcerer

Copy link
Copy Markdown
Member

charset silently ignored for non-text/ text-based media types

Yeah, this is what was standing out to me as a bit odd. I'm not sure this is the right design. I'm also wondering about getting the charset automatically..

Allows callers to set an explicit charset on the Content-Type header
for text-like MIME types (e.g. text/plain, text/html).

Fixes aio-libs#4559
@pctablet505
pctablet505 force-pushed the fix-4559-fileresponse-charset branch from 093f651 to 8997395 Compare August 21, 2026 15:18
@greptile-apps

greptile-apps Bot commented Aug 21, 2026

Copy link
Copy Markdown

Confidence Score: 4/5

The implementation appears safe to merge after the non-blocking repository documentation and changelog requirements are addressed.

The new charset behavior has focused functional coverage and no concrete runtime defect was established, but the public API addition lacks its required threat-model update and the changelog fragment lacks attribution.

Files Needing Attention: aiohttp/web_fileresponse.py, CHANGES/4559.feature.rst

Reviews (1): Last reviewed commit: "Add optional charset parameter to web.Fi..." | Re-trigger Greptile

status: int = 200,
reason: str | None = None,
headers: LooseHeaders | None = None,
charset: str | None = None,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Complete public API metadata

Adding charset to the public FileResponse constructor requires the corresponding THREAT_MODEL.md update, while the feature fragment also needs the repository-required -- by :user: attribution; leaving both out makes the security documentation and release metadata incomplete for this API.

Context Used: AGENTS.md (source)

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bot:chronographer:provided There is a change note present in this PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

web.FileResponse support charset

3 participants