Skip to content

Commit

Permalink
Avoid duplicate charset on Content-Type (#2443)
Browse files Browse the repository at this point in the history
* fix(response): avoid duplicated charset

* Update docs/responses.md

---------

Co-authored-by: Marcelo Trylesinski <marcelotryle@gmail.com>
  • Loading branch information
mikkelduif and Kludex committed Feb 3, 2024
1 parent 8da52c2 commit b8eebef
Show file tree
Hide file tree
Showing 3 changed files with 12 additions and 2 deletions.
2 changes: 1 addition & 1 deletion docs/responses.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ Signature: `Response(content, status_code=200, headers=None, media_type=None)`

Starlette will automatically include a Content-Length header. It will also
include a Content-Type header, based on the media_type and appending a charset
for text types.
for text types, unless a charset has already been specified in the `media_type`.

Once you've instantiated a response, you can send it by calling it as an
ASGI application instance.
Expand Down
5 changes: 4 additions & 1 deletion starlette/responses.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,10 @@ def init_headers(self, headers: typing.Mapping[str, str] | None = None) -> None:

content_type = self.media_type
if content_type is not None and populate_content_type:
if content_type.startswith("text/"):
if (
content_type.startswith("text/")
and "charset=" not in content_type.lower()
):
content_type += "; charset=" + self.charset
raw_headers.append((b"content-type", content_type.encode("latin-1")))

Expand Down
7 changes: 7 additions & 0 deletions tests/test_responses.py
Original file line number Diff line number Diff line change
Expand Up @@ -473,6 +473,13 @@ def test_non_empty_response(test_client_factory):
assert response.headers["content-length"] == "2"


def test_response_do_not_add_redundant_charset(test_client_factory):
app = Response(media_type="text/plain; charset=utf-8")
client = test_client_factory(app)
response = client.get("/")
assert response.headers["content-type"] == "text/plain; charset=utf-8"


def test_file_response_known_size(tmpdir, test_client_factory):
path = os.path.join(tmpdir, "xyz")
content = b"<file content>" * 1000
Expand Down

0 comments on commit b8eebef

Please sign in to comment.