Skip to content

Commit ce5fada

Browse files
nightcitybladenightcitybladeDreamsorcerer
authored
docs: clarify allowed compress request values (#12363)
Co-authored-by: nightcityblade <nightcityblade@gmail.com> Co-authored-by: Sam Bull <git@sambull.org>
1 parent 07bd8c1 commit ce5fada

File tree

7 files changed

+39
-12
lines changed

7 files changed

+39
-12
lines changed

CHANGES/10549.misc.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Document and narrow the allowed ``compress`` request values to ``True``/``False``, ``"deflate"``, or ``"gzip"``, and reject unsupported string values.

CONTRIBUTORS.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,7 @@ Sergey Skripnick
341341
Serhii Charykov
342342
Serhii Kostel
343343
Serhiy Storchaka
344+
Shensheng Shen
344345
Shubh Agarwal
345346
Simon Kennedy
346347
Sin-Woo Bang

aiohttp/client.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@ class _RequestOptions(TypedDict, total=False):
184184
auth: BasicAuth | None
185185
allow_redirects: bool
186186
max_redirects: int
187-
compress: str | bool
187+
compress: Literal["deflate", "gzip"] | bool
188188
chunked: bool | None
189189
expect100: bool
190190
raise_for_status: None | bool | Callable[[ClientResponse], Awaitable[None]]
@@ -488,7 +488,7 @@ async def _request(
488488
auth: BasicAuth | None = None,
489489
allow_redirects: bool = True,
490490
max_redirects: int = 10,
491-
compress: str | bool = False,
491+
compress: Literal["deflate", "gzip"] | bool = False,
492492
chunked: bool | None = None,
493493
expect100: bool = False,
494494
raise_for_status: (

aiohttp/client_reqrep.py

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
from hashlib import md5, sha1, sha256
1212
from http.cookies import BaseCookie, SimpleCookie
1313
from types import MappingProxyType, TracebackType
14-
from typing import TYPE_CHECKING, Any, NamedTuple, TypedDict
14+
from typing import TYPE_CHECKING, Any, Literal, NamedTuple, TypedDict
1515

1616
from multidict import CIMultiDict, CIMultiDictProxy, MultiDict, MultiDictProxy
1717
from yarl import URL, Query
@@ -935,7 +935,7 @@ class ClientRequestArgs(TypedDict, total=False):
935935
cookies: BaseCookie[str]
936936
auth: BasicAuth | None
937937
version: HttpVersion
938-
compress: str | bool
938+
compress: Literal["deflate", "gzip"] | bool
939939
chunked: bool | None
940940
expect100: bool
941941
loop: asyncio.AbstractEventLoop
@@ -979,7 +979,7 @@ def __init__(
979979
cookies: BaseCookie[str],
980980
auth: BasicAuth | None,
981981
version: HttpVersion,
982-
compress: str | bool,
982+
compress: Literal["deflate", "gzip"] | bool,
983983
chunked: bool | None,
984984
expect100: bool,
985985
loop: asyncio.AbstractEventLoop,
@@ -1099,7 +1099,9 @@ def _update_cookies(self, cookies: BaseCookie[str]) -> None:
10991099

11001100
self.headers[hdrs.COOKIE] = c.output(header="", sep=";").strip()
11011101

1102-
def _update_content_encoding(self, data: Any, compress: bool | str) -> None:
1102+
def _update_content_encoding(
1103+
self, data: Any, compress: bool | Literal["deflate", "gzip"]
1104+
) -> None:
11031105
"""Set request content encoding."""
11041106
self.compress = None
11051107
if not data:
@@ -1111,6 +1113,10 @@ def _update_content_encoding(self, data: Any, compress: bool | str) -> None:
11111113
"compress can not be set if Content-Encoding header is set"
11121114
)
11131115
elif compress:
1116+
if isinstance(compress, str) and compress not in {"deflate", "gzip"}:
1117+
raise ValueError(
1118+
"compress must be one of True, False, 'deflate', or 'gzip'"
1119+
)
11141120
self.compress = compress if isinstance(compress, str) else "deflate"
11151121
self.headers[hdrs.CONTENT_ENCODING] = self.compress
11161122
self.chunked = True # enable chunked, no need to deal with length

docs/client_reference.rst

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -978,10 +978,13 @@ certification chaining.
978978
Ignored when ``allow_redirects=False``.
979979
``10`` by default.
980980

981-
:param bool compress: Set to ``True`` if request has to be compressed
982-
with deflate encoding. If `compress` can not be combined
983-
with a *Content-Encoding* and *Content-Length* headers.
984-
``None`` by default (optional).
981+
:param compress: Set to ``True`` to compress the request body with
982+
``deflate`` encoding, or pass ``"deflate"`` or ``"gzip"``
983+
explicitly to choose the content encoding. ``False`` by
984+
default.
985+
986+
This parameter cannot be combined with
987+
*Content-Encoding* or *Content-Length* headers.
985988

986989
:param int chunked: Enables chunked transfer encoding.
987990
It is up to the developer

tests/test_client_request.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1006,6 +1006,22 @@ async def test_content_encoding_dont_set_headers_if_no_body(
10061006
resp.close()
10071007

10081008

1009+
async def test_content_encoding_rejects_unknown_string(
1010+
make_client_request: _RequestMaker,
1011+
) -> None:
1012+
with pytest.raises(
1013+
ValueError,
1014+
match="compress must be one of True, False, 'deflate', or 'gzip'",
1015+
):
1016+
make_client_request(
1017+
"post",
1018+
URL("http://python.org/"),
1019+
data="foo",
1020+
compress="br", # type: ignore[arg-type]
1021+
loop=asyncio.get_running_loop(),
1022+
)
1023+
1024+
10091025
@pytest.mark.usefixtures("parametrize_zlib_backend")
10101026
async def test_content_encoding_header( # type: ignore[misc]
10111027
loop: asyncio.AbstractEventLoop,

tests/test_client_session.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
from collections.abc import Awaitable, Callable, Iterator
1010
from http.cookies import BaseCookie, SimpleCookie
1111
from types import SimpleNamespace
12-
from typing import Any, NoReturn, TypedDict, cast
12+
from typing import Any, Literal, NoReturn, TypedDict, cast
1313
from unittest import mock
1414
from uuid import uuid4
1515

@@ -44,7 +44,7 @@
4444
class _Params(TypedDict):
4545
headers: dict[str, str]
4646
max_redirects: int
47-
compress: str
47+
compress: Literal["deflate", "gzip"]
4848
chunked: bool
4949
expect100: bool
5050
read_until_eof: bool

0 commit comments

Comments
 (0)