about summary refs log tree commit diff
path: root/.venv/lib/python3.12/site-packages/aiohttp/client.py
diff options
context:
space:
mode:
authorS. Solomon Darnell2025-03-28 21:52:21 -0500
committerS. Solomon Darnell2025-03-28 21:52:21 -0500
commit4a52a71956a8d46fcb7294ac71734504bb09bcc2 (patch)
treeee3dc5af3b6313e921cd920906356f5d4febc4ed /.venv/lib/python3.12/site-packages/aiohttp/client.py
parentcc961e04ba734dd72309fb548a2f97d67d578813 (diff)
downloadgn-ai-4a52a71956a8d46fcb7294ac71734504bb09bcc2.tar.gz
two version of R2R are here HEAD master
Diffstat (limited to '.venv/lib/python3.12/site-packages/aiohttp/client.py')
-rw-r--r--.venv/lib/python3.12/site-packages/aiohttp/client.py1550
1 files changed, 1550 insertions, 0 deletions
diff --git a/.venv/lib/python3.12/site-packages/aiohttp/client.py b/.venv/lib/python3.12/site-packages/aiohttp/client.py
new file mode 100644
index 00000000..7c788e82
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/aiohttp/client.py
@@ -0,0 +1,1550 @@
+"""HTTP Client for asyncio."""
+
+import asyncio
+import base64
+import hashlib
+import json
+import os
+import sys
+import traceback
+import warnings
+from contextlib import suppress
+from types import TracebackType
+from typing import (
+    TYPE_CHECKING,
+    Any,
+    Awaitable,
+    Callable,
+    Coroutine,
+    Final,
+    FrozenSet,
+    Generator,
+    Generic,
+    Iterable,
+    List,
+    Mapping,
+    Optional,
+    Set,
+    Tuple,
+    Type,
+    TypedDict,
+    TypeVar,
+    Union,
+)
+
+import attr
+from multidict import CIMultiDict, MultiDict, MultiDictProxy, istr
+from yarl import URL
+
+from . import hdrs, http, payload
+from ._websocket.reader import WebSocketDataQueue
+from .abc import AbstractCookieJar
+from .client_exceptions import (
+    ClientConnectionError,
+    ClientConnectionResetError,
+    ClientConnectorCertificateError,
+    ClientConnectorDNSError,
+    ClientConnectorError,
+    ClientConnectorSSLError,
+    ClientError,
+    ClientHttpProxyError,
+    ClientOSError,
+    ClientPayloadError,
+    ClientProxyConnectionError,
+    ClientResponseError,
+    ClientSSLError,
+    ConnectionTimeoutError,
+    ContentTypeError,
+    InvalidURL,
+    InvalidUrlClientError,
+    InvalidUrlRedirectClientError,
+    NonHttpUrlClientError,
+    NonHttpUrlRedirectClientError,
+    RedirectClientError,
+    ServerConnectionError,
+    ServerDisconnectedError,
+    ServerFingerprintMismatch,
+    ServerTimeoutError,
+    SocketTimeoutError,
+    TooManyRedirects,
+    WSMessageTypeError,
+    WSServerHandshakeError,
+)
+from .client_reqrep import (
+    ClientRequest as ClientRequest,
+    ClientResponse as ClientResponse,
+    Fingerprint as Fingerprint,
+    RequestInfo as RequestInfo,
+    _merge_ssl_params,
+)
+from .client_ws import (
+    DEFAULT_WS_CLIENT_TIMEOUT,
+    ClientWebSocketResponse as ClientWebSocketResponse,
+    ClientWSTimeout as ClientWSTimeout,
+)
+from .connector import (
+    HTTP_AND_EMPTY_SCHEMA_SET,
+    BaseConnector as BaseConnector,
+    NamedPipeConnector as NamedPipeConnector,
+    TCPConnector as TCPConnector,
+    UnixConnector as UnixConnector,
+)
+from .cookiejar import CookieJar
+from .helpers import (
+    _SENTINEL,
+    DEBUG,
+    EMPTY_BODY_METHODS,
+    BasicAuth,
+    TimeoutHandle,
+    get_env_proxy_for_url,
+    sentinel,
+    strip_auth_from_url,
+)
+from .http import WS_KEY, HttpVersion, WebSocketReader, WebSocketWriter
+from .http_websocket import WSHandshakeError, ws_ext_gen, ws_ext_parse
+from .tracing import Trace, TraceConfig
+from .typedefs import JSONEncoder, LooseCookies, LooseHeaders, Query, StrOrURL
+
+__all__ = (
+    # client_exceptions
+    "ClientConnectionError",
+    "ClientConnectionResetError",
+    "ClientConnectorCertificateError",
+    "ClientConnectorDNSError",
+    "ClientConnectorError",
+    "ClientConnectorSSLError",
+    "ClientError",
+    "ClientHttpProxyError",
+    "ClientOSError",
+    "ClientPayloadError",
+    "ClientProxyConnectionError",
+    "ClientResponseError",
+    "ClientSSLError",
+    "ConnectionTimeoutError",
+    "ContentTypeError",
+    "InvalidURL",
+    "InvalidUrlClientError",
+    "RedirectClientError",
+    "NonHttpUrlClientError",
+    "InvalidUrlRedirectClientError",
+    "NonHttpUrlRedirectClientError",
+    "ServerConnectionError",
+    "ServerDisconnectedError",
+    "ServerFingerprintMismatch",
+    "ServerTimeoutError",
+    "SocketTimeoutError",
+    "TooManyRedirects",
+    "WSServerHandshakeError",
+    # client_reqrep
+    "ClientRequest",
+    "ClientResponse",
+    "Fingerprint",
+    "RequestInfo",
+    # connector
+    "BaseConnector",
+    "TCPConnector",
+    "UnixConnector",
+    "NamedPipeConnector",
+    # client_ws
+    "ClientWebSocketResponse",
+    # client
+    "ClientSession",
+    "ClientTimeout",
+    "ClientWSTimeout",
+    "request",
+    "WSMessageTypeError",
+)
+
+
+if TYPE_CHECKING:
+    from ssl import SSLContext
+else:
+    SSLContext = None
+
+if sys.version_info >= (3, 11) and TYPE_CHECKING:
+    from typing import Unpack
+
+
+class _RequestOptions(TypedDict, total=False):
+    params: Query
+    data: Any
+    json: Any
+    cookies: Union[LooseCookies, None]
+    headers: Union[LooseHeaders, None]
+    skip_auto_headers: Union[Iterable[str], None]
+    auth: Union[BasicAuth, None]
+    allow_redirects: bool
+    max_redirects: int
+    compress: Union[str, bool, None]
+    chunked: Union[bool, None]
+    expect100: bool
+    raise_for_status: Union[None, bool, Callable[[ClientResponse], Awaitable[None]]]
+    read_until_eof: bool
+    proxy: Union[StrOrURL, None]
+    proxy_auth: Union[BasicAuth, None]
+    timeout: "Union[ClientTimeout, _SENTINEL, None]"
+    ssl: Union[SSLContext, bool, Fingerprint]
+    server_hostname: Union[str, None]
+    proxy_headers: Union[LooseHeaders, None]
+    trace_request_ctx: Union[Mapping[str, Any], None]
+    read_bufsize: Union[int, None]
+    auto_decompress: Union[bool, None]
+    max_line_size: Union[int, None]
+    max_field_size: Union[int, None]
+
+
+@attr.s(auto_attribs=True, frozen=True, slots=True)
+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 http://www.attrs.org/en/stable/api.html#attr.evolve
+    # to overwrite the defaults
+
+
+# 5 Minute default read timeout
+DEFAULT_TIMEOUT: Final[ClientTimeout] = ClientTimeout(total=5 * 60, sock_connect=30)
+
+# https://www.rfc-editor.org/rfc/rfc9110#section-9.2.2
+IDEMPOTENT_METHODS = frozenset({"GET", "HEAD", "OPTIONS", "TRACE", "PUT", "DELETE"})
+
+_RetType = TypeVar("_RetType", ClientResponse, ClientWebSocketResponse)
+_CharsetResolver = Callable[[ClientResponse, bytes], str]
+
+
+class ClientSession:
+    """First-class interface for making HTTP requests."""
+
+    ATTRS = frozenset(
+        [
+            "_base_url",
+            "_base_url_origin",
+            "_source_traceback",
+            "_connector",
+            "_loop",
+            "_cookie_jar",
+            "_connector_owner",
+            "_default_auth",
+            "_version",
+            "_json_serialize",
+            "_requote_redirect_url",
+            "_timeout",
+            "_raise_for_status",
+            "_auto_decompress",
+            "_trust_env",
+            "_default_headers",
+            "_skip_auto_headers",
+            "_request_class",
+            "_response_class",
+            "_ws_response_class",
+            "_trace_configs",
+            "_read_bufsize",
+            "_max_line_size",
+            "_max_field_size",
+            "_resolve_charset",
+            "_default_proxy",
+            "_default_proxy_auth",
+            "_retry_connection",
+            "requote_redirect_url",
+        ]
+    )
+
+    _source_traceback: Optional[traceback.StackSummary] = None
+    _connector: Optional[BaseConnector] = None
+
+    def __init__(
+        self,
+        base_url: Optional[StrOrURL] = None,
+        *,
+        connector: Optional[BaseConnector] = None,
+        loop: Optional[asyncio.AbstractEventLoop] = None,
+        cookies: Optional[LooseCookies] = None,
+        headers: Optional[LooseHeaders] = None,
+        proxy: Optional[StrOrURL] = None,
+        proxy_auth: Optional[BasicAuth] = None,
+        skip_auto_headers: Optional[Iterable[str]] = None,
+        auth: Optional[BasicAuth] = None,
+        json_serialize: JSONEncoder = json.dumps,
+        request_class: Type[ClientRequest] = ClientRequest,
+        response_class: Type[ClientResponse] = ClientResponse,
+        ws_response_class: Type[ClientWebSocketResponse] = ClientWebSocketResponse,
+        version: HttpVersion = http.HttpVersion11,
+        cookie_jar: Optional[AbstractCookieJar] = None,
+        connector_owner: bool = True,
+        raise_for_status: Union[
+            bool, Callable[[ClientResponse], Awaitable[None]]
+        ] = False,
+        read_timeout: Union[float, _SENTINEL] = sentinel,
+        conn_timeout: Optional[float] = None,
+        timeout: Union[object, ClientTimeout] = sentinel,
+        auto_decompress: bool = True,
+        trust_env: bool = False,
+        requote_redirect_url: bool = True,
+        trace_configs: Optional[List[TraceConfig]] = None,
+        read_bufsize: int = 2**16,
+        max_line_size: int = 8190,
+        max_field_size: int = 8190,
+        fallback_charset_resolver: _CharsetResolver = lambda r, b: "utf-8",
+    ) -> None:
+        # We initialise _connector to None immediately, as it's referenced in __del__()
+        # and could cause issues if an exception occurs during initialisation.
+        self._connector: Optional[BaseConnector] = None
+
+        if loop is None:
+            if connector is not None:
+                loop = connector._loop
+
+        loop = loop or asyncio.get_running_loop()
+
+        if base_url is None or isinstance(base_url, URL):
+            self._base_url: Optional[URL] = base_url
+            self._base_url_origin = None if base_url is None else base_url.origin()
+        else:
+            self._base_url = URL(base_url)
+            self._base_url_origin = self._base_url.origin()
+            assert self._base_url.absolute, "Only absolute URLs are supported"
+        if self._base_url is not None and not self._base_url.path.endswith("/"):
+            raise ValueError("base_url must have a trailing '/'")
+
+        if timeout is sentinel or timeout is None:
+            self._timeout = DEFAULT_TIMEOUT
+            if read_timeout is not sentinel:
+                warnings.warn(
+                    "read_timeout is deprecated, use timeout argument instead",
+                    DeprecationWarning,
+                    stacklevel=2,
+                )
+                self._timeout = attr.evolve(self._timeout, total=read_timeout)
+            if conn_timeout is not None:
+                self._timeout = attr.evolve(self._timeout, connect=conn_timeout)
+                warnings.warn(
+                    "conn_timeout is deprecated, use timeout argument instead",
+                    DeprecationWarning,
+                    stacklevel=2,
+                )
+        else:
+            if not isinstance(timeout, ClientTimeout):
+                raise ValueError(
+                    f"timeout parameter cannot be of {type(timeout)} type, "
+                    "please use 'timeout=ClientTimeout(...)'",
+                )
+            self._timeout = timeout
+            if read_timeout is not sentinel:
+                raise ValueError(
+                    "read_timeout and timeout parameters "
+                    "conflict, please setup "
+                    "timeout.read"
+                )
+            if conn_timeout is not None:
+                raise ValueError(
+                    "conn_timeout and timeout parameters "
+                    "conflict, please setup "
+                    "timeout.connect"
+                )
+
+        if connector is None:
+            connector = TCPConnector(loop=loop)
+
+        if connector._loop is not loop:
+            raise RuntimeError("Session and connector has to use same event loop")
+
+        self._loop = loop
+
+        if loop.get_debug():
+            self._source_traceback = traceback.extract_stack(sys._getframe(1))
+
+        if cookie_jar is None:
+            cookie_jar = CookieJar(loop=loop)
+        self._cookie_jar = cookie_jar
+
+        if cookies:
+            self._cookie_jar.update_cookies(cookies)
+
+        self._connector = connector
+        self._connector_owner = connector_owner
+        self._default_auth = auth
+        self._version = version
+        self._json_serialize = json_serialize
+        self._raise_for_status = raise_for_status
+        self._auto_decompress = auto_decompress
+        self._trust_env = trust_env
+        self._requote_redirect_url = requote_redirect_url
+        self._read_bufsize = read_bufsize
+        self._max_line_size = max_line_size
+        self._max_field_size = max_field_size
+
+        # Convert to list of tuples
+        if headers:
+            real_headers: CIMultiDict[str] = CIMultiDict(headers)
+        else:
+            real_headers = CIMultiDict()
+        self._default_headers: CIMultiDict[str] = real_headers
+        if skip_auto_headers is not None:
+            self._skip_auto_headers = frozenset(istr(i) for i in skip_auto_headers)
+        else:
+            self._skip_auto_headers = frozenset()
+
+        self._request_class = request_class
+        self._response_class = response_class
+        self._ws_response_class = ws_response_class
+
+        self._trace_configs = trace_configs or []
+        for trace_config in self._trace_configs:
+            trace_config.freeze()
+
+        self._resolve_charset = fallback_charset_resolver
+
+        self._default_proxy = proxy
+        self._default_proxy_auth = proxy_auth
+        self._retry_connection: bool = True
+
+    def __init_subclass__(cls: Type["ClientSession"]) -> None:
+        warnings.warn(
+            "Inheritance class {} from ClientSession "
+            "is discouraged".format(cls.__name__),
+            DeprecationWarning,
+            stacklevel=2,
+        )
+
+    if DEBUG:
+
+        def __setattr__(self, name: str, val: Any) -> None:
+            if name not in self.ATTRS:
+                warnings.warn(
+                    "Setting custom ClientSession.{} attribute "
+                    "is discouraged".format(name),
+                    DeprecationWarning,
+                    stacklevel=2,
+                )
+            super().__setattr__(name, val)
+
+    def __del__(self, _warnings: Any = warnings) -> None:
+        if not self.closed:
+            kwargs = {"source": self}
+            _warnings.warn(
+                f"Unclosed client session {self!r}", ResourceWarning, **kwargs
+            )
+            context = {"client_session": self, "message": "Unclosed client session"}
+            if self._source_traceback is not None:
+                context["source_traceback"] = self._source_traceback
+            self._loop.call_exception_handler(context)
+
+    if sys.version_info >= (3, 11) and TYPE_CHECKING:
+
+        def request(
+            self,
+            method: str,
+            url: StrOrURL,
+            **kwargs: Unpack[_RequestOptions],
+        ) -> "_RequestContextManager": ...
+
+    else:
+
+        def request(
+            self, method: str, url: StrOrURL, **kwargs: Any
+        ) -> "_RequestContextManager":
+            """Perform HTTP request."""
+            return _RequestContextManager(self._request(method, url, **kwargs))
+
+    def _build_url(self, str_or_url: StrOrURL) -> URL:
+        url = URL(str_or_url)
+        if self._base_url is None:
+            return url
+        else:
+            assert not url.absolute
+            return self._base_url.join(url)
+
+    async def _request(
+        self,
+        method: str,
+        str_or_url: StrOrURL,
+        *,
+        params: Query = None,
+        data: Any = None,
+        json: Any = None,
+        cookies: Optional[LooseCookies] = None,
+        headers: Optional[LooseHeaders] = None,
+        skip_auto_headers: Optional[Iterable[str]] = None,
+        auth: Optional[BasicAuth] = None,
+        allow_redirects: bool = True,
+        max_redirects: int = 10,
+        compress: Union[str, bool, None] = None,
+        chunked: Optional[bool] = None,
+        expect100: bool = False,
+        raise_for_status: Union[
+            None, bool, Callable[[ClientResponse], Awaitable[None]]
+        ] = None,
+        read_until_eof: bool = True,
+        proxy: Optional[StrOrURL] = None,
+        proxy_auth: Optional[BasicAuth] = None,
+        timeout: Union[ClientTimeout, _SENTINEL] = sentinel,
+        verify_ssl: Optional[bool] = None,
+        fingerprint: Optional[bytes] = None,
+        ssl_context: Optional[SSLContext] = None,
+        ssl: Union[SSLContext, bool, Fingerprint] = True,
+        server_hostname: Optional[str] = None,
+        proxy_headers: Optional[LooseHeaders] = None,
+        trace_request_ctx: Optional[Mapping[str, Any]] = None,
+        read_bufsize: Optional[int] = None,
+        auto_decompress: Optional[bool] = None,
+        max_line_size: Optional[int] = None,
+        max_field_size: Optional[int] = None,
+    ) -> ClientResponse:
+
+        # NOTE: timeout clamps existing connect and read timeouts.  We cannot
+        # set the default to None because we need to detect if the user wants
+        # to use the existing timeouts by setting timeout to None.
+
+        if self.closed:
+            raise RuntimeError("Session is closed")
+
+        ssl = _merge_ssl_params(ssl, verify_ssl, ssl_context, fingerprint)
+
+        if data is not None and json is not None:
+            raise ValueError(
+                "data and json parameters can not be used at the same time"
+            )
+        elif json is not None:
+            data = payload.JsonPayload(json, dumps=self._json_serialize)
+
+        if not isinstance(chunked, bool) and chunked is not None:
+            warnings.warn("Chunk size is deprecated #1615", DeprecationWarning)
+
+        redirects = 0
+        history: List[ClientResponse] = []
+        version = self._version
+        params = params or {}
+
+        # Merge with default headers and transform to CIMultiDict
+        headers = self._prepare_headers(headers)
+
+        try:
+            url = self._build_url(str_or_url)
+        except ValueError as e:
+            raise InvalidUrlClientError(str_or_url) from e
+
+        assert self._connector is not None
+        if url.scheme not in self._connector.allowed_protocol_schema_set:
+            raise NonHttpUrlClientError(url)
+
+        skip_headers: Optional[Iterable[istr]]
+        if skip_auto_headers is not None:
+            skip_headers = {
+                istr(i) for i in skip_auto_headers
+            } | self._skip_auto_headers
+        elif self._skip_auto_headers:
+            skip_headers = self._skip_auto_headers
+        else:
+            skip_headers = None
+
+        if proxy is None:
+            proxy = self._default_proxy
+        if proxy_auth is None:
+            proxy_auth = self._default_proxy_auth
+
+        if proxy is None:
+            proxy_headers = None
+        else:
+            proxy_headers = self._prepare_headers(proxy_headers)
+            try:
+                proxy = URL(proxy)
+            except ValueError as e:
+                raise InvalidURL(proxy) from e
+
+        if timeout is sentinel:
+            real_timeout: ClientTimeout = self._timeout
+        else:
+            if not isinstance(timeout, ClientTimeout):
+                real_timeout = ClientTimeout(total=timeout)
+            else:
+                real_timeout = timeout
+        # timeout is cumulative for all request operations
+        # (request, redirects, responses, data consuming)
+        tm = TimeoutHandle(
+            self._loop, real_timeout.total, ceil_threshold=real_timeout.ceil_threshold
+        )
+        handle = tm.start()
+
+        if read_bufsize is None:
+            read_bufsize = self._read_bufsize
+
+        if auto_decompress is None:
+            auto_decompress = self._auto_decompress
+
+        if max_line_size is None:
+            max_line_size = self._max_line_size
+
+        if max_field_size is None:
+            max_field_size = self._max_field_size
+
+        traces = [
+            Trace(
+                self,
+                trace_config,
+                trace_config.trace_config_ctx(trace_request_ctx=trace_request_ctx),
+            )
+            for trace_config in self._trace_configs
+        ]
+
+        for trace in traces:
+            await trace.send_request_start(method, url.update_query(params), headers)
+
+        timer = tm.timer()
+        try:
+            with timer:
+                # https://www.rfc-editor.org/rfc/rfc9112.html#name-retrying-requests
+                retry_persistent_connection = (
+                    self._retry_connection and method in IDEMPOTENT_METHODS
+                )
+                while True:
+                    url, auth_from_url = strip_auth_from_url(url)
+                    if not url.raw_host:
+                        # NOTE: Bail early, otherwise, causes `InvalidURL` through
+                        # NOTE: `self._request_class()` below.
+                        err_exc_cls = (
+                            InvalidUrlRedirectClientError
+                            if redirects
+                            else InvalidUrlClientError
+                        )
+                        raise err_exc_cls(url)
+                    # If `auth` was passed for an already authenticated URL,
+                    # disallow only if this is the initial URL; this is to avoid issues
+                    # with sketchy redirects that are not the caller's responsibility
+                    if not history and (auth and auth_from_url):
+                        raise ValueError(
+                            "Cannot combine AUTH argument with "
+                            "credentials encoded in URL"
+                        )
+
+                    # Override the auth with the one from the URL only if we
+                    # have no auth, or if we got an auth from a redirect URL
+                    if auth is None or (history and auth_from_url is not None):
+                        auth = auth_from_url
+
+                    if (
+                        auth is None
+                        and self._default_auth
+                        and (
+                            not self._base_url or self._base_url_origin == url.origin()
+                        )
+                    ):
+                        auth = self._default_auth
+                    # It would be confusing if we support explicit
+                    # Authorization header with auth argument
+                    if (
+                        headers is not None
+                        and auth is not None
+                        and hdrs.AUTHORIZATION in headers
+                    ):
+                        raise ValueError(
+                            "Cannot combine AUTHORIZATION header "
+                            "with AUTH argument or credentials "
+                            "encoded in URL"
+                        )
+
+                    all_cookies = self._cookie_jar.filter_cookies(url)
+
+                    if cookies is not None:
+                        tmp_cookie_jar = CookieJar(
+                            quote_cookie=self._cookie_jar.quote_cookie
+                        )
+                        tmp_cookie_jar.update_cookies(cookies)
+                        req_cookies = tmp_cookie_jar.filter_cookies(url)
+                        if req_cookies:
+                            all_cookies.load(req_cookies)
+
+                    if proxy is not None:
+                        proxy = URL(proxy)
+                    elif self._trust_env:
+                        with suppress(LookupError):
+                            proxy, proxy_auth = get_env_proxy_for_url(url)
+
+                    req = self._request_class(
+                        method,
+                        url,
+                        params=params,
+                        headers=headers,
+                        skip_auto_headers=skip_headers,
+                        data=data,
+                        cookies=all_cookies,
+                        auth=auth,
+                        version=version,
+                        compress=compress,
+                        chunked=chunked,
+                        expect100=expect100,
+                        loop=self._loop,
+                        response_class=self._response_class,
+                        proxy=proxy,
+                        proxy_auth=proxy_auth,
+                        timer=timer,
+                        session=self,
+                        ssl=ssl if ssl is not None else True,
+                        server_hostname=server_hostname,
+                        proxy_headers=proxy_headers,
+                        traces=traces,
+                        trust_env=self.trust_env,
+                    )
+
+                    # connection timeout
+                    try:
+                        conn = await self._connector.connect(
+                            req, traces=traces, timeout=real_timeout
+                        )
+                    except asyncio.TimeoutError as exc:
+                        raise ConnectionTimeoutError(
+                            f"Connection timeout to host {url}"
+                        ) from exc
+
+                    assert conn.transport is not None
+
+                    assert conn.protocol is not None
+                    conn.protocol.set_response_params(
+                        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,
+                    )
+
+                    try:
+                        try:
+                            resp = await req.send(conn)
+                            try:
+                                await resp.start(conn)
+                            except BaseException:
+                                resp.close()
+                                raise
+                        except BaseException:
+                            conn.close()
+                            raise
+                    except (ClientOSError, ServerDisconnectedError):
+                        if retry_persistent_connection:
+                            retry_persistent_connection = False
+                            continue
+                        raise
+                    except ClientError:
+                        raise
+                    except OSError as exc:
+                        if exc.errno is None and isinstance(exc, asyncio.TimeoutError):
+                            raise
+                        raise ClientOSError(*exc.args) from exc
+
+                    if cookies := resp._cookies:
+                        self._cookie_jar.update_cookies(cookies, resp.url)
+
+                    # redirects
+                    if resp.status in (301, 302, 303, 307, 308) and allow_redirects:
+
+                        for trace in traces:
+                            await trace.send_request_redirect(
+                                method, url.update_query(params), headers, resp
+                            )
+
+                        redirects += 1
+                        history.append(resp)
+                        if max_redirects and redirects >= max_redirects:
+                            resp.close()
+                            raise TooManyRedirects(
+                                history[0].request_info, tuple(history)
+                            )
+
+                        # For 301 and 302, mimic IE, now changed in RFC
+                        # https://github.com/kennethreitz/requests/pull/269
+                        if (resp.status == 303 and resp.method != hdrs.METH_HEAD) or (
+                            resp.status in (301, 302) and resp.method == hdrs.METH_POST
+                        ):
+                            method = hdrs.METH_GET
+                            data = None
+                            if headers.get(hdrs.CONTENT_LENGTH):
+                                headers.pop(hdrs.CONTENT_LENGTH)
+
+                        r_url = resp.headers.get(hdrs.LOCATION) or resp.headers.get(
+                            hdrs.URI
+                        )
+                        if r_url is None:
+                            # see github.com/aio-libs/aiohttp/issues/2022
+                            break
+                        else:
+                            # reading from correct redirection
+                            # response is forbidden
+                            resp.release()
+
+                        try:
+                            parsed_redirect_url = URL(
+                                r_url, encoded=not self._requote_redirect_url
+                            )
+                        except ValueError as e:
+                            raise InvalidUrlRedirectClientError(
+                                r_url,
+                                "Server attempted redirecting to a location that does not look like a URL",
+                            ) from e
+
+                        scheme = parsed_redirect_url.scheme
+                        if scheme not in HTTP_AND_EMPTY_SCHEMA_SET:
+                            resp.close()
+                            raise NonHttpUrlRedirectClientError(r_url)
+                        elif not scheme:
+                            parsed_redirect_url = url.join(parsed_redirect_url)
+
+                        try:
+                            redirect_origin = parsed_redirect_url.origin()
+                        except ValueError as origin_val_err:
+                            raise InvalidUrlRedirectClientError(
+                                parsed_redirect_url,
+                                "Invalid redirect URL origin",
+                            ) from origin_val_err
+
+                        if url.origin() != redirect_origin:
+                            auth = None
+                            headers.pop(hdrs.AUTHORIZATION, None)
+
+                        url = parsed_redirect_url
+                        params = {}
+                        resp.release()
+                        continue
+
+                    break
+
+            # check response status
+            if raise_for_status is None:
+                raise_for_status = self._raise_for_status
+
+            if raise_for_status is None:
+                pass
+            elif callable(raise_for_status):
+                await raise_for_status(resp)
+            elif raise_for_status:
+                resp.raise_for_status()
+
+            # register connection
+            if handle is not None:
+                if resp.connection is not None:
+                    resp.connection.add_callback(handle.cancel)
+                else:
+                    handle.cancel()
+
+            resp._history = tuple(history)
+
+            for trace in traces:
+                await trace.send_request_end(
+                    method, url.update_query(params), headers, resp
+                )
+            return resp
+
+        except BaseException as e:
+            # cleanup timer
+            tm.close()
+            if handle:
+                handle.cancel()
+                handle = None
+
+            for trace in traces:
+                await trace.send_request_exception(
+                    method, url.update_query(params), headers, e
+                )
+            raise
+
+    def ws_connect(
+        self,
+        url: StrOrURL,
+        *,
+        method: str = hdrs.METH_GET,
+        protocols: Iterable[str] = (),
+        timeout: Union[ClientWSTimeout, _SENTINEL] = sentinel,
+        receive_timeout: Optional[float] = None,
+        autoclose: bool = True,
+        autoping: bool = True,
+        heartbeat: Optional[float] = None,
+        auth: Optional[BasicAuth] = None,
+        origin: Optional[str] = None,
+        params: Query = None,
+        headers: Optional[LooseHeaders] = None,
+        proxy: Optional[StrOrURL] = None,
+        proxy_auth: Optional[BasicAuth] = None,
+        ssl: Union[SSLContext, bool, Fingerprint] = True,
+        verify_ssl: Optional[bool] = None,
+        fingerprint: Optional[bytes] = None,
+        ssl_context: Optional[SSLContext] = None,
+        server_hostname: Optional[str] = None,
+        proxy_headers: Optional[LooseHeaders] = None,
+        compress: int = 0,
+        max_msg_size: int = 4 * 1024 * 1024,
+    ) -> "_WSRequestContextManager":
+        """Initiate websocket connection."""
+        return _WSRequestContextManager(
+            self._ws_connect(
+                url,
+                method=method,
+                protocols=protocols,
+                timeout=timeout,
+                receive_timeout=receive_timeout,
+                autoclose=autoclose,
+                autoping=autoping,
+                heartbeat=heartbeat,
+                auth=auth,
+                origin=origin,
+                params=params,
+                headers=headers,
+                proxy=proxy,
+                proxy_auth=proxy_auth,
+                ssl=ssl,
+                verify_ssl=verify_ssl,
+                fingerprint=fingerprint,
+                ssl_context=ssl_context,
+                server_hostname=server_hostname,
+                proxy_headers=proxy_headers,
+                compress=compress,
+                max_msg_size=max_msg_size,
+            )
+        )
+
+    async def _ws_connect(
+        self,
+        url: StrOrURL,
+        *,
+        method: str = hdrs.METH_GET,
+        protocols: Iterable[str] = (),
+        timeout: Union[ClientWSTimeout, _SENTINEL] = sentinel,
+        receive_timeout: Optional[float] = None,
+        autoclose: bool = True,
+        autoping: bool = True,
+        heartbeat: Optional[float] = None,
+        auth: Optional[BasicAuth] = None,
+        origin: Optional[str] = None,
+        params: Query = None,
+        headers: Optional[LooseHeaders] = None,
+        proxy: Optional[StrOrURL] = None,
+        proxy_auth: Optional[BasicAuth] = None,
+        ssl: Union[SSLContext, bool, Fingerprint] = True,
+        verify_ssl: Optional[bool] = None,
+        fingerprint: Optional[bytes] = None,
+        ssl_context: Optional[SSLContext] = None,
+        server_hostname: Optional[str] = None,
+        proxy_headers: Optional[LooseHeaders] = None,
+        compress: int = 0,
+        max_msg_size: int = 4 * 1024 * 1024,
+    ) -> ClientWebSocketResponse:
+        if timeout is not sentinel:
+            if isinstance(timeout, ClientWSTimeout):
+                ws_timeout = timeout
+            else:
+                warnings.warn(
+                    "parameter 'timeout' of type 'float' "
+                    "is deprecated, please use "
+                    "'timeout=ClientWSTimeout(ws_close=...)'",
+                    DeprecationWarning,
+                    stacklevel=2,
+                )
+                ws_timeout = ClientWSTimeout(ws_close=timeout)
+        else:
+            ws_timeout = DEFAULT_WS_CLIENT_TIMEOUT
+        if receive_timeout is not None:
+            warnings.warn(
+                "float parameter 'receive_timeout' "
+                "is deprecated, please use parameter "
+                "'timeout=ClientWSTimeout(ws_receive=...)'",
+                DeprecationWarning,
+                stacklevel=2,
+            )
+            ws_timeout = attr.evolve(ws_timeout, ws_receive=receive_timeout)
+
+        if headers is None:
+            real_headers: CIMultiDict[str] = CIMultiDict()
+        else:
+            real_headers = CIMultiDict(headers)
+
+        default_headers = {
+            hdrs.UPGRADE: "websocket",
+            hdrs.CONNECTION: "Upgrade",
+            hdrs.SEC_WEBSOCKET_VERSION: "13",
+        }
+
+        for key, value in default_headers.items():
+            real_headers.setdefault(key, value)
+
+        sec_key = base64.b64encode(os.urandom(16))
+        real_headers[hdrs.SEC_WEBSOCKET_KEY] = sec_key.decode()
+
+        if protocols:
+            real_headers[hdrs.SEC_WEBSOCKET_PROTOCOL] = ",".join(protocols)
+        if origin is not None:
+            real_headers[hdrs.ORIGIN] = origin
+        if compress:
+            extstr = ws_ext_gen(compress=compress)
+            real_headers[hdrs.SEC_WEBSOCKET_EXTENSIONS] = extstr
+
+        # For the sake of backward compatibility, if user passes in None, convert it to True
+        if ssl is None:
+            warnings.warn(
+                "ssl=None is deprecated, please use ssl=True",
+                DeprecationWarning,
+                stacklevel=2,
+            )
+            ssl = True
+        ssl = _merge_ssl_params(ssl, verify_ssl, ssl_context, fingerprint)
+
+        # send request
+        resp = await self.request(
+            method,
+            url,
+            params=params,
+            headers=real_headers,
+            read_until_eof=False,
+            auth=auth,
+            proxy=proxy,
+            proxy_auth=proxy_auth,
+            ssl=ssl,
+            server_hostname=server_hostname,
+            proxy_headers=proxy_headers,
+        )
+
+        try:
+            # check handshake
+            if resp.status != 101:
+                raise WSServerHandshakeError(
+                    resp.request_info,
+                    resp.history,
+                    message="Invalid response status",
+                    status=resp.status,
+                    headers=resp.headers,
+                )
+
+            if resp.headers.get(hdrs.UPGRADE, "").lower() != "websocket":
+                raise WSServerHandshakeError(
+                    resp.request_info,
+                    resp.history,
+                    message="Invalid upgrade header",
+                    status=resp.status,
+                    headers=resp.headers,
+                )
+
+            if resp.headers.get(hdrs.CONNECTION, "").lower() != "upgrade":
+                raise WSServerHandshakeError(
+                    resp.request_info,
+                    resp.history,
+                    message="Invalid connection header",
+                    status=resp.status,
+                    headers=resp.headers,
+                )
+
+            # key calculation
+            r_key = resp.headers.get(hdrs.SEC_WEBSOCKET_ACCEPT, "")
+            match = base64.b64encode(hashlib.sha1(sec_key + WS_KEY).digest()).decode()
+            if r_key != match:
+                raise WSServerHandshakeError(
+                    resp.request_info,
+                    resp.history,
+                    message="Invalid challenge response",
+                    status=resp.status,
+                    headers=resp.headers,
+                )
+
+            # websocket protocol
+            protocol = None
+            if protocols and hdrs.SEC_WEBSOCKET_PROTOCOL in resp.headers:
+                resp_protocols = [
+                    proto.strip()
+                    for proto in resp.headers[hdrs.SEC_WEBSOCKET_PROTOCOL].split(",")
+                ]
+
+                for proto in resp_protocols:
+                    if proto in protocols:
+                        protocol = proto
+                        break
+
+            # websocket compress
+            notakeover = False
+            if compress:
+                compress_hdrs = resp.headers.get(hdrs.SEC_WEBSOCKET_EXTENSIONS)
+                if compress_hdrs:
+                    try:
+                        compress, notakeover = ws_ext_parse(compress_hdrs)
+                    except WSHandshakeError as exc:
+                        raise WSServerHandshakeError(
+                            resp.request_info,
+                            resp.history,
+                            message=exc.args[0],
+                            status=resp.status,
+                            headers=resp.headers,
+                        ) from exc
+                else:
+                    compress = 0
+                    notakeover = False
+
+            conn = resp.connection
+            assert conn is not None
+            conn_proto = conn.protocol
+            assert conn_proto is not None
+
+            # For WS connection the read_timeout must be either receive_timeout or greater
+            # None == no timeout, i.e. infinite timeout, so None is the max timeout possible
+            if ws_timeout.ws_receive is None:
+                # Reset regardless
+                conn_proto.read_timeout = None
+            elif conn_proto.read_timeout is not None:
+                conn_proto.read_timeout = max(
+                    ws_timeout.ws_receive, conn_proto.read_timeout
+                )
+
+            transport = conn.transport
+            assert transport is not None
+            reader = WebSocketDataQueue(conn_proto, 2**16, loop=self._loop)
+            conn_proto.set_parser(WebSocketReader(reader, max_msg_size), reader)
+            writer = WebSocketWriter(
+                conn_proto,
+                transport,
+                use_mask=True,
+                compress=compress,
+                notakeover=notakeover,
+            )
+        except BaseException:
+            resp.close()
+            raise
+        else:
+            return self._ws_response_class(
+                reader,
+                writer,
+                protocol,
+                resp,
+                ws_timeout,
+                autoclose,
+                autoping,
+                self._loop,
+                heartbeat=heartbeat,
+                compress=compress,
+                client_notakeover=notakeover,
+            )
+
+    def _prepare_headers(self, headers: Optional[LooseHeaders]) -> "CIMultiDict[str]":
+        """Add default headers and transform it to CIMultiDict"""
+        # Convert headers to MultiDict
+        result = CIMultiDict(self._default_headers)
+        if headers:
+            if not isinstance(headers, (MultiDictProxy, MultiDict)):
+                headers = CIMultiDict(headers)
+            added_names: Set[str] = set()
+            for key, value in headers.items():
+                if key in added_names:
+                    result.add(key, value)
+                else:
+                    result[key] = value
+                    added_names.add(key)
+        return result
+
+    if sys.version_info >= (3, 11) and TYPE_CHECKING:
+
+        def get(
+            self,
+            url: StrOrURL,
+            **kwargs: Unpack[_RequestOptions],
+        ) -> "_RequestContextManager": ...
+
+        def options(
+            self,
+            url: StrOrURL,
+            **kwargs: Unpack[_RequestOptions],
+        ) -> "_RequestContextManager": ...
+
+        def head(
+            self,
+            url: StrOrURL,
+            **kwargs: Unpack[_RequestOptions],
+        ) -> "_RequestContextManager": ...
+
+        def post(
+            self,
+            url: StrOrURL,
+            **kwargs: Unpack[_RequestOptions],
+        ) -> "_RequestContextManager": ...
+
+        def put(
+            self,
+            url: StrOrURL,
+            **kwargs: Unpack[_RequestOptions],
+        ) -> "_RequestContextManager": ...
+
+        def patch(
+            self,
+            url: StrOrURL,
+            **kwargs: Unpack[_RequestOptions],
+        ) -> "_RequestContextManager": ...
+
+        def delete(
+            self,
+            url: StrOrURL,
+            **kwargs: Unpack[_RequestOptions],
+        ) -> "_RequestContextManager": ...
+
+    else:
+
+        def get(
+            self, url: StrOrURL, *, allow_redirects: bool = True, **kwargs: Any
+        ) -> "_RequestContextManager":
+            """Perform HTTP GET request."""
+            return _RequestContextManager(
+                self._request(
+                    hdrs.METH_GET, url, allow_redirects=allow_redirects, **kwargs
+                )
+            )
+
+        def options(
+            self, url: StrOrURL, *, allow_redirects: bool = True, **kwargs: Any
+        ) -> "_RequestContextManager":
+            """Perform HTTP OPTIONS request."""
+            return _RequestContextManager(
+                self._request(
+                    hdrs.METH_OPTIONS, url, allow_redirects=allow_redirects, **kwargs
+                )
+            )
+
+        def head(
+            self, url: StrOrURL, *, allow_redirects: bool = False, **kwargs: Any
+        ) -> "_RequestContextManager":
+            """Perform HTTP HEAD request."""
+            return _RequestContextManager(
+                self._request(
+                    hdrs.METH_HEAD, url, allow_redirects=allow_redirects, **kwargs
+                )
+            )
+
+        def post(
+            self, url: StrOrURL, *, data: Any = None, **kwargs: Any
+        ) -> "_RequestContextManager":
+            """Perform HTTP POST request."""
+            return _RequestContextManager(
+                self._request(hdrs.METH_POST, url, data=data, **kwargs)
+            )
+
+        def put(
+            self, url: StrOrURL, *, data: Any = None, **kwargs: Any
+        ) -> "_RequestContextManager":
+            """Perform HTTP PUT request."""
+            return _RequestContextManager(
+                self._request(hdrs.METH_PUT, url, data=data, **kwargs)
+            )
+
+        def patch(
+            self, url: StrOrURL, *, data: Any = None, **kwargs: Any
+        ) -> "_RequestContextManager":
+            """Perform HTTP PATCH request."""
+            return _RequestContextManager(
+                self._request(hdrs.METH_PATCH, url, data=data, **kwargs)
+            )
+
+        def delete(self, url: StrOrURL, **kwargs: Any) -> "_RequestContextManager":
+            """Perform HTTP DELETE request."""
+            return _RequestContextManager(
+                self._request(hdrs.METH_DELETE, url, **kwargs)
+            )
+
+    async def close(self) -> None:
+        """Close underlying connector.
+
+        Release all acquired resources.
+        """
+        if not self.closed:
+            if self._connector is not None and self._connector_owner:
+                await self._connector.close()
+            self._connector = None
+
+    @property
+    def closed(self) -> bool:
+        """Is client session closed.
+
+        A readonly property.
+        """
+        return self._connector is None or self._connector.closed
+
+    @property
+    def connector(self) -> Optional[BaseConnector]:
+        """Connector instance used for the session."""
+        return self._connector
+
+    @property
+    def cookie_jar(self) -> AbstractCookieJar:
+        """The session cookies."""
+        return self._cookie_jar
+
+    @property
+    def version(self) -> Tuple[int, int]:
+        """The session HTTP protocol version."""
+        return self._version
+
+    @property
+    def requote_redirect_url(self) -> bool:
+        """Do URL requoting on redirection handling."""
+        return self._requote_redirect_url
+
+    @requote_redirect_url.setter
+    def requote_redirect_url(self, val: bool) -> None:
+        """Do URL requoting on redirection handling."""
+        warnings.warn(
+            "session.requote_redirect_url modification is deprecated #2778",
+            DeprecationWarning,
+            stacklevel=2,
+        )
+        self._requote_redirect_url = val
+
+    @property
+    def loop(self) -> asyncio.AbstractEventLoop:
+        """Session's loop."""
+        warnings.warn(
+            "client.loop property is deprecated", DeprecationWarning, stacklevel=2
+        )
+        return self._loop
+
+    @property
+    def timeout(self) -> ClientTimeout:
+        """Timeout for the session."""
+        return self._timeout
+
+    @property
+    def headers(self) -> "CIMultiDict[str]":
+        """The default headers of the client session."""
+        return self._default_headers
+
+    @property
+    def skip_auto_headers(self) -> FrozenSet[istr]:
+        """Headers for which autogeneration should be skipped"""
+        return self._skip_auto_headers
+
+    @property
+    def auth(self) -> Optional[BasicAuth]:
+        """An object that represents HTTP Basic Authorization"""
+        return self._default_auth
+
+    @property
+    def json_serialize(self) -> JSONEncoder:
+        """Json serializer callable"""
+        return self._json_serialize
+
+    @property
+    def connector_owner(self) -> bool:
+        """Should connector be closed on session closing"""
+        return self._connector_owner
+
+    @property
+    def raise_for_status(
+        self,
+    ) -> Union[bool, Callable[[ClientResponse], Awaitable[None]]]:
+        """Should `ClientResponse.raise_for_status()` be called for each response."""
+        return self._raise_for_status
+
+    @property
+    def auto_decompress(self) -> bool:
+        """Should the body response be automatically decompressed."""
+        return self._auto_decompress
+
+    @property
+    def trust_env(self) -> bool:
+        """
+        Should proxies information from environment or netrc be trusted.
+
+        Information is from HTTP_PROXY / HTTPS_PROXY environment variables
+        or ~/.netrc file if present.
+        """
+        return self._trust_env
+
+    @property
+    def trace_configs(self) -> List[TraceConfig]:
+        """A list of TraceConfig instances used for client tracing"""
+        return self._trace_configs
+
+    def detach(self) -> None:
+        """Detach connector from session without closing the former.
+
+        Session is switched to closed state anyway.
+        """
+        self._connector = None
+
+    def __enter__(self) -> None:
+        raise TypeError("Use async with instead")
+
+    def __exit__(
+        self,
+        exc_type: Optional[Type[BaseException]],
+        exc_val: Optional[BaseException],
+        exc_tb: Optional[TracebackType],
+    ) -> None:
+        # __exit__ should exist in pair with __enter__ but never executed
+        pass  # pragma: no cover
+
+    async def __aenter__(self) -> "ClientSession":
+        return self
+
+    async def __aexit__(
+        self,
+        exc_type: Optional[Type[BaseException]],
+        exc_val: Optional[BaseException],
+        exc_tb: Optional[TracebackType],
+    ) -> None:
+        await self.close()
+
+
+class _BaseRequestContextManager(Coroutine[Any, Any, _RetType], Generic[_RetType]):
+
+    __slots__ = ("_coro", "_resp")
+
+    def __init__(self, coro: Coroutine["asyncio.Future[Any]", None, _RetType]) -> None:
+        self._coro: Coroutine["asyncio.Future[Any]", None, _RetType] = coro
+
+    def send(self, arg: None) -> "asyncio.Future[Any]":
+        return self._coro.send(arg)
+
+    def throw(self, *args: Any, **kwargs: Any) -> "asyncio.Future[Any]":
+        return self._coro.throw(*args, **kwargs)
+
+    def close(self) -> None:
+        return self._coro.close()
+
+    def __await__(self) -> Generator[Any, None, _RetType]:
+        ret = self._coro.__await__()
+        return ret
+
+    def __iter__(self) -> Generator[Any, None, _RetType]:
+        return self.__await__()
+
+    async def __aenter__(self) -> _RetType:
+        self._resp: _RetType = await self._coro
+        return await self._resp.__aenter__()
+
+    async def __aexit__(
+        self,
+        exc_type: Optional[Type[BaseException]],
+        exc: Optional[BaseException],
+        tb: Optional[TracebackType],
+    ) -> None:
+        await self._resp.__aexit__(exc_type, exc, tb)
+
+
+_RequestContextManager = _BaseRequestContextManager[ClientResponse]
+_WSRequestContextManager = _BaseRequestContextManager[ClientWebSocketResponse]
+
+
+class _SessionRequestContextManager:
+
+    __slots__ = ("_coro", "_resp", "_session")
+
+    def __init__(
+        self,
+        coro: Coroutine["asyncio.Future[Any]", None, ClientResponse],
+        session: ClientSession,
+    ) -> None:
+        self._coro = coro
+        self._resp: Optional[ClientResponse] = None
+        self._session = session
+
+    async def __aenter__(self) -> ClientResponse:
+        try:
+            self._resp = await self._coro
+        except BaseException:
+            await self._session.close()
+            raise
+        else:
+            return self._resp
+
+    async def __aexit__(
+        self,
+        exc_type: Optional[Type[BaseException]],
+        exc: Optional[BaseException],
+        tb: Optional[TracebackType],
+    ) -> None:
+        assert self._resp is not None
+        self._resp.close()
+        await self._session.close()
+
+
+if sys.version_info >= (3, 11) and TYPE_CHECKING:
+
+    def request(
+        method: str,
+        url: StrOrURL,
+        *,
+        version: HttpVersion = http.HttpVersion11,
+        connector: Optional[BaseConnector] = None,
+        loop: Optional[asyncio.AbstractEventLoop] = None,
+        **kwargs: Unpack[_RequestOptions],
+    ) -> _SessionRequestContextManager: ...
+
+else:
+
+    def request(
+        method: str,
+        url: StrOrURL,
+        *,
+        version: HttpVersion = http.HttpVersion11,
+        connector: Optional[BaseConnector] = None,
+        loop: Optional[asyncio.AbstractEventLoop] = None,
+        **kwargs: Any,
+    ) -> _SessionRequestContextManager:
+        """Constructs and sends a request.
+
+        Returns response object.
+        method - HTTP method
+        url - request url
+        params - (optional) Dictionary or bytes to be sent in the query
+        string of the new request
+        data - (optional) Dictionary, bytes, or file-like object to
+        send in the body of the request
+        json - (optional) Any json compatible python object
+        headers - (optional) Dictionary of HTTP Headers to send with
+        the request
+        cookies - (optional) Dict object to send with the request
+        auth - (optional) BasicAuth named tuple represent HTTP Basic Auth
+        auth - aiohttp.helpers.BasicAuth
+        allow_redirects - (optional) If set to False, do not follow
+        redirects
+        version - Request HTTP version.
+        compress - Set to True if request has to be compressed
+        with deflate encoding.
+        chunked - Set to chunk size for chunked transfer encoding.
+        expect100 - Expect 100-continue response from server.
+        connector - BaseConnector sub-class instance to support
+        connection pooling.
+        read_until_eof - Read response until eof if response
+        does not have Content-Length header.
+        loop - Optional event loop.
+        timeout - Optional ClientTimeout settings structure, 5min
+        total timeout by default.
+        Usage::
+        >>> import aiohttp
+        >>> async with aiohttp.request('GET', 'http://python.org/') as resp:
+        ...    print(resp)
+        ...    data = await resp.read()
+        <ClientResponse(https://www.python.org/) [200 OK]>
+        """
+        connector_owner = False
+        if connector is None:
+            connector_owner = True
+            connector = TCPConnector(loop=loop, force_close=True)
+
+        session = ClientSession(
+            loop=loop,
+            cookies=kwargs.pop("cookies", None),
+            version=version,
+            timeout=kwargs.pop("timeout", sentinel),
+            connector=connector,
+            connector_owner=connector_owner,
+        )
+
+        return _SessionRequestContextManager(
+            session._request(method, url, **kwargs),
+            session,
+        )