70
70
WSMessageTypeError ,
71
71
WSServerHandshakeError ,
72
72
)
73
+ from .client_middlewares import ClientMiddlewareType , build_client_middlewares
73
74
from .client_reqrep import (
74
75
ClientRequest as ClientRequest ,
75
76
ClientResponse as ClientResponse ,
@@ -191,6 +192,7 @@ class _RequestOptions(TypedDict, total=False):
191
192
auto_decompress : Union [bool , None ]
192
193
max_line_size : Union [int , None ]
193
194
max_field_size : Union [int , None ]
195
+ middlewares : Optional [Tuple [ClientMiddlewareType , ...]]
194
196
195
197
196
198
@attr .s (auto_attribs = True , frozen = True , slots = True )
@@ -258,6 +260,7 @@ class ClientSession:
258
260
"_default_proxy" ,
259
261
"_default_proxy_auth" ,
260
262
"_retry_connection" ,
263
+ "_middlewares" ,
261
264
"requote_redirect_url" ,
262
265
]
263
266
)
@@ -298,6 +301,7 @@ def __init__(
298
301
max_line_size : int = 8190 ,
299
302
max_field_size : int = 8190 ,
300
303
fallback_charset_resolver : _CharsetResolver = lambda r , b : "utf-8" ,
304
+ middlewares : Optional [Tuple [ClientMiddlewareType , ...]] = None ,
301
305
) -> None :
302
306
# We initialise _connector to None immediately, as it's referenced in __del__()
303
307
# and could cause issues if an exception occurs during initialisation.
@@ -410,6 +414,7 @@ def __init__(
410
414
self ._default_proxy = proxy
411
415
self ._default_proxy_auth = proxy_auth
412
416
self ._retry_connection : bool = True
417
+ self ._middlewares = middlewares
413
418
414
419
def __init_subclass__ (cls : Type ["ClientSession" ]) -> None :
415
420
warnings .warn (
@@ -500,6 +505,7 @@ async def _request(
500
505
auto_decompress : Optional [bool ] = None ,
501
506
max_line_size : Optional [int ] = None ,
502
507
max_field_size : Optional [int ] = None ,
508
+ middlewares : Optional [Tuple [ClientMiddlewareType , ...]] = None ,
503
509
) -> ClientResponse :
504
510
505
511
# NOTE: timeout clamps existing connect and read timeouts. We cannot
@@ -699,32 +705,33 @@ async def _request(
699
705
trust_env = self .trust_env ,
700
706
)
701
707
702
- # connection timeout
703
- try :
704
- conn = await self ._connector .connect (
705
- req , traces = traces , timeout = real_timeout
708
+ # Core request handler - now includes connection logic
709
+ async def _connect_and_send_request (
710
+ req : ClientRequest ,
711
+ ) -> ClientResponse :
712
+ # connection timeout
713
+ assert self ._connector is not None
714
+ try :
715
+ conn = await self ._connector .connect (
716
+ req , traces = traces , timeout = real_timeout
717
+ )
718
+ except asyncio .TimeoutError as exc :
719
+ raise ConnectionTimeoutError (
720
+ f"Connection timeout to host { req .url } "
721
+ ) from exc
722
+
723
+ assert conn .protocol is not None
724
+ conn .protocol .set_response_params (
725
+ timer = timer ,
726
+ skip_payload = req .method in EMPTY_BODY_METHODS ,
727
+ read_until_eof = read_until_eof ,
728
+ auto_decompress = auto_decompress ,
729
+ read_timeout = real_timeout .sock_read ,
730
+ read_bufsize = read_bufsize ,
731
+ timeout_ceil_threshold = self ._connector ._timeout_ceil_threshold ,
732
+ max_line_size = max_line_size ,
733
+ max_field_size = max_field_size ,
706
734
)
707
- except asyncio .TimeoutError as exc :
708
- raise ConnectionTimeoutError (
709
- f"Connection timeout to host { url } "
710
- ) from exc
711
-
712
- assert conn .transport is not None
713
-
714
- assert conn .protocol is not None
715
- conn .protocol .set_response_params (
716
- timer = timer ,
717
- skip_payload = method in EMPTY_BODY_METHODS ,
718
- read_until_eof = read_until_eof ,
719
- auto_decompress = auto_decompress ,
720
- read_timeout = real_timeout .sock_read ,
721
- read_bufsize = read_bufsize ,
722
- timeout_ceil_threshold = self ._connector ._timeout_ceil_threshold ,
723
- max_line_size = max_line_size ,
724
- max_field_size = max_field_size ,
725
- )
726
-
727
- try :
728
735
try :
729
736
resp = await req .send (conn )
730
737
try :
@@ -735,6 +742,30 @@ async def _request(
735
742
except BaseException :
736
743
conn .close ()
737
744
raise
745
+ return resp
746
+
747
+ # Apply middleware (if any) - per-request middleware overrides session middleware
748
+ effective_middlewares = (
749
+ self ._middlewares if middlewares is None else middlewares
750
+ )
751
+
752
+ if effective_middlewares :
753
+ handler = build_client_middlewares (
754
+ _connect_and_send_request , effective_middlewares
755
+ )
756
+ else :
757
+ handler = _connect_and_send_request
758
+
759
+ try :
760
+ resp = await handler (req )
761
+ # Client connector errors should not be retried
762
+ except (
763
+ ConnectionTimeoutError ,
764
+ ClientConnectorError ,
765
+ ClientConnectorCertificateError ,
766
+ ClientConnectorSSLError ,
767
+ ):
768
+ raise
738
769
except (ClientOSError , ServerDisconnectedError ):
739
770
if retry_persistent_connection :
740
771
retry_persistent_connection = False
0 commit comments