Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/aiohttp/client.py: 56%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

602 statements  

1"""HTTP Client for asyncio.""" 

2 

3import asyncio 

4import base64 

5import hashlib 

6import json 

7import os 

8import sys 

9import traceback 

10import warnings 

11from contextlib import suppress 

12from types import TracebackType 

13from typing import ( 

14 TYPE_CHECKING, 

15 Any, 

16 Awaitable, 

17 Callable, 

18 Coroutine, 

19 Final, 

20 FrozenSet, 

21 Generator, 

22 Generic, 

23 Iterable, 

24 List, 

25 Mapping, 

26 Optional, 

27 Sequence, 

28 Set, 

29 Tuple, 

30 Type, 

31 TypedDict, 

32 TypeVar, 

33 Union, 

34) 

35 

36import attr 

37from multidict import CIMultiDict, MultiDict, MultiDictProxy, istr 

38from yarl import URL 

39 

40from . import hdrs, http, payload 

41from ._websocket.reader import WebSocketDataQueue 

42from .abc import AbstractCookieJar 

43from .client_exceptions import ( 

44 ClientConnectionError, 

45 ClientConnectionResetError, 

46 ClientConnectorCertificateError, 

47 ClientConnectorDNSError, 

48 ClientConnectorError, 

49 ClientConnectorSSLError, 

50 ClientError, 

51 ClientHttpProxyError, 

52 ClientOSError, 

53 ClientPayloadError, 

54 ClientProxyConnectionError, 

55 ClientResponseError, 

56 ClientSSLError, 

57 ConnectionTimeoutError, 

58 ContentTypeError, 

59 InvalidURL, 

60 InvalidUrlClientError, 

61 InvalidUrlRedirectClientError, 

62 NonHttpUrlClientError, 

63 NonHttpUrlRedirectClientError, 

64 RedirectClientError, 

65 ServerConnectionError, 

66 ServerDisconnectedError, 

67 ServerFingerprintMismatch, 

68 ServerTimeoutError, 

69 SocketTimeoutError, 

70 TooManyRedirects, 

71 WSMessageTypeError, 

72 WSServerHandshakeError, 

73) 

74from .client_middlewares import ClientMiddlewareType, build_client_middlewares 

75from .client_reqrep import ( 

76 ClientRequest as ClientRequest, 

77 ClientResponse as ClientResponse, 

78 Fingerprint as Fingerprint, 

79 RequestInfo as RequestInfo, 

80 _merge_ssl_params, 

81) 

82from .client_ws import ( 

83 DEFAULT_WS_CLIENT_TIMEOUT, 

84 ClientWebSocketResponse as ClientWebSocketResponse, 

85 ClientWSTimeout as ClientWSTimeout, 

86) 

87from .connector import ( 

88 HTTP_AND_EMPTY_SCHEMA_SET, 

89 BaseConnector as BaseConnector, 

90 NamedPipeConnector as NamedPipeConnector, 

91 TCPConnector as TCPConnector, 

92 UnixConnector as UnixConnector, 

93) 

94from .cookiejar import CookieJar 

95from .helpers import ( 

96 _SENTINEL, 

97 DEBUG, 

98 EMPTY_BODY_METHODS, 

99 BasicAuth, 

100 TimeoutHandle, 

101 get_env_proxy_for_url, 

102 sentinel, 

103 strip_auth_from_url, 

104) 

105from .http import WS_KEY, HttpVersion, WebSocketReader, WebSocketWriter 

106from .http_websocket import WSHandshakeError, ws_ext_gen, ws_ext_parse 

107from .tracing import Trace, TraceConfig 

108from .typedefs import JSONEncoder, LooseCookies, LooseHeaders, Query, StrOrURL 

109 

110__all__ = ( 

111 # client_exceptions 

112 "ClientConnectionError", 

113 "ClientConnectionResetError", 

114 "ClientConnectorCertificateError", 

115 "ClientConnectorDNSError", 

116 "ClientConnectorError", 

117 "ClientConnectorSSLError", 

118 "ClientError", 

119 "ClientHttpProxyError", 

120 "ClientOSError", 

121 "ClientPayloadError", 

122 "ClientProxyConnectionError", 

123 "ClientResponseError", 

124 "ClientSSLError", 

125 "ConnectionTimeoutError", 

126 "ContentTypeError", 

127 "InvalidURL", 

128 "InvalidUrlClientError", 

129 "RedirectClientError", 

130 "NonHttpUrlClientError", 

131 "InvalidUrlRedirectClientError", 

132 "NonHttpUrlRedirectClientError", 

133 "ServerConnectionError", 

134 "ServerDisconnectedError", 

135 "ServerFingerprintMismatch", 

136 "ServerTimeoutError", 

137 "SocketTimeoutError", 

138 "TooManyRedirects", 

139 "WSServerHandshakeError", 

140 # client_reqrep 

141 "ClientRequest", 

142 "ClientResponse", 

143 "Fingerprint", 

144 "RequestInfo", 

145 # connector 

146 "BaseConnector", 

147 "TCPConnector", 

148 "UnixConnector", 

149 "NamedPipeConnector", 

150 # client_ws 

151 "ClientWebSocketResponse", 

152 # client 

153 "ClientSession", 

154 "ClientTimeout", 

155 "ClientWSTimeout", 

156 "request", 

157 "WSMessageTypeError", 

158) 

159 

160 

161if TYPE_CHECKING: 

162 from ssl import SSLContext 

163else: 

164 SSLContext = None 

165 

166if sys.version_info >= (3, 11) and TYPE_CHECKING: 

167 from typing import Unpack 

168 

169 

170class _RequestOptions(TypedDict, total=False): 

171 params: Query 

172 data: Any 

173 json: Any 

174 cookies: Union[LooseCookies, None] 

175 headers: Union[LooseHeaders, None] 

176 skip_auto_headers: Union[Iterable[str], None] 

177 auth: Union[BasicAuth, None] 

178 allow_redirects: bool 

179 max_redirects: int 

180 compress: Union[str, bool, None] 

181 chunked: Union[bool, None] 

182 expect100: bool 

183 raise_for_status: Union[None, bool, Callable[[ClientResponse], Awaitable[None]]] 

184 read_until_eof: bool 

185 proxy: Union[StrOrURL, None] 

186 proxy_auth: Union[BasicAuth, None] 

187 timeout: "Union[ClientTimeout, _SENTINEL, None]" 

188 ssl: Union[SSLContext, bool, Fingerprint] 

189 server_hostname: Union[str, None] 

190 proxy_headers: Union[LooseHeaders, None] 

191 trace_request_ctx: Union[Mapping[str, Any], None] 

192 read_bufsize: Union[int, None] 

193 auto_decompress: Union[bool, None] 

194 max_line_size: Union[int, None] 

195 max_field_size: Union[int, None] 

196 middlewares: Optional[Sequence[ClientMiddlewareType]] 

197 

198 

199@attr.s(auto_attribs=True, frozen=True, slots=True) 

200class ClientTimeout: 

201 total: Optional[float] = None 

202 connect: Optional[float] = None 

203 sock_read: Optional[float] = None 

204 sock_connect: Optional[float] = None 

205 ceil_threshold: float = 5 

206 

207 # pool_queue_timeout: Optional[float] = None 

208 # dns_resolution_timeout: Optional[float] = None 

209 # socket_connect_timeout: Optional[float] = None 

210 # connection_acquiring_timeout: Optional[float] = None 

211 # new_connection_timeout: Optional[float] = None 

212 # http_header_timeout: Optional[float] = None 

213 # response_body_timeout: Optional[float] = None 

214 

215 # to create a timeout specific for a single request, either 

216 # - create a completely new one to overwrite the default 

217 # - or use http://www.attrs.org/en/stable/api.html#attr.evolve 

218 # to overwrite the defaults 

219 

220 

221# 5 Minute default read timeout 

222DEFAULT_TIMEOUT: Final[ClientTimeout] = ClientTimeout(total=5 * 60, sock_connect=30) 

223 

224# https://www.rfc-editor.org/rfc/rfc9110#section-9.2.2 

225IDEMPOTENT_METHODS = frozenset({"GET", "HEAD", "OPTIONS", "TRACE", "PUT", "DELETE"}) 

226 

227_RetType = TypeVar("_RetType", ClientResponse, ClientWebSocketResponse) 

228_CharsetResolver = Callable[[ClientResponse, bytes], str] 

229 

230 

231class ClientSession: 

232 """First-class interface for making HTTP requests.""" 

233 

234 ATTRS = frozenset( 

235 [ 

236 "_base_url", 

237 "_base_url_origin", 

238 "_source_traceback", 

239 "_connector", 

240 "_loop", 

241 "_cookie_jar", 

242 "_connector_owner", 

243 "_default_auth", 

244 "_version", 

245 "_json_serialize", 

246 "_requote_redirect_url", 

247 "_timeout", 

248 "_raise_for_status", 

249 "_auto_decompress", 

250 "_trust_env", 

251 "_default_headers", 

252 "_skip_auto_headers", 

253 "_request_class", 

254 "_response_class", 

255 "_ws_response_class", 

256 "_trace_configs", 

257 "_read_bufsize", 

258 "_max_line_size", 

259 "_max_field_size", 

260 "_resolve_charset", 

261 "_default_proxy", 

262 "_default_proxy_auth", 

263 "_retry_connection", 

264 "_middlewares", 

265 "requote_redirect_url", 

266 ] 

267 ) 

268 

269 _source_traceback: Optional[traceback.StackSummary] = None 

270 _connector: Optional[BaseConnector] = None 

271 

272 def __init__( 

273 self, 

274 base_url: Optional[StrOrURL] = None, 

275 *, 

276 connector: Optional[BaseConnector] = None, 

277 loop: Optional[asyncio.AbstractEventLoop] = None, 

278 cookies: Optional[LooseCookies] = None, 

279 headers: Optional[LooseHeaders] = None, 

280 proxy: Optional[StrOrURL] = None, 

281 proxy_auth: Optional[BasicAuth] = None, 

282 skip_auto_headers: Optional[Iterable[str]] = None, 

283 auth: Optional[BasicAuth] = None, 

284 json_serialize: JSONEncoder = json.dumps, 

285 request_class: Type[ClientRequest] = ClientRequest, 

286 response_class: Type[ClientResponse] = ClientResponse, 

287 ws_response_class: Type[ClientWebSocketResponse] = ClientWebSocketResponse, 

288 version: HttpVersion = http.HttpVersion11, 

289 cookie_jar: Optional[AbstractCookieJar] = None, 

290 connector_owner: bool = True, 

291 raise_for_status: Union[ 

292 bool, Callable[[ClientResponse], Awaitable[None]] 

293 ] = False, 

294 read_timeout: Union[float, _SENTINEL] = sentinel, 

295 conn_timeout: Optional[float] = None, 

296 timeout: Union[object, ClientTimeout] = sentinel, 

297 auto_decompress: bool = True, 

298 trust_env: bool = False, 

299 requote_redirect_url: bool = True, 

300 trace_configs: Optional[List[TraceConfig]] = None, 

301 read_bufsize: int = 2**16, 

302 max_line_size: int = 8190, 

303 max_field_size: int = 8190, 

304 fallback_charset_resolver: _CharsetResolver = lambda r, b: "utf-8", 

305 middlewares: Sequence[ClientMiddlewareType] = (), 

306 ssl_shutdown_timeout: Union[_SENTINEL, None, float] = sentinel, 

307 ) -> None: 

308 # We initialise _connector to None immediately, as it's referenced in __del__() 

309 # and could cause issues if an exception occurs during initialisation. 

310 self._connector: Optional[BaseConnector] = None 

311 

312 if loop is None: 

313 if connector is not None: 

314 loop = connector._loop 

315 

316 loop = loop or asyncio.get_running_loop() 

317 

318 if base_url is None or isinstance(base_url, URL): 

319 self._base_url: Optional[URL] = base_url 

320 self._base_url_origin = None if base_url is None else base_url.origin() 

321 else: 

322 self._base_url = URL(base_url) 

323 self._base_url_origin = self._base_url.origin() 

324 assert self._base_url.absolute, "Only absolute URLs are supported" 

325 if self._base_url is not None and not self._base_url.path.endswith("/"): 

326 raise ValueError("base_url must have a trailing '/'") 

327 

328 if timeout is sentinel or timeout is None: 

329 self._timeout = DEFAULT_TIMEOUT 

330 if read_timeout is not sentinel: 

331 warnings.warn( 

332 "read_timeout is deprecated, use timeout argument instead", 

333 DeprecationWarning, 

334 stacklevel=2, 

335 ) 

336 self._timeout = attr.evolve(self._timeout, total=read_timeout) 

337 if conn_timeout is not None: 

338 self._timeout = attr.evolve(self._timeout, connect=conn_timeout) 

339 warnings.warn( 

340 "conn_timeout is deprecated, use timeout argument instead", 

341 DeprecationWarning, 

342 stacklevel=2, 

343 ) 

344 else: 

345 if not isinstance(timeout, ClientTimeout): 

346 raise ValueError( 

347 f"timeout parameter cannot be of {type(timeout)} type, " 

348 "please use 'timeout=ClientTimeout(...)'", 

349 ) 

350 self._timeout = timeout 

351 if read_timeout is not sentinel: 

352 raise ValueError( 

353 "read_timeout and timeout parameters " 

354 "conflict, please setup " 

355 "timeout.read" 

356 ) 

357 if conn_timeout is not None: 

358 raise ValueError( 

359 "conn_timeout and timeout parameters " 

360 "conflict, please setup " 

361 "timeout.connect" 

362 ) 

363 

364 if ssl_shutdown_timeout is not sentinel: 

365 warnings.warn( 

366 "The ssl_shutdown_timeout parameter is deprecated and will be removed in aiohttp 4.0", 

367 DeprecationWarning, 

368 stacklevel=2, 

369 ) 

370 

371 if connector is None: 

372 connector = TCPConnector( 

373 loop=loop, ssl_shutdown_timeout=ssl_shutdown_timeout 

374 ) 

375 

376 if connector._loop is not loop: 

377 raise RuntimeError("Session and connector has to use same event loop") 

378 

379 self._loop = loop 

380 

381 if loop.get_debug(): 

382 self._source_traceback = traceback.extract_stack(sys._getframe(1)) 

383 

384 if cookie_jar is None: 

385 cookie_jar = CookieJar(loop=loop) 

386 self._cookie_jar = cookie_jar 

387 

388 if cookies: 

389 self._cookie_jar.update_cookies(cookies) 

390 

391 self._connector = connector 

392 self._connector_owner = connector_owner 

393 self._default_auth = auth 

394 self._version = version 

395 self._json_serialize = json_serialize 

396 self._raise_for_status = raise_for_status 

397 self._auto_decompress = auto_decompress 

398 self._trust_env = trust_env 

399 self._requote_redirect_url = requote_redirect_url 

400 self._read_bufsize = read_bufsize 

401 self._max_line_size = max_line_size 

402 self._max_field_size = max_field_size 

403 

404 # Convert to list of tuples 

405 if headers: 

406 real_headers: CIMultiDict[str] = CIMultiDict(headers) 

407 else: 

408 real_headers = CIMultiDict() 

409 self._default_headers: CIMultiDict[str] = real_headers 

410 if skip_auto_headers is not None: 

411 self._skip_auto_headers = frozenset(istr(i) for i in skip_auto_headers) 

412 else: 

413 self._skip_auto_headers = frozenset() 

414 

415 self._request_class = request_class 

416 self._response_class = response_class 

417 self._ws_response_class = ws_response_class 

418 

419 self._trace_configs = trace_configs or [] 

420 for trace_config in self._trace_configs: 

421 trace_config.freeze() 

422 

423 self._resolve_charset = fallback_charset_resolver 

424 

425 self._default_proxy = proxy 

426 self._default_proxy_auth = proxy_auth 

427 self._retry_connection: bool = True 

428 self._middlewares = middlewares 

429 

430 def __init_subclass__(cls: Type["ClientSession"]) -> None: 

431 warnings.warn( 

432 "Inheritance class {} from ClientSession " 

433 "is discouraged".format(cls.__name__), 

434 DeprecationWarning, 

435 stacklevel=2, 

436 ) 

437 

438 if DEBUG: 

439 

440 def __setattr__(self, name: str, val: Any) -> None: 

441 if name not in self.ATTRS: 

442 warnings.warn( 

443 "Setting custom ClientSession.{} attribute " 

444 "is discouraged".format(name), 

445 DeprecationWarning, 

446 stacklevel=2, 

447 ) 

448 super().__setattr__(name, val) 

449 

450 def __del__(self, _warnings: Any = warnings) -> None: 

451 if not self.closed: 

452 kwargs = {"source": self} 

453 _warnings.warn( 

454 f"Unclosed client session {self!r}", ResourceWarning, **kwargs 

455 ) 

456 context = {"client_session": self, "message": "Unclosed client session"} 

457 if self._source_traceback is not None: 

458 context["source_traceback"] = self._source_traceback 

459 self._loop.call_exception_handler(context) 

460 

461 if sys.version_info >= (3, 11) and TYPE_CHECKING: 

462 

463 def request( 

464 self, 

465 method: str, 

466 url: StrOrURL, 

467 **kwargs: Unpack[_RequestOptions], 

468 ) -> "_RequestContextManager": ... 

469 

470 else: 

471 

472 def request( 

473 self, method: str, url: StrOrURL, **kwargs: Any 

474 ) -> "_RequestContextManager": 

475 """Perform HTTP request.""" 

476 return _RequestContextManager(self._request(method, url, **kwargs)) 

477 

478 def _build_url(self, str_or_url: StrOrURL) -> URL: 

479 url = URL(str_or_url) 

480 if self._base_url and not url.absolute: 

481 return self._base_url.join(url) 

482 return url 

483 

484 async def _request( 

485 self, 

486 method: str, 

487 str_or_url: StrOrURL, 

488 *, 

489 params: Query = None, 

490 data: Any = None, 

491 json: Any = None, 

492 cookies: Optional[LooseCookies] = None, 

493 headers: Optional[LooseHeaders] = None, 

494 skip_auto_headers: Optional[Iterable[str]] = None, 

495 auth: Optional[BasicAuth] = None, 

496 allow_redirects: bool = True, 

497 max_redirects: int = 10, 

498 compress: Union[str, bool, None] = None, 

499 chunked: Optional[bool] = None, 

500 expect100: bool = False, 

501 raise_for_status: Union[ 

502 None, bool, Callable[[ClientResponse], Awaitable[None]] 

503 ] = None, 

504 read_until_eof: bool = True, 

505 proxy: Optional[StrOrURL] = None, 

506 proxy_auth: Optional[BasicAuth] = None, 

507 timeout: Union[ClientTimeout, _SENTINEL] = sentinel, 

508 verify_ssl: Optional[bool] = None, 

509 fingerprint: Optional[bytes] = None, 

510 ssl_context: Optional[SSLContext] = None, 

511 ssl: Union[SSLContext, bool, Fingerprint] = True, 

512 server_hostname: Optional[str] = None, 

513 proxy_headers: Optional[LooseHeaders] = None, 

514 trace_request_ctx: Optional[Mapping[str, Any]] = None, 

515 read_bufsize: Optional[int] = None, 

516 auto_decompress: Optional[bool] = None, 

517 max_line_size: Optional[int] = None, 

518 max_field_size: Optional[int] = None, 

519 middlewares: Optional[Sequence[ClientMiddlewareType]] = None, 

520 ) -> ClientResponse: 

521 

522 # NOTE: timeout clamps existing connect and read timeouts. We cannot 

523 # set the default to None because we need to detect if the user wants 

524 # to use the existing timeouts by setting timeout to None. 

525 

526 if self.closed: 

527 raise RuntimeError("Session is closed") 

528 

529 ssl = _merge_ssl_params(ssl, verify_ssl, ssl_context, fingerprint) 

530 

531 if data is not None and json is not None: 

532 raise ValueError( 

533 "data and json parameters can not be used at the same time" 

534 ) 

535 elif json is not None: 

536 data = payload.JsonPayload(json, dumps=self._json_serialize) 

537 

538 if not isinstance(chunked, bool) and chunked is not None: 

539 warnings.warn("Chunk size is deprecated #1615", DeprecationWarning) 

540 

541 redirects = 0 

542 history: List[ClientResponse] = [] 

543 version = self._version 

544 params = params or {} 

545 

546 # Merge with default headers and transform to CIMultiDict 

547 headers = self._prepare_headers(headers) 

548 

549 try: 

550 url = self._build_url(str_or_url) 

551 except ValueError as e: 

552 raise InvalidUrlClientError(str_or_url) from e 

553 

554 assert self._connector is not None 

555 if url.scheme not in self._connector.allowed_protocol_schema_set: 

556 raise NonHttpUrlClientError(url) 

557 

558 skip_headers: Optional[Iterable[istr]] 

559 if skip_auto_headers is not None: 

560 skip_headers = { 

561 istr(i) for i in skip_auto_headers 

562 } | self._skip_auto_headers 

563 elif self._skip_auto_headers: 

564 skip_headers = self._skip_auto_headers 

565 else: 

566 skip_headers = None 

567 

568 if proxy is None: 

569 proxy = self._default_proxy 

570 if proxy_auth is None: 

571 proxy_auth = self._default_proxy_auth 

572 

573 if proxy is None: 

574 proxy_headers = None 

575 else: 

576 proxy_headers = self._prepare_headers(proxy_headers) 

577 try: 

578 proxy = URL(proxy) 

579 except ValueError as e: 

580 raise InvalidURL(proxy) from e 

581 

582 if timeout is sentinel: 

583 real_timeout: ClientTimeout = self._timeout 

584 else: 

585 if not isinstance(timeout, ClientTimeout): 

586 real_timeout = ClientTimeout(total=timeout) 

587 else: 

588 real_timeout = timeout 

589 # timeout is cumulative for all request operations 

590 # (request, redirects, responses, data consuming) 

591 tm = TimeoutHandle( 

592 self._loop, real_timeout.total, ceil_threshold=real_timeout.ceil_threshold 

593 ) 

594 handle = tm.start() 

595 

596 if read_bufsize is None: 

597 read_bufsize = self._read_bufsize 

598 

599 if auto_decompress is None: 

600 auto_decompress = self._auto_decompress 

601 

602 if max_line_size is None: 

603 max_line_size = self._max_line_size 

604 

605 if max_field_size is None: 

606 max_field_size = self._max_field_size 

607 

608 traces = [ 

609 Trace( 

610 self, 

611 trace_config, 

612 trace_config.trace_config_ctx(trace_request_ctx=trace_request_ctx), 

613 ) 

614 for trace_config in self._trace_configs 

615 ] 

616 

617 for trace in traces: 

618 await trace.send_request_start(method, url.update_query(params), headers) 

619 

620 timer = tm.timer() 

621 try: 

622 with timer: 

623 # https://www.rfc-editor.org/rfc/rfc9112.html#name-retrying-requests 

624 retry_persistent_connection = ( 

625 self._retry_connection and method in IDEMPOTENT_METHODS 

626 ) 

627 while True: 

628 url, auth_from_url = strip_auth_from_url(url) 

629 if not url.raw_host: 

630 # NOTE: Bail early, otherwise, causes `InvalidURL` through 

631 # NOTE: `self._request_class()` below. 

632 err_exc_cls = ( 

633 InvalidUrlRedirectClientError 

634 if redirects 

635 else InvalidUrlClientError 

636 ) 

637 raise err_exc_cls(url) 

638 # If `auth` was passed for an already authenticated URL, 

639 # disallow only if this is the initial URL; this is to avoid issues 

640 # with sketchy redirects that are not the caller's responsibility 

641 if not history and (auth and auth_from_url): 

642 raise ValueError( 

643 "Cannot combine AUTH argument with " 

644 "credentials encoded in URL" 

645 ) 

646 

647 # Override the auth with the one from the URL only if we 

648 # have no auth, or if we got an auth from a redirect URL 

649 if auth is None or (history and auth_from_url is not None): 

650 auth = auth_from_url 

651 

652 if ( 

653 auth is None 

654 and self._default_auth 

655 and ( 

656 not self._base_url or self._base_url_origin == url.origin() 

657 ) 

658 ): 

659 auth = self._default_auth 

660 # It would be confusing if we support explicit 

661 # Authorization header with auth argument 

662 if ( 

663 headers is not None 

664 and auth is not None 

665 and hdrs.AUTHORIZATION in headers 

666 ): 

667 raise ValueError( 

668 "Cannot combine AUTHORIZATION header " 

669 "with AUTH argument or credentials " 

670 "encoded in URL" 

671 ) 

672 

673 all_cookies = self._cookie_jar.filter_cookies(url) 

674 

675 if cookies is not None: 

676 tmp_cookie_jar = CookieJar( 

677 quote_cookie=self._cookie_jar.quote_cookie 

678 ) 

679 tmp_cookie_jar.update_cookies(cookies) 

680 req_cookies = tmp_cookie_jar.filter_cookies(url) 

681 if req_cookies: 

682 all_cookies.load(req_cookies) 

683 

684 proxy_: Optional[URL] = None 

685 if proxy is not None: 

686 proxy_ = URL(proxy) 

687 elif self._trust_env: 

688 with suppress(LookupError): 

689 proxy_, proxy_auth = await asyncio.to_thread( 

690 get_env_proxy_for_url, url 

691 ) 

692 

693 req = self._request_class( 

694 method, 

695 url, 

696 params=params, 

697 headers=headers, 

698 skip_auto_headers=skip_headers, 

699 data=data, 

700 cookies=all_cookies, 

701 auth=auth, 

702 version=version, 

703 compress=compress, 

704 chunked=chunked, 

705 expect100=expect100, 

706 loop=self._loop, 

707 response_class=self._response_class, 

708 proxy=proxy_, 

709 proxy_auth=proxy_auth, 

710 timer=timer, 

711 session=self, 

712 ssl=ssl if ssl is not None else True, 

713 server_hostname=server_hostname, 

714 proxy_headers=proxy_headers, 

715 traces=traces, 

716 trust_env=self.trust_env, 

717 ) 

718 

719 async def _connect_and_send_request( 

720 req: ClientRequest, 

721 ) -> ClientResponse: 

722 # connection timeout 

723 assert self._connector is not None 

724 try: 

725 conn = await self._connector.connect( 

726 req, traces=traces, timeout=real_timeout 

727 ) 

728 except asyncio.TimeoutError as exc: 

729 raise ConnectionTimeoutError( 

730 f"Connection timeout to host {req.url}" 

731 ) from exc 

732 

733 assert conn.protocol is not None 

734 conn.protocol.set_response_params( 

735 timer=timer, 

736 skip_payload=req.method in EMPTY_BODY_METHODS, 

737 read_until_eof=read_until_eof, 

738 auto_decompress=auto_decompress, 

739 read_timeout=real_timeout.sock_read, 

740 read_bufsize=read_bufsize, 

741 timeout_ceil_threshold=self._connector._timeout_ceil_threshold, 

742 max_line_size=max_line_size, 

743 max_field_size=max_field_size, 

744 ) 

745 try: 

746 resp = await req.send(conn) 

747 try: 

748 await resp.start(conn) 

749 except BaseException: 

750 resp.close() 

751 raise 

752 except BaseException: 

753 conn.close() 

754 raise 

755 return resp 

756 

757 # Apply middleware (if any) - per-request middleware overrides session middleware 

758 effective_middlewares = ( 

759 self._middlewares if middlewares is None else middlewares 

760 ) 

761 

762 if effective_middlewares: 

763 handler = build_client_middlewares( 

764 _connect_and_send_request, effective_middlewares 

765 ) 

766 else: 

767 handler = _connect_and_send_request 

768 

769 try: 

770 resp = await handler(req) 

771 # Client connector errors should not be retried 

772 except ( 

773 ConnectionTimeoutError, 

774 ClientConnectorError, 

775 ClientConnectorCertificateError, 

776 ClientConnectorSSLError, 

777 ): 

778 raise 

779 except (ClientOSError, ServerDisconnectedError): 

780 if retry_persistent_connection: 

781 retry_persistent_connection = False 

782 continue 

783 raise 

784 except ClientError: 

785 raise 

786 except OSError as exc: 

787 if exc.errno is None and isinstance(exc, asyncio.TimeoutError): 

788 raise 

789 raise ClientOSError(*exc.args) from exc 

790 

791 # Update cookies from raw headers to preserve duplicates 

792 if resp._raw_cookie_headers: 

793 self._cookie_jar.update_cookies_from_headers( 

794 resp._raw_cookie_headers, resp.url 

795 ) 

796 

797 # redirects 

798 if resp.status in (301, 302, 303, 307, 308) and allow_redirects: 

799 

800 for trace in traces: 

801 await trace.send_request_redirect( 

802 method, url.update_query(params), headers, resp 

803 ) 

804 

805 redirects += 1 

806 history.append(resp) 

807 if max_redirects and redirects >= max_redirects: 

808 if req._body is not None: 

809 await req._body.close() 

810 resp.close() 

811 raise TooManyRedirects( 

812 history[0].request_info, tuple(history) 

813 ) 

814 

815 # For 301 and 302, mimic IE, now changed in RFC 

816 # https://github.com/kennethreitz/requests/pull/269 

817 if (resp.status == 303 and resp.method != hdrs.METH_HEAD) or ( 

818 resp.status in (301, 302) and resp.method == hdrs.METH_POST 

819 ): 

820 method = hdrs.METH_GET 

821 data = None 

822 if headers.get(hdrs.CONTENT_LENGTH): 

823 headers.pop(hdrs.CONTENT_LENGTH) 

824 

825 r_url = resp.headers.get(hdrs.LOCATION) or resp.headers.get( 

826 hdrs.URI 

827 ) 

828 if r_url is None: 

829 # see github.com/aio-libs/aiohttp/issues/2022 

830 break 

831 else: 

832 # reading from correct redirection 

833 # response is forbidden 

834 resp.release() 

835 

836 try: 

837 parsed_redirect_url = URL( 

838 r_url, encoded=not self._requote_redirect_url 

839 ) 

840 except ValueError as e: 

841 if req._body is not None: 

842 await req._body.close() 

843 resp.close() 

844 raise InvalidUrlRedirectClientError( 

845 r_url, 

846 "Server attempted redirecting to a location that does not look like a URL", 

847 ) from e 

848 

849 scheme = parsed_redirect_url.scheme 

850 if scheme not in HTTP_AND_EMPTY_SCHEMA_SET: 

851 if req._body is not None: 

852 await req._body.close() 

853 resp.close() 

854 raise NonHttpUrlRedirectClientError(r_url) 

855 elif not scheme: 

856 parsed_redirect_url = url.join(parsed_redirect_url) 

857 

858 try: 

859 redirect_origin = parsed_redirect_url.origin() 

860 except ValueError as origin_val_err: 

861 if req._body is not None: 

862 await req._body.close() 

863 resp.close() 

864 raise InvalidUrlRedirectClientError( 

865 parsed_redirect_url, 

866 "Invalid redirect URL origin", 

867 ) from origin_val_err 

868 

869 if url.origin() != redirect_origin: 

870 auth = None 

871 headers.pop(hdrs.AUTHORIZATION, None) 

872 

873 url = parsed_redirect_url 

874 params = {} 

875 resp.release() 

876 continue 

877 

878 break 

879 

880 if req._body is not None: 

881 await req._body.close() 

882 # check response status 

883 if raise_for_status is None: 

884 raise_for_status = self._raise_for_status 

885 

886 if raise_for_status is None: 

887 pass 

888 elif callable(raise_for_status): 

889 await raise_for_status(resp) 

890 elif raise_for_status: 

891 resp.raise_for_status() 

892 

893 # register connection 

894 if handle is not None: 

895 if resp.connection is not None: 

896 resp.connection.add_callback(handle.cancel) 

897 else: 

898 handle.cancel() 

899 

900 resp._history = tuple(history) 

901 

902 for trace in traces: 

903 await trace.send_request_end( 

904 method, url.update_query(params), headers, resp 

905 ) 

906 return resp 

907 

908 except BaseException as e: 

909 # cleanup timer 

910 tm.close() 

911 if handle: 

912 handle.cancel() 

913 handle = None 

914 

915 for trace in traces: 

916 await trace.send_request_exception( 

917 method, url.update_query(params), headers, e 

918 ) 

919 raise 

920 

921 def ws_connect( 

922 self, 

923 url: StrOrURL, 

924 *, 

925 method: str = hdrs.METH_GET, 

926 protocols: Iterable[str] = (), 

927 timeout: Union[ClientWSTimeout, _SENTINEL] = sentinel, 

928 receive_timeout: Optional[float] = None, 

929 autoclose: bool = True, 

930 autoping: bool = True, 

931 heartbeat: Optional[float] = None, 

932 auth: Optional[BasicAuth] = None, 

933 origin: Optional[str] = None, 

934 params: Query = None, 

935 headers: Optional[LooseHeaders] = None, 

936 proxy: Optional[StrOrURL] = None, 

937 proxy_auth: Optional[BasicAuth] = None, 

938 ssl: Union[SSLContext, bool, Fingerprint] = True, 

939 verify_ssl: Optional[bool] = None, 

940 fingerprint: Optional[bytes] = None, 

941 ssl_context: Optional[SSLContext] = None, 

942 server_hostname: Optional[str] = None, 

943 proxy_headers: Optional[LooseHeaders] = None, 

944 compress: int = 0, 

945 max_msg_size: int = 4 * 1024 * 1024, 

946 ) -> "_WSRequestContextManager": 

947 """Initiate websocket connection.""" 

948 return _WSRequestContextManager( 

949 self._ws_connect( 

950 url, 

951 method=method, 

952 protocols=protocols, 

953 timeout=timeout, 

954 receive_timeout=receive_timeout, 

955 autoclose=autoclose, 

956 autoping=autoping, 

957 heartbeat=heartbeat, 

958 auth=auth, 

959 origin=origin, 

960 params=params, 

961 headers=headers, 

962 proxy=proxy, 

963 proxy_auth=proxy_auth, 

964 ssl=ssl, 

965 verify_ssl=verify_ssl, 

966 fingerprint=fingerprint, 

967 ssl_context=ssl_context, 

968 server_hostname=server_hostname, 

969 proxy_headers=proxy_headers, 

970 compress=compress, 

971 max_msg_size=max_msg_size, 

972 ) 

973 ) 

974 

975 async def _ws_connect( 

976 self, 

977 url: StrOrURL, 

978 *, 

979 method: str = hdrs.METH_GET, 

980 protocols: Iterable[str] = (), 

981 timeout: Union[ClientWSTimeout, _SENTINEL] = sentinel, 

982 receive_timeout: Optional[float] = None, 

983 autoclose: bool = True, 

984 autoping: bool = True, 

985 heartbeat: Optional[float] = None, 

986 auth: Optional[BasicAuth] = None, 

987 origin: Optional[str] = None, 

988 params: Query = None, 

989 headers: Optional[LooseHeaders] = None, 

990 proxy: Optional[StrOrURL] = None, 

991 proxy_auth: Optional[BasicAuth] = None, 

992 ssl: Union[SSLContext, bool, Fingerprint] = True, 

993 verify_ssl: Optional[bool] = None, 

994 fingerprint: Optional[bytes] = None, 

995 ssl_context: Optional[SSLContext] = None, 

996 server_hostname: Optional[str] = None, 

997 proxy_headers: Optional[LooseHeaders] = None, 

998 compress: int = 0, 

999 max_msg_size: int = 4 * 1024 * 1024, 

1000 ) -> ClientWebSocketResponse: 

1001 if timeout is not sentinel: 

1002 if isinstance(timeout, ClientWSTimeout): 

1003 ws_timeout = timeout 

1004 else: 

1005 warnings.warn( 

1006 "parameter 'timeout' of type 'float' " 

1007 "is deprecated, please use " 

1008 "'timeout=ClientWSTimeout(ws_close=...)'", 

1009 DeprecationWarning, 

1010 stacklevel=2, 

1011 ) 

1012 ws_timeout = ClientWSTimeout(ws_close=timeout) 

1013 else: 

1014 ws_timeout = DEFAULT_WS_CLIENT_TIMEOUT 

1015 if receive_timeout is not None: 

1016 warnings.warn( 

1017 "float parameter 'receive_timeout' " 

1018 "is deprecated, please use parameter " 

1019 "'timeout=ClientWSTimeout(ws_receive=...)'", 

1020 DeprecationWarning, 

1021 stacklevel=2, 

1022 ) 

1023 ws_timeout = attr.evolve(ws_timeout, ws_receive=receive_timeout) 

1024 

1025 if headers is None: 

1026 real_headers: CIMultiDict[str] = CIMultiDict() 

1027 else: 

1028 real_headers = CIMultiDict(headers) 

1029 

1030 default_headers = { 

1031 hdrs.UPGRADE: "websocket", 

1032 hdrs.CONNECTION: "Upgrade", 

1033 hdrs.SEC_WEBSOCKET_VERSION: "13", 

1034 } 

1035 

1036 for key, value in default_headers.items(): 

1037 real_headers.setdefault(key, value) 

1038 

1039 sec_key = base64.b64encode(os.urandom(16)) 

1040 real_headers[hdrs.SEC_WEBSOCKET_KEY] = sec_key.decode() 

1041 

1042 if protocols: 

1043 real_headers[hdrs.SEC_WEBSOCKET_PROTOCOL] = ",".join(protocols) 

1044 if origin is not None: 

1045 real_headers[hdrs.ORIGIN] = origin 

1046 if compress: 

1047 extstr = ws_ext_gen(compress=compress) 

1048 real_headers[hdrs.SEC_WEBSOCKET_EXTENSIONS] = extstr 

1049 

1050 # For the sake of backward compatibility, if user passes in None, convert it to True 

1051 if ssl is None: 

1052 warnings.warn( 

1053 "ssl=None is deprecated, please use ssl=True", 

1054 DeprecationWarning, 

1055 stacklevel=2, 

1056 ) 

1057 ssl = True 

1058 ssl = _merge_ssl_params(ssl, verify_ssl, ssl_context, fingerprint) 

1059 

1060 # send request 

1061 resp = await self.request( 

1062 method, 

1063 url, 

1064 params=params, 

1065 headers=real_headers, 

1066 read_until_eof=False, 

1067 auth=auth, 

1068 proxy=proxy, 

1069 proxy_auth=proxy_auth, 

1070 ssl=ssl, 

1071 server_hostname=server_hostname, 

1072 proxy_headers=proxy_headers, 

1073 ) 

1074 

1075 try: 

1076 # check handshake 

1077 if resp.status != 101: 

1078 raise WSServerHandshakeError( 

1079 resp.request_info, 

1080 resp.history, 

1081 message="Invalid response status", 

1082 status=resp.status, 

1083 headers=resp.headers, 

1084 ) 

1085 

1086 if resp.headers.get(hdrs.UPGRADE, "").lower() != "websocket": 

1087 raise WSServerHandshakeError( 

1088 resp.request_info, 

1089 resp.history, 

1090 message="Invalid upgrade header", 

1091 status=resp.status, 

1092 headers=resp.headers, 

1093 ) 

1094 

1095 if resp.headers.get(hdrs.CONNECTION, "").lower() != "upgrade": 

1096 raise WSServerHandshakeError( 

1097 resp.request_info, 

1098 resp.history, 

1099 message="Invalid connection header", 

1100 status=resp.status, 

1101 headers=resp.headers, 

1102 ) 

1103 

1104 # key calculation 

1105 r_key = resp.headers.get(hdrs.SEC_WEBSOCKET_ACCEPT, "") 

1106 match = base64.b64encode(hashlib.sha1(sec_key + WS_KEY).digest()).decode() 

1107 if r_key != match: 

1108 raise WSServerHandshakeError( 

1109 resp.request_info, 

1110 resp.history, 

1111 message="Invalid challenge response", 

1112 status=resp.status, 

1113 headers=resp.headers, 

1114 ) 

1115 

1116 # websocket protocol 

1117 protocol = None 

1118 if protocols and hdrs.SEC_WEBSOCKET_PROTOCOL in resp.headers: 

1119 resp_protocols = [ 

1120 proto.strip() 

1121 for proto in resp.headers[hdrs.SEC_WEBSOCKET_PROTOCOL].split(",") 

1122 ] 

1123 

1124 for proto in resp_protocols: 

1125 if proto in protocols: 

1126 protocol = proto 

1127 break 

1128 

1129 # websocket compress 

1130 notakeover = False 

1131 if compress: 

1132 compress_hdrs = resp.headers.get(hdrs.SEC_WEBSOCKET_EXTENSIONS) 

1133 if compress_hdrs: 

1134 try: 

1135 compress, notakeover = ws_ext_parse(compress_hdrs) 

1136 except WSHandshakeError as exc: 

1137 raise WSServerHandshakeError( 

1138 resp.request_info, 

1139 resp.history, 

1140 message=exc.args[0], 

1141 status=resp.status, 

1142 headers=resp.headers, 

1143 ) from exc 

1144 else: 

1145 compress = 0 

1146 notakeover = False 

1147 

1148 conn = resp.connection 

1149 assert conn is not None 

1150 conn_proto = conn.protocol 

1151 assert conn_proto is not None 

1152 

1153 # For WS connection the read_timeout must be either receive_timeout or greater 

1154 # None == no timeout, i.e. infinite timeout, so None is the max timeout possible 

1155 if ws_timeout.ws_receive is None: 

1156 # Reset regardless 

1157 conn_proto.read_timeout = None 

1158 elif conn_proto.read_timeout is not None: 

1159 conn_proto.read_timeout = max( 

1160 ws_timeout.ws_receive, conn_proto.read_timeout 

1161 ) 

1162 

1163 transport = conn.transport 

1164 assert transport is not None 

1165 reader = WebSocketDataQueue(conn_proto, 2**16, loop=self._loop) 

1166 conn_proto.set_parser(WebSocketReader(reader, max_msg_size), reader) 

1167 writer = WebSocketWriter( 

1168 conn_proto, 

1169 transport, 

1170 use_mask=True, 

1171 compress=compress, 

1172 notakeover=notakeover, 

1173 ) 

1174 except BaseException: 

1175 resp.close() 

1176 raise 

1177 else: 

1178 return self._ws_response_class( 

1179 reader, 

1180 writer, 

1181 protocol, 

1182 resp, 

1183 ws_timeout, 

1184 autoclose, 

1185 autoping, 

1186 self._loop, 

1187 heartbeat=heartbeat, 

1188 compress=compress, 

1189 client_notakeover=notakeover, 

1190 ) 

1191 

1192 def _prepare_headers(self, headers: Optional[LooseHeaders]) -> "CIMultiDict[str]": 

1193 """Add default headers and transform it to CIMultiDict""" 

1194 # Convert headers to MultiDict 

1195 result = CIMultiDict(self._default_headers) 

1196 if headers: 

1197 if not isinstance(headers, (MultiDictProxy, MultiDict)): 

1198 headers = CIMultiDict(headers) 

1199 added_names: Set[str] = set() 

1200 for key, value in headers.items(): 

1201 if key in added_names: 

1202 result.add(key, value) 

1203 else: 

1204 result[key] = value 

1205 added_names.add(key) 

1206 return result 

1207 

1208 if sys.version_info >= (3, 11) and TYPE_CHECKING: 

1209 

1210 def get( 

1211 self, 

1212 url: StrOrURL, 

1213 **kwargs: Unpack[_RequestOptions], 

1214 ) -> "_RequestContextManager": ... 

1215 

1216 def options( 

1217 self, 

1218 url: StrOrURL, 

1219 **kwargs: Unpack[_RequestOptions], 

1220 ) -> "_RequestContextManager": ... 

1221 

1222 def head( 

1223 self, 

1224 url: StrOrURL, 

1225 **kwargs: Unpack[_RequestOptions], 

1226 ) -> "_RequestContextManager": ... 

1227 

1228 def post( 

1229 self, 

1230 url: StrOrURL, 

1231 **kwargs: Unpack[_RequestOptions], 

1232 ) -> "_RequestContextManager": ... 

1233 

1234 def put( 

1235 self, 

1236 url: StrOrURL, 

1237 **kwargs: Unpack[_RequestOptions], 

1238 ) -> "_RequestContextManager": ... 

1239 

1240 def patch( 

1241 self, 

1242 url: StrOrURL, 

1243 **kwargs: Unpack[_RequestOptions], 

1244 ) -> "_RequestContextManager": ... 

1245 

1246 def delete( 

1247 self, 

1248 url: StrOrURL, 

1249 **kwargs: Unpack[_RequestOptions], 

1250 ) -> "_RequestContextManager": ... 

1251 

1252 else: 

1253 

1254 def get( 

1255 self, url: StrOrURL, *, allow_redirects: bool = True, **kwargs: Any 

1256 ) -> "_RequestContextManager": 

1257 """Perform HTTP GET request.""" 

1258 return _RequestContextManager( 

1259 self._request( 

1260 hdrs.METH_GET, url, allow_redirects=allow_redirects, **kwargs 

1261 ) 

1262 ) 

1263 

1264 def options( 

1265 self, url: StrOrURL, *, allow_redirects: bool = True, **kwargs: Any 

1266 ) -> "_RequestContextManager": 

1267 """Perform HTTP OPTIONS request.""" 

1268 return _RequestContextManager( 

1269 self._request( 

1270 hdrs.METH_OPTIONS, url, allow_redirects=allow_redirects, **kwargs 

1271 ) 

1272 ) 

1273 

1274 def head( 

1275 self, url: StrOrURL, *, allow_redirects: bool = False, **kwargs: Any 

1276 ) -> "_RequestContextManager": 

1277 """Perform HTTP HEAD request.""" 

1278 return _RequestContextManager( 

1279 self._request( 

1280 hdrs.METH_HEAD, url, allow_redirects=allow_redirects, **kwargs 

1281 ) 

1282 ) 

1283 

1284 def post( 

1285 self, url: StrOrURL, *, data: Any = None, **kwargs: Any 

1286 ) -> "_RequestContextManager": 

1287 """Perform HTTP POST request.""" 

1288 return _RequestContextManager( 

1289 self._request(hdrs.METH_POST, url, data=data, **kwargs) 

1290 ) 

1291 

1292 def put( 

1293 self, url: StrOrURL, *, data: Any = None, **kwargs: Any 

1294 ) -> "_RequestContextManager": 

1295 """Perform HTTP PUT request.""" 

1296 return _RequestContextManager( 

1297 self._request(hdrs.METH_PUT, url, data=data, **kwargs) 

1298 ) 

1299 

1300 def patch( 

1301 self, url: StrOrURL, *, data: Any = None, **kwargs: Any 

1302 ) -> "_RequestContextManager": 

1303 """Perform HTTP PATCH request.""" 

1304 return _RequestContextManager( 

1305 self._request(hdrs.METH_PATCH, url, data=data, **kwargs) 

1306 ) 

1307 

1308 def delete(self, url: StrOrURL, **kwargs: Any) -> "_RequestContextManager": 

1309 """Perform HTTP DELETE request.""" 

1310 return _RequestContextManager( 

1311 self._request(hdrs.METH_DELETE, url, **kwargs) 

1312 ) 

1313 

1314 async def close(self) -> None: 

1315 """Close underlying connector. 

1316 

1317 Release all acquired resources. 

1318 """ 

1319 if not self.closed: 

1320 if self._connector is not None and self._connector_owner: 

1321 await self._connector.close() 

1322 self._connector = None 

1323 

1324 @property 

1325 def closed(self) -> bool: 

1326 """Is client session closed. 

1327 

1328 A readonly property. 

1329 """ 

1330 return self._connector is None or self._connector.closed 

1331 

1332 @property 

1333 def connector(self) -> Optional[BaseConnector]: 

1334 """Connector instance used for the session.""" 

1335 return self._connector 

1336 

1337 @property 

1338 def cookie_jar(self) -> AbstractCookieJar: 

1339 """The session cookies.""" 

1340 return self._cookie_jar 

1341 

1342 @property 

1343 def version(self) -> Tuple[int, int]: 

1344 """The session HTTP protocol version.""" 

1345 return self._version 

1346 

1347 @property 

1348 def requote_redirect_url(self) -> bool: 

1349 """Do URL requoting on redirection handling.""" 

1350 return self._requote_redirect_url 

1351 

1352 @requote_redirect_url.setter 

1353 def requote_redirect_url(self, val: bool) -> None: 

1354 """Do URL requoting on redirection handling.""" 

1355 warnings.warn( 

1356 "session.requote_redirect_url modification is deprecated #2778", 

1357 DeprecationWarning, 

1358 stacklevel=2, 

1359 ) 

1360 self._requote_redirect_url = val 

1361 

1362 @property 

1363 def loop(self) -> asyncio.AbstractEventLoop: 

1364 """Session's loop.""" 

1365 warnings.warn( 

1366 "client.loop property is deprecated", DeprecationWarning, stacklevel=2 

1367 ) 

1368 return self._loop 

1369 

1370 @property 

1371 def timeout(self) -> ClientTimeout: 

1372 """Timeout for the session.""" 

1373 return self._timeout 

1374 

1375 @property 

1376 def headers(self) -> "CIMultiDict[str]": 

1377 """The default headers of the client session.""" 

1378 return self._default_headers 

1379 

1380 @property 

1381 def skip_auto_headers(self) -> FrozenSet[istr]: 

1382 """Headers for which autogeneration should be skipped""" 

1383 return self._skip_auto_headers 

1384 

1385 @property 

1386 def auth(self) -> Optional[BasicAuth]: 

1387 """An object that represents HTTP Basic Authorization""" 

1388 return self._default_auth 

1389 

1390 @property 

1391 def json_serialize(self) -> JSONEncoder: 

1392 """Json serializer callable""" 

1393 return self._json_serialize 

1394 

1395 @property 

1396 def connector_owner(self) -> bool: 

1397 """Should connector be closed on session closing""" 

1398 return self._connector_owner 

1399 

1400 @property 

1401 def raise_for_status( 

1402 self, 

1403 ) -> Union[bool, Callable[[ClientResponse], Awaitable[None]]]: 

1404 """Should `ClientResponse.raise_for_status()` be called for each response.""" 

1405 return self._raise_for_status 

1406 

1407 @property 

1408 def auto_decompress(self) -> bool: 

1409 """Should the body response be automatically decompressed.""" 

1410 return self._auto_decompress 

1411 

1412 @property 

1413 def trust_env(self) -> bool: 

1414 """ 

1415 Should proxies information from environment or netrc be trusted. 

1416 

1417 Information is from HTTP_PROXY / HTTPS_PROXY environment variables 

1418 or ~/.netrc file if present. 

1419 """ 

1420 return self._trust_env 

1421 

1422 @property 

1423 def trace_configs(self) -> List[TraceConfig]: 

1424 """A list of TraceConfig instances used for client tracing""" 

1425 return self._trace_configs 

1426 

1427 def detach(self) -> None: 

1428 """Detach connector from session without closing the former. 

1429 

1430 Session is switched to closed state anyway. 

1431 """ 

1432 self._connector = None 

1433 

1434 def __enter__(self) -> None: 

1435 raise TypeError("Use async with instead") 

1436 

1437 def __exit__( 

1438 self, 

1439 exc_type: Optional[Type[BaseException]], 

1440 exc_val: Optional[BaseException], 

1441 exc_tb: Optional[TracebackType], 

1442 ) -> None: 

1443 # __exit__ should exist in pair with __enter__ but never executed 

1444 pass # pragma: no cover 

1445 

1446 async def __aenter__(self) -> "ClientSession": 

1447 return self 

1448 

1449 async def __aexit__( 

1450 self, 

1451 exc_type: Optional[Type[BaseException]], 

1452 exc_val: Optional[BaseException], 

1453 exc_tb: Optional[TracebackType], 

1454 ) -> None: 

1455 await self.close() 

1456 

1457 

1458class _BaseRequestContextManager(Coroutine[Any, Any, _RetType], Generic[_RetType]): 

1459 

1460 __slots__ = ("_coro", "_resp") 

1461 

1462 def __init__(self, coro: Coroutine["asyncio.Future[Any]", None, _RetType]) -> None: 

1463 self._coro: Coroutine["asyncio.Future[Any]", None, _RetType] = coro 

1464 

1465 def send(self, arg: None) -> "asyncio.Future[Any]": 

1466 return self._coro.send(arg) 

1467 

1468 def throw(self, *args: Any, **kwargs: Any) -> "asyncio.Future[Any]": 

1469 return self._coro.throw(*args, **kwargs) 

1470 

1471 def close(self) -> None: 

1472 return self._coro.close() 

1473 

1474 def __await__(self) -> Generator[Any, None, _RetType]: 

1475 ret = self._coro.__await__() 

1476 return ret 

1477 

1478 def __iter__(self) -> Generator[Any, None, _RetType]: 

1479 return self.__await__() 

1480 

1481 async def __aenter__(self) -> _RetType: 

1482 self._resp: _RetType = await self._coro 

1483 return await self._resp.__aenter__() 

1484 

1485 async def __aexit__( 

1486 self, 

1487 exc_type: Optional[Type[BaseException]], 

1488 exc: Optional[BaseException], 

1489 tb: Optional[TracebackType], 

1490 ) -> None: 

1491 await self._resp.__aexit__(exc_type, exc, tb) 

1492 

1493 

1494_RequestContextManager = _BaseRequestContextManager[ClientResponse] 

1495_WSRequestContextManager = _BaseRequestContextManager[ClientWebSocketResponse] 

1496 

1497 

1498class _SessionRequestContextManager: 

1499 

1500 __slots__ = ("_coro", "_resp", "_session") 

1501 

1502 def __init__( 

1503 self, 

1504 coro: Coroutine["asyncio.Future[Any]", None, ClientResponse], 

1505 session: ClientSession, 

1506 ) -> None: 

1507 self._coro = coro 

1508 self._resp: Optional[ClientResponse] = None 

1509 self._session = session 

1510 

1511 async def __aenter__(self) -> ClientResponse: 

1512 try: 

1513 self._resp = await self._coro 

1514 except BaseException: 

1515 await self._session.close() 

1516 raise 

1517 else: 

1518 return self._resp 

1519 

1520 async def __aexit__( 

1521 self, 

1522 exc_type: Optional[Type[BaseException]], 

1523 exc: Optional[BaseException], 

1524 tb: Optional[TracebackType], 

1525 ) -> None: 

1526 assert self._resp is not None 

1527 self._resp.close() 

1528 await self._session.close() 

1529 

1530 

1531if sys.version_info >= (3, 11) and TYPE_CHECKING: 

1532 

1533 def request( 

1534 method: str, 

1535 url: StrOrURL, 

1536 *, 

1537 version: HttpVersion = http.HttpVersion11, 

1538 connector: Optional[BaseConnector] = None, 

1539 loop: Optional[asyncio.AbstractEventLoop] = None, 

1540 **kwargs: Unpack[_RequestOptions], 

1541 ) -> _SessionRequestContextManager: ... 

1542 

1543else: 

1544 

1545 def request( 

1546 method: str, 

1547 url: StrOrURL, 

1548 *, 

1549 version: HttpVersion = http.HttpVersion11, 

1550 connector: Optional[BaseConnector] = None, 

1551 loop: Optional[asyncio.AbstractEventLoop] = None, 

1552 **kwargs: Any, 

1553 ) -> _SessionRequestContextManager: 

1554 """Constructs and sends a request. 

1555 

1556 Returns response object. 

1557 method - HTTP method 

1558 url - request url 

1559 params - (optional) Dictionary or bytes to be sent in the query 

1560 string of the new request 

1561 data - (optional) Dictionary, bytes, or file-like object to 

1562 send in the body of the request 

1563 json - (optional) Any json compatible python object 

1564 headers - (optional) Dictionary of HTTP Headers to send with 

1565 the request 

1566 cookies - (optional) Dict object to send with the request 

1567 auth - (optional) BasicAuth named tuple represent HTTP Basic Auth 

1568 auth - aiohttp.helpers.BasicAuth 

1569 allow_redirects - (optional) If set to False, do not follow 

1570 redirects 

1571 version - Request HTTP version. 

1572 compress - Set to True if request has to be compressed 

1573 with deflate encoding. 

1574 chunked - Set to chunk size for chunked transfer encoding. 

1575 expect100 - Expect 100-continue response from server. 

1576 connector - BaseConnector sub-class instance to support 

1577 connection pooling. 

1578 read_until_eof - Read response until eof if response 

1579 does not have Content-Length header. 

1580 loop - Optional event loop. 

1581 timeout - Optional ClientTimeout settings structure, 5min 

1582 total timeout by default. 

1583 Usage:: 

1584 >>> import aiohttp 

1585 >>> async with aiohttp.request('GET', 'http://python.org/') as resp: 

1586 ... print(resp) 

1587 ... data = await resp.read() 

1588 <ClientResponse(https://www.python.org/) [200 OK]> 

1589 """ 

1590 connector_owner = False 

1591 if connector is None: 

1592 connector_owner = True 

1593 connector = TCPConnector(loop=loop, force_close=True) 

1594 

1595 session = ClientSession( 

1596 loop=loop, 

1597 cookies=kwargs.pop("cookies", None), 

1598 version=version, 

1599 timeout=kwargs.pop("timeout", sentinel), 

1600 connector=connector, 

1601 connector_owner=connector_owner, 

1602 ) 

1603 

1604 return _SessionRequestContextManager( 

1605 session._request(method, url, **kwargs), 

1606 session, 

1607 )