Skip to content

Allow caching of middleware construction #10890

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 14 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 20 additions & 35 deletions aiohttp/client.py
Original file line number Diff line number Diff line change
@@ -77,8 +77,10 @@
SSL_ALLOWED_TYPES,
ClientRequest,
ClientResponse,
ClientTimeout,
Fingerprint,
RequestInfo,
ResponseParams,
)
from .client_ws import (
DEFAULT_WS_CLIENT_TIMEOUT,
@@ -98,7 +100,6 @@
EMPTY_BODY_METHODS,
BasicAuth,
TimeoutHandle,
frozen_dataclass_decorator,
get_env_proxy_for_url,
sentinel,
strip_auth_from_url,
@@ -197,28 +198,6 @@ class _RequestOptions(TypedDict, total=False):
middlewares: Optional[Tuple[ClientMiddlewareType, ...]]


@frozen_dataclass_decorator
class ClientTimeout:
total: Optional[float] = None
connect: Optional[float] = None
sock_read: Optional[float] = None
sock_connect: Optional[float] = None
ceil_threshold: float = 5

# pool_queue_timeout: Optional[float] = None
# dns_resolution_timeout: Optional[float] = None
# socket_connect_timeout: Optional[float] = None
# connection_acquiring_timeout: Optional[float] = None
# new_connection_timeout: Optional[float] = None
# http_header_timeout: Optional[float] = None
# response_body_timeout: Optional[float] = None

# to create a timeout specific for a single request, either
# - create a completely new one to overwrite the default
# - or use https://docs.python.org/3/library/dataclasses.html#dataclasses.replace
# to overwrite the defaults


# 5 Minute default read timeout
DEFAULT_TIMEOUT: Final[ClientTimeout] = ClientTimeout(total=5 * 60, sock_connect=30)

@@ -622,9 +601,23 @@ async def _request(
get_env_proxy_for_url, url
)

response_params: ResponseParams = {
"timer": timer,
"skip_payload": method in EMPTY_BODY_METHODS,
"read_until_eof": read_until_eof,
"auto_decompress": auto_decompress,
"read_timeout": real_timeout.sock_read,
"read_bufsize": read_bufsize,
"timeout_ceil_threshold": self._connector._timeout_ceil_threshold,
"max_line_size": max_line_size,
"max_field_size": max_field_size,
}

req = self._request_class(
method,
url,
response_params=response_params,
timeout=real_timeout,
params=params,
headers=headers,
skip_auto_headers=skip_headers,
@@ -654,27 +647,19 @@ async def _connect_and_send_request(
) -> ClientResponse:
# connection timeout
assert self._connector is not None
assert req._timeout is not None
try:
conn = await self._connector.connect(
req, traces=traces, timeout=real_timeout
req, traces=traces, timeout=req._timeout
)
except asyncio.TimeoutError as exc:
raise ConnectionTimeoutError(
f"Connection timeout to host {req.url}"
) from exc

assert conn.protocol is not None
conn.protocol.set_response_params(
timer=timer,
skip_payload=req.method in EMPTY_BODY_METHODS,
read_until_eof=read_until_eof,
auto_decompress=auto_decompress,
read_timeout=real_timeout.sock_read,
read_bufsize=read_bufsize,
timeout_ceil_threshold=self._connector._timeout_ceil_threshold,
max_line_size=max_line_size,
max_field_size=max_field_size,
)
assert req._response_params is not None
conn.protocol.set_response_params(**req._response_params)
try:
resp = await req.send(conn)
try:
41 changes: 41 additions & 0 deletions aiohttp/client_reqrep.py
Original file line number Diff line number Diff line change
@@ -22,6 +22,7 @@
Optional,
Tuple,
Type,
TypedDict,
Union,
)

@@ -98,6 +99,28 @@
_CONTAINS_CONTROL_CHAR_RE = re.compile(r"[^-!#$%&'*+.^_`|~0-9a-zA-Z]")


@frozen_dataclass_decorator
class ClientTimeout:
total: Optional[float] = None
connect: Optional[float] = None
sock_read: Optional[float] = None
sock_connect: Optional[float] = None
ceil_threshold: float = 5

# pool_queue_timeout: Optional[float] = None
# dns_resolution_timeout: Optional[float] = None
# socket_connect_timeout: Optional[float] = None
# connection_acquiring_timeout: Optional[float] = None
# new_connection_timeout: Optional[float] = None
# http_header_timeout: Optional[float] = None
# response_body_timeout: Optional[float] = None

# to create a timeout specific for a single request, either
# - create a completely new one to overwrite the default
# - or use https://docs.python.org/3/library/dataclasses.html#dataclasses.replace
# to overwrite the defaults


def _gen_default_accept_encoding() -> str:
return "gzip, deflate, br" if HAS_BROTLI else "gzip, deflate"

@@ -190,6 +213,18 @@ class ConnectionKey(NamedTuple):
proxy_headers_hash: Optional[int] # hash(CIMultiDict)


class ResponseParams(TypedDict):
timer: Optional[BaseTimerContext]
skip_payload: bool
read_until_eof: bool
auto_decompress: bool
read_timeout: Optional[float]
read_bufsize: int
timeout_ceil_threshold: float
max_line_size: int
max_field_size: int


class ClientRequest:
GET_METHODS = {
hdrs.METH_GET,
@@ -209,11 +244,13 @@ class ClientRequest:
body: Any = b""
auth = None
response = None
_response_params = None

# These class defaults help create_autospec() work correctly.
# If autospec is improved in future, maybe these can be removed.
url = URL()
method = "GET"
_timeout: Optional[ClientTimeout] = ClientTimeout()

__writer: Optional["asyncio.Task[None]"] = None # async task for streaming data
_continue = None # waiter future for '100 Continue' response
@@ -251,6 +288,8 @@ def __init__(
traces: Optional[List["Trace"]] = None,
trust_env: bool = False,
server_hostname: Optional[str] = None,
response_params: Optional[ResponseParams] = None,
timeout: Optional[ClientTimeout] = None,
):
if match := _CONTAINS_CONTROL_CHAR_RE.search(method):
raise ValueError(
@@ -281,6 +320,8 @@ def __init__(
self.response_class: Type[ClientResponse] = real_response_class
self._timer = timer if timer is not None else TimerNoop()
self._ssl = ssl
self._response_params = response_params
self._timeout = timeout
self.server_hostname = server_hostname

if loop.get_debug():