{
    "file_diffs": [
        {
            "old_file_content": "",
            "new_file_content": "Fixed resolve_host() 'Task was destroyed but is pending' errors -- by :user:`Dreamsorcerer`.\n",
            "header": {
                "file": {
                    "path": "CHANGES/8967.bugfix.rst"
                },
                "misc_line": "new file mode 100644"
            },
            "index_line": {
                "old_commit_hash": "00000000",
                "new_commit_hash": "1046f36b",
                "mode": ""
            },
            "is_binary_file": false,
            "binary_line": null,
            "minus_file": {
                "path": "/dev/null"
            },
            "plus_file": {
                "path": "b/CHANGES/8967.bugfix.rst"
            },
            "hunks": [
                {
                    "descriptor": {
                        "old_range": {
                            "start": 0,
                            "length": 0
                        },
                        "new_range": {
                            "start": 1,
                            "length": null
                        },
                        "section": ""
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "Fixed resolve_host() 'Task was destroyed but is pending' errors -- by :user:`Dreamsorcerer`.",
                                "type": "added"
                            }
                        ]
                    },
                    "modified_entities": [],
                    "added_entities": [],
                    "deleted_entities": []
                }
            ]
        },
        {
            "old_file_content": "import asyncio\nimport functools\nimport random\nimport socket\nimport sys\nimport traceback\nimport warnings\nfrom collections import defaultdict, deque\nfrom contextlib import suppress\nfrom http import HTTPStatus\nfrom http.cookies import SimpleCookie\nfrom itertools import cycle, islice\nfrom time import monotonic\nfrom types import TracebackType\nfrom typing import (\n    TYPE_CHECKING,\n    Any,\n    Awaitable,\n    Callable,\n    DefaultDict,\n    Dict,\n    Iterator,\n    List,\n    Literal,\n    Optional,\n    Sequence,\n    Set,\n    Tuple,\n    Type,\n    Union,\n    cast,\n)\n\nimport aiohappyeyeballs\nimport attr\n\nfrom . import hdrs, helpers\nfrom .abc import AbstractResolver, ResolveResult\nfrom .client_exceptions import (\n    ClientConnectionError,\n    ClientConnectorCertificateError,\n    ClientConnectorError,\n    ClientConnectorSSLError,\n    ClientHttpProxyError,\n    ClientProxyConnectionError,\n    ServerFingerprintMismatch,\n    UnixClientConnectorError,\n    cert_errors,\n    ssl_errors,\n)\nfrom .client_proto import ResponseHandler\nfrom .client_reqrep import ClientRequest, Fingerprint, _merge_ssl_params\nfrom .helpers import (\n    ceil_timeout,\n    is_ip_address,\n    noop,\n    sentinel,\n    set_exception,\n    set_result,\n)\nfrom .locks import EventResultOrError\nfrom .resolver import DefaultResolver\n\ntry:\n    import ssl\n\n    SSLContext = ssl.SSLContext\nexcept ImportError:  # pragma: no cover\n    ssl = None  # type: ignore[assignment]\n    SSLContext = object  # type: ignore[misc,assignment]\n\n\nEMPTY_SCHEMA_SET = frozenset({\"\"})\nHTTP_SCHEMA_SET = frozenset({\"http\", \"https\"})\nWS_SCHEMA_SET = frozenset({\"ws\", \"wss\"})\n\nHTTP_AND_EMPTY_SCHEMA_SET = HTTP_SCHEMA_SET | EMPTY_SCHEMA_SET\nHIGH_LEVEL_SCHEMA_SET = HTTP_AND_EMPTY_SCHEMA_SET | WS_SCHEMA_SET\n\n\n__all__ = (\"BaseConnector\", \"TCPConnector\", \"UnixConnector\", \"NamedPipeConnector\")\n\n\nif TYPE_CHECKING:\n    from .client import ClientTimeout\n    from .client_reqrep import ConnectionKey\n    from .tracing import Trace\n\n\nclass _DeprecationWaiter:\n    __slots__ = (\"_awaitable\", \"_awaited\")\n\n    def __init__(self, awaitable: Awaitable[Any]) -> None:\n        self._awaitable = awaitable\n        self._awaited = False\n\n    def __await__(self) -> Any:\n        self._awaited = True\n        return self._awaitable.__await__()\n\n    def __del__(self) -> None:\n        if not self._awaited:\n            warnings.warn(\n                \"Connector.close() is a coroutine, \"\n                \"please use await connector.close()\",\n                DeprecationWarning,\n            )\n\n\nclass Connection:\n\n    _source_traceback = None\n    _transport = None\n\n    def __init__(\n        self,\n        connector: \"BaseConnector\",\n        key: \"ConnectionKey\",\n        protocol: ResponseHandler,\n        loop: asyncio.AbstractEventLoop,\n    ) -> None:\n        self._key = key\n        self._connector = connector\n        self._loop = loop\n        self._protocol: Optional[ResponseHandler] = protocol\n        self._callbacks: List[Callable[[], None]] = []\n\n        if loop.get_debug():\n            self._source_traceback = traceback.extract_stack(sys._getframe(1))\n\n    def __repr__(self) -> str:\n        return f\"Connection<{self._key}>\"\n\n    def __del__(self, _warnings: Any = warnings) -> None:\n        if self._protocol is not None:\n            kwargs = {\"source\": self}\n            _warnings.warn(f\"Unclosed connection {self!r}\", ResourceWarning, **kwargs)\n            if self._loop.is_closed():\n                return\n\n            self._connector._release(self._key, self._protocol, should_close=True)\n\n            context = {\"client_connection\": self, \"message\": \"Unclosed connection\"}\n            if self._source_traceback is not None:\n                context[\"source_traceback\"] = self._source_traceback\n            self._loop.call_exception_handler(context)\n\n    def __bool__(self) -> Literal[True]:\n        \"\"\"Force subclasses to not be falsy, to make checks simpler.\"\"\"\n        return True\n\n    @property\n    def loop(self) -> asyncio.AbstractEventLoop:\n        warnings.warn(\n            \"connector.loop property is deprecated\", DeprecationWarning, stacklevel=2\n        )\n        return self._loop\n\n    @property\n    def transport(self) -> Optional[asyncio.Transport]:\n        if self._protocol is None:\n            return None\n        return self._protocol.transport\n\n    @property\n    def protocol(self) -> Optional[ResponseHandler]:\n        return self._protocol\n\n    def add_callback(self, callback: Callable[[], None]) -> None:\n        if callback is not None:\n            self._callbacks.append(callback)\n\n    def _notify_release(self) -> None:\n        callbacks, self._callbacks = self._callbacks[:], []\n\n        for cb in callbacks:\n            with suppress(Exception):\n                cb()\n\n    def close(self) -> None:\n        self._notify_release()\n\n        if self._protocol is not None:\n            self._connector._release(self._key, self._protocol, should_close=True)\n            self._protocol = None\n\n    def release(self) -> None:\n        self._notify_release()\n\n        if self._protocol is not None:\n            self._connector._release(\n                self._key, self._protocol, should_close=self._protocol.should_close\n            )\n            self._protocol = None\n\n    @property\n    def closed(self) -> bool:\n        return self._protocol is None or not self._protocol.is_connected()\n\n\nclass _TransportPlaceholder:\n    \"\"\"placeholder for BaseConnector.connect function\"\"\"\n\n    def close(self) -> None:\n        pass\n\n\nclass BaseConnector:\n    \"\"\"Base connector class.\n\n    keepalive_timeout - (optional) Keep-alive timeout.\n    force_close - Set to True to force close and do reconnect\n        after each request (and between redirects).\n    limit - The total number of simultaneous connections.\n    limit_per_host - Number of simultaneous connections to one host.\n    enable_cleanup_closed - Enables clean-up closed ssl transports.\n                            Disabled by default.\n    timeout_ceil_threshold - Trigger ceiling of timeout values when\n                             it's above timeout_ceil_threshold.\n    loop - Optional event loop.\n    \"\"\"\n\n    _closed = True  # prevent AttributeError in __del__ if ctor was failed\n    _source_traceback = None\n\n    # abort transport after 2 seconds (cleanup broken connections)\n    _cleanup_closed_period = 2.0\n\n    allowed_protocol_schema_set = HIGH_LEVEL_SCHEMA_SET\n\n    def __init__(\n        self,\n        *,\n        keepalive_timeout: Union[object, None, float] = sentinel,\n        force_close: bool = False,\n        limit: int = 100,\n        limit_per_host: int = 0,\n        enable_cleanup_closed: bool = False,\n        loop: Optional[asyncio.AbstractEventLoop] = None,\n        timeout_ceil_threshold: float = 5,\n    ) -> None:\n\n        if force_close:\n            if keepalive_timeout is not None and keepalive_timeout is not sentinel:\n                raise ValueError(\n                    \"keepalive_timeout cannot \" \"be set if force_close is True\"\n                )\n        else:\n            if keepalive_timeout is sentinel:\n                keepalive_timeout = 15.0\n\n        loop = loop or asyncio.get_running_loop()\n        self._timeout_ceil_threshold = timeout_ceil_threshold\n\n        self._closed = False\n        if loop.get_debug():\n            self._source_traceback = traceback.extract_stack(sys._getframe(1))\n\n        self._conns: Dict[ConnectionKey, List[Tuple[ResponseHandler, float]]] = {}\n        self._limit = limit\n        self._limit_per_host = limit_per_host\n        self._acquired: Set[ResponseHandler] = set()\n        self._acquired_per_host: DefaultDict[ConnectionKey, Set[ResponseHandler]] = (\n            defaultdict(set)\n        )\n        self._keepalive_timeout = cast(float, keepalive_timeout)\n        self._force_close = force_close\n\n        # {host_key: FIFO list of waiters}\n        self._waiters = defaultdict(deque)  # type: ignore[var-annotated]\n\n        self._loop = loop\n        self._factory = functools.partial(ResponseHandler, loop=loop)\n\n        self.cookies = SimpleCookie()\n\n        # start keep-alive connection cleanup task\n        self._cleanup_handle: Optional[asyncio.TimerHandle] = None\n\n        # start cleanup closed transports task\n        self._cleanup_closed_handle: Optional[asyncio.TimerHandle] = None\n        self._cleanup_closed_disabled = not enable_cleanup_closed\n        self._cleanup_closed_transports: List[Optional[asyncio.Transport]] = []\n        self._cleanup_closed()\n\n    def __del__(self, _warnings: Any = warnings) -> None:\n        if self._closed:\n            return\n        if not self._conns:\n            return\n\n        conns = [repr(c) for c in self._conns.values()]\n\n        self._close()\n\n        kwargs = {\"source\": self}\n        _warnings.warn(f\"Unclosed connector {self!r}\", ResourceWarning, **kwargs)\n        context = {\n            \"connector\": self,\n            \"connections\": conns,\n            \"message\": \"Unclosed connector\",\n        }\n        if self._source_traceback is not None:\n            context[\"source_traceback\"] = self._source_traceback\n        self._loop.call_exception_handler(context)\n\n    def __enter__(self) -> \"BaseConnector\":\n        warnings.warn(\n            '\"with Connector():\" is deprecated, '\n            'use \"async with Connector():\" instead',\n            DeprecationWarning,\n        )\n        return self\n\n    def __exit__(self, *exc: Any) -> None:\n        self._close()\n\n    async def __aenter__(self) -> \"BaseConnector\":\n        return self\n\n    async def __aexit__(\n        self,\n        exc_type: Optional[Type[BaseException]] = None,\n        exc_value: Optional[BaseException] = None,\n        exc_traceback: Optional[TracebackType] = None,\n    ) -> None:\n        await self.close()\n\n    @property\n    def force_close(self) -> bool:\n        \"\"\"Ultimately close connection on releasing if True.\"\"\"\n        return self._force_close\n\n    @property\n    def limit(self) -> int:\n        \"\"\"The total number for simultaneous connections.\n\n        If limit is 0 the connector has no limit.\n        The default limit size is 100.\n        \"\"\"\n        return self._limit\n\n    @property\n    def limit_per_host(self) -> int:\n        \"\"\"The limit for simultaneous connections to the same endpoint.\n\n        Endpoints are the same if they are have equal\n        (host, port, is_ssl) triple.\n        \"\"\"\n        return self._limit_per_host\n\n    def _cleanup(self) -> None:\n        \"\"\"Cleanup unused transports.\"\"\"\n        if self._cleanup_handle:\n            self._cleanup_handle.cancel()\n            # _cleanup_handle should be unset, otherwise _release() will not\n            # recreate it ever!\n            self._cleanup_handle = None\n\n        now = self._loop.time()\n        timeout = self._keepalive_timeout\n\n        if self._conns:\n            connections = {}\n            deadline = now - timeout\n            for key, conns in self._conns.items():\n                alive = []\n                for proto, use_time in conns:\n                    if proto.is_connected():\n                        if use_time - deadline < 0:\n                            transport = proto.transport\n                            proto.close()\n                            if key.is_ssl and not self._cleanup_closed_disabled:\n                                self._cleanup_closed_transports.append(transport)\n                        else:\n                            alive.append((proto, use_time))\n                    else:\n                        transport = proto.transport\n                        proto.close()\n                        if key.is_ssl and not self._cleanup_closed_disabled:\n                            self._cleanup_closed_transports.append(transport)\n\n                if alive:\n                    connections[key] = alive\n\n            self._conns = connections\n\n        if self._conns:\n            self._cleanup_handle = helpers.weakref_handle(\n                self,\n                \"_cleanup\",\n                timeout,\n                self._loop,\n                timeout_ceil_threshold=self._timeout_ceil_threshold,\n            )\n\n    def _drop_acquired_per_host(\n        self, key: \"ConnectionKey\", val: ResponseHandler\n    ) -> None:\n        acquired_per_host = self._acquired_per_host\n        if key not in acquired_per_host:\n            return\n        conns = acquired_per_host[key]\n        conns.remove(val)\n        if not conns:\n            del self._acquired_per_host[key]\n\n    def _cleanup_closed(self) -> None:\n        \"\"\"Double confirmation for transport close.\n\n        Some broken ssl servers may leave socket open without proper close.\n        \"\"\"\n        if self._cleanup_closed_handle:\n            self._cleanup_closed_handle.cancel()\n\n        for transport in self._cleanup_closed_transports:\n            if transport is not None:\n                transport.abort()\n\n        self._cleanup_closed_transports = []\n\n        if not self._cleanup_closed_disabled:\n            self._cleanup_closed_handle = helpers.weakref_handle(\n                self,\n                \"_cleanup_closed\",\n                self._cleanup_closed_period,\n                self._loop,\n                timeout_ceil_threshold=self._timeout_ceil_threshold,\n            )\n\n    def close(self) -> Awaitable[None]:\n        \"\"\"Close all opened transports.\"\"\"\n        self._close()\n        return _DeprecationWaiter(noop())\n\n    def _close(self) -> None:\n        if self._closed:\n            return\n\n        self._closed = True\n\n        try:\n            if self._loop.is_closed():\n                return\n\n            # cancel cleanup task\n            if self._cleanup_handle:\n                self._cleanup_handle.cancel()\n\n            # cancel cleanup close task\n            if self._cleanup_closed_handle:\n                self._cleanup_closed_handle.cancel()\n\n            for data in self._conns.values():\n                for proto, t0 in data:\n                    proto.close()\n\n            for proto in self._acquired:\n                proto.close()\n\n            for transport in self._cleanup_closed_transports:\n                if transport is not None:\n                    transport.abort()\n\n        finally:\n            self._conns.clear()\n            self._acquired.clear()\n            self._waiters.clear()\n            self._cleanup_handle = None\n            self._cleanup_closed_transports.clear()\n            self._cleanup_closed_handle = None\n\n    @property\n    def closed(self) -> bool:\n        \"\"\"Is connector closed.\n\n        A readonly property.\n        \"\"\"\n        return self._closed\n\n    def _available_connections(self, key: \"ConnectionKey\") -> int:\n        \"\"\"\n        Return number of available connections.\n\n        The limit, limit_per_host and the connection key are taken into account.\n\n        If it returns less than 1 means that there are no connections\n        available.\n        \"\"\"\n        if self._limit:\n            # total calc available connections\n            available = self._limit - len(self._acquired)\n\n            # check limit per host\n            if (\n                self._limit_per_host\n                and available > 0\n                and key in self._acquired_per_host\n            ):\n                acquired = self._acquired_per_host.get(key)\n                assert acquired is not None\n                available = self._limit_per_host - len(acquired)\n\n        elif self._limit_per_host and key in self._acquired_per_host:\n            # check limit per host\n            acquired = self._acquired_per_host.get(key)\n            assert acquired is not None\n            available = self._limit_per_host - len(acquired)\n        else:\n            available = 1\n\n        return available\n\n    async def connect(\n        self, req: ClientRequest, traces: List[\"Trace\"], timeout: \"ClientTimeout\"\n    ) -> Connection:\n        \"\"\"Get from pool or create new connection.\"\"\"\n        key = req.connection_key\n        available = self._available_connections(key)\n\n        # Wait if there are no available connections or if there are/were\n        # waiters (i.e. don't steal connection from a waiter about to wake up)\n        if available <= 0 or key in self._waiters:\n            fut = self._loop.create_future()\n\n            # This connection will now count towards the limit.\n            self._waiters[key].append(fut)\n\n            if traces:\n                for trace in traces:\n                    await trace.send_connection_queued_start()\n\n            try:\n                await fut\n            except BaseException as e:\n                if key in self._waiters:\n                    # remove a waiter even if it was cancelled, normally it's\n                    #  removed when it's notified\n                    try:\n                        self._waiters[key].remove(fut)\n                    except ValueError:  # fut may no longer be in list\n                        pass\n\n                raise e\n            finally:\n                if key in self._waiters and not self._waiters[key]:\n                    del self._waiters[key]\n\n            if traces:\n                for trace in traces:\n                    await trace.send_connection_queued_end()\n\n        proto = self._get(key)\n        if proto is None:\n            placeholder = cast(ResponseHandler, _TransportPlaceholder())\n            self._acquired.add(placeholder)\n            self._acquired_per_host[key].add(placeholder)\n\n            if traces:\n                for trace in traces:\n                    await trace.send_connection_create_start()\n\n            try:\n                proto = await self._create_connection(req, traces, timeout)\n                if self._closed:\n                    proto.close()\n                    raise ClientConnectionError(\"Connector is closed.\")\n            except BaseException:\n                if not self._closed:\n                    self._acquired.remove(placeholder)\n                    self._drop_acquired_per_host(key, placeholder)\n                    self._release_waiter()\n                raise\n            else:\n                if not self._closed:\n                    self._acquired.remove(placeholder)\n                    self._drop_acquired_per_host(key, placeholder)\n\n            if traces:\n                for trace in traces:\n                    await trace.send_connection_create_end()\n        else:\n            if traces:\n                # Acquire the connection to prevent race conditions with limits\n                placeholder = cast(ResponseHandler, _TransportPlaceholder())\n                self._acquired.add(placeholder)\n                self._acquired_per_host[key].add(placeholder)\n                for trace in traces:\n                    await trace.send_connection_reuseconn()\n                self._acquired.remove(placeholder)\n                self._drop_acquired_per_host(key, placeholder)\n\n        self._acquired.add(proto)\n        self._acquired_per_host[key].add(proto)\n        return Connection(self, key, proto, self._loop)\n\n    def _get(self, key: \"ConnectionKey\") -> Optional[ResponseHandler]:\n        try:\n            conns = self._conns[key]\n        except KeyError:\n            return None\n\n        t1 = self._loop.time()\n        while conns:\n            proto, t0 = conns.pop()\n            if proto.is_connected():\n                if t1 - t0 > self._keepalive_timeout:\n                    transport = proto.transport\n                    proto.close()\n                    # only for SSL transports\n                    if key.is_ssl and not self._cleanup_closed_disabled:\n                        self._cleanup_closed_transports.append(transport)\n                else:\n                    if not conns:\n                        # The very last connection was reclaimed: drop the key\n                        del self._conns[key]\n                    return proto\n            else:\n                transport = proto.transport\n                proto.close()\n                if key.is_ssl and not self._cleanup_closed_disabled:\n                    self._cleanup_closed_transports.append(transport)\n\n        # No more connections: drop the key\n        del self._conns[key]\n        return None\n\n    def _release_waiter(self) -> None:\n        \"\"\"\n        Iterates over all waiters until one to be released is found.\n\n        The one to be released is not finished and\n        belongs to a host that has available connections.\n        \"\"\"\n        if not self._waiters:\n            return\n\n        # Having the dict keys ordered this avoids to iterate\n        # at the same order at each call.\n        queues = list(self._waiters.keys())\n        random.shuffle(queues)\n\n        for key in queues:\n            if self._available_connections(key) < 1:\n                continue\n\n            waiters = self._waiters[key]\n            while waiters:\n                waiter = waiters.popleft()\n                if not waiter.done():\n                    waiter.set_result(None)\n                    return\n\n    def _release_acquired(self, key: \"ConnectionKey\", proto: ResponseHandler) -> None:\n        if self._closed:\n            # acquired connection is already released on connector closing\n            return\n\n        try:\n            self._acquired.remove(proto)\n            self._drop_acquired_per_host(key, proto)\n        except KeyError:  # pragma: no cover\n            # this may be result of undetermenistic order of objects\n            # finalization due garbage collection.\n            pass\n        else:\n            self._release_waiter()\n\n    def _release(\n        self,\n        key: \"ConnectionKey\",\n        protocol: ResponseHandler,\n        *,\n        should_close: bool = False,\n    ) -> None:\n        if self._closed:\n            # acquired connection is already released on connector closing\n            return\n\n        self._release_acquired(key, protocol)\n\n        if self._force_close:\n            should_close = True\n\n        if should_close or protocol.should_close:\n            transport = protocol.transport\n            protocol.close()\n\n            if key.is_ssl and not self._cleanup_closed_disabled:\n                self._cleanup_closed_transports.append(transport)\n        else:\n            conns = self._conns.get(key)\n            if conns is None:\n                conns = self._conns[key] = []\n            conns.append((protocol, self._loop.time()))\n\n            if self._cleanup_handle is None:\n                self._cleanup_handle = helpers.weakref_handle(\n                    self,\n                    \"_cleanup\",\n                    self._keepalive_timeout,\n                    self._loop,\n                    timeout_ceil_threshold=self._timeout_ceil_threshold,\n                )\n\n    async def _create_connection(\n        self, req: ClientRequest, traces: List[\"Trace\"], timeout: \"ClientTimeout\"\n    ) -> ResponseHandler:\n        raise NotImplementedError()\n\n\nclass _DNSCacheTable:\n    def __init__(self, ttl: Optional[float] = None) -> None:\n        self._addrs_rr: Dict[Tuple[str, int], Tuple[Iterator[ResolveResult], int]] = {}\n        self._timestamps: Dict[Tuple[str, int], float] = {}\n        self._ttl = ttl\n\n    def __contains__(self, host: object) -> bool:\n        return host in self._addrs_rr\n\n    def add(self, key: Tuple[str, int], addrs: List[ResolveResult]) -> None:\n        self._addrs_rr[key] = (cycle(addrs), len(addrs))\n\n        if self._ttl is not None:\n            self._timestamps[key] = monotonic()\n\n    def remove(self, key: Tuple[str, int]) -> None:\n        self._addrs_rr.pop(key, None)\n\n        if self._ttl is not None:\n            self._timestamps.pop(key, None)\n\n    def clear(self) -> None:\n        self._addrs_rr.clear()\n        self._timestamps.clear()\n\n    def next_addrs(self, key: Tuple[str, int]) -> List[ResolveResult]:\n        loop, length = self._addrs_rr[key]\n        addrs = list(islice(loop, length))\n        # Consume one more element to shift internal state of `cycle`\n        next(loop)\n        return addrs\n\n    def expired(self, key: Tuple[str, int]) -> bool:\n        if self._ttl is None:\n            return False\n\n        return self._timestamps[key] + self._ttl < monotonic()\n\n\nclass TCPConnector(BaseConnector):\n    \"\"\"TCP connector.\n\n    verify_ssl - Set to True to check ssl certifications.\n    fingerprint - Pass the binary sha256\n        digest of the expected certificate in DER format to verify\n        that the certificate the server presents matches. See also\n        https://en.wikipedia.org/wiki/HTTP_Public_Key_Pinning\n    resolver - Enable DNS lookups and use this\n        resolver\n    use_dns_cache - Use memory cache for DNS lookups.\n    ttl_dns_cache - Max seconds having cached a DNS entry, None forever.\n    family - socket address family\n    local_addr - local tuple of (host, port) to bind socket to\n\n    keepalive_timeout - (optional) Keep-alive timeout.\n    force_close - Set to True to force close and do reconnect\n        after each request (and between redirects).\n    limit - The total number of simultaneous connections.\n    limit_per_host - Number of simultaneous connections to one host.\n    enable_cleanup_closed - Enables clean-up closed ssl transports.\n                            Disabled by default.\n    happy_eyeballs_delay - This is the “Connection Attempt Delay”\n                           as defined in RFC 8305. To disable\n                           the happy eyeballs algorithm, set to None.\n    interleave - “First Address Family Count” as defined in RFC 8305\n    loop - Optional event loop.\n    \"\"\"\n\n    allowed_protocol_schema_set = HIGH_LEVEL_SCHEMA_SET | frozenset({\"tcp\"})\n    _made_ssl_context: Dict[bool, \"asyncio.Future[SSLContext]\"] = {}\n\n    def __init__(\n        self,\n        *,\n        verify_ssl: bool = True,\n        fingerprint: Optional[bytes] = None,\n        use_dns_cache: bool = True,\n        ttl_dns_cache: Optional[int] = 10,\n        family: socket.AddressFamily = socket.AddressFamily.AF_UNSPEC,\n        ssl_context: Optional[SSLContext] = None,\n        ssl: Union[bool, Fingerprint, SSLContext] = True,\n        local_addr: Optional[Tuple[str, int]] = None,\n        resolver: Optional[AbstractResolver] = None,\n        keepalive_timeout: Union[None, float, object] = sentinel,\n        force_close: bool = False,\n        limit: int = 100,\n        limit_per_host: int = 0,\n        enable_cleanup_closed: bool = False,\n        loop: Optional[asyncio.AbstractEventLoop] = None,\n        timeout_ceil_threshold: float = 5,\n        happy_eyeballs_delay: Optional[float] = 0.25,\n        interleave: Optional[int] = None,\n    ):\n        super().__init__(\n            keepalive_timeout=keepalive_timeout,\n            force_close=force_close,\n            limit=limit,\n            limit_per_host=limit_per_host,\n            enable_cleanup_closed=enable_cleanup_closed,\n            loop=loop,\n            timeout_ceil_threshold=timeout_ceil_threshold,\n        )\n\n        self._ssl = _merge_ssl_params(ssl, verify_ssl, ssl_context, fingerprint)\n        if resolver is None:\n            resolver = DefaultResolver(loop=self._loop)\n        self._resolver = resolver\n\n        self._use_dns_cache = use_dns_cache\n        self._cached_hosts = _DNSCacheTable(ttl=ttl_dns_cache)\n        self._throttle_dns_events: Dict[Tuple[str, int], EventResultOrError] = {}\n        self._family = family\n        self._local_addr_infos = aiohappyeyeballs.addr_to_addr_infos(local_addr)\n        self._happy_eyeballs_delay = happy_eyeballs_delay\n        self._interleave = interleave\n\n    def close(self) -> Awaitable[None]:\n        \"\"\"Close all ongoing DNS calls.\"\"\"\n        for ev in self._throttle_dns_events.values():\n            ev.cancel()\n\n        return super().close()\n\n    @property\n    def family(self) -> int:\n        \"\"\"Socket family like AF_INET.\"\"\"\n        return self._family\n\n    @property\n    def use_dns_cache(self) -> bool:\n        \"\"\"True if local DNS caching is enabled.\"\"\"\n        return self._use_dns_cache\n\n    def clear_dns_cache(\n        self, host: Optional[str] = None, port: Optional[int] = None\n    ) -> None:\n        \"\"\"Remove specified host/port or clear all dns local cache.\"\"\"\n        if host is not None and port is not None:\n            self._cached_hosts.remove((host, port))\n        elif host is not None or port is not None:\n            raise ValueError(\"either both host and port \" \"or none of them are allowed\")\n        else:\n            self._cached_hosts.clear()\n\n    async def _resolve_host(\n        self, host: str, port: int, traces: Optional[Sequence[\"Trace\"]] = None\n    ) -> List[ResolveResult]:\n        \"\"\"Resolve host and return list of addresses.\"\"\"\n        if is_ip_address(host):\n            return [\n                {\n                    \"hostname\": host,\n                    \"host\": host,\n                    \"port\": port,\n                    \"family\": self._family,\n                    \"proto\": 0,\n                    \"flags\": 0,\n                }\n            ]\n\n        if not self._use_dns_cache:\n\n            if traces:\n                for trace in traces:\n                    await trace.send_dns_resolvehost_start(host)\n\n            res = await self._resolver.resolve(host, port, family=self._family)\n\n            if traces:\n                for trace in traces:\n                    await trace.send_dns_resolvehost_end(host)\n\n            return res\n\n        key = (host, port)\n        if key in self._cached_hosts and not self._cached_hosts.expired(key):\n            # get result early, before any await (#4014)\n            result = self._cached_hosts.next_addrs(key)\n\n            if traces:\n                for trace in traces:\n                    await trace.send_dns_cache_hit(host)\n            return result\n\n        #\n        # If multiple connectors are resolving the same host, we wait\n        # for the first one to resolve and then use the result for all of them.\n        # We use a throttle event to ensure that we only resolve the host once\n        # and then use the result for all the waiters.\n        #\n        # In this case we need to create a task to ensure that we can shield\n        # the task from cancellation as cancelling this lookup should not cancel\n        # the underlying lookup or else the cancel event will get broadcast to\n        # all the waiters across all connections.\n        #\n        resolved_host_task = asyncio.create_task(\n            self._resolve_host_with_throttle(key, host, port, traces)\n        )\n        try:\n            return await asyncio.shield(resolved_host_task)\n        except asyncio.CancelledError:\n\n            def drop_exception(fut: \"asyncio.Future[List[ResolveResult]]\") -> None:\n                with suppress(Exception, asyncio.CancelledError):\n                    fut.result()\n\n            resolved_host_task.add_done_callback(drop_exception)\n            raise\n\n    async def _resolve_host_with_throttle(\n        self,\n        key: Tuple[str, int],\n        host: str,\n        port: int,\n        traces: Optional[Sequence[\"Trace\"]],\n    ) -> List[ResolveResult]:\n        \"\"\"Resolve host with a dns events throttle.\"\"\"\n        if key in self._throttle_dns_events:\n            # get event early, before any await (#4014)\n            event = self._throttle_dns_events[key]\n            if traces:\n                for trace in traces:\n                    await trace.send_dns_cache_hit(host)\n            await event.wait()\n        else:\n            # update dict early, before any await (#4014)\n            self._throttle_dns_events[key] = EventResultOrError(self._loop)\n            if traces:\n                for trace in traces:\n                    await trace.send_dns_cache_miss(host)\n            try:\n\n                if traces:\n                    for trace in traces:\n                        await trace.send_dns_resolvehost_start(host)\n\n                addrs = await self._resolver.resolve(host, port, family=self._family)\n                if traces:\n                    for trace in traces:\n                        await trace.send_dns_resolvehost_end(host)\n\n                self._cached_hosts.add(key, addrs)\n                self._throttle_dns_events[key].set()\n            except BaseException as e:\n                # any DNS exception, independently of the implementation\n                # is set for the waiters to raise the same exception.\n                self._throttle_dns_events[key].set(exc=e)\n                raise\n            finally:\n                self._throttle_dns_events.pop(key)\n\n        return self._cached_hosts.next_addrs(key)\n\n    async def _create_connection(\n        self, req: ClientRequest, traces: List[\"Trace\"], timeout: \"ClientTimeout\"\n    ) -> ResponseHandler:\n        \"\"\"Create connection.\n\n        Has same keyword arguments as BaseEventLoop.create_connection.\n        \"\"\"\n        if req.proxy:\n            _, proto = await self._create_proxy_connection(req, traces, timeout)\n        else:\n            _, proto = await self._create_direct_connection(req, traces, timeout)\n\n        return proto\n\n    @staticmethod\n    def _make_ssl_context(verified: bool) -> SSLContext:\n        \"\"\"Create SSL context.\n\n        This method is not async-friendly and should be called from a thread\n        because it will load certificates from disk and do other blocking I/O.\n        \"\"\"\n        if verified:\n            return ssl.create_default_context()\n        sslcontext = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)\n        sslcontext.options |= ssl.OP_NO_SSLv2\n        sslcontext.options |= ssl.OP_NO_SSLv3\n        sslcontext.check_hostname = False\n        sslcontext.verify_mode = ssl.CERT_NONE\n        sslcontext.options |= ssl.OP_NO_COMPRESSION\n        sslcontext.set_default_verify_paths()\n        return sslcontext\n\n    async def _get_ssl_context(self, req: ClientRequest) -> Optional[SSLContext]:\n        \"\"\"Logic to get the correct SSL context\n\n        0. if req.ssl is false, return None\n\n        1. if ssl_context is specified in req, use it\n        2. if _ssl_context is specified in self, use it\n        3. otherwise:\n            1. if verify_ssl is not specified in req, use self.ssl_context\n               (will generate a default context according to self.verify_ssl)\n            2. if verify_ssl is True in req, generate a default SSL context\n            3. if verify_ssl is False in req, generate a SSL context that\n               won't verify\n        \"\"\"\n        if not req.is_ssl():\n            return None\n\n        if ssl is None:  # pragma: no cover\n            raise RuntimeError(\"SSL is not supported.\")\n        sslcontext = req.ssl\n        if isinstance(sslcontext, ssl.SSLContext):\n            return sslcontext\n        if sslcontext is not True:\n            # not verified or fingerprinted\n            return await self._make_or_get_ssl_context(False)\n        sslcontext = self._ssl\n        if isinstance(sslcontext, ssl.SSLContext):\n            return sslcontext\n        if sslcontext is not True:\n            # not verified or fingerprinted\n            return await self._make_or_get_ssl_context(False)\n        return await self._make_or_get_ssl_context(True)\n\n    async def _make_or_get_ssl_context(self, verified: bool) -> SSLContext:\n        \"\"\"Create or get cached SSL context.\"\"\"\n        try:\n            return await self._made_ssl_context[verified]\n        except KeyError:\n            loop = self._loop\n            future = loop.create_future()\n            self._made_ssl_context[verified] = future\n            try:\n                result = await loop.run_in_executor(\n                    None, self._make_ssl_context, verified\n                )\n            # BaseException is used since we might get CancelledError\n            except BaseException as ex:\n                del self._made_ssl_context[verified]\n                set_exception(future, ex)\n                raise\n            else:\n                set_result(future, result)\n            return result\n\n    def _get_fingerprint(self, req: ClientRequest) -> Optional[\"Fingerprint\"]:\n        ret = req.ssl\n        if isinstance(ret, Fingerprint):\n            return ret\n        ret = self._ssl\n        if isinstance(ret, Fingerprint):\n            return ret\n        return None\n\n    async def _wrap_create_connection(\n        self,\n        *args: Any,\n        addr_infos: List[aiohappyeyeballs.AddrInfoType],\n        req: ClientRequest,\n        timeout: \"ClientTimeout\",\n        client_error: Type[Exception] = ClientConnectorError,\n        **kwargs: Any,\n    ) -> Tuple[asyncio.Transport, ResponseHandler]:\n        try:\n            async with ceil_timeout(\n                timeout.sock_connect, ceil_threshold=timeout.ceil_threshold\n            ):\n                sock = await aiohappyeyeballs.start_connection(\n                    addr_infos=addr_infos,\n                    local_addr_infos=self._local_addr_infos,\n                    happy_eyeballs_delay=self._happy_eyeballs_delay,\n                    interleave=self._interleave,\n                    loop=self._loop,\n                )\n                return await self._loop.create_connection(*args, **kwargs, sock=sock)\n        except cert_errors as exc:\n            raise ClientConnectorCertificateError(req.connection_key, exc) from exc\n        except ssl_errors as exc:\n            raise ClientConnectorSSLError(req.connection_key, exc) from exc\n        except OSError as exc:\n            if exc.errno is None and isinstance(exc, asyncio.TimeoutError):\n                raise\n            raise client_error(req.connection_key, exc) from exc\n\n    async def _wrap_existing_connection(\n        self,\n        *args: Any,\n        req: ClientRequest,\n        timeout: \"ClientTimeout\",\n        client_error: Type[Exception] = ClientConnectorError,\n        **kwargs: Any,\n    ) -> Tuple[asyncio.Transport, ResponseHandler]:\n        try:\n            async with ceil_timeout(\n                timeout.sock_connect, ceil_threshold=timeout.ceil_threshold\n            ):\n                return await self._loop.create_connection(*args, **kwargs)\n        except cert_errors as exc:\n            raise ClientConnectorCertificateError(req.connection_key, exc) from exc\n        except ssl_errors as exc:\n            raise ClientConnectorSSLError(req.connection_key, exc) from exc\n        except OSError as exc:\n            if exc.errno is None and isinstance(exc, asyncio.TimeoutError):\n                raise\n            raise client_error(req.connection_key, exc) from exc\n\n    def _fail_on_no_start_tls(self, req: \"ClientRequest\") -> None:\n        \"\"\"Raise a :py:exc:`RuntimeError` on missing ``start_tls()``.\n\n        It is necessary for TLS-in-TLS so that it is possible to\n        send HTTPS queries through HTTPS proxies.\n\n        This doesn't affect regular HTTP requests, though.\n        \"\"\"\n        if not req.is_ssl():\n            return\n\n        proxy_url = req.proxy\n        assert proxy_url is not None\n        if proxy_url.scheme != \"https\":\n            return\n\n        self._check_loop_for_start_tls()\n\n    def _check_loop_for_start_tls(self) -> None:\n        try:\n            self._loop.start_tls\n        except AttributeError as attr_exc:\n            raise RuntimeError(\n                \"An HTTPS request is being sent through an HTTPS proxy. \"\n                \"This needs support for TLS in TLS but it is not implemented \"\n                \"in your runtime for the stdlib asyncio.\\n\\n\"\n                \"Please upgrade to Python 3.11 or higher. For more details, \"\n                \"please see:\\n\"\n                \"* https://bugs.python.org/issue37179\\n\"\n                \"* https://github.com/python/cpython/pull/28073\\n\"\n                \"* https://docs.aiohttp.org/en/stable/\"\n                \"client_advanced.html#proxy-support\\n\"\n                \"* https://github.com/aio-libs/aiohttp/discussions/6044\\n\",\n            ) from attr_exc\n\n    def _loop_supports_start_tls(self) -> bool:\n        try:\n            self._check_loop_for_start_tls()\n        except RuntimeError:\n            return False\n        else:\n            return True\n\n    def _warn_about_tls_in_tls(\n        self,\n        underlying_transport: asyncio.Transport,\n        req: ClientRequest,\n    ) -> None:\n        \"\"\"Issue a warning if the requested URL has HTTPS scheme.\"\"\"\n        if req.request_info.url.scheme != \"https\":\n            return\n\n        asyncio_supports_tls_in_tls = getattr(\n            underlying_transport,\n            \"_start_tls_compatible\",\n            False,\n        )\n\n        if asyncio_supports_tls_in_tls:\n            return\n\n        warnings.warn(\n            \"An HTTPS request is being sent through an HTTPS proxy. \"\n            \"This support for TLS in TLS is known to be disabled \"\n            \"in the stdlib asyncio (Python <3.11). This is why you'll probably see \"\n            \"an error in the log below.\\n\\n\"\n            \"It is possible to enable it via monkeypatching. \"\n            \"For more details, see:\\n\"\n            \"* https://bugs.python.org/issue37179\\n\"\n            \"* https://github.com/python/cpython/pull/28073\\n\\n\"\n            \"You can temporarily patch this as follows:\\n\"\n            \"* https://docs.aiohttp.org/en/stable/client_advanced.html#proxy-support\\n\"\n            \"* https://github.com/aio-libs/aiohttp/discussions/6044\\n\",\n            RuntimeWarning,\n            source=self,\n            # Why `4`? At least 3 of the calls in the stack originate\n            # from the methods in this class.\n            stacklevel=3,\n        )\n\n    async def _start_tls_connection(\n        self,\n        underlying_transport: asyncio.Transport,\n        req: ClientRequest,\n        timeout: \"ClientTimeout\",\n        client_error: Type[Exception] = ClientConnectorError,\n    ) -> Tuple[asyncio.BaseTransport, ResponseHandler]:\n        \"\"\"Wrap the raw TCP transport with TLS.\"\"\"\n        tls_proto = self._factory()  # Create a brand new proto for TLS\n\n        # Safety of the `cast()` call here is based on the fact that\n        # internally `_get_ssl_context()` only returns `None` when\n        # `req.is_ssl()` evaluates to `False` which is never gonna happen\n        # in this code path. Of course, it's rather fragile\n        # maintainability-wise but this is to be solved separately.\n        sslcontext = cast(ssl.SSLContext, await self._get_ssl_context(req))\n\n        try:\n            async with ceil_timeout(\n                timeout.sock_connect, ceil_threshold=timeout.ceil_threshold\n            ):\n                try:\n                    tls_transport = await self._loop.start_tls(\n                        underlying_transport,\n                        tls_proto,\n                        sslcontext,\n                        server_hostname=req.server_hostname or req.host,\n                        ssl_handshake_timeout=timeout.total,\n                    )\n                except BaseException:\n                    # We need to close the underlying transport since\n                    # `start_tls()` probably failed before it had a\n                    # chance to do this:\n                    underlying_transport.close()\n                    raise\n        except cert_errors as exc:\n            raise ClientConnectorCertificateError(req.connection_key, exc) from exc\n        except ssl_errors as exc:\n            raise ClientConnectorSSLError(req.connection_key, exc) from exc\n        except OSError as exc:\n            if exc.errno is None and isinstance(exc, asyncio.TimeoutError):\n                raise\n            raise client_error(req.connection_key, exc) from exc\n        except TypeError as type_err:\n            # Example cause looks like this:\n            # TypeError: transport <asyncio.sslproto._SSLProtocolTransport\n            # object at 0x7f760615e460> is not supported by start_tls()\n\n            raise ClientConnectionError(\n                \"Cannot initialize a TLS-in-TLS connection to host \"\n                f\"{req.host!s}:{req.port:d} through an underlying connection \"\n                f\"to an HTTPS proxy {req.proxy!s} ssl:{req.ssl or 'default'} \"\n                f\"[{type_err!s}]\"\n            ) from type_err\n        else:\n            if tls_transport is None:\n                msg = \"Failed to start TLS (possibly caused by closing transport)\"\n                raise client_error(req.connection_key, OSError(msg))\n            tls_proto.connection_made(\n                tls_transport\n            )  # Kick the state machine of the new TLS protocol\n\n        return tls_transport, tls_proto\n\n    def _convert_hosts_to_addr_infos(\n        self, hosts: List[ResolveResult]\n    ) -> List[aiohappyeyeballs.AddrInfoType]:\n        \"\"\"Converts the list of hosts to a list of addr_infos.\n\n        The list of hosts is the result of a DNS lookup. The list of\n        addr_infos is the result of a call to `socket.getaddrinfo()`.\n        \"\"\"\n        addr_infos: List[aiohappyeyeballs.AddrInfoType] = []\n        for hinfo in hosts:\n            host = hinfo[\"host\"]\n            is_ipv6 = \":\" in host\n            family = socket.AF_INET6 if is_ipv6 else socket.AF_INET\n            if self._family and self._family != family:\n                continue\n            addr = (host, hinfo[\"port\"], 0, 0) if is_ipv6 else (host, hinfo[\"port\"])\n            addr_infos.append(\n                (family, socket.SOCK_STREAM, socket.IPPROTO_TCP, \"\", addr)\n            )\n        return addr_infos\n\n    async def _create_direct_connection(\n        self,\n        req: ClientRequest,\n        traces: List[\"Trace\"],\n        timeout: \"ClientTimeout\",\n        *,\n        client_error: Type[Exception] = ClientConnectorError,\n    ) -> Tuple[asyncio.Transport, ResponseHandler]:\n        sslcontext = await self._get_ssl_context(req)\n        fingerprint = self._get_fingerprint(req)\n\n        host = req.url.raw_host\n        assert host is not None\n        # Replace multiple trailing dots with a single one.\n        # A trailing dot is only present for fully-qualified domain names.\n        # See https://github.com/aio-libs/aiohttp/pull/7364.\n        if host.endswith(\"..\"):\n            host = host.rstrip(\".\") + \".\"\n        port = req.port\n        assert port is not None\n        try:\n            # Cancelling this lookup should not cancel the underlying lookup\n            #  or else the cancel event will get broadcast to all the waiters\n            #  across all connections.\n            hosts = await self._resolve_host(host, port, traces=traces)\n        except OSError as exc:\n            if exc.errno is None and isinstance(exc, asyncio.TimeoutError):\n                raise\n            # in case of proxy it is not ClientProxyConnectionError\n            # it is problem of resolving proxy ip itself\n            raise ClientConnectorError(req.connection_key, exc) from exc\n\n        last_exc: Optional[Exception] = None\n        addr_infos = self._convert_hosts_to_addr_infos(hosts)\n        while addr_infos:\n            # Strip trailing dots, certificates contain FQDN without dots.\n            # See https://github.com/aio-libs/aiohttp/issues/3636\n            server_hostname = (\n                (req.server_hostname or host).rstrip(\".\") if sslcontext else None\n            )\n\n            try:\n                transp, proto = await self._wrap_create_connection(\n                    self._factory,\n                    timeout=timeout,\n                    ssl=sslcontext,\n                    addr_infos=addr_infos,\n                    server_hostname=server_hostname,\n                    req=req,\n                    client_error=client_error,\n                )\n            except ClientConnectorError as exc:\n                last_exc = exc\n                aiohappyeyeballs.pop_addr_infos_interleave(addr_infos, self._interleave)\n                continue\n\n            if req.is_ssl() and fingerprint:\n                try:\n                    fingerprint.check(transp)\n                except ServerFingerprintMismatch as exc:\n                    transp.close()\n                    if not self._cleanup_closed_disabled:\n                        self._cleanup_closed_transports.append(transp)\n                    last_exc = exc\n                    # Remove the bad peer from the list of addr_infos\n                    sock: socket.socket = transp.get_extra_info(\"socket\")\n                    bad_peer = sock.getpeername()\n                    aiohappyeyeballs.remove_addr_infos(addr_infos, bad_peer)\n                    continue\n\n            return transp, proto\n        else:\n            assert last_exc is not None\n            raise last_exc\n\n    async def _create_proxy_connection(\n        self, req: ClientRequest, traces: List[\"Trace\"], timeout: \"ClientTimeout\"\n    ) -> Tuple[asyncio.BaseTransport, ResponseHandler]:\n        self._fail_on_no_start_tls(req)\n        runtime_has_start_tls = self._loop_supports_start_tls()\n\n        headers: Dict[str, str] = {}\n        if req.proxy_headers is not None:\n            headers = req.proxy_headers  # type: ignore[assignment]\n        headers[hdrs.HOST] = req.headers[hdrs.HOST]\n\n        url = req.proxy\n        assert url is not None\n        proxy_req = ClientRequest(\n            hdrs.METH_GET,\n            url,\n            headers=headers,\n            auth=req.proxy_auth,\n            loop=self._loop,\n            ssl=req.ssl,\n        )\n\n        # create connection to proxy server\n        transport, proto = await self._create_direct_connection(\n            proxy_req, [], timeout, client_error=ClientProxyConnectionError\n        )\n\n        auth = proxy_req.headers.pop(hdrs.AUTHORIZATION, None)\n        if auth is not None:\n            if not req.is_ssl():\n                req.headers[hdrs.PROXY_AUTHORIZATION] = auth\n            else:\n                proxy_req.headers[hdrs.PROXY_AUTHORIZATION] = auth\n\n        if req.is_ssl():\n            if runtime_has_start_tls:\n                self._warn_about_tls_in_tls(transport, req)\n\n            # For HTTPS requests over HTTP proxy\n            # we must notify proxy to tunnel connection\n            # so we send CONNECT command:\n            #   CONNECT www.python.org:443 HTTP/1.1\n            #   Host: www.python.org\n            #\n            # next we must do TLS handshake and so on\n            # to do this we must wrap raw socket into secure one\n            # asyncio handles this perfectly\n            proxy_req.method = hdrs.METH_CONNECT\n            proxy_req.url = req.url\n            key = attr.evolve(\n                req.connection_key, proxy=None, proxy_auth=None, proxy_headers_hash=None\n            )\n            conn = Connection(self, key, proto, self._loop)\n            proxy_resp = await proxy_req.send(conn)\n            try:\n                protocol = conn._protocol\n                assert protocol is not None\n\n                # read_until_eof=True will ensure the connection isn't closed\n                # once the response is received and processed allowing\n                # START_TLS to work on the connection below.\n                protocol.set_response_params(\n                    read_until_eof=runtime_has_start_tls,\n                    timeout_ceil_threshold=self._timeout_ceil_threshold,\n                )\n                resp = await proxy_resp.start(conn)\n            except BaseException:\n                proxy_resp.close()\n                conn.close()\n                raise\n            else:\n                conn._protocol = None\n                conn._transport = None\n                try:\n                    if resp.status != 200:\n                        message = resp.reason\n                        if message is None:\n                            message = HTTPStatus(resp.status).phrase\n                        raise ClientHttpProxyError(\n                            proxy_resp.request_info,\n                            resp.history,\n                            status=resp.status,\n                            message=message,\n                            headers=resp.headers,\n                        )\n                    if not runtime_has_start_tls:\n                        rawsock = transport.get_extra_info(\"socket\", default=None)\n                        if rawsock is None:\n                            raise RuntimeError(\n                                \"Transport does not expose socket instance\"\n                            )\n                        # Duplicate the socket, so now we can close proxy transport\n                        rawsock = rawsock.dup()\n                except BaseException:\n                    # It shouldn't be closed in `finally` because it's fed to\n                    # `loop.start_tls()` and the docs say not to touch it after\n                    # passing there.\n                    transport.close()\n                    raise\n                finally:\n                    if not runtime_has_start_tls:\n                        transport.close()\n\n                if not runtime_has_start_tls:\n                    # HTTP proxy with support for upgrade to HTTPS\n                    sslcontext = self._get_ssl_context(req)\n                    return await self._wrap_existing_connection(\n                        self._factory,\n                        timeout=timeout,\n                        ssl=sslcontext,\n                        sock=rawsock,\n                        server_hostname=req.host,\n                        req=req,\n                    )\n\n                return await self._start_tls_connection(\n                    # Access the old transport for the last time before it's\n                    # closed and forgotten forever:\n                    transport,\n                    req=req,\n                    timeout=timeout,\n                )\n            finally:\n                proxy_resp.close()\n\n        return transport, proto\n\n\nclass UnixConnector(BaseConnector):\n    \"\"\"Unix socket connector.\n\n    path - Unix socket path.\n    keepalive_timeout - (optional) Keep-alive timeout.\n    force_close - Set to True to force close and do reconnect\n        after each request (and between redirects).\n    limit - The total number of simultaneous connections.\n    limit_per_host - Number of simultaneous connections to one host.\n    loop - Optional event loop.\n    \"\"\"\n\n    allowed_protocol_schema_set = HIGH_LEVEL_SCHEMA_SET | frozenset({\"unix\"})\n\n    def __init__(\n        self,\n        path: str,\n        force_close: bool = False,\n        keepalive_timeout: Union[object, float, None] = sentinel,\n        limit: int = 100,\n        limit_per_host: int = 0,\n        loop: Optional[asyncio.AbstractEventLoop] = None,\n    ) -> None:\n        super().__init__(\n            force_close=force_close,\n            keepalive_timeout=keepalive_timeout,\n            limit=limit,\n            limit_per_host=limit_per_host,\n            loop=loop,\n        )\n        self._path = path\n\n    @property\n    def path(self) -> str:\n        \"\"\"Path to unix socket.\"\"\"\n        return self._path\n\n    async def _create_connection(\n        self, req: ClientRequest, traces: List[\"Trace\"], timeout: \"ClientTimeout\"\n    ) -> ResponseHandler:\n        try:\n            async with ceil_timeout(\n                timeout.sock_connect, ceil_threshold=timeout.ceil_threshold\n            ):\n                _, proto = await self._loop.create_unix_connection(\n                    self._factory, self._path\n                )\n        except OSError as exc:\n            if exc.errno is None and isinstance(exc, asyncio.TimeoutError):\n                raise\n            raise UnixClientConnectorError(self.path, req.connection_key, exc) from exc\n\n        return proto\n\n\nclass NamedPipeConnector(BaseConnector):\n    \"\"\"Named pipe connector.\n\n    Only supported by the proactor event loop.\n    See also: https://docs.python.org/3/library/asyncio-eventloop.html\n\n    path - Windows named pipe path.\n    keepalive_timeout - (optional) Keep-alive timeout.\n    force_close - Set to True to force close and do reconnect\n        after each request (and between redirects).\n    limit - The total number of simultaneous connections.\n    limit_per_host - Number of simultaneous connections to one host.\n    loop - Optional event loop.\n    \"\"\"\n\n    allowed_protocol_schema_set = HIGH_LEVEL_SCHEMA_SET | frozenset({\"npipe\"})\n\n    def __init__(\n        self,\n        path: str,\n        force_close: bool = False,\n        keepalive_timeout: Union[object, float, None] = sentinel,\n        limit: int = 100,\n        limit_per_host: int = 0,\n        loop: Optional[asyncio.AbstractEventLoop] = None,\n    ) -> None:\n        super().__init__(\n            force_close=force_close,\n            keepalive_timeout=keepalive_timeout,\n            limit=limit,\n            limit_per_host=limit_per_host,\n            loop=loop,\n        )\n        if not isinstance(\n            self._loop, asyncio.ProactorEventLoop  # type: ignore[attr-defined]\n        ):\n            raise RuntimeError(\n                \"Named Pipes only available in proactor \" \"loop under windows\"\n            )\n        self._path = path\n\n    @property\n    def path(self) -> str:\n        \"\"\"Path to the named pipe.\"\"\"\n        return self._path\n\n    async def _create_connection(\n        self, req: ClientRequest, traces: List[\"Trace\"], timeout: \"ClientTimeout\"\n    ) -> ResponseHandler:\n        try:\n            async with ceil_timeout(\n                timeout.sock_connect, ceil_threshold=timeout.ceil_threshold\n            ):\n                _, proto = await self._loop.create_pipe_connection(  # type: ignore[attr-defined]\n                    self._factory, self._path\n                )\n                # the drain is required so that the connection_made is called\n                # and transport is set otherwise it is not set before the\n                # `assert conn.transport is not None`\n                # in client.py's _request method\n                await asyncio.sleep(0)\n                # other option is to manually set transport like\n                # `proto.transport = trans`\n        except OSError as exc:\n            if exc.errno is None and isinstance(exc, asyncio.TimeoutError):\n                raise\n            raise ClientConnectorError(req.connection_key, exc) from exc\n\n        return cast(ResponseHandler, proto)\n",
            "new_file_content": "import asyncio\nimport functools\nimport random\nimport socket\nimport sys\nimport traceback\nimport warnings\nfrom collections import defaultdict, deque\nfrom contextlib import suppress\nfrom http import HTTPStatus\nfrom http.cookies import SimpleCookie\nfrom itertools import cycle, islice\nfrom time import monotonic\nfrom types import TracebackType\nfrom typing import (\n    TYPE_CHECKING,\n    Any,\n    Awaitable,\n    Callable,\n    DefaultDict,\n    Dict,\n    Iterator,\n    List,\n    Literal,\n    Optional,\n    Sequence,\n    Set,\n    Tuple,\n    Type,\n    Union,\n    cast,\n)\n\nimport aiohappyeyeballs\nimport attr\n\nfrom . import hdrs, helpers\nfrom .abc import AbstractResolver, ResolveResult\nfrom .client_exceptions import (\n    ClientConnectionError,\n    ClientConnectorCertificateError,\n    ClientConnectorError,\n    ClientConnectorSSLError,\n    ClientHttpProxyError,\n    ClientProxyConnectionError,\n    ServerFingerprintMismatch,\n    UnixClientConnectorError,\n    cert_errors,\n    ssl_errors,\n)\nfrom .client_proto import ResponseHandler\nfrom .client_reqrep import ClientRequest, Fingerprint, _merge_ssl_params\nfrom .helpers import (\n    ceil_timeout,\n    is_ip_address,\n    noop,\n    sentinel,\n    set_exception,\n    set_result,\n)\nfrom .locks import EventResultOrError\nfrom .resolver import DefaultResolver\n\ntry:\n    import ssl\n\n    SSLContext = ssl.SSLContext\nexcept ImportError:  # pragma: no cover\n    ssl = None  # type: ignore[assignment]\n    SSLContext = object  # type: ignore[misc,assignment]\n\n\nEMPTY_SCHEMA_SET = frozenset({\"\"})\nHTTP_SCHEMA_SET = frozenset({\"http\", \"https\"})\nWS_SCHEMA_SET = frozenset({\"ws\", \"wss\"})\n\nHTTP_AND_EMPTY_SCHEMA_SET = HTTP_SCHEMA_SET | EMPTY_SCHEMA_SET\nHIGH_LEVEL_SCHEMA_SET = HTTP_AND_EMPTY_SCHEMA_SET | WS_SCHEMA_SET\n\n\n__all__ = (\"BaseConnector\", \"TCPConnector\", \"UnixConnector\", \"NamedPipeConnector\")\n\n\nif TYPE_CHECKING:\n    from .client import ClientTimeout\n    from .client_reqrep import ConnectionKey\n    from .tracing import Trace\n\n\nclass _DeprecationWaiter:\n    __slots__ = (\"_awaitable\", \"_awaited\")\n\n    def __init__(self, awaitable: Awaitable[Any]) -> None:\n        self._awaitable = awaitable\n        self._awaited = False\n\n    def __await__(self) -> Any:\n        self._awaited = True\n        return self._awaitable.__await__()\n\n    def __del__(self) -> None:\n        if not self._awaited:\n            warnings.warn(\n                \"Connector.close() is a coroutine, \"\n                \"please use await connector.close()\",\n                DeprecationWarning,\n            )\n\n\nclass Connection:\n\n    _source_traceback = None\n    _transport = None\n\n    def __init__(\n        self,\n        connector: \"BaseConnector\",\n        key: \"ConnectionKey\",\n        protocol: ResponseHandler,\n        loop: asyncio.AbstractEventLoop,\n    ) -> None:\n        self._key = key\n        self._connector = connector\n        self._loop = loop\n        self._protocol: Optional[ResponseHandler] = protocol\n        self._callbacks: List[Callable[[], None]] = []\n\n        if loop.get_debug():\n            self._source_traceback = traceback.extract_stack(sys._getframe(1))\n\n    def __repr__(self) -> str:\n        return f\"Connection<{self._key}>\"\n\n    def __del__(self, _warnings: Any = warnings) -> None:\n        if self._protocol is not None:\n            kwargs = {\"source\": self}\n            _warnings.warn(f\"Unclosed connection {self!r}\", ResourceWarning, **kwargs)\n            if self._loop.is_closed():\n                return\n\n            self._connector._release(self._key, self._protocol, should_close=True)\n\n            context = {\"client_connection\": self, \"message\": \"Unclosed connection\"}\n            if self._source_traceback is not None:\n                context[\"source_traceback\"] = self._source_traceback\n            self._loop.call_exception_handler(context)\n\n    def __bool__(self) -> Literal[True]:\n        \"\"\"Force subclasses to not be falsy, to make checks simpler.\"\"\"\n        return True\n\n    @property\n    def loop(self) -> asyncio.AbstractEventLoop:\n        warnings.warn(\n            \"connector.loop property is deprecated\", DeprecationWarning, stacklevel=2\n        )\n        return self._loop\n\n    @property\n    def transport(self) -> Optional[asyncio.Transport]:\n        if self._protocol is None:\n            return None\n        return self._protocol.transport\n\n    @property\n    def protocol(self) -> Optional[ResponseHandler]:\n        return self._protocol\n\n    def add_callback(self, callback: Callable[[], None]) -> None:\n        if callback is not None:\n            self._callbacks.append(callback)\n\n    def _notify_release(self) -> None:\n        callbacks, self._callbacks = self._callbacks[:], []\n\n        for cb in callbacks:\n            with suppress(Exception):\n                cb()\n\n    def close(self) -> None:\n        self._notify_release()\n\n        if self._protocol is not None:\n            self._connector._release(self._key, self._protocol, should_close=True)\n            self._protocol = None\n\n    def release(self) -> None:\n        self._notify_release()\n\n        if self._protocol is not None:\n            self._connector._release(\n                self._key, self._protocol, should_close=self._protocol.should_close\n            )\n            self._protocol = None\n\n    @property\n    def closed(self) -> bool:\n        return self._protocol is None or not self._protocol.is_connected()\n\n\nclass _TransportPlaceholder:\n    \"\"\"placeholder for BaseConnector.connect function\"\"\"\n\n    def close(self) -> None:\n        pass\n\n\nclass BaseConnector:\n    \"\"\"Base connector class.\n\n    keepalive_timeout - (optional) Keep-alive timeout.\n    force_close - Set to True to force close and do reconnect\n        after each request (and between redirects).\n    limit - The total number of simultaneous connections.\n    limit_per_host - Number of simultaneous connections to one host.\n    enable_cleanup_closed - Enables clean-up closed ssl transports.\n                            Disabled by default.\n    timeout_ceil_threshold - Trigger ceiling of timeout values when\n                             it's above timeout_ceil_threshold.\n    loop - Optional event loop.\n    \"\"\"\n\n    _closed = True  # prevent AttributeError in __del__ if ctor was failed\n    _source_traceback = None\n\n    # abort transport after 2 seconds (cleanup broken connections)\n    _cleanup_closed_period = 2.0\n\n    allowed_protocol_schema_set = HIGH_LEVEL_SCHEMA_SET\n\n    def __init__(\n        self,\n        *,\n        keepalive_timeout: Union[object, None, float] = sentinel,\n        force_close: bool = False,\n        limit: int = 100,\n        limit_per_host: int = 0,\n        enable_cleanup_closed: bool = False,\n        loop: Optional[asyncio.AbstractEventLoop] = None,\n        timeout_ceil_threshold: float = 5,\n    ) -> None:\n\n        if force_close:\n            if keepalive_timeout is not None and keepalive_timeout is not sentinel:\n                raise ValueError(\n                    \"keepalive_timeout cannot \" \"be set if force_close is True\"\n                )\n        else:\n            if keepalive_timeout is sentinel:\n                keepalive_timeout = 15.0\n\n        loop = loop or asyncio.get_running_loop()\n        self._timeout_ceil_threshold = timeout_ceil_threshold\n\n        self._closed = False\n        if loop.get_debug():\n            self._source_traceback = traceback.extract_stack(sys._getframe(1))\n\n        self._conns: Dict[ConnectionKey, List[Tuple[ResponseHandler, float]]] = {}\n        self._limit = limit\n        self._limit_per_host = limit_per_host\n        self._acquired: Set[ResponseHandler] = set()\n        self._acquired_per_host: DefaultDict[ConnectionKey, Set[ResponseHandler]] = (\n            defaultdict(set)\n        )\n        self._keepalive_timeout = cast(float, keepalive_timeout)\n        self._force_close = force_close\n\n        # {host_key: FIFO list of waiters}\n        self._waiters = defaultdict(deque)  # type: ignore[var-annotated]\n\n        self._loop = loop\n        self._factory = functools.partial(ResponseHandler, loop=loop)\n\n        self.cookies = SimpleCookie()\n\n        # start keep-alive connection cleanup task\n        self._cleanup_handle: Optional[asyncio.TimerHandle] = None\n\n        # start cleanup closed transports task\n        self._cleanup_closed_handle: Optional[asyncio.TimerHandle] = None\n        self._cleanup_closed_disabled = not enable_cleanup_closed\n        self._cleanup_closed_transports: List[Optional[asyncio.Transport]] = []\n        self._cleanup_closed()\n\n    def __del__(self, _warnings: Any = warnings) -> None:\n        if self._closed:\n            return\n        if not self._conns:\n            return\n\n        conns = [repr(c) for c in self._conns.values()]\n\n        self._close()\n\n        kwargs = {\"source\": self}\n        _warnings.warn(f\"Unclosed connector {self!r}\", ResourceWarning, **kwargs)\n        context = {\n            \"connector\": self,\n            \"connections\": conns,\n            \"message\": \"Unclosed connector\",\n        }\n        if self._source_traceback is not None:\n            context[\"source_traceback\"] = self._source_traceback\n        self._loop.call_exception_handler(context)\n\n    def __enter__(self) -> \"BaseConnector\":\n        warnings.warn(\n            '\"with Connector():\" is deprecated, '\n            'use \"async with Connector():\" instead',\n            DeprecationWarning,\n        )\n        return self\n\n    def __exit__(self, *exc: Any) -> None:\n        self._close()\n\n    async def __aenter__(self) -> \"BaseConnector\":\n        return self\n\n    async def __aexit__(\n        self,\n        exc_type: Optional[Type[BaseException]] = None,\n        exc_value: Optional[BaseException] = None,\n        exc_traceback: Optional[TracebackType] = None,\n    ) -> None:\n        await self.close()\n\n    @property\n    def force_close(self) -> bool:\n        \"\"\"Ultimately close connection on releasing if True.\"\"\"\n        return self._force_close\n\n    @property\n    def limit(self) -> int:\n        \"\"\"The total number for simultaneous connections.\n\n        If limit is 0 the connector has no limit.\n        The default limit size is 100.\n        \"\"\"\n        return self._limit\n\n    @property\n    def limit_per_host(self) -> int:\n        \"\"\"The limit for simultaneous connections to the same endpoint.\n\n        Endpoints are the same if they are have equal\n        (host, port, is_ssl) triple.\n        \"\"\"\n        return self._limit_per_host\n\n    def _cleanup(self) -> None:\n        \"\"\"Cleanup unused transports.\"\"\"\n        if self._cleanup_handle:\n            self._cleanup_handle.cancel()\n            # _cleanup_handle should be unset, otherwise _release() will not\n            # recreate it ever!\n            self._cleanup_handle = None\n\n        now = self._loop.time()\n        timeout = self._keepalive_timeout\n\n        if self._conns:\n            connections = {}\n            deadline = now - timeout\n            for key, conns in self._conns.items():\n                alive = []\n                for proto, use_time in conns:\n                    if proto.is_connected():\n                        if use_time - deadline < 0:\n                            transport = proto.transport\n                            proto.close()\n                            if key.is_ssl and not self._cleanup_closed_disabled:\n                                self._cleanup_closed_transports.append(transport)\n                        else:\n                            alive.append((proto, use_time))\n                    else:\n                        transport = proto.transport\n                        proto.close()\n                        if key.is_ssl and not self._cleanup_closed_disabled:\n                            self._cleanup_closed_transports.append(transport)\n\n                if alive:\n                    connections[key] = alive\n\n            self._conns = connections\n\n        if self._conns:\n            self._cleanup_handle = helpers.weakref_handle(\n                self,\n                \"_cleanup\",\n                timeout,\n                self._loop,\n                timeout_ceil_threshold=self._timeout_ceil_threshold,\n            )\n\n    def _drop_acquired_per_host(\n        self, key: \"ConnectionKey\", val: ResponseHandler\n    ) -> None:\n        acquired_per_host = self._acquired_per_host\n        if key not in acquired_per_host:\n            return\n        conns = acquired_per_host[key]\n        conns.remove(val)\n        if not conns:\n            del self._acquired_per_host[key]\n\n    def _cleanup_closed(self) -> None:\n        \"\"\"Double confirmation for transport close.\n\n        Some broken ssl servers may leave socket open without proper close.\n        \"\"\"\n        if self._cleanup_closed_handle:\n            self._cleanup_closed_handle.cancel()\n\n        for transport in self._cleanup_closed_transports:\n            if transport is not None:\n                transport.abort()\n\n        self._cleanup_closed_transports = []\n\n        if not self._cleanup_closed_disabled:\n            self._cleanup_closed_handle = helpers.weakref_handle(\n                self,\n                \"_cleanup_closed\",\n                self._cleanup_closed_period,\n                self._loop,\n                timeout_ceil_threshold=self._timeout_ceil_threshold,\n            )\n\n    def close(self) -> Awaitable[None]:\n        \"\"\"Close all opened transports.\"\"\"\n        self._close()\n        return _DeprecationWaiter(noop())\n\n    def _close(self) -> None:\n        if self._closed:\n            return\n\n        self._closed = True\n\n        try:\n            if self._loop.is_closed():\n                return\n\n            # cancel cleanup task\n            if self._cleanup_handle:\n                self._cleanup_handle.cancel()\n\n            # cancel cleanup close task\n            if self._cleanup_closed_handle:\n                self._cleanup_closed_handle.cancel()\n\n            for data in self._conns.values():\n                for proto, t0 in data:\n                    proto.close()\n\n            for proto in self._acquired:\n                proto.close()\n\n            for transport in self._cleanup_closed_transports:\n                if transport is not None:\n                    transport.abort()\n\n        finally:\n            self._conns.clear()\n            self._acquired.clear()\n            self._waiters.clear()\n            self._cleanup_handle = None\n            self._cleanup_closed_transports.clear()\n            self._cleanup_closed_handle = None\n\n    @property\n    def closed(self) -> bool:\n        \"\"\"Is connector closed.\n\n        A readonly property.\n        \"\"\"\n        return self._closed\n\n    def _available_connections(self, key: \"ConnectionKey\") -> int:\n        \"\"\"\n        Return number of available connections.\n\n        The limit, limit_per_host and the connection key are taken into account.\n\n        If it returns less than 1 means that there are no connections\n        available.\n        \"\"\"\n        if self._limit:\n            # total calc available connections\n            available = self._limit - len(self._acquired)\n\n            # check limit per host\n            if (\n                self._limit_per_host\n                and available > 0\n                and key in self._acquired_per_host\n            ):\n                acquired = self._acquired_per_host.get(key)\n                assert acquired is not None\n                available = self._limit_per_host - len(acquired)\n\n        elif self._limit_per_host and key in self._acquired_per_host:\n            # check limit per host\n            acquired = self._acquired_per_host.get(key)\n            assert acquired is not None\n            available = self._limit_per_host - len(acquired)\n        else:\n            available = 1\n\n        return available\n\n    async def connect(\n        self, req: ClientRequest, traces: List[\"Trace\"], timeout: \"ClientTimeout\"\n    ) -> Connection:\n        \"\"\"Get from pool or create new connection.\"\"\"\n        key = req.connection_key\n        available = self._available_connections(key)\n\n        # Wait if there are no available connections or if there are/were\n        # waiters (i.e. don't steal connection from a waiter about to wake up)\n        if available <= 0 or key in self._waiters:\n            fut = self._loop.create_future()\n\n            # This connection will now count towards the limit.\n            self._waiters[key].append(fut)\n\n            if traces:\n                for trace in traces:\n                    await trace.send_connection_queued_start()\n\n            try:\n                await fut\n            except BaseException as e:\n                if key in self._waiters:\n                    # remove a waiter even if it was cancelled, normally it's\n                    #  removed when it's notified\n                    try:\n                        self._waiters[key].remove(fut)\n                    except ValueError:  # fut may no longer be in list\n                        pass\n\n                raise e\n            finally:\n                if key in self._waiters and not self._waiters[key]:\n                    del self._waiters[key]\n\n            if traces:\n                for trace in traces:\n                    await trace.send_connection_queued_end()\n\n        proto = self._get(key)\n        if proto is None:\n            placeholder = cast(ResponseHandler, _TransportPlaceholder())\n            self._acquired.add(placeholder)\n            self._acquired_per_host[key].add(placeholder)\n\n            if traces:\n                for trace in traces:\n                    await trace.send_connection_create_start()\n\n            try:\n                proto = await self._create_connection(req, traces, timeout)\n                if self._closed:\n                    proto.close()\n                    raise ClientConnectionError(\"Connector is closed.\")\n            except BaseException:\n                if not self._closed:\n                    self._acquired.remove(placeholder)\n                    self._drop_acquired_per_host(key, placeholder)\n                    self._release_waiter()\n                raise\n            else:\n                if not self._closed:\n                    self._acquired.remove(placeholder)\n                    self._drop_acquired_per_host(key, placeholder)\n\n            if traces:\n                for trace in traces:\n                    await trace.send_connection_create_end()\n        else:\n            if traces:\n                # Acquire the connection to prevent race conditions with limits\n                placeholder = cast(ResponseHandler, _TransportPlaceholder())\n                self._acquired.add(placeholder)\n                self._acquired_per_host[key].add(placeholder)\n                for trace in traces:\n                    await trace.send_connection_reuseconn()\n                self._acquired.remove(placeholder)\n                self._drop_acquired_per_host(key, placeholder)\n\n        self._acquired.add(proto)\n        self._acquired_per_host[key].add(proto)\n        return Connection(self, key, proto, self._loop)\n\n    def _get(self, key: \"ConnectionKey\") -> Optional[ResponseHandler]:\n        try:\n            conns = self._conns[key]\n        except KeyError:\n            return None\n\n        t1 = self._loop.time()\n        while conns:\n            proto, t0 = conns.pop()\n            if proto.is_connected():\n                if t1 - t0 > self._keepalive_timeout:\n                    transport = proto.transport\n                    proto.close()\n                    # only for SSL transports\n                    if key.is_ssl and not self._cleanup_closed_disabled:\n                        self._cleanup_closed_transports.append(transport)\n                else:\n                    if not conns:\n                        # The very last connection was reclaimed: drop the key\n                        del self._conns[key]\n                    return proto\n            else:\n                transport = proto.transport\n                proto.close()\n                if key.is_ssl and not self._cleanup_closed_disabled:\n                    self._cleanup_closed_transports.append(transport)\n\n        # No more connections: drop the key\n        del self._conns[key]\n        return None\n\n    def _release_waiter(self) -> None:\n        \"\"\"\n        Iterates over all waiters until one to be released is found.\n\n        The one to be released is not finished and\n        belongs to a host that has available connections.\n        \"\"\"\n        if not self._waiters:\n            return\n\n        # Having the dict keys ordered this avoids to iterate\n        # at the same order at each call.\n        queues = list(self._waiters.keys())\n        random.shuffle(queues)\n\n        for key in queues:\n            if self._available_connections(key) < 1:\n                continue\n\n            waiters = self._waiters[key]\n            while waiters:\n                waiter = waiters.popleft()\n                if not waiter.done():\n                    waiter.set_result(None)\n                    return\n\n    def _release_acquired(self, key: \"ConnectionKey\", proto: ResponseHandler) -> None:\n        if self._closed:\n            # acquired connection is already released on connector closing\n            return\n\n        try:\n            self._acquired.remove(proto)\n            self._drop_acquired_per_host(key, proto)\n        except KeyError:  # pragma: no cover\n            # this may be result of undetermenistic order of objects\n            # finalization due garbage collection.\n            pass\n        else:\n            self._release_waiter()\n\n    def _release(\n        self,\n        key: \"ConnectionKey\",\n        protocol: ResponseHandler,\n        *,\n        should_close: bool = False,\n    ) -> None:\n        if self._closed:\n            # acquired connection is already released on connector closing\n            return\n\n        self._release_acquired(key, protocol)\n\n        if self._force_close:\n            should_close = True\n\n        if should_close or protocol.should_close:\n            transport = protocol.transport\n            protocol.close()\n\n            if key.is_ssl and not self._cleanup_closed_disabled:\n                self._cleanup_closed_transports.append(transport)\n        else:\n            conns = self._conns.get(key)\n            if conns is None:\n                conns = self._conns[key] = []\n            conns.append((protocol, self._loop.time()))\n\n            if self._cleanup_handle is None:\n                self._cleanup_handle = helpers.weakref_handle(\n                    self,\n                    \"_cleanup\",\n                    self._keepalive_timeout,\n                    self._loop,\n                    timeout_ceil_threshold=self._timeout_ceil_threshold,\n                )\n\n    async def _create_connection(\n        self, req: ClientRequest, traces: List[\"Trace\"], timeout: \"ClientTimeout\"\n    ) -> ResponseHandler:\n        raise NotImplementedError()\n\n\nclass _DNSCacheTable:\n    def __init__(self, ttl: Optional[float] = None) -> None:\n        self._addrs_rr: Dict[Tuple[str, int], Tuple[Iterator[ResolveResult], int]] = {}\n        self._timestamps: Dict[Tuple[str, int], float] = {}\n        self._ttl = ttl\n\n    def __contains__(self, host: object) -> bool:\n        return host in self._addrs_rr\n\n    def add(self, key: Tuple[str, int], addrs: List[ResolveResult]) -> None:\n        self._addrs_rr[key] = (cycle(addrs), len(addrs))\n\n        if self._ttl is not None:\n            self._timestamps[key] = monotonic()\n\n    def remove(self, key: Tuple[str, int]) -> None:\n        self._addrs_rr.pop(key, None)\n\n        if self._ttl is not None:\n            self._timestamps.pop(key, None)\n\n    def clear(self) -> None:\n        self._addrs_rr.clear()\n        self._timestamps.clear()\n\n    def next_addrs(self, key: Tuple[str, int]) -> List[ResolveResult]:\n        loop, length = self._addrs_rr[key]\n        addrs = list(islice(loop, length))\n        # Consume one more element to shift internal state of `cycle`\n        next(loop)\n        return addrs\n\n    def expired(self, key: Tuple[str, int]) -> bool:\n        if self._ttl is None:\n            return False\n\n        return self._timestamps[key] + self._ttl < monotonic()\n\n\nclass TCPConnector(BaseConnector):\n    \"\"\"TCP connector.\n\n    verify_ssl - Set to True to check ssl certifications.\n    fingerprint - Pass the binary sha256\n        digest of the expected certificate in DER format to verify\n        that the certificate the server presents matches. See also\n        https://en.wikipedia.org/wiki/HTTP_Public_Key_Pinning\n    resolver - Enable DNS lookups and use this\n        resolver\n    use_dns_cache - Use memory cache for DNS lookups.\n    ttl_dns_cache - Max seconds having cached a DNS entry, None forever.\n    family - socket address family\n    local_addr - local tuple of (host, port) to bind socket to\n\n    keepalive_timeout - (optional) Keep-alive timeout.\n    force_close - Set to True to force close and do reconnect\n        after each request (and between redirects).\n    limit - The total number of simultaneous connections.\n    limit_per_host - Number of simultaneous connections to one host.\n    enable_cleanup_closed - Enables clean-up closed ssl transports.\n                            Disabled by default.\n    happy_eyeballs_delay - This is the “Connection Attempt Delay”\n                           as defined in RFC 8305. To disable\n                           the happy eyeballs algorithm, set to None.\n    interleave - “First Address Family Count” as defined in RFC 8305\n    loop - Optional event loop.\n    \"\"\"\n\n    allowed_protocol_schema_set = HIGH_LEVEL_SCHEMA_SET | frozenset({\"tcp\"})\n    _made_ssl_context: Dict[bool, \"asyncio.Future[SSLContext]\"] = {}\n\n    def __init__(\n        self,\n        *,\n        verify_ssl: bool = True,\n        fingerprint: Optional[bytes] = None,\n        use_dns_cache: bool = True,\n        ttl_dns_cache: Optional[int] = 10,\n        family: socket.AddressFamily = socket.AddressFamily.AF_UNSPEC,\n        ssl_context: Optional[SSLContext] = None,\n        ssl: Union[bool, Fingerprint, SSLContext] = True,\n        local_addr: Optional[Tuple[str, int]] = None,\n        resolver: Optional[AbstractResolver] = None,\n        keepalive_timeout: Union[None, float, object] = sentinel,\n        force_close: bool = False,\n        limit: int = 100,\n        limit_per_host: int = 0,\n        enable_cleanup_closed: bool = False,\n        loop: Optional[asyncio.AbstractEventLoop] = None,\n        timeout_ceil_threshold: float = 5,\n        happy_eyeballs_delay: Optional[float] = 0.25,\n        interleave: Optional[int] = None,\n    ):\n        super().__init__(\n            keepalive_timeout=keepalive_timeout,\n            force_close=force_close,\n            limit=limit,\n            limit_per_host=limit_per_host,\n            enable_cleanup_closed=enable_cleanup_closed,\n            loop=loop,\n            timeout_ceil_threshold=timeout_ceil_threshold,\n        )\n\n        self._ssl = _merge_ssl_params(ssl, verify_ssl, ssl_context, fingerprint)\n        if resolver is None:\n            resolver = DefaultResolver(loop=self._loop)\n        self._resolver = resolver\n\n        self._use_dns_cache = use_dns_cache\n        self._cached_hosts = _DNSCacheTable(ttl=ttl_dns_cache)\n        self._throttle_dns_events: Dict[Tuple[str, int], EventResultOrError] = {}\n        self._family = family\n        self._local_addr_infos = aiohappyeyeballs.addr_to_addr_infos(local_addr)\n        self._happy_eyeballs_delay = happy_eyeballs_delay\n        self._interleave = interleave\n        self._resolve_host_tasks: Set[\"asyncio.Task[List[ResolveResult]]\"] = set()\n\n    def close(self) -> Awaitable[None]:\n        \"\"\"Close all ongoing DNS calls.\"\"\"\n        for ev in self._throttle_dns_events.values():\n            ev.cancel()\n\n        for t in self._resolve_host_tasks:\n            t.cancel()\n\n        return super().close()\n\n    @property\n    def family(self) -> int:\n        \"\"\"Socket family like AF_INET.\"\"\"\n        return self._family\n\n    @property\n    def use_dns_cache(self) -> bool:\n        \"\"\"True if local DNS caching is enabled.\"\"\"\n        return self._use_dns_cache\n\n    def clear_dns_cache(\n        self, host: Optional[str] = None, port: Optional[int] = None\n    ) -> None:\n        \"\"\"Remove specified host/port or clear all dns local cache.\"\"\"\n        if host is not None and port is not None:\n            self._cached_hosts.remove((host, port))\n        elif host is not None or port is not None:\n            raise ValueError(\"either both host and port \" \"or none of them are allowed\")\n        else:\n            self._cached_hosts.clear()\n\n    async def _resolve_host(\n        self, host: str, port: int, traces: Optional[Sequence[\"Trace\"]] = None\n    ) -> List[ResolveResult]:\n        \"\"\"Resolve host and return list of addresses.\"\"\"\n        if is_ip_address(host):\n            return [\n                {\n                    \"hostname\": host,\n                    \"host\": host,\n                    \"port\": port,\n                    \"family\": self._family,\n                    \"proto\": 0,\n                    \"flags\": 0,\n                }\n            ]\n\n        if not self._use_dns_cache:\n\n            if traces:\n                for trace in traces:\n                    await trace.send_dns_resolvehost_start(host)\n\n            res = await self._resolver.resolve(host, port, family=self._family)\n\n            if traces:\n                for trace in traces:\n                    await trace.send_dns_resolvehost_end(host)\n\n            return res\n\n        key = (host, port)\n        if key in self._cached_hosts and not self._cached_hosts.expired(key):\n            # get result early, before any await (#4014)\n            result = self._cached_hosts.next_addrs(key)\n\n            if traces:\n                for trace in traces:\n                    await trace.send_dns_cache_hit(host)\n            return result\n\n        #\n        # If multiple connectors are resolving the same host, we wait\n        # for the first one to resolve and then use the result for all of them.\n        # We use a throttle event to ensure that we only resolve the host once\n        # and then use the result for all the waiters.\n        #\n        # In this case we need to create a task to ensure that we can shield\n        # the task from cancellation as cancelling this lookup should not cancel\n        # the underlying lookup or else the cancel event will get broadcast to\n        # all the waiters across all connections.\n        #\n        resolved_host_task = asyncio.create_task(\n            self._resolve_host_with_throttle(key, host, port, traces)\n        )\n        self._resolve_host_tasks.add(resolved_host_task)\n        resolved_host_task.add_done_callback(self._resolve_host_tasks.discard)\n        try:\n            return await asyncio.shield(resolved_host_task)\n        except asyncio.CancelledError:\n\n            def drop_exception(fut: \"asyncio.Future[List[ResolveResult]]\") -> None:\n                with suppress(Exception, asyncio.CancelledError):\n                    fut.result()\n\n            resolved_host_task.add_done_callback(drop_exception)\n            raise\n\n    async def _resolve_host_with_throttle(\n        self,\n        key: Tuple[str, int],\n        host: str,\n        port: int,\n        traces: Optional[Sequence[\"Trace\"]],\n    ) -> List[ResolveResult]:\n        \"\"\"Resolve host with a dns events throttle.\"\"\"\n        if key in self._throttle_dns_events:\n            # get event early, before any await (#4014)\n            event = self._throttle_dns_events[key]\n            if traces:\n                for trace in traces:\n                    await trace.send_dns_cache_hit(host)\n            await event.wait()\n        else:\n            # update dict early, before any await (#4014)\n            self._throttle_dns_events[key] = EventResultOrError(self._loop)\n            if traces:\n                for trace in traces:\n                    await trace.send_dns_cache_miss(host)\n            try:\n\n                if traces:\n                    for trace in traces:\n                        await trace.send_dns_resolvehost_start(host)\n\n                addrs = await self._resolver.resolve(host, port, family=self._family)\n                if traces:\n                    for trace in traces:\n                        await trace.send_dns_resolvehost_end(host)\n\n                self._cached_hosts.add(key, addrs)\n                self._throttle_dns_events[key].set()\n            except BaseException as e:\n                # any DNS exception, independently of the implementation\n                # is set for the waiters to raise the same exception.\n                self._throttle_dns_events[key].set(exc=e)\n                raise\n            finally:\n                self._throttle_dns_events.pop(key)\n\n        return self._cached_hosts.next_addrs(key)\n\n    async def _create_connection(\n        self, req: ClientRequest, traces: List[\"Trace\"], timeout: \"ClientTimeout\"\n    ) -> ResponseHandler:\n        \"\"\"Create connection.\n\n        Has same keyword arguments as BaseEventLoop.create_connection.\n        \"\"\"\n        if req.proxy:\n            _, proto = await self._create_proxy_connection(req, traces, timeout)\n        else:\n            _, proto = await self._create_direct_connection(req, traces, timeout)\n\n        return proto\n\n    @staticmethod\n    def _make_ssl_context(verified: bool) -> SSLContext:\n        \"\"\"Create SSL context.\n\n        This method is not async-friendly and should be called from a thread\n        because it will load certificates from disk and do other blocking I/O.\n        \"\"\"\n        if verified:\n            return ssl.create_default_context()\n        sslcontext = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)\n        sslcontext.options |= ssl.OP_NO_SSLv2\n        sslcontext.options |= ssl.OP_NO_SSLv3\n        sslcontext.check_hostname = False\n        sslcontext.verify_mode = ssl.CERT_NONE\n        sslcontext.options |= ssl.OP_NO_COMPRESSION\n        sslcontext.set_default_verify_paths()\n        return sslcontext\n\n    async def _get_ssl_context(self, req: ClientRequest) -> Optional[SSLContext]:\n        \"\"\"Logic to get the correct SSL context\n\n        0. if req.ssl is false, return None\n\n        1. if ssl_context is specified in req, use it\n        2. if _ssl_context is specified in self, use it\n        3. otherwise:\n            1. if verify_ssl is not specified in req, use self.ssl_context\n               (will generate a default context according to self.verify_ssl)\n            2. if verify_ssl is True in req, generate a default SSL context\n            3. if verify_ssl is False in req, generate a SSL context that\n               won't verify\n        \"\"\"\n        if not req.is_ssl():\n            return None\n\n        if ssl is None:  # pragma: no cover\n            raise RuntimeError(\"SSL is not supported.\")\n        sslcontext = req.ssl\n        if isinstance(sslcontext, ssl.SSLContext):\n            return sslcontext\n        if sslcontext is not True:\n            # not verified or fingerprinted\n            return await self._make_or_get_ssl_context(False)\n        sslcontext = self._ssl\n        if isinstance(sslcontext, ssl.SSLContext):\n            return sslcontext\n        if sslcontext is not True:\n            # not verified or fingerprinted\n            return await self._make_or_get_ssl_context(False)\n        return await self._make_or_get_ssl_context(True)\n\n    async def _make_or_get_ssl_context(self, verified: bool) -> SSLContext:\n        \"\"\"Create or get cached SSL context.\"\"\"\n        try:\n            return await self._made_ssl_context[verified]\n        except KeyError:\n            loop = self._loop\n            future = loop.create_future()\n            self._made_ssl_context[verified] = future\n            try:\n                result = await loop.run_in_executor(\n                    None, self._make_ssl_context, verified\n                )\n            # BaseException is used since we might get CancelledError\n            except BaseException as ex:\n                del self._made_ssl_context[verified]\n                set_exception(future, ex)\n                raise\n            else:\n                set_result(future, result)\n            return result\n\n    def _get_fingerprint(self, req: ClientRequest) -> Optional[\"Fingerprint\"]:\n        ret = req.ssl\n        if isinstance(ret, Fingerprint):\n            return ret\n        ret = self._ssl\n        if isinstance(ret, Fingerprint):\n            return ret\n        return None\n\n    async def _wrap_create_connection(\n        self,\n        *args: Any,\n        addr_infos: List[aiohappyeyeballs.AddrInfoType],\n        req: ClientRequest,\n        timeout: \"ClientTimeout\",\n        client_error: Type[Exception] = ClientConnectorError,\n        **kwargs: Any,\n    ) -> Tuple[asyncio.Transport, ResponseHandler]:\n        try:\n            async with ceil_timeout(\n                timeout.sock_connect, ceil_threshold=timeout.ceil_threshold\n            ):\n                sock = await aiohappyeyeballs.start_connection(\n                    addr_infos=addr_infos,\n                    local_addr_infos=self._local_addr_infos,\n                    happy_eyeballs_delay=self._happy_eyeballs_delay,\n                    interleave=self._interleave,\n                    loop=self._loop,\n                )\n                return await self._loop.create_connection(*args, **kwargs, sock=sock)\n        except cert_errors as exc:\n            raise ClientConnectorCertificateError(req.connection_key, exc) from exc\n        except ssl_errors as exc:\n            raise ClientConnectorSSLError(req.connection_key, exc) from exc\n        except OSError as exc:\n            if exc.errno is None and isinstance(exc, asyncio.TimeoutError):\n                raise\n            raise client_error(req.connection_key, exc) from exc\n\n    async def _wrap_existing_connection(\n        self,\n        *args: Any,\n        req: ClientRequest,\n        timeout: \"ClientTimeout\",\n        client_error: Type[Exception] = ClientConnectorError,\n        **kwargs: Any,\n    ) -> Tuple[asyncio.Transport, ResponseHandler]:\n        try:\n            async with ceil_timeout(\n                timeout.sock_connect, ceil_threshold=timeout.ceil_threshold\n            ):\n                return await self._loop.create_connection(*args, **kwargs)\n        except cert_errors as exc:\n            raise ClientConnectorCertificateError(req.connection_key, exc) from exc\n        except ssl_errors as exc:\n            raise ClientConnectorSSLError(req.connection_key, exc) from exc\n        except OSError as exc:\n            if exc.errno is None and isinstance(exc, asyncio.TimeoutError):\n                raise\n            raise client_error(req.connection_key, exc) from exc\n\n    def _fail_on_no_start_tls(self, req: \"ClientRequest\") -> None:\n        \"\"\"Raise a :py:exc:`RuntimeError` on missing ``start_tls()``.\n\n        It is necessary for TLS-in-TLS so that it is possible to\n        send HTTPS queries through HTTPS proxies.\n\n        This doesn't affect regular HTTP requests, though.\n        \"\"\"\n        if not req.is_ssl():\n            return\n\n        proxy_url = req.proxy\n        assert proxy_url is not None\n        if proxy_url.scheme != \"https\":\n            return\n\n        self._check_loop_for_start_tls()\n\n    def _check_loop_for_start_tls(self) -> None:\n        try:\n            self._loop.start_tls\n        except AttributeError as attr_exc:\n            raise RuntimeError(\n                \"An HTTPS request is being sent through an HTTPS proxy. \"\n                \"This needs support for TLS in TLS but it is not implemented \"\n                \"in your runtime for the stdlib asyncio.\\n\\n\"\n                \"Please upgrade to Python 3.11 or higher. For more details, \"\n                \"please see:\\n\"\n                \"* https://bugs.python.org/issue37179\\n\"\n                \"* https://github.com/python/cpython/pull/28073\\n\"\n                \"* https://docs.aiohttp.org/en/stable/\"\n                \"client_advanced.html#proxy-support\\n\"\n                \"* https://github.com/aio-libs/aiohttp/discussions/6044\\n\",\n            ) from attr_exc\n\n    def _loop_supports_start_tls(self) -> bool:\n        try:\n            self._check_loop_for_start_tls()\n        except RuntimeError:\n            return False\n        else:\n            return True\n\n    def _warn_about_tls_in_tls(\n        self,\n        underlying_transport: asyncio.Transport,\n        req: ClientRequest,\n    ) -> None:\n        \"\"\"Issue a warning if the requested URL has HTTPS scheme.\"\"\"\n        if req.request_info.url.scheme != \"https\":\n            return\n\n        asyncio_supports_tls_in_tls = getattr(\n            underlying_transport,\n            \"_start_tls_compatible\",\n            False,\n        )\n\n        if asyncio_supports_tls_in_tls:\n            return\n\n        warnings.warn(\n            \"An HTTPS request is being sent through an HTTPS proxy. \"\n            \"This support for TLS in TLS is known to be disabled \"\n            \"in the stdlib asyncio (Python <3.11). This is why you'll probably see \"\n            \"an error in the log below.\\n\\n\"\n            \"It is possible to enable it via monkeypatching. \"\n            \"For more details, see:\\n\"\n            \"* https://bugs.python.org/issue37179\\n\"\n            \"* https://github.com/python/cpython/pull/28073\\n\\n\"\n            \"You can temporarily patch this as follows:\\n\"\n            \"* https://docs.aiohttp.org/en/stable/client_advanced.html#proxy-support\\n\"\n            \"* https://github.com/aio-libs/aiohttp/discussions/6044\\n\",\n            RuntimeWarning,\n            source=self,\n            # Why `4`? At least 3 of the calls in the stack originate\n            # from the methods in this class.\n            stacklevel=3,\n        )\n\n    async def _start_tls_connection(\n        self,\n        underlying_transport: asyncio.Transport,\n        req: ClientRequest,\n        timeout: \"ClientTimeout\",\n        client_error: Type[Exception] = ClientConnectorError,\n    ) -> Tuple[asyncio.BaseTransport, ResponseHandler]:\n        \"\"\"Wrap the raw TCP transport with TLS.\"\"\"\n        tls_proto = self._factory()  # Create a brand new proto for TLS\n\n        # Safety of the `cast()` call here is based on the fact that\n        # internally `_get_ssl_context()` only returns `None` when\n        # `req.is_ssl()` evaluates to `False` which is never gonna happen\n        # in this code path. Of course, it's rather fragile\n        # maintainability-wise but this is to be solved separately.\n        sslcontext = cast(ssl.SSLContext, await self._get_ssl_context(req))\n\n        try:\n            async with ceil_timeout(\n                timeout.sock_connect, ceil_threshold=timeout.ceil_threshold\n            ):\n                try:\n                    tls_transport = await self._loop.start_tls(\n                        underlying_transport,\n                        tls_proto,\n                        sslcontext,\n                        server_hostname=req.server_hostname or req.host,\n                        ssl_handshake_timeout=timeout.total,\n                    )\n                except BaseException:\n                    # We need to close the underlying transport since\n                    # `start_tls()` probably failed before it had a\n                    # chance to do this:\n                    underlying_transport.close()\n                    raise\n        except cert_errors as exc:\n            raise ClientConnectorCertificateError(req.connection_key, exc) from exc\n        except ssl_errors as exc:\n            raise ClientConnectorSSLError(req.connection_key, exc) from exc\n        except OSError as exc:\n            if exc.errno is None and isinstance(exc, asyncio.TimeoutError):\n                raise\n            raise client_error(req.connection_key, exc) from exc\n        except TypeError as type_err:\n            # Example cause looks like this:\n            # TypeError: transport <asyncio.sslproto._SSLProtocolTransport\n            # object at 0x7f760615e460> is not supported by start_tls()\n\n            raise ClientConnectionError(\n                \"Cannot initialize a TLS-in-TLS connection to host \"\n                f\"{req.host!s}:{req.port:d} through an underlying connection \"\n                f\"to an HTTPS proxy {req.proxy!s} ssl:{req.ssl or 'default'} \"\n                f\"[{type_err!s}]\"\n            ) from type_err\n        else:\n            if tls_transport is None:\n                msg = \"Failed to start TLS (possibly caused by closing transport)\"\n                raise client_error(req.connection_key, OSError(msg))\n            tls_proto.connection_made(\n                tls_transport\n            )  # Kick the state machine of the new TLS protocol\n\n        return tls_transport, tls_proto\n\n    def _convert_hosts_to_addr_infos(\n        self, hosts: List[ResolveResult]\n    ) -> List[aiohappyeyeballs.AddrInfoType]:\n        \"\"\"Converts the list of hosts to a list of addr_infos.\n\n        The list of hosts is the result of a DNS lookup. The list of\n        addr_infos is the result of a call to `socket.getaddrinfo()`.\n        \"\"\"\n        addr_infos: List[aiohappyeyeballs.AddrInfoType] = []\n        for hinfo in hosts:\n            host = hinfo[\"host\"]\n            is_ipv6 = \":\" in host\n            family = socket.AF_INET6 if is_ipv6 else socket.AF_INET\n            if self._family and self._family != family:\n                continue\n            addr = (host, hinfo[\"port\"], 0, 0) if is_ipv6 else (host, hinfo[\"port\"])\n            addr_infos.append(\n                (family, socket.SOCK_STREAM, socket.IPPROTO_TCP, \"\", addr)\n            )\n        return addr_infos\n\n    async def _create_direct_connection(\n        self,\n        req: ClientRequest,\n        traces: List[\"Trace\"],\n        timeout: \"ClientTimeout\",\n        *,\n        client_error: Type[Exception] = ClientConnectorError,\n    ) -> Tuple[asyncio.Transport, ResponseHandler]:\n        sslcontext = await self._get_ssl_context(req)\n        fingerprint = self._get_fingerprint(req)\n\n        host = req.url.raw_host\n        assert host is not None\n        # Replace multiple trailing dots with a single one.\n        # A trailing dot is only present for fully-qualified domain names.\n        # See https://github.com/aio-libs/aiohttp/pull/7364.\n        if host.endswith(\"..\"):\n            host = host.rstrip(\".\") + \".\"\n        port = req.port\n        assert port is not None\n        try:\n            # Cancelling this lookup should not cancel the underlying lookup\n            #  or else the cancel event will get broadcast to all the waiters\n            #  across all connections.\n            hosts = await self._resolve_host(host, port, traces=traces)\n        except OSError as exc:\n            if exc.errno is None and isinstance(exc, asyncio.TimeoutError):\n                raise\n            # in case of proxy it is not ClientProxyConnectionError\n            # it is problem of resolving proxy ip itself\n            raise ClientConnectorError(req.connection_key, exc) from exc\n\n        last_exc: Optional[Exception] = None\n        addr_infos = self._convert_hosts_to_addr_infos(hosts)\n        while addr_infos:\n            # Strip trailing dots, certificates contain FQDN without dots.\n            # See https://github.com/aio-libs/aiohttp/issues/3636\n            server_hostname = (\n                (req.server_hostname or host).rstrip(\".\") if sslcontext else None\n            )\n\n            try:\n                transp, proto = await self._wrap_create_connection(\n                    self._factory,\n                    timeout=timeout,\n                    ssl=sslcontext,\n                    addr_infos=addr_infos,\n                    server_hostname=server_hostname,\n                    req=req,\n                    client_error=client_error,\n                )\n            except ClientConnectorError as exc:\n                last_exc = exc\n                aiohappyeyeballs.pop_addr_infos_interleave(addr_infos, self._interleave)\n                continue\n\n            if req.is_ssl() and fingerprint:\n                try:\n                    fingerprint.check(transp)\n                except ServerFingerprintMismatch as exc:\n                    transp.close()\n                    if not self._cleanup_closed_disabled:\n                        self._cleanup_closed_transports.append(transp)\n                    last_exc = exc\n                    # Remove the bad peer from the list of addr_infos\n                    sock: socket.socket = transp.get_extra_info(\"socket\")\n                    bad_peer = sock.getpeername()\n                    aiohappyeyeballs.remove_addr_infos(addr_infos, bad_peer)\n                    continue\n\n            return transp, proto\n        else:\n            assert last_exc is not None\n            raise last_exc\n\n    async def _create_proxy_connection(\n        self, req: ClientRequest, traces: List[\"Trace\"], timeout: \"ClientTimeout\"\n    ) -> Tuple[asyncio.BaseTransport, ResponseHandler]:\n        self._fail_on_no_start_tls(req)\n        runtime_has_start_tls = self._loop_supports_start_tls()\n\n        headers: Dict[str, str] = {}\n        if req.proxy_headers is not None:\n            headers = req.proxy_headers  # type: ignore[assignment]\n        headers[hdrs.HOST] = req.headers[hdrs.HOST]\n\n        url = req.proxy\n        assert url is not None\n        proxy_req = ClientRequest(\n            hdrs.METH_GET,\n            url,\n            headers=headers,\n            auth=req.proxy_auth,\n            loop=self._loop,\n            ssl=req.ssl,\n        )\n\n        # create connection to proxy server\n        transport, proto = await self._create_direct_connection(\n            proxy_req, [], timeout, client_error=ClientProxyConnectionError\n        )\n\n        auth = proxy_req.headers.pop(hdrs.AUTHORIZATION, None)\n        if auth is not None:\n            if not req.is_ssl():\n                req.headers[hdrs.PROXY_AUTHORIZATION] = auth\n            else:\n                proxy_req.headers[hdrs.PROXY_AUTHORIZATION] = auth\n\n        if req.is_ssl():\n            if runtime_has_start_tls:\n                self._warn_about_tls_in_tls(transport, req)\n\n            # For HTTPS requests over HTTP proxy\n            # we must notify proxy to tunnel connection\n            # so we send CONNECT command:\n            #   CONNECT www.python.org:443 HTTP/1.1\n            #   Host: www.python.org\n            #\n            # next we must do TLS handshake and so on\n            # to do this we must wrap raw socket into secure one\n            # asyncio handles this perfectly\n            proxy_req.method = hdrs.METH_CONNECT\n            proxy_req.url = req.url\n            key = attr.evolve(\n                req.connection_key, proxy=None, proxy_auth=None, proxy_headers_hash=None\n            )\n            conn = Connection(self, key, proto, self._loop)\n            proxy_resp = await proxy_req.send(conn)\n            try:\n                protocol = conn._protocol\n                assert protocol is not None\n\n                # read_until_eof=True will ensure the connection isn't closed\n                # once the response is received and processed allowing\n                # START_TLS to work on the connection below.\n                protocol.set_response_params(\n                    read_until_eof=runtime_has_start_tls,\n                    timeout_ceil_threshold=self._timeout_ceil_threshold,\n                )\n                resp = await proxy_resp.start(conn)\n            except BaseException:\n                proxy_resp.close()\n                conn.close()\n                raise\n            else:\n                conn._protocol = None\n                conn._transport = None\n                try:\n                    if resp.status != 200:\n                        message = resp.reason\n                        if message is None:\n                            message = HTTPStatus(resp.status).phrase\n                        raise ClientHttpProxyError(\n                            proxy_resp.request_info,\n                            resp.history,\n                            status=resp.status,\n                            message=message,\n                            headers=resp.headers,\n                        )\n                    if not runtime_has_start_tls:\n                        rawsock = transport.get_extra_info(\"socket\", default=None)\n                        if rawsock is None:\n                            raise RuntimeError(\n                                \"Transport does not expose socket instance\"\n                            )\n                        # Duplicate the socket, so now we can close proxy transport\n                        rawsock = rawsock.dup()\n                except BaseException:\n                    # It shouldn't be closed in `finally` because it's fed to\n                    # `loop.start_tls()` and the docs say not to touch it after\n                    # passing there.\n                    transport.close()\n                    raise\n                finally:\n                    if not runtime_has_start_tls:\n                        transport.close()\n\n                if not runtime_has_start_tls:\n                    # HTTP proxy with support for upgrade to HTTPS\n                    sslcontext = self._get_ssl_context(req)\n                    return await self._wrap_existing_connection(\n                        self._factory,\n                        timeout=timeout,\n                        ssl=sslcontext,\n                        sock=rawsock,\n                        server_hostname=req.host,\n                        req=req,\n                    )\n\n                return await self._start_tls_connection(\n                    # Access the old transport for the last time before it's\n                    # closed and forgotten forever:\n                    transport,\n                    req=req,\n                    timeout=timeout,\n                )\n            finally:\n                proxy_resp.close()\n\n        return transport, proto\n\n\nclass UnixConnector(BaseConnector):\n    \"\"\"Unix socket connector.\n\n    path - Unix socket path.\n    keepalive_timeout - (optional) Keep-alive timeout.\n    force_close - Set to True to force close and do reconnect\n        after each request (and between redirects).\n    limit - The total number of simultaneous connections.\n    limit_per_host - Number of simultaneous connections to one host.\n    loop - Optional event loop.\n    \"\"\"\n\n    allowed_protocol_schema_set = HIGH_LEVEL_SCHEMA_SET | frozenset({\"unix\"})\n\n    def __init__(\n        self,\n        path: str,\n        force_close: bool = False,\n        keepalive_timeout: Union[object, float, None] = sentinel,\n        limit: int = 100,\n        limit_per_host: int = 0,\n        loop: Optional[asyncio.AbstractEventLoop] = None,\n    ) -> None:\n        super().__init__(\n            force_close=force_close,\n            keepalive_timeout=keepalive_timeout,\n            limit=limit,\n            limit_per_host=limit_per_host,\n            loop=loop,\n        )\n        self._path = path\n\n    @property\n    def path(self) -> str:\n        \"\"\"Path to unix socket.\"\"\"\n        return self._path\n\n    async def _create_connection(\n        self, req: ClientRequest, traces: List[\"Trace\"], timeout: \"ClientTimeout\"\n    ) -> ResponseHandler:\n        try:\n            async with ceil_timeout(\n                timeout.sock_connect, ceil_threshold=timeout.ceil_threshold\n            ):\n                _, proto = await self._loop.create_unix_connection(\n                    self._factory, self._path\n                )\n        except OSError as exc:\n            if exc.errno is None and isinstance(exc, asyncio.TimeoutError):\n                raise\n            raise UnixClientConnectorError(self.path, req.connection_key, exc) from exc\n\n        return proto\n\n\nclass NamedPipeConnector(BaseConnector):\n    \"\"\"Named pipe connector.\n\n    Only supported by the proactor event loop.\n    See also: https://docs.python.org/3/library/asyncio-eventloop.html\n\n    path - Windows named pipe path.\n    keepalive_timeout - (optional) Keep-alive timeout.\n    force_close - Set to True to force close and do reconnect\n        after each request (and between redirects).\n    limit - The total number of simultaneous connections.\n    limit_per_host - Number of simultaneous connections to one host.\n    loop - Optional event loop.\n    \"\"\"\n\n    allowed_protocol_schema_set = HIGH_LEVEL_SCHEMA_SET | frozenset({\"npipe\"})\n\n    def __init__(\n        self,\n        path: str,\n        force_close: bool = False,\n        keepalive_timeout: Union[object, float, None] = sentinel,\n        limit: int = 100,\n        limit_per_host: int = 0,\n        loop: Optional[asyncio.AbstractEventLoop] = None,\n    ) -> None:\n        super().__init__(\n            force_close=force_close,\n            keepalive_timeout=keepalive_timeout,\n            limit=limit,\n            limit_per_host=limit_per_host,\n            loop=loop,\n        )\n        if not isinstance(\n            self._loop, asyncio.ProactorEventLoop  # type: ignore[attr-defined]\n        ):\n            raise RuntimeError(\n                \"Named Pipes only available in proactor \" \"loop under windows\"\n            )\n        self._path = path\n\n    @property\n    def path(self) -> str:\n        \"\"\"Path to the named pipe.\"\"\"\n        return self._path\n\n    async def _create_connection(\n        self, req: ClientRequest, traces: List[\"Trace\"], timeout: \"ClientTimeout\"\n    ) -> ResponseHandler:\n        try:\n            async with ceil_timeout(\n                timeout.sock_connect, ceil_threshold=timeout.ceil_threshold\n            ):\n                _, proto = await self._loop.create_pipe_connection(  # type: ignore[attr-defined]\n                    self._factory, self._path\n                )\n                # the drain is required so that the connection_made is called\n                # and transport is set otherwise it is not set before the\n                # `assert conn.transport is not None`\n                # in client.py's _request method\n                await asyncio.sleep(0)\n                # other option is to manually set transport like\n                # `proto.transport = trans`\n        except OSError as exc:\n            if exc.errno is None and isinstance(exc, asyncio.TimeoutError):\n                raise\n            raise ClientConnectorError(req.connection_key, exc) from exc\n\n        return cast(ResponseHandler, proto)\n",
            "header": {
                "file": {
                    "path": "aiohttp/connector.py"
                },
                "misc_line": null
            },
            "index_line": {
                "old_commit_hash": "91174e31",
                "new_commit_hash": "93c78c62",
                "mode": "100644"
            },
            "is_binary_file": false,
            "binary_line": null,
            "minus_file": {
                "path": "a/aiohttp/connector.py"
            },
            "plus_file": {
                "path": "b/aiohttp/connector.py"
            },
            "hunks": [
                {
                    "descriptor": {
                        "old_range": {
                            "start": 824,
                            "length": 12
                        },
                        "new_range": {
                            "start": 824,
                            "length": 16
                        },
                        "section": "class TCPConnector(BaseConnector):"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "        self._local_addr_infos = aiohappyeyeballs.addr_to_addr_infos(local_addr)",
                                "type": "context"
                            },
                            {
                                "content": "        self._happy_eyeballs_delay = happy_eyeballs_delay",
                                "type": "context"
                            },
                            {
                                "content": "        self._interleave = interleave",
                                "type": "context"
                            },
                            {
                                "content": "        self._resolve_host_tasks: Set[\"asyncio.Task[List[ResolveResult]]\"] = set()",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "    def close(self) -> Awaitable[None]:",
                                "type": "context"
                            },
                            {
                                "content": "        \"\"\"Close all ongoing DNS calls.\"\"\"",
                                "type": "context"
                            },
                            {
                                "content": "        for ev in self._throttle_dns_events.values():",
                                "type": "context"
                            },
                            {
                                "content": "            ev.cancel()",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "        for t in self._resolve_host_tasks:",
                                "type": "added"
                            },
                            {
                                "content": "            t.cancel()",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "        return super().close()",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "    @property",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [
                        {
                            "file_name": "aiohttp/connector.py",
                            "type": "method",
                            "name": "TCPConnector.__init__",
                            "content": "class TCPConnector(BaseConnector):\n    \"\"\"TCP connector.\n\n    verify_ssl - Set to True to check ssl certifications.\n    fingerprint - Pass the binary sha256\n        digest of the expected certificate in DER format to verify\n        that the certificate the server presents matches. See also\n        https://en.wikipedia.org/wiki/HTTP_Public_Key_Pinning\n    resolver - Enable DNS lookups and use this\n        resolver\n    use_dns_cache - Use memory cache for DNS lookups.\n    ttl_dns_cache - Max seconds having cached a DNS entry, None forever.\n    family - socket address family\n    local_addr - local tuple of (host, port) to bind socket to\n\n    keepalive_timeout - (optional) Keep-alive timeout.\n    force_close - Set to True to force close and do reconnect\n        after each request (and between redirects).\n    limit - The total number of simultaneous connections.\n    limit_per_host - Number of simultaneous connections to one host.\n    enable_cleanup_closed - Enables clean-up closed ssl transports.\n                            Disabled by default.\n    happy_eyeballs_delay - This is the “Connection Attempt Delay”\n                           as defined in RFC 8305. To disable\n                           the happy eyeballs algorithm, set to None.\n    interleave - “First Address Family Count” as defined in RFC 8305\n    loop - Optional event loop.\n    \"\"\"\n\n    allowed_protocol_schema_set = HIGH_LEVEL_SCHEMA_SET | frozenset({\"tcp\"})\n    _made_ssl_context: Dict[bool, \"asyncio.Future[SSLContext]\"] = {}\n\n    def __init__(\n        self,\n        *,\n        verify_ssl: bool = True,\n        fingerprint: Optional[bytes] = None,\n        use_dns_cache: bool = True,\n        ttl_dns_cache: Optional[int] = 10,\n        family: socket.AddressFamily = socket.AddressFamily.AF_UNSPEC,\n        ssl_context: Optional[SSLContext] = None,\n        ssl: Union[bool, Fingerprint, SSLContext] = True,\n        local_addr: Optional[Tuple[str, int]] = None,\n        resolver: Optional[AbstractResolver] = None,\n        keepalive_timeout: Union[None, float, object] = sentinel,\n        force_close: bool = False,\n        limit: int = 100,\n        limit_per_host: int = 0,\n        enable_cleanup_closed: bool = False,\n        loop: Optional[asyncio.AbstractEventLoop] = None,\n        timeout_ceil_threshold: float = 5,\n        happy_eyeballs_delay: Optional[float] = 0.25,\n        interleave: Optional[int] = None,\n    ):\n        super().__init__(\n            keepalive_timeout=keepalive_timeout,\n            force_close=force_close,\n            limit=limit,\n            limit_per_host=limit_per_host,\n            enable_cleanup_closed=enable_cleanup_closed,\n            loop=loop,\n            timeout_ceil_threshold=timeout_ceil_threshold,\n        )\n\n        self._ssl = _merge_ssl_params(ssl, verify_ssl, ssl_context, fingerprint)\n        if resolver is None:\n            resolver = DefaultResolver(loop=self._loop)\n        self._resolver = resolver\n\n        self._use_dns_cache = use_dns_cache\n        self._cached_hosts = _DNSCacheTable(ttl=ttl_dns_cache)\n        self._throttle_dns_events: Dict[Tuple[str, int], EventResultOrError] = {}\n        self._family = family\n        self._local_addr_infos = aiohappyeyeballs.addr_to_addr_infos(local_addr)\n        self._happy_eyeballs_delay = happy_eyeballs_delay\n        self._interleave = interleave\n        self._resolve_host_tasks: Set[\"asyncio.Task[List[ResolveResult]]\"] = set()\n\n    def close(self) -> Awaitable[None]:\n        \"\"\"Close all ongoing DNS calls.\"\"\"\n        for ev in self._throttle_dns_events.values():\n            ev.cancel()\n\n        for t in self._resolve_host_tasks:\n            t.cancel()\n\n        return super().close()\n\n    @property\n    def family(self) -> int:\n        \"\"\"Socket family like AF_INET.\"\"\"\n        return self._family\n\n    @property\n    def use_dns_cache(self) -> bool:\n        \"\"\"True if local DNS caching is enabled.\"\"\"\n        return self._use_dns_cache\n\n    def clear_dns_cache(\n        self, host: Optional[str] = None, port: Optional[int] = None\n    ) -> None:\n        \"\"\"Remove specified host/port or clear all dns local cache.\"\"\"\n        if host is not None and port is not None:\n            self._cached_hosts.remove((host, port))\n        elif host is not None or port is not None:\n            raise ValueError(\"either both host and port \" \"or none of them are allowed\")\n        else:\n            self._cached_hosts.clear()\n\n    async def _resolve_host(\n        self, host: str, port: int, traces: Optional[Sequence[\"Trace\"]] = None\n    ) -> List[ResolveResult]:\n        \"\"\"Resolve host and return list of addresses.\"\"\"\n        if is_ip_address(host):\n            return [\n                {\n                    \"hostname\": host,\n                    \"host\": host,\n                    \"port\": port,\n                    \"family\": self._family,\n                    \"proto\": 0,\n                    \"flags\": 0,\n                }\n            ]\n\n        if not self._use_dns_cache:\n\n            if traces:\n                for trace in traces:\n                    await trace.send_dns_resolvehost_start(host)\n\n            res = await self._resolver.resolve(host, port, family=self._family)\n\n            if traces:\n                for trace in traces:\n                    await trace.send_dns_resolvehost_end(host)\n\n            return res\n\n        key = (host, port)\n        if key in self._cached_hosts and not self._cached_hosts.expired(key):\n            # get result early, before any await (#4014)\n            result = self._cached_hosts.next_addrs(key)\n\n            if traces:\n                for trace in traces:\n                    await trace.send_dns_cache_hit(host)\n            return result\n\n        #\n        # If multiple connectors are resolving the same host, we wait\n        # for the first one to resolve and then use the result for all of them.\n        # We use a throttle event to ensure that we only resolve the host once\n        # and then use the result for all the waiters.\n        #\n        # In this case we need to create a task to ensure that we can shield\n        # the task from cancellation as cancelling this lookup should not cancel\n        # the underlying lookup or else the cancel event will get broadcast to\n        # all the waiters across all connections.\n        #\n        resolved_host_task = asyncio.create_task(\n            self._resolve_host_with_throttle(key, host, port, traces)\n        )\n        self._resolve_host_tasks.add(resolved_host_task)\n        resolved_host_task.add_done_callback(self._resolve_host_tasks.discard)\n        try:\n            return await asyncio.shield(resolved_host_task)\n        except asyncio.CancelledError:\n\n            def drop_exception(fut: \"asyncio.Future[List[ResolveResult]]\") -> None:\n                with suppress(Exception, asyncio.CancelledError):\n                    fut.result()\n\n            resolved_host_task.add_done_callback(drop_exception)\n            raise\n\n    async def _resolve_host_with_throttle(\n        self,\n        key: Tuple[str, int],\n        host: str,\n        port: int,\n        traces: Optional[Sequence[\"Trace\"]],\n    ) -> List[ResolveResult]:\n        \"\"\"Resolve host with a dns events throttle.\"\"\"\n        if key in self._throttle_dns_events:\n            # get event early, before any await (#4014)\n            event = self._throttle_dns_events[key]\n            if traces:\n                for trace in traces:\n                    await trace.send_dns_cache_hit(host)\n            await event.wait()\n        else:\n            # update dict early, before any await (#4014)\n            self._throttle_dns_events[key] = EventResultOrError(self._loop)\n            if traces:\n                for trace in traces:\n                    await trace.send_dns_cache_miss(host)\n            try:\n\n                if traces:\n                    for trace in traces:\n                        await trace.send_dns_resolvehost_start(host)\n\n                addrs = await self._resolver.resolve(host, port, family=self._family)\n                if traces:\n                    for trace in traces:\n                        await trace.send_dns_resolvehost_end(host)\n\n                self._cached_hosts.add(key, addrs)\n                self._throttle_dns_events[key].set()\n            except BaseException as e:\n                # any DNS exception, independently of the implementation\n                # is set for the waiters to raise the same exception.\n                self._throttle_dns_events[key].set(exc=e)\n                raise\n            finally:\n                self._throttle_dns_events.pop(key)\n\n        return self._cached_hosts.next_addrs(key)\n\n    async def _create_connection(\n        self, req: ClientRequest, traces: List[\"Trace\"], timeout: \"ClientTimeout\"\n    ) -> ResponseHandler:\n        \"\"\"Create connection.\n\n        Has same keyword arguments as BaseEventLoop.create_connection.\n        \"\"\"\n        if req.proxy:\n            _, proto = await self._create_proxy_connection(req, traces, timeout)\n        else:\n            _, proto = await self._create_direct_connection(req, traces, timeout)\n\n        return proto\n\n    @staticmethod\n    def _make_ssl_context(verified: bool) -> SSLContext:\n        \"\"\"Create SSL context.\n\n        This method is not async-friendly and should be called from a thread\n        because it will load certificates from disk and do other blocking I/O.\n        \"\"\"\n        if verified:\n            return ssl.create_default_context()\n        sslcontext = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)\n        sslcontext.options |= ssl.OP_NO_SSLv2\n        sslcontext.options |= ssl.OP_NO_SSLv3\n        sslcontext.check_hostname = False\n        sslcontext.verify_mode = ssl.CERT_NONE\n        sslcontext.options |= ssl.OP_NO_COMPRESSION\n        sslcontext.set_default_verify_paths()\n        return sslcontext\n\n    async def _get_ssl_context(self, req: ClientRequest) -> Optional[SSLContext]:\n        \"\"\"Logic to get the correct SSL context\n\n        0. if req.ssl is false, return None\n\n        1. if ssl_context is specified in req, use it\n        2. if _ssl_context is specified in self, use it\n        3. otherwise:\n            1. if verify_ssl is not specified in req, use self.ssl_context\n               (will generate a default context according to self.verify_ssl)\n            2. if verify_ssl is True in req, generate a default SSL context\n            3. if verify_ssl is False in req, generate a SSL context that\n               won't verify\n        \"\"\"\n        if not req.is_ssl():\n            return None\n\n        if ssl is None:  # pragma: no cover\n            raise RuntimeError(\"SSL is not supported.\")\n        sslcontext = req.ssl\n        if isinstance(sslcontext, ssl.SSLContext):\n            return sslcontext\n        if sslcontext is not True:\n            # not verified or fingerprinted\n            return await self._make_or_get_ssl_context(False)\n        sslcontext = self._ssl\n        if isinstance(sslcontext, ssl.SSLContext):\n            return sslcontext\n        if sslcontext is not True:\n            # not verified or fingerprinted\n            return await self._make_or_get_ssl_context(False)\n        return await self._make_or_get_ssl_context(True)\n\n    async def _make_or_get_ssl_context(self, verified: bool) -> SSLContext:\n        \"\"\"Create or get cached SSL context.\"\"\"\n        try:\n            return await self._made_ssl_context[verified]\n        except KeyError:\n            loop = self._loop\n            future = loop.create_future()\n            self._made_ssl_context[verified] = future\n            try:\n                result = await loop.run_in_executor(\n                    None, self._make_ssl_context, verified\n                )\n            # BaseException is used since we might get CancelledError\n            except BaseException as ex:\n                del self._made_ssl_context[verified]\n                set_exception(future, ex)\n                raise\n            else:\n                set_result(future, result)\n            return result\n\n    def _get_fingerprint(self, req: ClientRequest) -> Optional[\"Fingerprint\"]:\n        ret = req.ssl\n        if isinstance(ret, Fingerprint):\n            return ret\n        ret = self._ssl\n        if isinstance(ret, Fingerprint):\n            return ret\n        return None\n\n    async def _wrap_create_connection(\n        self,\n        *args: Any,\n        addr_infos: List[aiohappyeyeballs.AddrInfoType],\n        req: ClientRequest,\n        timeout: \"ClientTimeout\",\n        client_error: Type[Exception] = ClientConnectorError,\n        **kwargs: Any,\n    ) -> Tuple[asyncio.Transport, ResponseHandler]:\n        try:\n            async with ceil_timeout(\n                timeout.sock_connect, ceil_threshold=timeout.ceil_threshold\n            ):\n                sock = await aiohappyeyeballs.start_connection(\n                    addr_infos=addr_infos,\n                    local_addr_infos=self._local_addr_infos,\n                    happy_eyeballs_delay=self._happy_eyeballs_delay,\n                    interleave=self._interleave,\n                    loop=self._loop,\n                )\n                return await self._loop.create_connection(*args, **kwargs, sock=sock)\n        except cert_errors as exc:\n            raise ClientConnectorCertificateError(req.connection_key, exc) from exc\n        except ssl_errors as exc:\n            raise ClientConnectorSSLError(req.connection_key, exc) from exc\n        except OSError as exc:\n            if exc.errno is None and isinstance(exc, asyncio.TimeoutError):\n                raise\n            raise client_error(req.connection_key, exc) from exc\n\n    async def _wrap_existing_connection(\n        self,\n        *args: Any,\n        req: ClientRequest,\n        timeout: \"ClientTimeout\",\n        client_error: Type[Exception] = ClientConnectorError,\n        **kwargs: Any,\n    ) -> Tuple[asyncio.Transport, ResponseHandler]:\n        try:\n            async with ceil_timeout(\n                timeout.sock_connect, ceil_threshold=timeout.ceil_threshold\n            ):\n                return await self._loop.create_connection(*args, **kwargs)\n        except cert_errors as exc:\n            raise ClientConnectorCertificateError(req.connection_key, exc) from exc\n        except ssl_errors as exc:\n            raise ClientConnectorSSLError(req.connection_key, exc) from exc\n        except OSError as exc:\n            if exc.errno is None and isinstance(exc, asyncio.TimeoutError):\n                raise\n            raise client_error(req.connection_key, exc) from exc\n\n    def _fail_on_no_start_tls(self, req: \"ClientRequest\") -> None:\n        \"\"\"Raise a :py:exc:`RuntimeError` on missing ``start_tls()``.\n\n        It is necessary for TLS-in-TLS so that it is possible to\n        send HTTPS queries through HTTPS proxies.\n\n        This doesn't affect regular HTTP requests, though.\n        \"\"\"\n        if not req.is_ssl():\n            return\n\n        proxy_url = req.proxy\n        assert proxy_url is not None\n        if proxy_url.scheme != \"https\":\n            return\n\n        self._check_loop_for_start_tls()\n\n    def _check_loop_for_start_tls(self) -> None:\n        try:\n            self._loop.start_tls\n        except AttributeError as attr_exc:\n            raise RuntimeError(\n                \"An HTTPS request is being sent through an HTTPS proxy. \"\n                \"This needs support for TLS in TLS but it is not implemented \"\n                \"in your runtime for the stdlib asyncio.\\n\\n\"\n                \"Please upgrade to Python 3.11 or higher. For more details, \"\n                \"please see:\\n\"\n                \"* https://bugs.python.org/issue37179\\n\"\n                \"* https://github.com/python/cpython/pull/28073\\n\"\n                \"* https://docs.aiohttp.org/en/stable/\"\n                \"client_advanced.html#proxy-support\\n\"\n                \"* https://github.com/aio-libs/aiohttp/discussions/6044\\n\",\n            ) from attr_exc\n\n    def _loop_supports_start_tls(self) -> bool:\n        try:\n            self._check_loop_for_start_tls()\n        except RuntimeError:\n            return False\n        else:\n            return True\n\n    def _warn_about_tls_in_tls(\n        self,\n        underlying_transport: asyncio.Transport,\n        req: ClientRequest,\n    ) -> None:\n        \"\"\"Issue a warning if the requested URL has HTTPS scheme.\"\"\"\n        if req.request_info.url.scheme != \"https\":\n            return\n\n        asyncio_supports_tls_in_tls = getattr(\n            underlying_transport,\n            \"_start_tls_compatible\",\n            False,\n        )\n\n        if asyncio_supports_tls_in_tls:\n            return\n\n        warnings.warn(\n            \"An HTTPS request is being sent through an HTTPS proxy. \"\n            \"This support for TLS in TLS is known to be disabled \"\n            \"in the stdlib asyncio (Python <3.11). This is why you'll probably see \"\n            \"an error in the log below.\\n\\n\"\n            \"It is possible to enable it via monkeypatching. \"\n            \"For more details, see:\\n\"\n            \"* https://bugs.python.org/issue37179\\n\"\n            \"* https://github.com/python/cpython/pull/28073\\n\\n\"\n            \"You can temporarily patch this as follows:\\n\"\n            \"* https://docs.aiohttp.org/en/stable/client_advanced.html#proxy-support\\n\"\n            \"* https://github.com/aio-libs/aiohttp/discussions/6044\\n\",\n            RuntimeWarning,\n            source=self,\n            # Why `4`? At least 3 of the calls in the stack originate\n            # from the methods in this class.\n            stacklevel=3,\n        )\n\n    async def _start_tls_connection(\n        self,\n        underlying_transport: asyncio.Transport,\n        req: ClientRequest,\n        timeout: \"ClientTimeout\",\n        client_error: Type[Exception] = ClientConnectorError,\n    ) -> Tuple[asyncio.BaseTransport, ResponseHandler]:\n        \"\"\"Wrap the raw TCP transport with TLS.\"\"\"\n        tls_proto = self._factory()  # Create a brand new proto for TLS\n\n        # Safety of the `cast()` call here is based on the fact that\n        # internally `_get_ssl_context()` only returns `None` when\n        # `req.is_ssl()` evaluates to `False` which is never gonna happen\n        # in this code path. Of course, it's rather fragile\n        # maintainability-wise but this is to be solved separately.\n        sslcontext = cast(ssl.SSLContext, await self._get_ssl_context(req))\n\n        try:\n            async with ceil_timeout(\n                timeout.sock_connect, ceil_threshold=timeout.ceil_threshold\n            ):\n                try:\n                    tls_transport = await self._loop.start_tls(\n                        underlying_transport,\n                        tls_proto,\n                        sslcontext,\n                        server_hostname=req.server_hostname or req.host,\n                        ssl_handshake_timeout=timeout.total,\n                    )\n                except BaseException:\n                    # We need to close the underlying transport since\n                    # `start_tls()` probably failed before it had a\n                    # chance to do this:\n                    underlying_transport.close()\n                    raise\n        except cert_errors as exc:\n            raise ClientConnectorCertificateError(req.connection_key, exc) from exc\n        except ssl_errors as exc:\n            raise ClientConnectorSSLError(req.connection_key, exc) from exc\n        except OSError as exc:\n            if exc.errno is None and isinstance(exc, asyncio.TimeoutError):\n                raise\n            raise client_error(req.connection_key, exc) from exc\n        except TypeError as type_err:\n            # Example cause looks like this:\n            # TypeError: transport <asyncio.sslproto._SSLProtocolTransport\n            # object at 0x7f760615e460> is not supported by start_tls()\n\n            raise ClientConnectionError(\n                \"Cannot initialize a TLS-in-TLS connection to host \"\n                f\"{req.host!s}:{req.port:d} through an underlying connection \"\n                f\"to an HTTPS proxy {req.proxy!s} ssl:{req.ssl or 'default'} \"\n                f\"[{type_err!s}]\"\n            ) from type_err\n        else:\n            if tls_transport is None:\n                msg = \"Failed to start TLS (possibly caused by closing transport)\"\n                raise client_error(req.connection_key, OSError(msg))\n            tls_proto.connection_made(\n                tls_transport\n            )  # Kick the state machine of the new TLS protocol\n\n        return tls_transport, tls_proto\n\n    def _convert_hosts_to_addr_infos(\n        self, hosts: List[ResolveResult]\n    ) -> List[aiohappyeyeballs.AddrInfoType]:\n        \"\"\"Converts the list of hosts to a list of addr_infos.\n\n        The list of hosts is the result of a DNS lookup. The list of\n        addr_infos is the result of a call to `socket.getaddrinfo()`.\n        \"\"\"\n        addr_infos: List[aiohappyeyeballs.AddrInfoType] = []\n        for hinfo in hosts:\n            host = hinfo[\"host\"]\n            is_ipv6 = \":\" in host\n            family = socket.AF_INET6 if is_ipv6 else socket.AF_INET\n            if self._family and self._family != family:\n                continue\n            addr = (host, hinfo[\"port\"], 0, 0) if is_ipv6 else (host, hinfo[\"port\"])\n            addr_infos.append(\n                (family, socket.SOCK_STREAM, socket.IPPROTO_TCP, \"\", addr)\n            )\n        return addr_infos\n\n    async def _create_direct_connection(\n        self,\n        req: ClientRequest,\n        traces: List[\"Trace\"],\n        timeout: \"ClientTimeout\",\n        *,\n        client_error: Type[Exception] = ClientConnectorError,\n    ) -> Tuple[asyncio.Transport, ResponseHandler]:\n        sslcontext = await self._get_ssl_context(req)\n        fingerprint = self._get_fingerprint(req)\n\n        host = req.url.raw_host\n        assert host is not None\n        # Replace multiple trailing dots with a single one.\n        # A trailing dot is only present for fully-qualified domain names.\n        # See https://github.com/aio-libs/aiohttp/pull/7364.\n        if host.endswith(\"..\"):\n            host = host.rstrip(\".\") + \".\"\n        port = req.port\n        assert port is not None\n        try:\n            # Cancelling this lookup should not cancel the underlying lookup\n            #  or else the cancel event will get broadcast to all the waiters\n            #  across all connections.\n            hosts = await self._resolve_host(host, port, traces=traces)\n        except OSError as exc:\n            if exc.errno is None and isinstance(exc, asyncio.TimeoutError):\n                raise\n            # in case of proxy it is not ClientProxyConnectionError\n            # it is problem of resolving proxy ip itself\n            raise ClientConnectorError(req.connection_key, exc) from exc\n\n        last_exc: Optional[Exception] = None\n        addr_infos = self._convert_hosts_to_addr_infos(hosts)\n        while addr_infos:\n            # Strip trailing dots, certificates contain FQDN without dots.\n            # See https://github.com/aio-libs/aiohttp/issues/3636\n            server_hostname = (\n                (req.server_hostname or host).rstrip(\".\") if sslcontext else None\n            )\n\n            try:\n                transp, proto = await self._wrap_create_connection(\n                    self._factory,\n                    timeout=timeout,\n                    ssl=sslcontext,\n                    addr_infos=addr_infos,\n                    server_hostname=server_hostname,\n                    req=req,\n                    client_error=client_error,\n                )\n            except ClientConnectorError as exc:\n                last_exc = exc\n                aiohappyeyeballs.pop_addr_infos_interleave(addr_infos, self._interleave)\n                continue\n\n            if req.is_ssl() and fingerprint:\n                try:\n                    fingerprint.check(transp)\n                except ServerFingerprintMismatch as exc:\n                    transp.close()\n                    if not self._cleanup_closed_disabled:\n                        self._cleanup_closed_transports.append(transp)\n                    last_exc = exc\n                    # Remove the bad peer from the list of addr_infos\n                    sock: socket.socket = transp.get_extra_info(\"socket\")\n                    bad_peer = sock.getpeername()\n                    aiohappyeyeballs.remove_addr_infos(addr_infos, bad_peer)\n                    continue\n\n            return transp, proto\n        else:\n            assert last_exc is not None\n            raise last_exc\n\n    async def _create_proxy_connection(\n        self, req: ClientRequest, traces: List[\"Trace\"], timeout: \"ClientTimeout\"\n    ) -> Tuple[asyncio.BaseTransport, ResponseHandler]:\n        self._fail_on_no_start_tls(req)\n        runtime_has_start_tls = self._loop_supports_start_tls()\n\n        headers: Dict[str, str] = {}\n        if req.proxy_headers is not None:\n            headers = req.proxy_headers  # type: ignore[assignment]\n        headers[hdrs.HOST] = req.headers[hdrs.HOST]\n\n        url = req.proxy\n        assert url is not None\n        proxy_req = ClientRequest(\n            hdrs.METH_GET,\n            url,\n            headers=headers,\n            auth=req.proxy_auth,\n            loop=self._loop,\n            ssl=req.ssl,\n        )\n\n        # create connection to proxy server\n        transport, proto = await self._create_direct_connection(\n            proxy_req, [], timeout, client_error=ClientProxyConnectionError\n        )\n\n        auth = proxy_req.headers.pop(hdrs.AUTHORIZATION, None)\n        if auth is not None:\n            if not req.is_ssl():\n                req.headers[hdrs.PROXY_AUTHORIZATION] = auth\n            else:\n                proxy_req.headers[hdrs.PROXY_AUTHORIZATION] = auth\n\n        if req.is_ssl():\n            if runtime_has_start_tls:\n                self._warn_about_tls_in_tls(transport, req)\n\n            # For HTTPS requests over HTTP proxy\n            # we must notify proxy to tunnel connection\n            # so we send CONNECT command:\n            #   CONNECT www.python.org:443 HTTP/1.1\n            #   Host: www.python.org\n            #\n            # next we must do TLS handshake and so on\n            # to do this we must wrap raw socket into secure one\n            # asyncio handles this perfectly\n            proxy_req.method = hdrs.METH_CONNECT\n            proxy_req.url = req.url\n            key = attr.evolve(\n                req.connection_key, proxy=None, proxy_auth=None, proxy_headers_hash=None\n            )\n            conn = Connection(self, key, proto, self._loop)\n            proxy_resp = await proxy_req.send(conn)\n            try:\n                protocol = conn._protocol\n                assert protocol is not None\n\n                # read_until_eof=True will ensure the connection isn't closed\n                # once the response is received and processed allowing\n                # START_TLS to work on the connection below.\n                protocol.set_response_params(\n                    read_until_eof=runtime_has_start_tls,\n                    timeout_ceil_threshold=self._timeout_ceil_threshold,\n                )\n                resp = await proxy_resp.start(conn)\n            except BaseException:\n                proxy_resp.close()\n                conn.close()\n                raise\n            else:\n                conn._protocol = None\n                conn._transport = None\n                try:\n                    if resp.status != 200:\n                        message = resp.reason\n                        if message is None:\n                            message = HTTPStatus(resp.status).phrase\n                        raise ClientHttpProxyError(\n                            proxy_resp.request_info,\n                            resp.history,\n                            status=resp.status,\n                            message=message,\n                            headers=resp.headers,\n                        )\n                    if not runtime_has_start_tls:\n                        rawsock = transport.get_extra_info(\"socket\", default=None)\n                        if rawsock is None:\n                            raise RuntimeError(\n                                \"Transport does not expose socket instance\"\n                            )\n                        # Duplicate the socket, so now we can close proxy transport\n                        rawsock = rawsock.dup()\n                except BaseException:\n                    # It shouldn't be closed in `finally` because it's fed to\n                    # `loop.start_tls()` and the docs say not to touch it after\n                    # passing there.\n                    transport.close()\n                    raise\n                finally:\n                    if not runtime_has_start_tls:\n                        transport.close()\n\n                if not runtime_has_start_tls:\n                    # HTTP proxy with support for upgrade to HTTPS\n                    sslcontext = self._get_ssl_context(req)\n                    return await self._wrap_existing_connection(\n                        self._factory,\n                        timeout=timeout,\n                        ssl=sslcontext,\n                        sock=rawsock,\n                        server_hostname=req.host,\n                        req=req,\n                    )\n\n                return await self._start_tls_connection(\n                    # Access the old transport for the last time before it's\n                    # closed and forgotten forever:\n                    transport,\n                    req=req,\n                    timeout=timeout,\n                )\n            finally:\n                proxy_resp.close()\n\n        return transport, proto",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 783,
                            "end_lineno": 827,
                            "parent": {
                                "file_name": "aiohttp/connector.py",
                                "type": "class",
                                "name": "TCPConnector",
                                "content": "class TCPConnector(BaseConnector):\n    \"\"\"TCP connector.\n\n    verify_ssl - Set to True to check ssl certifications.\n    fingerprint - Pass the binary sha256\n        digest of the expected certificate in DER format to verify\n        that the certificate the server presents matches. See also\n        https://en.wikipedia.org/wiki/HTTP_Public_Key_Pinning\n    resolver - Enable DNS lookups and use this\n        resolver\n    use_dns_cache - Use memory cache for DNS lookups.\n    ttl_dns_cache - Max seconds having cached a DNS entry, None forever.\n    family - socket address family\n    local_addr - local tuple of (host, port) to bind socket to\n\n    keepalive_timeout - (optional) Keep-alive timeout.\n    force_close - Set to True to force close and do reconnect\n        after each request (and between redirects).\n    limit - The total number of simultaneous connections.\n    limit_per_host - Number of simultaneous connections to one host.\n    enable_cleanup_closed - Enables clean-up closed ssl transports.\n                            Disabled by default.\n    happy_eyeballs_delay - This is the “Connection Attempt Delay”\n                           as defined in RFC 8305. To disable\n                           the happy eyeballs algorithm, set to None.\n    interleave - “First Address Family Count” as defined in RFC 8305\n    loop - Optional event loop.\n    \"\"\"\n\n    allowed_protocol_schema_set = HIGH_LEVEL_SCHEMA_SET | frozenset({\"tcp\"})\n    _made_ssl_context: Dict[bool, \"asyncio.Future[SSLContext]\"] = {}\n\n    def __init__(\n        self,\n        *,\n        verify_ssl: bool = True,\n        fingerprint: Optional[bytes] = None,\n        use_dns_cache: bool = True,\n        ttl_dns_cache: Optional[int] = 10,\n        family: socket.AddressFamily = socket.AddressFamily.AF_UNSPEC,\n        ssl_context: Optional[SSLContext] = None,\n        ssl: Union[bool, Fingerprint, SSLContext] = True,\n        local_addr: Optional[Tuple[str, int]] = None,\n        resolver: Optional[AbstractResolver] = None,\n        keepalive_timeout: Union[None, float, object] = sentinel,\n        force_close: bool = False,\n        limit: int = 100,\n        limit_per_host: int = 0,\n        enable_cleanup_closed: bool = False,\n        loop: Optional[asyncio.AbstractEventLoop] = None,\n        timeout_ceil_threshold: float = 5,\n        happy_eyeballs_delay: Optional[float] = 0.25,\n        interleave: Optional[int] = None,\n    ):\n        super().__init__(\n            keepalive_timeout=keepalive_timeout,\n            force_close=force_close,\n            limit=limit,\n            limit_per_host=limit_per_host,\n            enable_cleanup_closed=enable_cleanup_closed,\n            loop=loop,\n            timeout_ceil_threshold=timeout_ceil_threshold,\n        )\n\n        self._ssl = _merge_ssl_params(ssl, verify_ssl, ssl_context, fingerprint)\n        if resolver is None:\n            resolver = DefaultResolver(loop=self._loop)\n        self._resolver = resolver\n\n        self._use_dns_cache = use_dns_cache\n        self._cached_hosts = _DNSCacheTable(ttl=ttl_dns_cache)\n        self._throttle_dns_events: Dict[Tuple[str, int], EventResultOrError] = {}\n        self._family = family\n        self._local_addr_infos = aiohappyeyeballs.addr_to_addr_infos(local_addr)\n        self._happy_eyeballs_delay = happy_eyeballs_delay\n        self._interleave = interleave\n        self._resolve_host_tasks: Set[\"asyncio.Task[List[ResolveResult]]\"] = set()\n\n    def close(self) -> Awaitable[None]:\n        \"\"\"Close all ongoing DNS calls.\"\"\"\n        for ev in self._throttle_dns_events.values():\n            ev.cancel()\n\n        for t in self._resolve_host_tasks:\n            t.cancel()\n\n        return super().close()\n\n    @property\n    def family(self) -> int:\n        \"\"\"Socket family like AF_INET.\"\"\"\n        return self._family\n\n    @property\n    def use_dns_cache(self) -> bool:\n        \"\"\"True if local DNS caching is enabled.\"\"\"\n        return self._use_dns_cache\n\n    def clear_dns_cache(\n        self, host: Optional[str] = None, port: Optional[int] = None\n    ) -> None:\n        \"\"\"Remove specified host/port or clear all dns local cache.\"\"\"\n        if host is not None and port is not None:\n            self._cached_hosts.remove((host, port))\n        elif host is not None or port is not None:\n            raise ValueError(\"either both host and port \" \"or none of them are allowed\")\n        else:\n            self._cached_hosts.clear()\n\n    async def _resolve_host(\n        self, host: str, port: int, traces: Optional[Sequence[\"Trace\"]] = None\n    ) -> List[ResolveResult]:\n        \"\"\"Resolve host and return list of addresses.\"\"\"\n        if is_ip_address(host):\n            return [\n                {\n                    \"hostname\": host,\n                    \"host\": host,\n                    \"port\": port,\n                    \"family\": self._family,\n                    \"proto\": 0,\n                    \"flags\": 0,\n                }\n            ]\n\n        if not self._use_dns_cache:\n\n            if traces:\n                for trace in traces:\n                    await trace.send_dns_resolvehost_start(host)\n\n            res = await self._resolver.resolve(host, port, family=self._family)\n\n            if traces:\n                for trace in traces:\n                    await trace.send_dns_resolvehost_end(host)\n\n            return res\n\n        key = (host, port)\n        if key in self._cached_hosts and not self._cached_hosts.expired(key):\n            # get result early, before any await (#4014)\n            result = self._cached_hosts.next_addrs(key)\n\n            if traces:\n                for trace in traces:\n                    await trace.send_dns_cache_hit(host)\n            return result\n\n        #\n        # If multiple connectors are resolving the same host, we wait\n        # for the first one to resolve and then use the result for all of them.\n        # We use a throttle event to ensure that we only resolve the host once\n        # and then use the result for all the waiters.\n        #\n        # In this case we need to create a task to ensure that we can shield\n        # the task from cancellation as cancelling this lookup should not cancel\n        # the underlying lookup or else the cancel event will get broadcast to\n        # all the waiters across all connections.\n        #\n        resolved_host_task = asyncio.create_task(\n            self._resolve_host_with_throttle(key, host, port, traces)\n        )\n        self._resolve_host_tasks.add(resolved_host_task)\n        resolved_host_task.add_done_callback(self._resolve_host_tasks.discard)\n        try:\n            return await asyncio.shield(resolved_host_task)\n        except asyncio.CancelledError:\n\n            def drop_exception(fut: \"asyncio.Future[List[ResolveResult]]\") -> None:\n                with suppress(Exception, asyncio.CancelledError):\n                    fut.result()\n\n            resolved_host_task.add_done_callback(drop_exception)\n            raise\n\n    async def _resolve_host_with_throttle(\n        self,\n        key: Tuple[str, int],\n        host: str,\n        port: int,\n        traces: Optional[Sequence[\"Trace\"]],\n    ) -> List[ResolveResult]:\n        \"\"\"Resolve host with a dns events throttle.\"\"\"\n        if key in self._throttle_dns_events:\n            # get event early, before any await (#4014)\n            event = self._throttle_dns_events[key]\n            if traces:\n                for trace in traces:\n                    await trace.send_dns_cache_hit(host)\n            await event.wait()\n        else:\n            # update dict early, before any await (#4014)\n            self._throttle_dns_events[key] = EventResultOrError(self._loop)\n            if traces:\n                for trace in traces:\n                    await trace.send_dns_cache_miss(host)\n            try:\n\n                if traces:\n                    for trace in traces:\n                        await trace.send_dns_resolvehost_start(host)\n\n                addrs = await self._resolver.resolve(host, port, family=self._family)\n                if traces:\n                    for trace in traces:\n                        await trace.send_dns_resolvehost_end(host)\n\n                self._cached_hosts.add(key, addrs)\n                self._throttle_dns_events[key].set()\n            except BaseException as e:\n                # any DNS exception, independently of the implementation\n                # is set for the waiters to raise the same exception.\n                self._throttle_dns_events[key].set(exc=e)\n                raise\n            finally:\n                self._throttle_dns_events.pop(key)\n\n        return self._cached_hosts.next_addrs(key)\n\n    async def _create_connection(\n        self, req: ClientRequest, traces: List[\"Trace\"], timeout: \"ClientTimeout\"\n    ) -> ResponseHandler:\n        \"\"\"Create connection.\n\n        Has same keyword arguments as BaseEventLoop.create_connection.\n        \"\"\"\n        if req.proxy:\n            _, proto = await self._create_proxy_connection(req, traces, timeout)\n        else:\n            _, proto = await self._create_direct_connection(req, traces, timeout)\n\n        return proto\n\n    @staticmethod\n    def _make_ssl_context(verified: bool) -> SSLContext:\n        \"\"\"Create SSL context.\n\n        This method is not async-friendly and should be called from a thread\n        because it will load certificates from disk and do other blocking I/O.\n        \"\"\"\n        if verified:\n            return ssl.create_default_context()\n        sslcontext = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)\n        sslcontext.options |= ssl.OP_NO_SSLv2\n        sslcontext.options |= ssl.OP_NO_SSLv3\n        sslcontext.check_hostname = False\n        sslcontext.verify_mode = ssl.CERT_NONE\n        sslcontext.options |= ssl.OP_NO_COMPRESSION\n        sslcontext.set_default_verify_paths()\n        return sslcontext\n\n    async def _get_ssl_context(self, req: ClientRequest) -> Optional[SSLContext]:\n        \"\"\"Logic to get the correct SSL context\n\n        0. if req.ssl is false, return None\n\n        1. if ssl_context is specified in req, use it\n        2. if _ssl_context is specified in self, use it\n        3. otherwise:\n            1. if verify_ssl is not specified in req, use self.ssl_context\n               (will generate a default context according to self.verify_ssl)\n            2. if verify_ssl is True in req, generate a default SSL context\n            3. if verify_ssl is False in req, generate a SSL context that\n               won't verify\n        \"\"\"\n        if not req.is_ssl():\n            return None\n\n        if ssl is None:  # pragma: no cover\n            raise RuntimeError(\"SSL is not supported.\")\n        sslcontext = req.ssl\n        if isinstance(sslcontext, ssl.SSLContext):\n            return sslcontext\n        if sslcontext is not True:\n            # not verified or fingerprinted\n            return await self._make_or_get_ssl_context(False)\n        sslcontext = self._ssl\n        if isinstance(sslcontext, ssl.SSLContext):\n            return sslcontext\n        if sslcontext is not True:\n            # not verified or fingerprinted\n            return await self._make_or_get_ssl_context(False)\n        return await self._make_or_get_ssl_context(True)\n\n    async def _make_or_get_ssl_context(self, verified: bool) -> SSLContext:\n        \"\"\"Create or get cached SSL context.\"\"\"\n        try:\n            return await self._made_ssl_context[verified]\n        except KeyError:\n            loop = self._loop\n            future = loop.create_future()\n            self._made_ssl_context[verified] = future\n            try:\n                result = await loop.run_in_executor(\n                    None, self._make_ssl_context, verified\n                )\n            # BaseException is used since we might get CancelledError\n            except BaseException as ex:\n                del self._made_ssl_context[verified]\n                set_exception(future, ex)\n                raise\n            else:\n                set_result(future, result)\n            return result\n\n    def _get_fingerprint(self, req: ClientRequest) -> Optional[\"Fingerprint\"]:\n        ret = req.ssl\n        if isinstance(ret, Fingerprint):\n            return ret\n        ret = self._ssl\n        if isinstance(ret, Fingerprint):\n            return ret\n        return None\n\n    async def _wrap_create_connection(\n        self,\n        *args: Any,\n        addr_infos: List[aiohappyeyeballs.AddrInfoType],\n        req: ClientRequest,\n        timeout: \"ClientTimeout\",\n        client_error: Type[Exception] = ClientConnectorError,\n        **kwargs: Any,\n    ) -> Tuple[asyncio.Transport, ResponseHandler]:\n        try:\n            async with ceil_timeout(\n                timeout.sock_connect, ceil_threshold=timeout.ceil_threshold\n            ):\n                sock = await aiohappyeyeballs.start_connection(\n                    addr_infos=addr_infos,\n                    local_addr_infos=self._local_addr_infos,\n                    happy_eyeballs_delay=self._happy_eyeballs_delay,\n                    interleave=self._interleave,\n                    loop=self._loop,\n                )\n                return await self._loop.create_connection(*args, **kwargs, sock=sock)\n        except cert_errors as exc:\n            raise ClientConnectorCertificateError(req.connection_key, exc) from exc\n        except ssl_errors as exc:\n            raise ClientConnectorSSLError(req.connection_key, exc) from exc\n        except OSError as exc:\n            if exc.errno is None and isinstance(exc, asyncio.TimeoutError):\n                raise\n            raise client_error(req.connection_key, exc) from exc\n\n    async def _wrap_existing_connection(\n        self,\n        *args: Any,\n        req: ClientRequest,\n        timeout: \"ClientTimeout\",\n        client_error: Type[Exception] = ClientConnectorError,\n        **kwargs: Any,\n    ) -> Tuple[asyncio.Transport, ResponseHandler]:\n        try:\n            async with ceil_timeout(\n                timeout.sock_connect, ceil_threshold=timeout.ceil_threshold\n            ):\n                return await self._loop.create_connection(*args, **kwargs)\n        except cert_errors as exc:\n            raise ClientConnectorCertificateError(req.connection_key, exc) from exc\n        except ssl_errors as exc:\n            raise ClientConnectorSSLError(req.connection_key, exc) from exc\n        except OSError as exc:\n            if exc.errno is None and isinstance(exc, asyncio.TimeoutError):\n                raise\n            raise client_error(req.connection_key, exc) from exc\n\n    def _fail_on_no_start_tls(self, req: \"ClientRequest\") -> None:\n        \"\"\"Raise a :py:exc:`RuntimeError` on missing ``start_tls()``.\n\n        It is necessary for TLS-in-TLS so that it is possible to\n        send HTTPS queries through HTTPS proxies.\n\n        This doesn't affect regular HTTP requests, though.\n        \"\"\"\n        if not req.is_ssl():\n            return\n\n        proxy_url = req.proxy\n        assert proxy_url is not None\n        if proxy_url.scheme != \"https\":\n            return\n\n        self._check_loop_for_start_tls()\n\n    def _check_loop_for_start_tls(self) -> None:\n        try:\n            self._loop.start_tls\n        except AttributeError as attr_exc:\n            raise RuntimeError(\n                \"An HTTPS request is being sent through an HTTPS proxy. \"\n                \"This needs support for TLS in TLS but it is not implemented \"\n                \"in your runtime for the stdlib asyncio.\\n\\n\"\n                \"Please upgrade to Python 3.11 or higher. For more details, \"\n                \"please see:\\n\"\n                \"* https://bugs.python.org/issue37179\\n\"\n                \"* https://github.com/python/cpython/pull/28073\\n\"\n                \"* https://docs.aiohttp.org/en/stable/\"\n                \"client_advanced.html#proxy-support\\n\"\n                \"* https://github.com/aio-libs/aiohttp/discussions/6044\\n\",\n            ) from attr_exc\n\n    def _loop_supports_start_tls(self) -> bool:\n        try:\n            self._check_loop_for_start_tls()\n        except RuntimeError:\n            return False\n        else:\n            return True\n\n    def _warn_about_tls_in_tls(\n        self,\n        underlying_transport: asyncio.Transport,\n        req: ClientRequest,\n    ) -> None:\n        \"\"\"Issue a warning if the requested URL has HTTPS scheme.\"\"\"\n        if req.request_info.url.scheme != \"https\":\n            return\n\n        asyncio_supports_tls_in_tls = getattr(\n            underlying_transport,\n            \"_start_tls_compatible\",\n            False,\n        )\n\n        if asyncio_supports_tls_in_tls:\n            return\n\n        warnings.warn(\n            \"An HTTPS request is being sent through an HTTPS proxy. \"\n            \"This support for TLS in TLS is known to be disabled \"\n            \"in the stdlib asyncio (Python <3.11). This is why you'll probably see \"\n            \"an error in the log below.\\n\\n\"\n            \"It is possible to enable it via monkeypatching. \"\n            \"For more details, see:\\n\"\n            \"* https://bugs.python.org/issue37179\\n\"\n            \"* https://github.com/python/cpython/pull/28073\\n\\n\"\n            \"You can temporarily patch this as follows:\\n\"\n            \"* https://docs.aiohttp.org/en/stable/client_advanced.html#proxy-support\\n\"\n            \"* https://github.com/aio-libs/aiohttp/discussions/6044\\n\",\n            RuntimeWarning,\n            source=self,\n            # Why `4`? At least 3 of the calls in the stack originate\n            # from the methods in this class.\n            stacklevel=3,\n        )\n\n    async def _start_tls_connection(\n        self,\n        underlying_transport: asyncio.Transport,\n        req: ClientRequest,\n        timeout: \"ClientTimeout\",\n        client_error: Type[Exception] = ClientConnectorError,\n    ) -> Tuple[asyncio.BaseTransport, ResponseHandler]:\n        \"\"\"Wrap the raw TCP transport with TLS.\"\"\"\n        tls_proto = self._factory()  # Create a brand new proto for TLS\n\n        # Safety of the `cast()` call here is based on the fact that\n        # internally `_get_ssl_context()` only returns `None` when\n        # `req.is_ssl()` evaluates to `False` which is never gonna happen\n        # in this code path. Of course, it's rather fragile\n        # maintainability-wise but this is to be solved separately.\n        sslcontext = cast(ssl.SSLContext, await self._get_ssl_context(req))\n\n        try:\n            async with ceil_timeout(\n                timeout.sock_connect, ceil_threshold=timeout.ceil_threshold\n            ):\n                try:\n                    tls_transport = await self._loop.start_tls(\n                        underlying_transport,\n                        tls_proto,\n                        sslcontext,\n                        server_hostname=req.server_hostname or req.host,\n                        ssl_handshake_timeout=timeout.total,\n                    )\n                except BaseException:\n                    # We need to close the underlying transport since\n                    # `start_tls()` probably failed before it had a\n                    # chance to do this:\n                    underlying_transport.close()\n                    raise\n        except cert_errors as exc:\n            raise ClientConnectorCertificateError(req.connection_key, exc) from exc\n        except ssl_errors as exc:\n            raise ClientConnectorSSLError(req.connection_key, exc) from exc\n        except OSError as exc:\n            if exc.errno is None and isinstance(exc, asyncio.TimeoutError):\n                raise\n            raise client_error(req.connection_key, exc) from exc\n        except TypeError as type_err:\n            # Example cause looks like this:\n            # TypeError: transport <asyncio.sslproto._SSLProtocolTransport\n            # object at 0x7f760615e460> is not supported by start_tls()\n\n            raise ClientConnectionError(\n                \"Cannot initialize a TLS-in-TLS connection to host \"\n                f\"{req.host!s}:{req.port:d} through an underlying connection \"\n                f\"to an HTTPS proxy {req.proxy!s} ssl:{req.ssl or 'default'} \"\n                f\"[{type_err!s}]\"\n            ) from type_err\n        else:\n            if tls_transport is None:\n                msg = \"Failed to start TLS (possibly caused by closing transport)\"\n                raise client_error(req.connection_key, OSError(msg))\n            tls_proto.connection_made(\n                tls_transport\n            )  # Kick the state machine of the new TLS protocol\n\n        return tls_transport, tls_proto\n\n    def _convert_hosts_to_addr_infos(\n        self, hosts: List[ResolveResult]\n    ) -> List[aiohappyeyeballs.AddrInfoType]:\n        \"\"\"Converts the list of hosts to a list of addr_infos.\n\n        The list of hosts is the result of a DNS lookup. The list of\n        addr_infos is the result of a call to `socket.getaddrinfo()`.\n        \"\"\"\n        addr_infos: List[aiohappyeyeballs.AddrInfoType] = []\n        for hinfo in hosts:\n            host = hinfo[\"host\"]\n            is_ipv6 = \":\" in host\n            family = socket.AF_INET6 if is_ipv6 else socket.AF_INET\n            if self._family and self._family != family:\n                continue\n            addr = (host, hinfo[\"port\"], 0, 0) if is_ipv6 else (host, hinfo[\"port\"])\n            addr_infos.append(\n                (family, socket.SOCK_STREAM, socket.IPPROTO_TCP, \"\", addr)\n            )\n        return addr_infos\n\n    async def _create_direct_connection(\n        self,\n        req: ClientRequest,\n        traces: List[\"Trace\"],\n        timeout: \"ClientTimeout\",\n        *,\n        client_error: Type[Exception] = ClientConnectorError,\n    ) -> Tuple[asyncio.Transport, ResponseHandler]:\n        sslcontext = await self._get_ssl_context(req)\n        fingerprint = self._get_fingerprint(req)\n\n        host = req.url.raw_host\n        assert host is not None\n        # Replace multiple trailing dots with a single one.\n        # A trailing dot is only present for fully-qualified domain names.\n        # See https://github.com/aio-libs/aiohttp/pull/7364.\n        if host.endswith(\"..\"):\n            host = host.rstrip(\".\") + \".\"\n        port = req.port\n        assert port is not None\n        try:\n            # Cancelling this lookup should not cancel the underlying lookup\n            #  or else the cancel event will get broadcast to all the waiters\n            #  across all connections.\n            hosts = await self._resolve_host(host, port, traces=traces)\n        except OSError as exc:\n            if exc.errno is None and isinstance(exc, asyncio.TimeoutError):\n                raise\n            # in case of proxy it is not ClientProxyConnectionError\n            # it is problem of resolving proxy ip itself\n            raise ClientConnectorError(req.connection_key, exc) from exc\n\n        last_exc: Optional[Exception] = None\n        addr_infos = self._convert_hosts_to_addr_infos(hosts)\n        while addr_infos:\n            # Strip trailing dots, certificates contain FQDN without dots.\n            # See https://github.com/aio-libs/aiohttp/issues/3636\n            server_hostname = (\n                (req.server_hostname or host).rstrip(\".\") if sslcontext else None\n            )\n\n            try:\n                transp, proto = await self._wrap_create_connection(\n                    self._factory,\n                    timeout=timeout,\n                    ssl=sslcontext,\n                    addr_infos=addr_infos,\n                    server_hostname=server_hostname,\n                    req=req,\n                    client_error=client_error,\n                )\n            except ClientConnectorError as exc:\n                last_exc = exc\n                aiohappyeyeballs.pop_addr_infos_interleave(addr_infos, self._interleave)\n                continue\n\n            if req.is_ssl() and fingerprint:\n                try:\n                    fingerprint.check(transp)\n                except ServerFingerprintMismatch as exc:\n                    transp.close()\n                    if not self._cleanup_closed_disabled:\n                        self._cleanup_closed_transports.append(transp)\n                    last_exc = exc\n                    # Remove the bad peer from the list of addr_infos\n                    sock: socket.socket = transp.get_extra_info(\"socket\")\n                    bad_peer = sock.getpeername()\n                    aiohappyeyeballs.remove_addr_infos(addr_infos, bad_peer)\n                    continue\n\n            return transp, proto\n        else:\n            assert last_exc is not None\n            raise last_exc\n\n    async def _create_proxy_connection(\n        self, req: ClientRequest, traces: List[\"Trace\"], timeout: \"ClientTimeout\"\n    ) -> Tuple[asyncio.BaseTransport, ResponseHandler]:\n        self._fail_on_no_start_tls(req)\n        runtime_has_start_tls = self._loop_supports_start_tls()\n\n        headers: Dict[str, str] = {}\n        if req.proxy_headers is not None:\n            headers = req.proxy_headers  # type: ignore[assignment]\n        headers[hdrs.HOST] = req.headers[hdrs.HOST]\n\n        url = req.proxy\n        assert url is not None\n        proxy_req = ClientRequest(\n            hdrs.METH_GET,\n            url,\n            headers=headers,\n            auth=req.proxy_auth,\n            loop=self._loop,\n            ssl=req.ssl,\n        )\n\n        # create connection to proxy server\n        transport, proto = await self._create_direct_connection(\n            proxy_req, [], timeout, client_error=ClientProxyConnectionError\n        )\n\n        auth = proxy_req.headers.pop(hdrs.AUTHORIZATION, None)\n        if auth is not None:\n            if not req.is_ssl():\n                req.headers[hdrs.PROXY_AUTHORIZATION] = auth\n            else:\n                proxy_req.headers[hdrs.PROXY_AUTHORIZATION] = auth\n\n        if req.is_ssl():\n            if runtime_has_start_tls:\n                self._warn_about_tls_in_tls(transport, req)\n\n            # For HTTPS requests over HTTP proxy\n            # we must notify proxy to tunnel connection\n            # so we send CONNECT command:\n            #   CONNECT www.python.org:443 HTTP/1.1\n            #   Host: www.python.org\n            #\n            # next we must do TLS handshake and so on\n            # to do this we must wrap raw socket into secure one\n            # asyncio handles this perfectly\n            proxy_req.method = hdrs.METH_CONNECT\n            proxy_req.url = req.url\n            key = attr.evolve(\n                req.connection_key, proxy=None, proxy_auth=None, proxy_headers_hash=None\n            )\n            conn = Connection(self, key, proto, self._loop)\n            proxy_resp = await proxy_req.send(conn)\n            try:\n                protocol = conn._protocol\n                assert protocol is not None\n\n                # read_until_eof=True will ensure the connection isn't closed\n                # once the response is received and processed allowing\n                # START_TLS to work on the connection below.\n                protocol.set_response_params(\n                    read_until_eof=runtime_has_start_tls,\n                    timeout_ceil_threshold=self._timeout_ceil_threshold,\n                )\n                resp = await proxy_resp.start(conn)\n            except BaseException:\n                proxy_resp.close()\n                conn.close()\n                raise\n            else:\n                conn._protocol = None\n                conn._transport = None\n                try:\n                    if resp.status != 200:\n                        message = resp.reason\n                        if message is None:\n                            message = HTTPStatus(resp.status).phrase\n                        raise ClientHttpProxyError(\n                            proxy_resp.request_info,\n                            resp.history,\n                            status=resp.status,\n                            message=message,\n                            headers=resp.headers,\n                        )\n                    if not runtime_has_start_tls:\n                        rawsock = transport.get_extra_info(\"socket\", default=None)\n                        if rawsock is None:\n                            raise RuntimeError(\n                                \"Transport does not expose socket instance\"\n                            )\n                        # Duplicate the socket, so now we can close proxy transport\n                        rawsock = rawsock.dup()\n                except BaseException:\n                    # It shouldn't be closed in `finally` because it's fed to\n                    # `loop.start_tls()` and the docs say not to touch it after\n                    # passing there.\n                    transport.close()\n                    raise\n                finally:\n                    if not runtime_has_start_tls:\n                        transport.close()\n\n                if not runtime_has_start_tls:\n                    # HTTP proxy with support for upgrade to HTTPS\n                    sslcontext = self._get_ssl_context(req)\n                    return await self._wrap_existing_connection(\n                        self._factory,\n                        timeout=timeout,\n                        ssl=sslcontext,\n                        sock=rawsock,\n                        server_hostname=req.host,\n                        req=req,\n                    )\n\n                return await self._start_tls_connection(\n                    # Access the old transport for the last time before it's\n                    # closed and forgotten forever:\n                    transport,\n                    req=req,\n                    timeout=timeout,\n                )\n            finally:\n                proxy_resp.close()\n\n        return transport, proto",
                                "ast_type_str": "ClassDef",
                                "start_lineno": 751,
                                "end_lineno": 1483,
                                "parent": null
                            }
                        },
                        {
                            "file_name": "aiohttp/connector.py",
                            "type": "method",
                            "name": "TCPConnector.close",
                            "content": "class TCPConnector(BaseConnector):\n    \"\"\"TCP connector.\n\n    verify_ssl - Set to True to check ssl certifications.\n    fingerprint - Pass the binary sha256\n        digest of the expected certificate in DER format to verify\n        that the certificate the server presents matches. See also\n        https://en.wikipedia.org/wiki/HTTP_Public_Key_Pinning\n    resolver - Enable DNS lookups and use this\n        resolver\n    use_dns_cache - Use memory cache for DNS lookups.\n    ttl_dns_cache - Max seconds having cached a DNS entry, None forever.\n    family - socket address family\n    local_addr - local tuple of (host, port) to bind socket to\n\n    keepalive_timeout - (optional) Keep-alive timeout.\n    force_close - Set to True to force close and do reconnect\n        after each request (and between redirects).\n    limit - The total number of simultaneous connections.\n    limit_per_host - Number of simultaneous connections to one host.\n    enable_cleanup_closed - Enables clean-up closed ssl transports.\n                            Disabled by default.\n    happy_eyeballs_delay - This is the “Connection Attempt Delay”\n                           as defined in RFC 8305. To disable\n                           the happy eyeballs algorithm, set to None.\n    interleave - “First Address Family Count” as defined in RFC 8305\n    loop - Optional event loop.\n    \"\"\"\n\n    allowed_protocol_schema_set = HIGH_LEVEL_SCHEMA_SET | frozenset({\"tcp\"})\n    _made_ssl_context: Dict[bool, \"asyncio.Future[SSLContext]\"] = {}\n\n    def __init__(\n        self,\n        *,\n        verify_ssl: bool = True,\n        fingerprint: Optional[bytes] = None,\n        use_dns_cache: bool = True,\n        ttl_dns_cache: Optional[int] = 10,\n        family: socket.AddressFamily = socket.AddressFamily.AF_UNSPEC,\n        ssl_context: Optional[SSLContext] = None,\n        ssl: Union[bool, Fingerprint, SSLContext] = True,\n        local_addr: Optional[Tuple[str, int]] = None,\n        resolver: Optional[AbstractResolver] = None,\n        keepalive_timeout: Union[None, float, object] = sentinel,\n        force_close: bool = False,\n        limit: int = 100,\n        limit_per_host: int = 0,\n        enable_cleanup_closed: bool = False,\n        loop: Optional[asyncio.AbstractEventLoop] = None,\n        timeout_ceil_threshold: float = 5,\n        happy_eyeballs_delay: Optional[float] = 0.25,\n        interleave: Optional[int] = None,\n    ):\n        super().__init__(\n            keepalive_timeout=keepalive_timeout,\n            force_close=force_close,\n            limit=limit,\n            limit_per_host=limit_per_host,\n            enable_cleanup_closed=enable_cleanup_closed,\n            loop=loop,\n            timeout_ceil_threshold=timeout_ceil_threshold,\n        )\n\n        self._ssl = _merge_ssl_params(ssl, verify_ssl, ssl_context, fingerprint)\n        if resolver is None:\n            resolver = DefaultResolver(loop=self._loop)\n        self._resolver = resolver\n\n        self._use_dns_cache = use_dns_cache\n        self._cached_hosts = _DNSCacheTable(ttl=ttl_dns_cache)\n        self._throttle_dns_events: Dict[Tuple[str, int], EventResultOrError] = {}\n        self._family = family\n        self._local_addr_infos = aiohappyeyeballs.addr_to_addr_infos(local_addr)\n        self._happy_eyeballs_delay = happy_eyeballs_delay\n        self._interleave = interleave\n        self._resolve_host_tasks: Set[\"asyncio.Task[List[ResolveResult]]\"] = set()\n\n    def close(self) -> Awaitable[None]:\n        \"\"\"Close all ongoing DNS calls.\"\"\"\n        for ev in self._throttle_dns_events.values():\n            ev.cancel()\n\n        for t in self._resolve_host_tasks:\n            t.cancel()\n\n        return super().close()\n\n    @property\n    def family(self) -> int:\n        \"\"\"Socket family like AF_INET.\"\"\"\n        return self._family\n\n    @property\n    def use_dns_cache(self) -> bool:\n        \"\"\"True if local DNS caching is enabled.\"\"\"\n        return self._use_dns_cache\n\n    def clear_dns_cache(\n        self, host: Optional[str] = None, port: Optional[int] = None\n    ) -> None:\n        \"\"\"Remove specified host/port or clear all dns local cache.\"\"\"\n        if host is not None and port is not None:\n            self._cached_hosts.remove((host, port))\n        elif host is not None or port is not None:\n            raise ValueError(\"either both host and port \" \"or none of them are allowed\")\n        else:\n            self._cached_hosts.clear()\n\n    async def _resolve_host(\n        self, host: str, port: int, traces: Optional[Sequence[\"Trace\"]] = None\n    ) -> List[ResolveResult]:\n        \"\"\"Resolve host and return list of addresses.\"\"\"\n        if is_ip_address(host):\n            return [\n                {\n                    \"hostname\": host,\n                    \"host\": host,\n                    \"port\": port,\n                    \"family\": self._family,\n                    \"proto\": 0,\n                    \"flags\": 0,\n                }\n            ]\n\n        if not self._use_dns_cache:\n\n            if traces:\n                for trace in traces:\n                    await trace.send_dns_resolvehost_start(host)\n\n            res = await self._resolver.resolve(host, port, family=self._family)\n\n            if traces:\n                for trace in traces:\n                    await trace.send_dns_resolvehost_end(host)\n\n            return res\n\n        key = (host, port)\n        if key in self._cached_hosts and not self._cached_hosts.expired(key):\n            # get result early, before any await (#4014)\n            result = self._cached_hosts.next_addrs(key)\n\n            if traces:\n                for trace in traces:\n                    await trace.send_dns_cache_hit(host)\n            return result\n\n        #\n        # If multiple connectors are resolving the same host, we wait\n        # for the first one to resolve and then use the result for all of them.\n        # We use a throttle event to ensure that we only resolve the host once\n        # and then use the result for all the waiters.\n        #\n        # In this case we need to create a task to ensure that we can shield\n        # the task from cancellation as cancelling this lookup should not cancel\n        # the underlying lookup or else the cancel event will get broadcast to\n        # all the waiters across all connections.\n        #\n        resolved_host_task = asyncio.create_task(\n            self._resolve_host_with_throttle(key, host, port, traces)\n        )\n        self._resolve_host_tasks.add(resolved_host_task)\n        resolved_host_task.add_done_callback(self._resolve_host_tasks.discard)\n        try:\n            return await asyncio.shield(resolved_host_task)\n        except asyncio.CancelledError:\n\n            def drop_exception(fut: \"asyncio.Future[List[ResolveResult]]\") -> None:\n                with suppress(Exception, asyncio.CancelledError):\n                    fut.result()\n\n            resolved_host_task.add_done_callback(drop_exception)\n            raise\n\n    async def _resolve_host_with_throttle(\n        self,\n        key: Tuple[str, int],\n        host: str,\n        port: int,\n        traces: Optional[Sequence[\"Trace\"]],\n    ) -> List[ResolveResult]:\n        \"\"\"Resolve host with a dns events throttle.\"\"\"\n        if key in self._throttle_dns_events:\n            # get event early, before any await (#4014)\n            event = self._throttle_dns_events[key]\n            if traces:\n                for trace in traces:\n                    await trace.send_dns_cache_hit(host)\n            await event.wait()\n        else:\n            # update dict early, before any await (#4014)\n            self._throttle_dns_events[key] = EventResultOrError(self._loop)\n            if traces:\n                for trace in traces:\n                    await trace.send_dns_cache_miss(host)\n            try:\n\n                if traces:\n                    for trace in traces:\n                        await trace.send_dns_resolvehost_start(host)\n\n                addrs = await self._resolver.resolve(host, port, family=self._family)\n                if traces:\n                    for trace in traces:\n                        await trace.send_dns_resolvehost_end(host)\n\n                self._cached_hosts.add(key, addrs)\n                self._throttle_dns_events[key].set()\n            except BaseException as e:\n                # any DNS exception, independently of the implementation\n                # is set for the waiters to raise the same exception.\n                self._throttle_dns_events[key].set(exc=e)\n                raise\n            finally:\n                self._throttle_dns_events.pop(key)\n\n        return self._cached_hosts.next_addrs(key)\n\n    async def _create_connection(\n        self, req: ClientRequest, traces: List[\"Trace\"], timeout: \"ClientTimeout\"\n    ) -> ResponseHandler:\n        \"\"\"Create connection.\n\n        Has same keyword arguments as BaseEventLoop.create_connection.\n        \"\"\"\n        if req.proxy:\n            _, proto = await self._create_proxy_connection(req, traces, timeout)\n        else:\n            _, proto = await self._create_direct_connection(req, traces, timeout)\n\n        return proto\n\n    @staticmethod\n    def _make_ssl_context(verified: bool) -> SSLContext:\n        \"\"\"Create SSL context.\n\n        This method is not async-friendly and should be called from a thread\n        because it will load certificates from disk and do other blocking I/O.\n        \"\"\"\n        if verified:\n            return ssl.create_default_context()\n        sslcontext = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)\n        sslcontext.options |= ssl.OP_NO_SSLv2\n        sslcontext.options |= ssl.OP_NO_SSLv3\n        sslcontext.check_hostname = False\n        sslcontext.verify_mode = ssl.CERT_NONE\n        sslcontext.options |= ssl.OP_NO_COMPRESSION\n        sslcontext.set_default_verify_paths()\n        return sslcontext\n\n    async def _get_ssl_context(self, req: ClientRequest) -> Optional[SSLContext]:\n        \"\"\"Logic to get the correct SSL context\n\n        0. if req.ssl is false, return None\n\n        1. if ssl_context is specified in req, use it\n        2. if _ssl_context is specified in self, use it\n        3. otherwise:\n            1. if verify_ssl is not specified in req, use self.ssl_context\n               (will generate a default context according to self.verify_ssl)\n            2. if verify_ssl is True in req, generate a default SSL context\n            3. if verify_ssl is False in req, generate a SSL context that\n               won't verify\n        \"\"\"\n        if not req.is_ssl():\n            return None\n\n        if ssl is None:  # pragma: no cover\n            raise RuntimeError(\"SSL is not supported.\")\n        sslcontext = req.ssl\n        if isinstance(sslcontext, ssl.SSLContext):\n            return sslcontext\n        if sslcontext is not True:\n            # not verified or fingerprinted\n            return await self._make_or_get_ssl_context(False)\n        sslcontext = self._ssl\n        if isinstance(sslcontext, ssl.SSLContext):\n            return sslcontext\n        if sslcontext is not True:\n            # not verified or fingerprinted\n            return await self._make_or_get_ssl_context(False)\n        return await self._make_or_get_ssl_context(True)\n\n    async def _make_or_get_ssl_context(self, verified: bool) -> SSLContext:\n        \"\"\"Create or get cached SSL context.\"\"\"\n        try:\n            return await self._made_ssl_context[verified]\n        except KeyError:\n            loop = self._loop\n            future = loop.create_future()\n            self._made_ssl_context[verified] = future\n            try:\n                result = await loop.run_in_executor(\n                    None, self._make_ssl_context, verified\n                )\n            # BaseException is used since we might get CancelledError\n            except BaseException as ex:\n                del self._made_ssl_context[verified]\n                set_exception(future, ex)\n                raise\n            else:\n                set_result(future, result)\n            return result\n\n    def _get_fingerprint(self, req: ClientRequest) -> Optional[\"Fingerprint\"]:\n        ret = req.ssl\n        if isinstance(ret, Fingerprint):\n            return ret\n        ret = self._ssl\n        if isinstance(ret, Fingerprint):\n            return ret\n        return None\n\n    async def _wrap_create_connection(\n        self,\n        *args: Any,\n        addr_infos: List[aiohappyeyeballs.AddrInfoType],\n        req: ClientRequest,\n        timeout: \"ClientTimeout\",\n        client_error: Type[Exception] = ClientConnectorError,\n        **kwargs: Any,\n    ) -> Tuple[asyncio.Transport, ResponseHandler]:\n        try:\n            async with ceil_timeout(\n                timeout.sock_connect, ceil_threshold=timeout.ceil_threshold\n            ):\n                sock = await aiohappyeyeballs.start_connection(\n                    addr_infos=addr_infos,\n                    local_addr_infos=self._local_addr_infos,\n                    happy_eyeballs_delay=self._happy_eyeballs_delay,\n                    interleave=self._interleave,\n                    loop=self._loop,\n                )\n                return await self._loop.create_connection(*args, **kwargs, sock=sock)\n        except cert_errors as exc:\n            raise ClientConnectorCertificateError(req.connection_key, exc) from exc\n        except ssl_errors as exc:\n            raise ClientConnectorSSLError(req.connection_key, exc) from exc\n        except OSError as exc:\n            if exc.errno is None and isinstance(exc, asyncio.TimeoutError):\n                raise\n            raise client_error(req.connection_key, exc) from exc\n\n    async def _wrap_existing_connection(\n        self,\n        *args: Any,\n        req: ClientRequest,\n        timeout: \"ClientTimeout\",\n        client_error: Type[Exception] = ClientConnectorError,\n        **kwargs: Any,\n    ) -> Tuple[asyncio.Transport, ResponseHandler]:\n        try:\n            async with ceil_timeout(\n                timeout.sock_connect, ceil_threshold=timeout.ceil_threshold\n            ):\n                return await self._loop.create_connection(*args, **kwargs)\n        except cert_errors as exc:\n            raise ClientConnectorCertificateError(req.connection_key, exc) from exc\n        except ssl_errors as exc:\n            raise ClientConnectorSSLError(req.connection_key, exc) from exc\n        except OSError as exc:\n            if exc.errno is None and isinstance(exc, asyncio.TimeoutError):\n                raise\n            raise client_error(req.connection_key, exc) from exc\n\n    def _fail_on_no_start_tls(self, req: \"ClientRequest\") -> None:\n        \"\"\"Raise a :py:exc:`RuntimeError` on missing ``start_tls()``.\n\n        It is necessary for TLS-in-TLS so that it is possible to\n        send HTTPS queries through HTTPS proxies.\n\n        This doesn't affect regular HTTP requests, though.\n        \"\"\"\n        if not req.is_ssl():\n            return\n\n        proxy_url = req.proxy\n        assert proxy_url is not None\n        if proxy_url.scheme != \"https\":\n            return\n\n        self._check_loop_for_start_tls()\n\n    def _check_loop_for_start_tls(self) -> None:\n        try:\n            self._loop.start_tls\n        except AttributeError as attr_exc:\n            raise RuntimeError(\n                \"An HTTPS request is being sent through an HTTPS proxy. \"\n                \"This needs support for TLS in TLS but it is not implemented \"\n                \"in your runtime for the stdlib asyncio.\\n\\n\"\n                \"Please upgrade to Python 3.11 or higher. For more details, \"\n                \"please see:\\n\"\n                \"* https://bugs.python.org/issue37179\\n\"\n                \"* https://github.com/python/cpython/pull/28073\\n\"\n                \"* https://docs.aiohttp.org/en/stable/\"\n                \"client_advanced.html#proxy-support\\n\"\n                \"* https://github.com/aio-libs/aiohttp/discussions/6044\\n\",\n            ) from attr_exc\n\n    def _loop_supports_start_tls(self) -> bool:\n        try:\n            self._check_loop_for_start_tls()\n        except RuntimeError:\n            return False\n        else:\n            return True\n\n    def _warn_about_tls_in_tls(\n        self,\n        underlying_transport: asyncio.Transport,\n        req: ClientRequest,\n    ) -> None:\n        \"\"\"Issue a warning if the requested URL has HTTPS scheme.\"\"\"\n        if req.request_info.url.scheme != \"https\":\n            return\n\n        asyncio_supports_tls_in_tls = getattr(\n            underlying_transport,\n            \"_start_tls_compatible\",\n            False,\n        )\n\n        if asyncio_supports_tls_in_tls:\n            return\n\n        warnings.warn(\n            \"An HTTPS request is being sent through an HTTPS proxy. \"\n            \"This support for TLS in TLS is known to be disabled \"\n            \"in the stdlib asyncio (Python <3.11). This is why you'll probably see \"\n            \"an error in the log below.\\n\\n\"\n            \"It is possible to enable it via monkeypatching. \"\n            \"For more details, see:\\n\"\n            \"* https://bugs.python.org/issue37179\\n\"\n            \"* https://github.com/python/cpython/pull/28073\\n\\n\"\n            \"You can temporarily patch this as follows:\\n\"\n            \"* https://docs.aiohttp.org/en/stable/client_advanced.html#proxy-support\\n\"\n            \"* https://github.com/aio-libs/aiohttp/discussions/6044\\n\",\n            RuntimeWarning,\n            source=self,\n            # Why `4`? At least 3 of the calls in the stack originate\n            # from the methods in this class.\n            stacklevel=3,\n        )\n\n    async def _start_tls_connection(\n        self,\n        underlying_transport: asyncio.Transport,\n        req: ClientRequest,\n        timeout: \"ClientTimeout\",\n        client_error: Type[Exception] = ClientConnectorError,\n    ) -> Tuple[asyncio.BaseTransport, ResponseHandler]:\n        \"\"\"Wrap the raw TCP transport with TLS.\"\"\"\n        tls_proto = self._factory()  # Create a brand new proto for TLS\n\n        # Safety of the `cast()` call here is based on the fact that\n        # internally `_get_ssl_context()` only returns `None` when\n        # `req.is_ssl()` evaluates to `False` which is never gonna happen\n        # in this code path. Of course, it's rather fragile\n        # maintainability-wise but this is to be solved separately.\n        sslcontext = cast(ssl.SSLContext, await self._get_ssl_context(req))\n\n        try:\n            async with ceil_timeout(\n                timeout.sock_connect, ceil_threshold=timeout.ceil_threshold\n            ):\n                try:\n                    tls_transport = await self._loop.start_tls(\n                        underlying_transport,\n                        tls_proto,\n                        sslcontext,\n                        server_hostname=req.server_hostname or req.host,\n                        ssl_handshake_timeout=timeout.total,\n                    )\n                except BaseException:\n                    # We need to close the underlying transport since\n                    # `start_tls()` probably failed before it had a\n                    # chance to do this:\n                    underlying_transport.close()\n                    raise\n        except cert_errors as exc:\n            raise ClientConnectorCertificateError(req.connection_key, exc) from exc\n        except ssl_errors as exc:\n            raise ClientConnectorSSLError(req.connection_key, exc) from exc\n        except OSError as exc:\n            if exc.errno is None and isinstance(exc, asyncio.TimeoutError):\n                raise\n            raise client_error(req.connection_key, exc) from exc\n        except TypeError as type_err:\n            # Example cause looks like this:\n            # TypeError: transport <asyncio.sslproto._SSLProtocolTransport\n            # object at 0x7f760615e460> is not supported by start_tls()\n\n            raise ClientConnectionError(\n                \"Cannot initialize a TLS-in-TLS connection to host \"\n                f\"{req.host!s}:{req.port:d} through an underlying connection \"\n                f\"to an HTTPS proxy {req.proxy!s} ssl:{req.ssl or 'default'} \"\n                f\"[{type_err!s}]\"\n            ) from type_err\n        else:\n            if tls_transport is None:\n                msg = \"Failed to start TLS (possibly caused by closing transport)\"\n                raise client_error(req.connection_key, OSError(msg))\n            tls_proto.connection_made(\n                tls_transport\n            )  # Kick the state machine of the new TLS protocol\n\n        return tls_transport, tls_proto\n\n    def _convert_hosts_to_addr_infos(\n        self, hosts: List[ResolveResult]\n    ) -> List[aiohappyeyeballs.AddrInfoType]:\n        \"\"\"Converts the list of hosts to a list of addr_infos.\n\n        The list of hosts is the result of a DNS lookup. The list of\n        addr_infos is the result of a call to `socket.getaddrinfo()`.\n        \"\"\"\n        addr_infos: List[aiohappyeyeballs.AddrInfoType] = []\n        for hinfo in hosts:\n            host = hinfo[\"host\"]\n            is_ipv6 = \":\" in host\n            family = socket.AF_INET6 if is_ipv6 else socket.AF_INET\n            if self._family and self._family != family:\n                continue\n            addr = (host, hinfo[\"port\"], 0, 0) if is_ipv6 else (host, hinfo[\"port\"])\n            addr_infos.append(\n                (family, socket.SOCK_STREAM, socket.IPPROTO_TCP, \"\", addr)\n            )\n        return addr_infos\n\n    async def _create_direct_connection(\n        self,\n        req: ClientRequest,\n        traces: List[\"Trace\"],\n        timeout: \"ClientTimeout\",\n        *,\n        client_error: Type[Exception] = ClientConnectorError,\n    ) -> Tuple[asyncio.Transport, ResponseHandler]:\n        sslcontext = await self._get_ssl_context(req)\n        fingerprint = self._get_fingerprint(req)\n\n        host = req.url.raw_host\n        assert host is not None\n        # Replace multiple trailing dots with a single one.\n        # A trailing dot is only present for fully-qualified domain names.\n        # See https://github.com/aio-libs/aiohttp/pull/7364.\n        if host.endswith(\"..\"):\n            host = host.rstrip(\".\") + \".\"\n        port = req.port\n        assert port is not None\n        try:\n            # Cancelling this lookup should not cancel the underlying lookup\n            #  or else the cancel event will get broadcast to all the waiters\n            #  across all connections.\n            hosts = await self._resolve_host(host, port, traces=traces)\n        except OSError as exc:\n            if exc.errno is None and isinstance(exc, asyncio.TimeoutError):\n                raise\n            # in case of proxy it is not ClientProxyConnectionError\n            # it is problem of resolving proxy ip itself\n            raise ClientConnectorError(req.connection_key, exc) from exc\n\n        last_exc: Optional[Exception] = None\n        addr_infos = self._convert_hosts_to_addr_infos(hosts)\n        while addr_infos:\n            # Strip trailing dots, certificates contain FQDN without dots.\n            # See https://github.com/aio-libs/aiohttp/issues/3636\n            server_hostname = (\n                (req.server_hostname or host).rstrip(\".\") if sslcontext else None\n            )\n\n            try:\n                transp, proto = await self._wrap_create_connection(\n                    self._factory,\n                    timeout=timeout,\n                    ssl=sslcontext,\n                    addr_infos=addr_infos,\n                    server_hostname=server_hostname,\n                    req=req,\n                    client_error=client_error,\n                )\n            except ClientConnectorError as exc:\n                last_exc = exc\n                aiohappyeyeballs.pop_addr_infos_interleave(addr_infos, self._interleave)\n                continue\n\n            if req.is_ssl() and fingerprint:\n                try:\n                    fingerprint.check(transp)\n                except ServerFingerprintMismatch as exc:\n                    transp.close()\n                    if not self._cleanup_closed_disabled:\n                        self._cleanup_closed_transports.append(transp)\n                    last_exc = exc\n                    # Remove the bad peer from the list of addr_infos\n                    sock: socket.socket = transp.get_extra_info(\"socket\")\n                    bad_peer = sock.getpeername()\n                    aiohappyeyeballs.remove_addr_infos(addr_infos, bad_peer)\n                    continue\n\n            return transp, proto\n        else:\n            assert last_exc is not None\n            raise last_exc\n\n    async def _create_proxy_connection(\n        self, req: ClientRequest, traces: List[\"Trace\"], timeout: \"ClientTimeout\"\n    ) -> Tuple[asyncio.BaseTransport, ResponseHandler]:\n        self._fail_on_no_start_tls(req)\n        runtime_has_start_tls = self._loop_supports_start_tls()\n\n        headers: Dict[str, str] = {}\n        if req.proxy_headers is not None:\n            headers = req.proxy_headers  # type: ignore[assignment]\n        headers[hdrs.HOST] = req.headers[hdrs.HOST]\n\n        url = req.proxy\n        assert url is not None\n        proxy_req = ClientRequest(\n            hdrs.METH_GET,\n            url,\n            headers=headers,\n            auth=req.proxy_auth,\n            loop=self._loop,\n            ssl=req.ssl,\n        )\n\n        # create connection to proxy server\n        transport, proto = await self._create_direct_connection(\n            proxy_req, [], timeout, client_error=ClientProxyConnectionError\n        )\n\n        auth = proxy_req.headers.pop(hdrs.AUTHORIZATION, None)\n        if auth is not None:\n            if not req.is_ssl():\n                req.headers[hdrs.PROXY_AUTHORIZATION] = auth\n            else:\n                proxy_req.headers[hdrs.PROXY_AUTHORIZATION] = auth\n\n        if req.is_ssl():\n            if runtime_has_start_tls:\n                self._warn_about_tls_in_tls(transport, req)\n\n            # For HTTPS requests over HTTP proxy\n            # we must notify proxy to tunnel connection\n            # so we send CONNECT command:\n            #   CONNECT www.python.org:443 HTTP/1.1\n            #   Host: www.python.org\n            #\n            # next we must do TLS handshake and so on\n            # to do this we must wrap raw socket into secure one\n            # asyncio handles this perfectly\n            proxy_req.method = hdrs.METH_CONNECT\n            proxy_req.url = req.url\n            key = attr.evolve(\n                req.connection_key, proxy=None, proxy_auth=None, proxy_headers_hash=None\n            )\n            conn = Connection(self, key, proto, self._loop)\n            proxy_resp = await proxy_req.send(conn)\n            try:\n                protocol = conn._protocol\n                assert protocol is not None\n\n                # read_until_eof=True will ensure the connection isn't closed\n                # once the response is received and processed allowing\n                # START_TLS to work on the connection below.\n                protocol.set_response_params(\n                    read_until_eof=runtime_has_start_tls,\n                    timeout_ceil_threshold=self._timeout_ceil_threshold,\n                )\n                resp = await proxy_resp.start(conn)\n            except BaseException:\n                proxy_resp.close()\n                conn.close()\n                raise\n            else:\n                conn._protocol = None\n                conn._transport = None\n                try:\n                    if resp.status != 200:\n                        message = resp.reason\n                        if message is None:\n                            message = HTTPStatus(resp.status).phrase\n                        raise ClientHttpProxyError(\n                            proxy_resp.request_info,\n                            resp.history,\n                            status=resp.status,\n                            message=message,\n                            headers=resp.headers,\n                        )\n                    if not runtime_has_start_tls:\n                        rawsock = transport.get_extra_info(\"socket\", default=None)\n                        if rawsock is None:\n                            raise RuntimeError(\n                                \"Transport does not expose socket instance\"\n                            )\n                        # Duplicate the socket, so now we can close proxy transport\n                        rawsock = rawsock.dup()\n                except BaseException:\n                    # It shouldn't be closed in `finally` because it's fed to\n                    # `loop.start_tls()` and the docs say not to touch it after\n                    # passing there.\n                    transport.close()\n                    raise\n                finally:\n                    if not runtime_has_start_tls:\n                        transport.close()\n\n                if not runtime_has_start_tls:\n                    # HTTP proxy with support for upgrade to HTTPS\n                    sslcontext = self._get_ssl_context(req)\n                    return await self._wrap_existing_connection(\n                        self._factory,\n                        timeout=timeout,\n                        ssl=sslcontext,\n                        sock=rawsock,\n                        server_hostname=req.host,\n                        req=req,\n                    )\n\n                return await self._start_tls_connection(\n                    # Access the old transport for the last time before it's\n                    # closed and forgotten forever:\n                    transport,\n                    req=req,\n                    timeout=timeout,\n                )\n            finally:\n                proxy_resp.close()\n\n        return transport, proto",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 829,
                            "end_lineno": 837,
                            "parent": {
                                "file_name": "aiohttp/connector.py",
                                "type": "class",
                                "name": "TCPConnector",
                                "content": "class TCPConnector(BaseConnector):\n    \"\"\"TCP connector.\n\n    verify_ssl - Set to True to check ssl certifications.\n    fingerprint - Pass the binary sha256\n        digest of the expected certificate in DER format to verify\n        that the certificate the server presents matches. See also\n        https://en.wikipedia.org/wiki/HTTP_Public_Key_Pinning\n    resolver - Enable DNS lookups and use this\n        resolver\n    use_dns_cache - Use memory cache for DNS lookups.\n    ttl_dns_cache - Max seconds having cached a DNS entry, None forever.\n    family - socket address family\n    local_addr - local tuple of (host, port) to bind socket to\n\n    keepalive_timeout - (optional) Keep-alive timeout.\n    force_close - Set to True to force close and do reconnect\n        after each request (and between redirects).\n    limit - The total number of simultaneous connections.\n    limit_per_host - Number of simultaneous connections to one host.\n    enable_cleanup_closed - Enables clean-up closed ssl transports.\n                            Disabled by default.\n    happy_eyeballs_delay - This is the “Connection Attempt Delay”\n                           as defined in RFC 8305. To disable\n                           the happy eyeballs algorithm, set to None.\n    interleave - “First Address Family Count” as defined in RFC 8305\n    loop - Optional event loop.\n    \"\"\"\n\n    allowed_protocol_schema_set = HIGH_LEVEL_SCHEMA_SET | frozenset({\"tcp\"})\n    _made_ssl_context: Dict[bool, \"asyncio.Future[SSLContext]\"] = {}\n\n    def __init__(\n        self,\n        *,\n        verify_ssl: bool = True,\n        fingerprint: Optional[bytes] = None,\n        use_dns_cache: bool = True,\n        ttl_dns_cache: Optional[int] = 10,\n        family: socket.AddressFamily = socket.AddressFamily.AF_UNSPEC,\n        ssl_context: Optional[SSLContext] = None,\n        ssl: Union[bool, Fingerprint, SSLContext] = True,\n        local_addr: Optional[Tuple[str, int]] = None,\n        resolver: Optional[AbstractResolver] = None,\n        keepalive_timeout: Union[None, float, object] = sentinel,\n        force_close: bool = False,\n        limit: int = 100,\n        limit_per_host: int = 0,\n        enable_cleanup_closed: bool = False,\n        loop: Optional[asyncio.AbstractEventLoop] = None,\n        timeout_ceil_threshold: float = 5,\n        happy_eyeballs_delay: Optional[float] = 0.25,\n        interleave: Optional[int] = None,\n    ):\n        super().__init__(\n            keepalive_timeout=keepalive_timeout,\n            force_close=force_close,\n            limit=limit,\n            limit_per_host=limit_per_host,\n            enable_cleanup_closed=enable_cleanup_closed,\n            loop=loop,\n            timeout_ceil_threshold=timeout_ceil_threshold,\n        )\n\n        self._ssl = _merge_ssl_params(ssl, verify_ssl, ssl_context, fingerprint)\n        if resolver is None:\n            resolver = DefaultResolver(loop=self._loop)\n        self._resolver = resolver\n\n        self._use_dns_cache = use_dns_cache\n        self._cached_hosts = _DNSCacheTable(ttl=ttl_dns_cache)\n        self._throttle_dns_events: Dict[Tuple[str, int], EventResultOrError] = {}\n        self._family = family\n        self._local_addr_infos = aiohappyeyeballs.addr_to_addr_infos(local_addr)\n        self._happy_eyeballs_delay = happy_eyeballs_delay\n        self._interleave = interleave\n        self._resolve_host_tasks: Set[\"asyncio.Task[List[ResolveResult]]\"] = set()\n\n    def close(self) -> Awaitable[None]:\n        \"\"\"Close all ongoing DNS calls.\"\"\"\n        for ev in self._throttle_dns_events.values():\n            ev.cancel()\n\n        for t in self._resolve_host_tasks:\n            t.cancel()\n\n        return super().close()\n\n    @property\n    def family(self) -> int:\n        \"\"\"Socket family like AF_INET.\"\"\"\n        return self._family\n\n    @property\n    def use_dns_cache(self) -> bool:\n        \"\"\"True if local DNS caching is enabled.\"\"\"\n        return self._use_dns_cache\n\n    def clear_dns_cache(\n        self, host: Optional[str] = None, port: Optional[int] = None\n    ) -> None:\n        \"\"\"Remove specified host/port or clear all dns local cache.\"\"\"\n        if host is not None and port is not None:\n            self._cached_hosts.remove((host, port))\n        elif host is not None or port is not None:\n            raise ValueError(\"either both host and port \" \"or none of them are allowed\")\n        else:\n            self._cached_hosts.clear()\n\n    async def _resolve_host(\n        self, host: str, port: int, traces: Optional[Sequence[\"Trace\"]] = None\n    ) -> List[ResolveResult]:\n        \"\"\"Resolve host and return list of addresses.\"\"\"\n        if is_ip_address(host):\n            return [\n                {\n                    \"hostname\": host,\n                    \"host\": host,\n                    \"port\": port,\n                    \"family\": self._family,\n                    \"proto\": 0,\n                    \"flags\": 0,\n                }\n            ]\n\n        if not self._use_dns_cache:\n\n            if traces:\n                for trace in traces:\n                    await trace.send_dns_resolvehost_start(host)\n\n            res = await self._resolver.resolve(host, port, family=self._family)\n\n            if traces:\n                for trace in traces:\n                    await trace.send_dns_resolvehost_end(host)\n\n            return res\n\n        key = (host, port)\n        if key in self._cached_hosts and not self._cached_hosts.expired(key):\n            # get result early, before any await (#4014)\n            result = self._cached_hosts.next_addrs(key)\n\n            if traces:\n                for trace in traces:\n                    await trace.send_dns_cache_hit(host)\n            return result\n\n        #\n        # If multiple connectors are resolving the same host, we wait\n        # for the first one to resolve and then use the result for all of them.\n        # We use a throttle event to ensure that we only resolve the host once\n        # and then use the result for all the waiters.\n        #\n        # In this case we need to create a task to ensure that we can shield\n        # the task from cancellation as cancelling this lookup should not cancel\n        # the underlying lookup or else the cancel event will get broadcast to\n        # all the waiters across all connections.\n        #\n        resolved_host_task = asyncio.create_task(\n            self._resolve_host_with_throttle(key, host, port, traces)\n        )\n        self._resolve_host_tasks.add(resolved_host_task)\n        resolved_host_task.add_done_callback(self._resolve_host_tasks.discard)\n        try:\n            return await asyncio.shield(resolved_host_task)\n        except asyncio.CancelledError:\n\n            def drop_exception(fut: \"asyncio.Future[List[ResolveResult]]\") -> None:\n                with suppress(Exception, asyncio.CancelledError):\n                    fut.result()\n\n            resolved_host_task.add_done_callback(drop_exception)\n            raise\n\n    async def _resolve_host_with_throttle(\n        self,\n        key: Tuple[str, int],\n        host: str,\n        port: int,\n        traces: Optional[Sequence[\"Trace\"]],\n    ) -> List[ResolveResult]:\n        \"\"\"Resolve host with a dns events throttle.\"\"\"\n        if key in self._throttle_dns_events:\n            # get event early, before any await (#4014)\n            event = self._throttle_dns_events[key]\n            if traces:\n                for trace in traces:\n                    await trace.send_dns_cache_hit(host)\n            await event.wait()\n        else:\n            # update dict early, before any await (#4014)\n            self._throttle_dns_events[key] = EventResultOrError(self._loop)\n            if traces:\n                for trace in traces:\n                    await trace.send_dns_cache_miss(host)\n            try:\n\n                if traces:\n                    for trace in traces:\n                        await trace.send_dns_resolvehost_start(host)\n\n                addrs = await self._resolver.resolve(host, port, family=self._family)\n                if traces:\n                    for trace in traces:\n                        await trace.send_dns_resolvehost_end(host)\n\n                self._cached_hosts.add(key, addrs)\n                self._throttle_dns_events[key].set()\n            except BaseException as e:\n                # any DNS exception, independently of the implementation\n                # is set for the waiters to raise the same exception.\n                self._throttle_dns_events[key].set(exc=e)\n                raise\n            finally:\n                self._throttle_dns_events.pop(key)\n\n        return self._cached_hosts.next_addrs(key)\n\n    async def _create_connection(\n        self, req: ClientRequest, traces: List[\"Trace\"], timeout: \"ClientTimeout\"\n    ) -> ResponseHandler:\n        \"\"\"Create connection.\n\n        Has same keyword arguments as BaseEventLoop.create_connection.\n        \"\"\"\n        if req.proxy:\n            _, proto = await self._create_proxy_connection(req, traces, timeout)\n        else:\n            _, proto = await self._create_direct_connection(req, traces, timeout)\n\n        return proto\n\n    @staticmethod\n    def _make_ssl_context(verified: bool) -> SSLContext:\n        \"\"\"Create SSL context.\n\n        This method is not async-friendly and should be called from a thread\n        because it will load certificates from disk and do other blocking I/O.\n        \"\"\"\n        if verified:\n            return ssl.create_default_context()\n        sslcontext = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)\n        sslcontext.options |= ssl.OP_NO_SSLv2\n        sslcontext.options |= ssl.OP_NO_SSLv3\n        sslcontext.check_hostname = False\n        sslcontext.verify_mode = ssl.CERT_NONE\n        sslcontext.options |= ssl.OP_NO_COMPRESSION\n        sslcontext.set_default_verify_paths()\n        return sslcontext\n\n    async def _get_ssl_context(self, req: ClientRequest) -> Optional[SSLContext]:\n        \"\"\"Logic to get the correct SSL context\n\n        0. if req.ssl is false, return None\n\n        1. if ssl_context is specified in req, use it\n        2. if _ssl_context is specified in self, use it\n        3. otherwise:\n            1. if verify_ssl is not specified in req, use self.ssl_context\n               (will generate a default context according to self.verify_ssl)\n            2. if verify_ssl is True in req, generate a default SSL context\n            3. if verify_ssl is False in req, generate a SSL context that\n               won't verify\n        \"\"\"\n        if not req.is_ssl():\n            return None\n\n        if ssl is None:  # pragma: no cover\n            raise RuntimeError(\"SSL is not supported.\")\n        sslcontext = req.ssl\n        if isinstance(sslcontext, ssl.SSLContext):\n            return sslcontext\n        if sslcontext is not True:\n            # not verified or fingerprinted\n            return await self._make_or_get_ssl_context(False)\n        sslcontext = self._ssl\n        if isinstance(sslcontext, ssl.SSLContext):\n            return sslcontext\n        if sslcontext is not True:\n            # not verified or fingerprinted\n            return await self._make_or_get_ssl_context(False)\n        return await self._make_or_get_ssl_context(True)\n\n    async def _make_or_get_ssl_context(self, verified: bool) -> SSLContext:\n        \"\"\"Create or get cached SSL context.\"\"\"\n        try:\n            return await self._made_ssl_context[verified]\n        except KeyError:\n            loop = self._loop\n            future = loop.create_future()\n            self._made_ssl_context[verified] = future\n            try:\n                result = await loop.run_in_executor(\n                    None, self._make_ssl_context, verified\n                )\n            # BaseException is used since we might get CancelledError\n            except BaseException as ex:\n                del self._made_ssl_context[verified]\n                set_exception(future, ex)\n                raise\n            else:\n                set_result(future, result)\n            return result\n\n    def _get_fingerprint(self, req: ClientRequest) -> Optional[\"Fingerprint\"]:\n        ret = req.ssl\n        if isinstance(ret, Fingerprint):\n            return ret\n        ret = self._ssl\n        if isinstance(ret, Fingerprint):\n            return ret\n        return None\n\n    async def _wrap_create_connection(\n        self,\n        *args: Any,\n        addr_infos: List[aiohappyeyeballs.AddrInfoType],\n        req: ClientRequest,\n        timeout: \"ClientTimeout\",\n        client_error: Type[Exception] = ClientConnectorError,\n        **kwargs: Any,\n    ) -> Tuple[asyncio.Transport, ResponseHandler]:\n        try:\n            async with ceil_timeout(\n                timeout.sock_connect, ceil_threshold=timeout.ceil_threshold\n            ):\n                sock = await aiohappyeyeballs.start_connection(\n                    addr_infos=addr_infos,\n                    local_addr_infos=self._local_addr_infos,\n                    happy_eyeballs_delay=self._happy_eyeballs_delay,\n                    interleave=self._interleave,\n                    loop=self._loop,\n                )\n                return await self._loop.create_connection(*args, **kwargs, sock=sock)\n        except cert_errors as exc:\n            raise ClientConnectorCertificateError(req.connection_key, exc) from exc\n        except ssl_errors as exc:\n            raise ClientConnectorSSLError(req.connection_key, exc) from exc\n        except OSError as exc:\n            if exc.errno is None and isinstance(exc, asyncio.TimeoutError):\n                raise\n            raise client_error(req.connection_key, exc) from exc\n\n    async def _wrap_existing_connection(\n        self,\n        *args: Any,\n        req: ClientRequest,\n        timeout: \"ClientTimeout\",\n        client_error: Type[Exception] = ClientConnectorError,\n        **kwargs: Any,\n    ) -> Tuple[asyncio.Transport, ResponseHandler]:\n        try:\n            async with ceil_timeout(\n                timeout.sock_connect, ceil_threshold=timeout.ceil_threshold\n            ):\n                return await self._loop.create_connection(*args, **kwargs)\n        except cert_errors as exc:\n            raise ClientConnectorCertificateError(req.connection_key, exc) from exc\n        except ssl_errors as exc:\n            raise ClientConnectorSSLError(req.connection_key, exc) from exc\n        except OSError as exc:\n            if exc.errno is None and isinstance(exc, asyncio.TimeoutError):\n                raise\n            raise client_error(req.connection_key, exc) from exc\n\n    def _fail_on_no_start_tls(self, req: \"ClientRequest\") -> None:\n        \"\"\"Raise a :py:exc:`RuntimeError` on missing ``start_tls()``.\n\n        It is necessary for TLS-in-TLS so that it is possible to\n        send HTTPS queries through HTTPS proxies.\n\n        This doesn't affect regular HTTP requests, though.\n        \"\"\"\n        if not req.is_ssl():\n            return\n\n        proxy_url = req.proxy\n        assert proxy_url is not None\n        if proxy_url.scheme != \"https\":\n            return\n\n        self._check_loop_for_start_tls()\n\n    def _check_loop_for_start_tls(self) -> None:\n        try:\n            self._loop.start_tls\n        except AttributeError as attr_exc:\n            raise RuntimeError(\n                \"An HTTPS request is being sent through an HTTPS proxy. \"\n                \"This needs support for TLS in TLS but it is not implemented \"\n                \"in your runtime for the stdlib asyncio.\\n\\n\"\n                \"Please upgrade to Python 3.11 or higher. For more details, \"\n                \"please see:\\n\"\n                \"* https://bugs.python.org/issue37179\\n\"\n                \"* https://github.com/python/cpython/pull/28073\\n\"\n                \"* https://docs.aiohttp.org/en/stable/\"\n                \"client_advanced.html#proxy-support\\n\"\n                \"* https://github.com/aio-libs/aiohttp/discussions/6044\\n\",\n            ) from attr_exc\n\n    def _loop_supports_start_tls(self) -> bool:\n        try:\n            self._check_loop_for_start_tls()\n        except RuntimeError:\n            return False\n        else:\n            return True\n\n    def _warn_about_tls_in_tls(\n        self,\n        underlying_transport: asyncio.Transport,\n        req: ClientRequest,\n    ) -> None:\n        \"\"\"Issue a warning if the requested URL has HTTPS scheme.\"\"\"\n        if req.request_info.url.scheme != \"https\":\n            return\n\n        asyncio_supports_tls_in_tls = getattr(\n            underlying_transport,\n            \"_start_tls_compatible\",\n            False,\n        )\n\n        if asyncio_supports_tls_in_tls:\n            return\n\n        warnings.warn(\n            \"An HTTPS request is being sent through an HTTPS proxy. \"\n            \"This support for TLS in TLS is known to be disabled \"\n            \"in the stdlib asyncio (Python <3.11). This is why you'll probably see \"\n            \"an error in the log below.\\n\\n\"\n            \"It is possible to enable it via monkeypatching. \"\n            \"For more details, see:\\n\"\n            \"* https://bugs.python.org/issue37179\\n\"\n            \"* https://github.com/python/cpython/pull/28073\\n\\n\"\n            \"You can temporarily patch this as follows:\\n\"\n            \"* https://docs.aiohttp.org/en/stable/client_advanced.html#proxy-support\\n\"\n            \"* https://github.com/aio-libs/aiohttp/discussions/6044\\n\",\n            RuntimeWarning,\n            source=self,\n            # Why `4`? At least 3 of the calls in the stack originate\n            # from the methods in this class.\n            stacklevel=3,\n        )\n\n    async def _start_tls_connection(\n        self,\n        underlying_transport: asyncio.Transport,\n        req: ClientRequest,\n        timeout: \"ClientTimeout\",\n        client_error: Type[Exception] = ClientConnectorError,\n    ) -> Tuple[asyncio.BaseTransport, ResponseHandler]:\n        \"\"\"Wrap the raw TCP transport with TLS.\"\"\"\n        tls_proto = self._factory()  # Create a brand new proto for TLS\n\n        # Safety of the `cast()` call here is based on the fact that\n        # internally `_get_ssl_context()` only returns `None` when\n        # `req.is_ssl()` evaluates to `False` which is never gonna happen\n        # in this code path. Of course, it's rather fragile\n        # maintainability-wise but this is to be solved separately.\n        sslcontext = cast(ssl.SSLContext, await self._get_ssl_context(req))\n\n        try:\n            async with ceil_timeout(\n                timeout.sock_connect, ceil_threshold=timeout.ceil_threshold\n            ):\n                try:\n                    tls_transport = await self._loop.start_tls(\n                        underlying_transport,\n                        tls_proto,\n                        sslcontext,\n                        server_hostname=req.server_hostname or req.host,\n                        ssl_handshake_timeout=timeout.total,\n                    )\n                except BaseException:\n                    # We need to close the underlying transport since\n                    # `start_tls()` probably failed before it had a\n                    # chance to do this:\n                    underlying_transport.close()\n                    raise\n        except cert_errors as exc:\n            raise ClientConnectorCertificateError(req.connection_key, exc) from exc\n        except ssl_errors as exc:\n            raise ClientConnectorSSLError(req.connection_key, exc) from exc\n        except OSError as exc:\n            if exc.errno is None and isinstance(exc, asyncio.TimeoutError):\n                raise\n            raise client_error(req.connection_key, exc) from exc\n        except TypeError as type_err:\n            # Example cause looks like this:\n            # TypeError: transport <asyncio.sslproto._SSLProtocolTransport\n            # object at 0x7f760615e460> is not supported by start_tls()\n\n            raise ClientConnectionError(\n                \"Cannot initialize a TLS-in-TLS connection to host \"\n                f\"{req.host!s}:{req.port:d} through an underlying connection \"\n                f\"to an HTTPS proxy {req.proxy!s} ssl:{req.ssl or 'default'} \"\n                f\"[{type_err!s}]\"\n            ) from type_err\n        else:\n            if tls_transport is None:\n                msg = \"Failed to start TLS (possibly caused by closing transport)\"\n                raise client_error(req.connection_key, OSError(msg))\n            tls_proto.connection_made(\n                tls_transport\n            )  # Kick the state machine of the new TLS protocol\n\n        return tls_transport, tls_proto\n\n    def _convert_hosts_to_addr_infos(\n        self, hosts: List[ResolveResult]\n    ) -> List[aiohappyeyeballs.AddrInfoType]:\n        \"\"\"Converts the list of hosts to a list of addr_infos.\n\n        The list of hosts is the result of a DNS lookup. The list of\n        addr_infos is the result of a call to `socket.getaddrinfo()`.\n        \"\"\"\n        addr_infos: List[aiohappyeyeballs.AddrInfoType] = []\n        for hinfo in hosts:\n            host = hinfo[\"host\"]\n            is_ipv6 = \":\" in host\n            family = socket.AF_INET6 if is_ipv6 else socket.AF_INET\n            if self._family and self._family != family:\n                continue\n            addr = (host, hinfo[\"port\"], 0, 0) if is_ipv6 else (host, hinfo[\"port\"])\n            addr_infos.append(\n                (family, socket.SOCK_STREAM, socket.IPPROTO_TCP, \"\", addr)\n            )\n        return addr_infos\n\n    async def _create_direct_connection(\n        self,\n        req: ClientRequest,\n        traces: List[\"Trace\"],\n        timeout: \"ClientTimeout\",\n        *,\n        client_error: Type[Exception] = ClientConnectorError,\n    ) -> Tuple[asyncio.Transport, ResponseHandler]:\n        sslcontext = await self._get_ssl_context(req)\n        fingerprint = self._get_fingerprint(req)\n\n        host = req.url.raw_host\n        assert host is not None\n        # Replace multiple trailing dots with a single one.\n        # A trailing dot is only present for fully-qualified domain names.\n        # See https://github.com/aio-libs/aiohttp/pull/7364.\n        if host.endswith(\"..\"):\n            host = host.rstrip(\".\") + \".\"\n        port = req.port\n        assert port is not None\n        try:\n            # Cancelling this lookup should not cancel the underlying lookup\n            #  or else the cancel event will get broadcast to all the waiters\n            #  across all connections.\n            hosts = await self._resolve_host(host, port, traces=traces)\n        except OSError as exc:\n            if exc.errno is None and isinstance(exc, asyncio.TimeoutError):\n                raise\n            # in case of proxy it is not ClientProxyConnectionError\n            # it is problem of resolving proxy ip itself\n            raise ClientConnectorError(req.connection_key, exc) from exc\n\n        last_exc: Optional[Exception] = None\n        addr_infos = self._convert_hosts_to_addr_infos(hosts)\n        while addr_infos:\n            # Strip trailing dots, certificates contain FQDN without dots.\n            # See https://github.com/aio-libs/aiohttp/issues/3636\n            server_hostname = (\n                (req.server_hostname or host).rstrip(\".\") if sslcontext else None\n            )\n\n            try:\n                transp, proto = await self._wrap_create_connection(\n                    self._factory,\n                    timeout=timeout,\n                    ssl=sslcontext,\n                    addr_infos=addr_infos,\n                    server_hostname=server_hostname,\n                    req=req,\n                    client_error=client_error,\n                )\n            except ClientConnectorError as exc:\n                last_exc = exc\n                aiohappyeyeballs.pop_addr_infos_interleave(addr_infos, self._interleave)\n                continue\n\n            if req.is_ssl() and fingerprint:\n                try:\n                    fingerprint.check(transp)\n                except ServerFingerprintMismatch as exc:\n                    transp.close()\n                    if not self._cleanup_closed_disabled:\n                        self._cleanup_closed_transports.append(transp)\n                    last_exc = exc\n                    # Remove the bad peer from the list of addr_infos\n                    sock: socket.socket = transp.get_extra_info(\"socket\")\n                    bad_peer = sock.getpeername()\n                    aiohappyeyeballs.remove_addr_infos(addr_infos, bad_peer)\n                    continue\n\n            return transp, proto\n        else:\n            assert last_exc is not None\n            raise last_exc\n\n    async def _create_proxy_connection(\n        self, req: ClientRequest, traces: List[\"Trace\"], timeout: \"ClientTimeout\"\n    ) -> Tuple[asyncio.BaseTransport, ResponseHandler]:\n        self._fail_on_no_start_tls(req)\n        runtime_has_start_tls = self._loop_supports_start_tls()\n\n        headers: Dict[str, str] = {}\n        if req.proxy_headers is not None:\n            headers = req.proxy_headers  # type: ignore[assignment]\n        headers[hdrs.HOST] = req.headers[hdrs.HOST]\n\n        url = req.proxy\n        assert url is not None\n        proxy_req = ClientRequest(\n            hdrs.METH_GET,\n            url,\n            headers=headers,\n            auth=req.proxy_auth,\n            loop=self._loop,\n            ssl=req.ssl,\n        )\n\n        # create connection to proxy server\n        transport, proto = await self._create_direct_connection(\n            proxy_req, [], timeout, client_error=ClientProxyConnectionError\n        )\n\n        auth = proxy_req.headers.pop(hdrs.AUTHORIZATION, None)\n        if auth is not None:\n            if not req.is_ssl():\n                req.headers[hdrs.PROXY_AUTHORIZATION] = auth\n            else:\n                proxy_req.headers[hdrs.PROXY_AUTHORIZATION] = auth\n\n        if req.is_ssl():\n            if runtime_has_start_tls:\n                self._warn_about_tls_in_tls(transport, req)\n\n            # For HTTPS requests over HTTP proxy\n            # we must notify proxy to tunnel connection\n            # so we send CONNECT command:\n            #   CONNECT www.python.org:443 HTTP/1.1\n            #   Host: www.python.org\n            #\n            # next we must do TLS handshake and so on\n            # to do this we must wrap raw socket into secure one\n            # asyncio handles this perfectly\n            proxy_req.method = hdrs.METH_CONNECT\n            proxy_req.url = req.url\n            key = attr.evolve(\n                req.connection_key, proxy=None, proxy_auth=None, proxy_headers_hash=None\n            )\n            conn = Connection(self, key, proto, self._loop)\n            proxy_resp = await proxy_req.send(conn)\n            try:\n                protocol = conn._protocol\n                assert protocol is not None\n\n                # read_until_eof=True will ensure the connection isn't closed\n                # once the response is received and processed allowing\n                # START_TLS to work on the connection below.\n                protocol.set_response_params(\n                    read_until_eof=runtime_has_start_tls,\n                    timeout_ceil_threshold=self._timeout_ceil_threshold,\n                )\n                resp = await proxy_resp.start(conn)\n            except BaseException:\n                proxy_resp.close()\n                conn.close()\n                raise\n            else:\n                conn._protocol = None\n                conn._transport = None\n                try:\n                    if resp.status != 200:\n                        message = resp.reason\n                        if message is None:\n                            message = HTTPStatus(resp.status).phrase\n                        raise ClientHttpProxyError(\n                            proxy_resp.request_info,\n                            resp.history,\n                            status=resp.status,\n                            message=message,\n                            headers=resp.headers,\n                        )\n                    if not runtime_has_start_tls:\n                        rawsock = transport.get_extra_info(\"socket\", default=None)\n                        if rawsock is None:\n                            raise RuntimeError(\n                                \"Transport does not expose socket instance\"\n                            )\n                        # Duplicate the socket, so now we can close proxy transport\n                        rawsock = rawsock.dup()\n                except BaseException:\n                    # It shouldn't be closed in `finally` because it's fed to\n                    # `loop.start_tls()` and the docs say not to touch it after\n                    # passing there.\n                    transport.close()\n                    raise\n                finally:\n                    if not runtime_has_start_tls:\n                        transport.close()\n\n                if not runtime_has_start_tls:\n                    # HTTP proxy with support for upgrade to HTTPS\n                    sslcontext = self._get_ssl_context(req)\n                    return await self._wrap_existing_connection(\n                        self._factory,\n                        timeout=timeout,\n                        ssl=sslcontext,\n                        sock=rawsock,\n                        server_hostname=req.host,\n                        req=req,\n                    )\n\n                return await self._start_tls_connection(\n                    # Access the old transport for the last time before it's\n                    # closed and forgotten forever:\n                    transport,\n                    req=req,\n                    timeout=timeout,\n                )\n            finally:\n                proxy_resp.close()\n\n        return transport, proto",
                                "ast_type_str": "ClassDef",
                                "start_lineno": 751,
                                "end_lineno": 1483,
                                "parent": null
                            }
                        },
                        {
                            "file_name": "aiohttp/connector.py",
                            "type": "class",
                            "name": "TCPConnector",
                            "content": "class TCPConnector(BaseConnector):\n    \"\"\"TCP connector.\n\n    verify_ssl - Set to True to check ssl certifications.\n    fingerprint - Pass the binary sha256\n        digest of the expected certificate in DER format to verify\n        that the certificate the server presents matches. See also\n        https://en.wikipedia.org/wiki/HTTP_Public_Key_Pinning\n    resolver - Enable DNS lookups and use this\n        resolver\n    use_dns_cache - Use memory cache for DNS lookups.\n    ttl_dns_cache - Max seconds having cached a DNS entry, None forever.\n    family - socket address family\n    local_addr - local tuple of (host, port) to bind socket to\n\n    keepalive_timeout - (optional) Keep-alive timeout.\n    force_close - Set to True to force close and do reconnect\n        after each request (and between redirects).\n    limit - The total number of simultaneous connections.\n    limit_per_host - Number of simultaneous connections to one host.\n    enable_cleanup_closed - Enables clean-up closed ssl transports.\n                            Disabled by default.\n    happy_eyeballs_delay - This is the “Connection Attempt Delay”\n                           as defined in RFC 8305. To disable\n                           the happy eyeballs algorithm, set to None.\n    interleave - “First Address Family Count” as defined in RFC 8305\n    loop - Optional event loop.\n    \"\"\"\n\n    allowed_protocol_schema_set = HIGH_LEVEL_SCHEMA_SET | frozenset({\"tcp\"})\n    _made_ssl_context: Dict[bool, \"asyncio.Future[SSLContext]\"] = {}\n\n    def __init__(\n        self,\n        *,\n        verify_ssl: bool = True,\n        fingerprint: Optional[bytes] = None,\n        use_dns_cache: bool = True,\n        ttl_dns_cache: Optional[int] = 10,\n        family: socket.AddressFamily = socket.AddressFamily.AF_UNSPEC,\n        ssl_context: Optional[SSLContext] = None,\n        ssl: Union[bool, Fingerprint, SSLContext] = True,\n        local_addr: Optional[Tuple[str, int]] = None,\n        resolver: Optional[AbstractResolver] = None,\n        keepalive_timeout: Union[None, float, object] = sentinel,\n        force_close: bool = False,\n        limit: int = 100,\n        limit_per_host: int = 0,\n        enable_cleanup_closed: bool = False,\n        loop: Optional[asyncio.AbstractEventLoop] = None,\n        timeout_ceil_threshold: float = 5,\n        happy_eyeballs_delay: Optional[float] = 0.25,\n        interleave: Optional[int] = None,\n    ):\n        super().__init__(\n            keepalive_timeout=keepalive_timeout,\n            force_close=force_close,\n            limit=limit,\n            limit_per_host=limit_per_host,\n            enable_cleanup_closed=enable_cleanup_closed,\n            loop=loop,\n            timeout_ceil_threshold=timeout_ceil_threshold,\n        )\n\n        self._ssl = _merge_ssl_params(ssl, verify_ssl, ssl_context, fingerprint)\n        if resolver is None:\n            resolver = DefaultResolver(loop=self._loop)\n        self._resolver = resolver\n\n        self._use_dns_cache = use_dns_cache\n        self._cached_hosts = _DNSCacheTable(ttl=ttl_dns_cache)\n        self._throttle_dns_events: Dict[Tuple[str, int], EventResultOrError] = {}\n        self._family = family\n        self._local_addr_infos = aiohappyeyeballs.addr_to_addr_infos(local_addr)\n        self._happy_eyeballs_delay = happy_eyeballs_delay\n        self._interleave = interleave\n        self._resolve_host_tasks: Set[\"asyncio.Task[List[ResolveResult]]\"] = set()\n\n    def close(self) -> Awaitable[None]:\n        \"\"\"Close all ongoing DNS calls.\"\"\"\n        for ev in self._throttle_dns_events.values():\n            ev.cancel()\n\n        for t in self._resolve_host_tasks:\n            t.cancel()\n\n        return super().close()\n\n    @property\n    def family(self) -> int:\n        \"\"\"Socket family like AF_INET.\"\"\"\n        return self._family\n\n    @property\n    def use_dns_cache(self) -> bool:\n        \"\"\"True if local DNS caching is enabled.\"\"\"\n        return self._use_dns_cache\n\n    def clear_dns_cache(\n        self, host: Optional[str] = None, port: Optional[int] = None\n    ) -> None:\n        \"\"\"Remove specified host/port or clear all dns local cache.\"\"\"\n        if host is not None and port is not None:\n            self._cached_hosts.remove((host, port))\n        elif host is not None or port is not None:\n            raise ValueError(\"either both host and port \" \"or none of them are allowed\")\n        else:\n            self._cached_hosts.clear()\n\n    async def _resolve_host(\n        self, host: str, port: int, traces: Optional[Sequence[\"Trace\"]] = None\n    ) -> List[ResolveResult]:\n        \"\"\"Resolve host and return list of addresses.\"\"\"\n        if is_ip_address(host):\n            return [\n                {\n                    \"hostname\": host,\n                    \"host\": host,\n                    \"port\": port,\n                    \"family\": self._family,\n                    \"proto\": 0,\n                    \"flags\": 0,\n                }\n            ]\n\n        if not self._use_dns_cache:\n\n            if traces:\n                for trace in traces:\n                    await trace.send_dns_resolvehost_start(host)\n\n            res = await self._resolver.resolve(host, port, family=self._family)\n\n            if traces:\n                for trace in traces:\n                    await trace.send_dns_resolvehost_end(host)\n\n            return res\n\n        key = (host, port)\n        if key in self._cached_hosts and not self._cached_hosts.expired(key):\n            # get result early, before any await (#4014)\n            result = self._cached_hosts.next_addrs(key)\n\n            if traces:\n                for trace in traces:\n                    await trace.send_dns_cache_hit(host)\n            return result\n\n        #\n        # If multiple connectors are resolving the same host, we wait\n        # for the first one to resolve and then use the result for all of them.\n        # We use a throttle event to ensure that we only resolve the host once\n        # and then use the result for all the waiters.\n        #\n        # In this case we need to create a task to ensure that we can shield\n        # the task from cancellation as cancelling this lookup should not cancel\n        # the underlying lookup or else the cancel event will get broadcast to\n        # all the waiters across all connections.\n        #\n        resolved_host_task = asyncio.create_task(\n            self._resolve_host_with_throttle(key, host, port, traces)\n        )\n        self._resolve_host_tasks.add(resolved_host_task)\n        resolved_host_task.add_done_callback(self._resolve_host_tasks.discard)\n        try:\n            return await asyncio.shield(resolved_host_task)\n        except asyncio.CancelledError:\n\n            def drop_exception(fut: \"asyncio.Future[List[ResolveResult]]\") -> None:\n                with suppress(Exception, asyncio.CancelledError):\n                    fut.result()\n\n            resolved_host_task.add_done_callback(drop_exception)\n            raise\n\n    async def _resolve_host_with_throttle(\n        self,\n        key: Tuple[str, int],\n        host: str,\n        port: int,\n        traces: Optional[Sequence[\"Trace\"]],\n    ) -> List[ResolveResult]:\n        \"\"\"Resolve host with a dns events throttle.\"\"\"\n        if key in self._throttle_dns_events:\n            # get event early, before any await (#4014)\n            event = self._throttle_dns_events[key]\n            if traces:\n                for trace in traces:\n                    await trace.send_dns_cache_hit(host)\n            await event.wait()\n        else:\n            # update dict early, before any await (#4014)\n            self._throttle_dns_events[key] = EventResultOrError(self._loop)\n            if traces:\n                for trace in traces:\n                    await trace.send_dns_cache_miss(host)\n            try:\n\n                if traces:\n                    for trace in traces:\n                        await trace.send_dns_resolvehost_start(host)\n\n                addrs = await self._resolver.resolve(host, port, family=self._family)\n                if traces:\n                    for trace in traces:\n                        await trace.send_dns_resolvehost_end(host)\n\n                self._cached_hosts.add(key, addrs)\n                self._throttle_dns_events[key].set()\n            except BaseException as e:\n                # any DNS exception, independently of the implementation\n                # is set for the waiters to raise the same exception.\n                self._throttle_dns_events[key].set(exc=e)\n                raise\n            finally:\n                self._throttle_dns_events.pop(key)\n\n        return self._cached_hosts.next_addrs(key)\n\n    async def _create_connection(\n        self, req: ClientRequest, traces: List[\"Trace\"], timeout: \"ClientTimeout\"\n    ) -> ResponseHandler:\n        \"\"\"Create connection.\n\n        Has same keyword arguments as BaseEventLoop.create_connection.\n        \"\"\"\n        if req.proxy:\n            _, proto = await self._create_proxy_connection(req, traces, timeout)\n        else:\n            _, proto = await self._create_direct_connection(req, traces, timeout)\n\n        return proto\n\n    @staticmethod\n    def _make_ssl_context(verified: bool) -> SSLContext:\n        \"\"\"Create SSL context.\n\n        This method is not async-friendly and should be called from a thread\n        because it will load certificates from disk and do other blocking I/O.\n        \"\"\"\n        if verified:\n            return ssl.create_default_context()\n        sslcontext = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)\n        sslcontext.options |= ssl.OP_NO_SSLv2\n        sslcontext.options |= ssl.OP_NO_SSLv3\n        sslcontext.check_hostname = False\n        sslcontext.verify_mode = ssl.CERT_NONE\n        sslcontext.options |= ssl.OP_NO_COMPRESSION\n        sslcontext.set_default_verify_paths()\n        return sslcontext\n\n    async def _get_ssl_context(self, req: ClientRequest) -> Optional[SSLContext]:\n        \"\"\"Logic to get the correct SSL context\n\n        0. if req.ssl is false, return None\n\n        1. if ssl_context is specified in req, use it\n        2. if _ssl_context is specified in self, use it\n        3. otherwise:\n            1. if verify_ssl is not specified in req, use self.ssl_context\n               (will generate a default context according to self.verify_ssl)\n            2. if verify_ssl is True in req, generate a default SSL context\n            3. if verify_ssl is False in req, generate a SSL context that\n               won't verify\n        \"\"\"\n        if not req.is_ssl():\n            return None\n\n        if ssl is None:  # pragma: no cover\n            raise RuntimeError(\"SSL is not supported.\")\n        sslcontext = req.ssl\n        if isinstance(sslcontext, ssl.SSLContext):\n            return sslcontext\n        if sslcontext is not True:\n            # not verified or fingerprinted\n            return await self._make_or_get_ssl_context(False)\n        sslcontext = self._ssl\n        if isinstance(sslcontext, ssl.SSLContext):\n            return sslcontext\n        if sslcontext is not True:\n            # not verified or fingerprinted\n            return await self._make_or_get_ssl_context(False)\n        return await self._make_or_get_ssl_context(True)\n\n    async def _make_or_get_ssl_context(self, verified: bool) -> SSLContext:\n        \"\"\"Create or get cached SSL context.\"\"\"\n        try:\n            return await self._made_ssl_context[verified]\n        except KeyError:\n            loop = self._loop\n            future = loop.create_future()\n            self._made_ssl_context[verified] = future\n            try:\n                result = await loop.run_in_executor(\n                    None, self._make_ssl_context, verified\n                )\n            # BaseException is used since we might get CancelledError\n            except BaseException as ex:\n                del self._made_ssl_context[verified]\n                set_exception(future, ex)\n                raise\n            else:\n                set_result(future, result)\n            return result\n\n    def _get_fingerprint(self, req: ClientRequest) -> Optional[\"Fingerprint\"]:\n        ret = req.ssl\n        if isinstance(ret, Fingerprint):\n            return ret\n        ret = self._ssl\n        if isinstance(ret, Fingerprint):\n            return ret\n        return None\n\n    async def _wrap_create_connection(\n        self,\n        *args: Any,\n        addr_infos: List[aiohappyeyeballs.AddrInfoType],\n        req: ClientRequest,\n        timeout: \"ClientTimeout\",\n        client_error: Type[Exception] = ClientConnectorError,\n        **kwargs: Any,\n    ) -> Tuple[asyncio.Transport, ResponseHandler]:\n        try:\n            async with ceil_timeout(\n                timeout.sock_connect, ceil_threshold=timeout.ceil_threshold\n            ):\n                sock = await aiohappyeyeballs.start_connection(\n                    addr_infos=addr_infos,\n                    local_addr_infos=self._local_addr_infos,\n                    happy_eyeballs_delay=self._happy_eyeballs_delay,\n                    interleave=self._interleave,\n                    loop=self._loop,\n                )\n                return await self._loop.create_connection(*args, **kwargs, sock=sock)\n        except cert_errors as exc:\n            raise ClientConnectorCertificateError(req.connection_key, exc) from exc\n        except ssl_errors as exc:\n            raise ClientConnectorSSLError(req.connection_key, exc) from exc\n        except OSError as exc:\n            if exc.errno is None and isinstance(exc, asyncio.TimeoutError):\n                raise\n            raise client_error(req.connection_key, exc) from exc\n\n    async def _wrap_existing_connection(\n        self,\n        *args: Any,\n        req: ClientRequest,\n        timeout: \"ClientTimeout\",\n        client_error: Type[Exception] = ClientConnectorError,\n        **kwargs: Any,\n    ) -> Tuple[asyncio.Transport, ResponseHandler]:\n        try:\n            async with ceil_timeout(\n                timeout.sock_connect, ceil_threshold=timeout.ceil_threshold\n            ):\n                return await self._loop.create_connection(*args, **kwargs)\n        except cert_errors as exc:\n            raise ClientConnectorCertificateError(req.connection_key, exc) from exc\n        except ssl_errors as exc:\n            raise ClientConnectorSSLError(req.connection_key, exc) from exc\n        except OSError as exc:\n            if exc.errno is None and isinstance(exc, asyncio.TimeoutError):\n                raise\n            raise client_error(req.connection_key, exc) from exc\n\n    def _fail_on_no_start_tls(self, req: \"ClientRequest\") -> None:\n        \"\"\"Raise a :py:exc:`RuntimeError` on missing ``start_tls()``.\n\n        It is necessary for TLS-in-TLS so that it is possible to\n        send HTTPS queries through HTTPS proxies.\n\n        This doesn't affect regular HTTP requests, though.\n        \"\"\"\n        if not req.is_ssl():\n            return\n\n        proxy_url = req.proxy\n        assert proxy_url is not None\n        if proxy_url.scheme != \"https\":\n            return\n\n        self._check_loop_for_start_tls()\n\n    def _check_loop_for_start_tls(self) -> None:\n        try:\n            self._loop.start_tls\n        except AttributeError as attr_exc:\n            raise RuntimeError(\n                \"An HTTPS request is being sent through an HTTPS proxy. \"\n                \"This needs support for TLS in TLS but it is not implemented \"\n                \"in your runtime for the stdlib asyncio.\\n\\n\"\n                \"Please upgrade to Python 3.11 or higher. For more details, \"\n                \"please see:\\n\"\n                \"* https://bugs.python.org/issue37179\\n\"\n                \"* https://github.com/python/cpython/pull/28073\\n\"\n                \"* https://docs.aiohttp.org/en/stable/\"\n                \"client_advanced.html#proxy-support\\n\"\n                \"* https://github.com/aio-libs/aiohttp/discussions/6044\\n\",\n            ) from attr_exc\n\n    def _loop_supports_start_tls(self) -> bool:\n        try:\n            self._check_loop_for_start_tls()\n        except RuntimeError:\n            return False\n        else:\n            return True\n\n    def _warn_about_tls_in_tls(\n        self,\n        underlying_transport: asyncio.Transport,\n        req: ClientRequest,\n    ) -> None:\n        \"\"\"Issue a warning if the requested URL has HTTPS scheme.\"\"\"\n        if req.request_info.url.scheme != \"https\":\n            return\n\n        asyncio_supports_tls_in_tls = getattr(\n            underlying_transport,\n            \"_start_tls_compatible\",\n            False,\n        )\n\n        if asyncio_supports_tls_in_tls:\n            return\n\n        warnings.warn(\n            \"An HTTPS request is being sent through an HTTPS proxy. \"\n            \"This support for TLS in TLS is known to be disabled \"\n            \"in the stdlib asyncio (Python <3.11). This is why you'll probably see \"\n            \"an error in the log below.\\n\\n\"\n            \"It is possible to enable it via monkeypatching. \"\n            \"For more details, see:\\n\"\n            \"* https://bugs.python.org/issue37179\\n\"\n            \"* https://github.com/python/cpython/pull/28073\\n\\n\"\n            \"You can temporarily patch this as follows:\\n\"\n            \"* https://docs.aiohttp.org/en/stable/client_advanced.html#proxy-support\\n\"\n            \"* https://github.com/aio-libs/aiohttp/discussions/6044\\n\",\n            RuntimeWarning,\n            source=self,\n            # Why `4`? At least 3 of the calls in the stack originate\n            # from the methods in this class.\n            stacklevel=3,\n        )\n\n    async def _start_tls_connection(\n        self,\n        underlying_transport: asyncio.Transport,\n        req: ClientRequest,\n        timeout: \"ClientTimeout\",\n        client_error: Type[Exception] = ClientConnectorError,\n    ) -> Tuple[asyncio.BaseTransport, ResponseHandler]:\n        \"\"\"Wrap the raw TCP transport with TLS.\"\"\"\n        tls_proto = self._factory()  # Create a brand new proto for TLS\n\n        # Safety of the `cast()` call here is based on the fact that\n        # internally `_get_ssl_context()` only returns `None` when\n        # `req.is_ssl()` evaluates to `False` which is never gonna happen\n        # in this code path. Of course, it's rather fragile\n        # maintainability-wise but this is to be solved separately.\n        sslcontext = cast(ssl.SSLContext, await self._get_ssl_context(req))\n\n        try:\n            async with ceil_timeout(\n                timeout.sock_connect, ceil_threshold=timeout.ceil_threshold\n            ):\n                try:\n                    tls_transport = await self._loop.start_tls(\n                        underlying_transport,\n                        tls_proto,\n                        sslcontext,\n                        server_hostname=req.server_hostname or req.host,\n                        ssl_handshake_timeout=timeout.total,\n                    )\n                except BaseException:\n                    # We need to close the underlying transport since\n                    # `start_tls()` probably failed before it had a\n                    # chance to do this:\n                    underlying_transport.close()\n                    raise\n        except cert_errors as exc:\n            raise ClientConnectorCertificateError(req.connection_key, exc) from exc\n        except ssl_errors as exc:\n            raise ClientConnectorSSLError(req.connection_key, exc) from exc\n        except OSError as exc:\n            if exc.errno is None and isinstance(exc, asyncio.TimeoutError):\n                raise\n            raise client_error(req.connection_key, exc) from exc\n        except TypeError as type_err:\n            # Example cause looks like this:\n            # TypeError: transport <asyncio.sslproto._SSLProtocolTransport\n            # object at 0x7f760615e460> is not supported by start_tls()\n\n            raise ClientConnectionError(\n                \"Cannot initialize a TLS-in-TLS connection to host \"\n                f\"{req.host!s}:{req.port:d} through an underlying connection \"\n                f\"to an HTTPS proxy {req.proxy!s} ssl:{req.ssl or 'default'} \"\n                f\"[{type_err!s}]\"\n            ) from type_err\n        else:\n            if tls_transport is None:\n                msg = \"Failed to start TLS (possibly caused by closing transport)\"\n                raise client_error(req.connection_key, OSError(msg))\n            tls_proto.connection_made(\n                tls_transport\n            )  # Kick the state machine of the new TLS protocol\n\n        return tls_transport, tls_proto\n\n    def _convert_hosts_to_addr_infos(\n        self, hosts: List[ResolveResult]\n    ) -> List[aiohappyeyeballs.AddrInfoType]:\n        \"\"\"Converts the list of hosts to a list of addr_infos.\n\n        The list of hosts is the result of a DNS lookup. The list of\n        addr_infos is the result of a call to `socket.getaddrinfo()`.\n        \"\"\"\n        addr_infos: List[aiohappyeyeballs.AddrInfoType] = []\n        for hinfo in hosts:\n            host = hinfo[\"host\"]\n            is_ipv6 = \":\" in host\n            family = socket.AF_INET6 if is_ipv6 else socket.AF_INET\n            if self._family and self._family != family:\n                continue\n            addr = (host, hinfo[\"port\"], 0, 0) if is_ipv6 else (host, hinfo[\"port\"])\n            addr_infos.append(\n                (family, socket.SOCK_STREAM, socket.IPPROTO_TCP, \"\", addr)\n            )\n        return addr_infos\n\n    async def _create_direct_connection(\n        self,\n        req: ClientRequest,\n        traces: List[\"Trace\"],\n        timeout: \"ClientTimeout\",\n        *,\n        client_error: Type[Exception] = ClientConnectorError,\n    ) -> Tuple[asyncio.Transport, ResponseHandler]:\n        sslcontext = await self._get_ssl_context(req)\n        fingerprint = self._get_fingerprint(req)\n\n        host = req.url.raw_host\n        assert host is not None\n        # Replace multiple trailing dots with a single one.\n        # A trailing dot is only present for fully-qualified domain names.\n        # See https://github.com/aio-libs/aiohttp/pull/7364.\n        if host.endswith(\"..\"):\n            host = host.rstrip(\".\") + \".\"\n        port = req.port\n        assert port is not None\n        try:\n            # Cancelling this lookup should not cancel the underlying lookup\n            #  or else the cancel event will get broadcast to all the waiters\n            #  across all connections.\n            hosts = await self._resolve_host(host, port, traces=traces)\n        except OSError as exc:\n            if exc.errno is None and isinstance(exc, asyncio.TimeoutError):\n                raise\n            # in case of proxy it is not ClientProxyConnectionError\n            # it is problem of resolving proxy ip itself\n            raise ClientConnectorError(req.connection_key, exc) from exc\n\n        last_exc: Optional[Exception] = None\n        addr_infos = self._convert_hosts_to_addr_infos(hosts)\n        while addr_infos:\n            # Strip trailing dots, certificates contain FQDN without dots.\n            # See https://github.com/aio-libs/aiohttp/issues/3636\n            server_hostname = (\n                (req.server_hostname or host).rstrip(\".\") if sslcontext else None\n            )\n\n            try:\n                transp, proto = await self._wrap_create_connection(\n                    self._factory,\n                    timeout=timeout,\n                    ssl=sslcontext,\n                    addr_infos=addr_infos,\n                    server_hostname=server_hostname,\n                    req=req,\n                    client_error=client_error,\n                )\n            except ClientConnectorError as exc:\n                last_exc = exc\n                aiohappyeyeballs.pop_addr_infos_interleave(addr_infos, self._interleave)\n                continue\n\n            if req.is_ssl() and fingerprint:\n                try:\n                    fingerprint.check(transp)\n                except ServerFingerprintMismatch as exc:\n                    transp.close()\n                    if not self._cleanup_closed_disabled:\n                        self._cleanup_closed_transports.append(transp)\n                    last_exc = exc\n                    # Remove the bad peer from the list of addr_infos\n                    sock: socket.socket = transp.get_extra_info(\"socket\")\n                    bad_peer = sock.getpeername()\n                    aiohappyeyeballs.remove_addr_infos(addr_infos, bad_peer)\n                    continue\n\n            return transp, proto\n        else:\n            assert last_exc is not None\n            raise last_exc\n\n    async def _create_proxy_connection(\n        self, req: ClientRequest, traces: List[\"Trace\"], timeout: \"ClientTimeout\"\n    ) -> Tuple[asyncio.BaseTransport, ResponseHandler]:\n        self._fail_on_no_start_tls(req)\n        runtime_has_start_tls = self._loop_supports_start_tls()\n\n        headers: Dict[str, str] = {}\n        if req.proxy_headers is not None:\n            headers = req.proxy_headers  # type: ignore[assignment]\n        headers[hdrs.HOST] = req.headers[hdrs.HOST]\n\n        url = req.proxy\n        assert url is not None\n        proxy_req = ClientRequest(\n            hdrs.METH_GET,\n            url,\n            headers=headers,\n            auth=req.proxy_auth,\n            loop=self._loop,\n            ssl=req.ssl,\n        )\n\n        # create connection to proxy server\n        transport, proto = await self._create_direct_connection(\n            proxy_req, [], timeout, client_error=ClientProxyConnectionError\n        )\n\n        auth = proxy_req.headers.pop(hdrs.AUTHORIZATION, None)\n        if auth is not None:\n            if not req.is_ssl():\n                req.headers[hdrs.PROXY_AUTHORIZATION] = auth\n            else:\n                proxy_req.headers[hdrs.PROXY_AUTHORIZATION] = auth\n\n        if req.is_ssl():\n            if runtime_has_start_tls:\n                self._warn_about_tls_in_tls(transport, req)\n\n            # For HTTPS requests over HTTP proxy\n            # we must notify proxy to tunnel connection\n            # so we send CONNECT command:\n            #   CONNECT www.python.org:443 HTTP/1.1\n            #   Host: www.python.org\n            #\n            # next we must do TLS handshake and so on\n            # to do this we must wrap raw socket into secure one\n            # asyncio handles this perfectly\n            proxy_req.method = hdrs.METH_CONNECT\n            proxy_req.url = req.url\n            key = attr.evolve(\n                req.connection_key, proxy=None, proxy_auth=None, proxy_headers_hash=None\n            )\n            conn = Connection(self, key, proto, self._loop)\n            proxy_resp = await proxy_req.send(conn)\n            try:\n                protocol = conn._protocol\n                assert protocol is not None\n\n                # read_until_eof=True will ensure the connection isn't closed\n                # once the response is received and processed allowing\n                # START_TLS to work on the connection below.\n                protocol.set_response_params(\n                    read_until_eof=runtime_has_start_tls,\n                    timeout_ceil_threshold=self._timeout_ceil_threshold,\n                )\n                resp = await proxy_resp.start(conn)\n            except BaseException:\n                proxy_resp.close()\n                conn.close()\n                raise\n            else:\n                conn._protocol = None\n                conn._transport = None\n                try:\n                    if resp.status != 200:\n                        message = resp.reason\n                        if message is None:\n                            message = HTTPStatus(resp.status).phrase\n                        raise ClientHttpProxyError(\n                            proxy_resp.request_info,\n                            resp.history,\n                            status=resp.status,\n                            message=message,\n                            headers=resp.headers,\n                        )\n                    if not runtime_has_start_tls:\n                        rawsock = transport.get_extra_info(\"socket\", default=None)\n                        if rawsock is None:\n                            raise RuntimeError(\n                                \"Transport does not expose socket instance\"\n                            )\n                        # Duplicate the socket, so now we can close proxy transport\n                        rawsock = rawsock.dup()\n                except BaseException:\n                    # It shouldn't be closed in `finally` because it's fed to\n                    # `loop.start_tls()` and the docs say not to touch it after\n                    # passing there.\n                    transport.close()\n                    raise\n                finally:\n                    if not runtime_has_start_tls:\n                        transport.close()\n\n                if not runtime_has_start_tls:\n                    # HTTP proxy with support for upgrade to HTTPS\n                    sslcontext = self._get_ssl_context(req)\n                    return await self._wrap_existing_connection(\n                        self._factory,\n                        timeout=timeout,\n                        ssl=sslcontext,\n                        sock=rawsock,\n                        server_hostname=req.host,\n                        req=req,\n                    )\n\n                return await self._start_tls_connection(\n                    # Access the old transport for the last time before it's\n                    # closed and forgotten forever:\n                    transport,\n                    req=req,\n                    timeout=timeout,\n                )\n            finally:\n                proxy_resp.close()\n\n        return transport, proto",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 751,
                            "end_lineno": 1483,
                            "parent": null
                        }
                    ],
                    "added_entities": [],
                    "deleted_entities": []
                },
                {
                    "descriptor": {
                        "old_range": {
                            "start": 907,
                            "length": 6
                        },
                        "new_range": {
                            "start": 911,
                            "length": 8
                        },
                        "section": "class TCPConnector(BaseConnector):"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "        resolved_host_task = asyncio.create_task(",
                                "type": "context"
                            },
                            {
                                "content": "            self._resolve_host_with_throttle(key, host, port, traces)",
                                "type": "context"
                            },
                            {
                                "content": "        )",
                                "type": "context"
                            },
                            {
                                "content": "        self._resolve_host_tasks.add(resolved_host_task)",
                                "type": "added"
                            },
                            {
                                "content": "        resolved_host_task.add_done_callback(self._resolve_host_tasks.discard)",
                                "type": "added"
                            },
                            {
                                "content": "        try:",
                                "type": "context"
                            },
                            {
                                "content": "            return await asyncio.shield(resolved_host_task)",
                                "type": "context"
                            },
                            {
                                "content": "        except asyncio.CancelledError:",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [
                        {
                            "file_name": "aiohttp/connector.py",
                            "type": "method",
                            "name": "TCPConnector._resolve_host",
                            "content": "class TCPConnector(BaseConnector):\n    \"\"\"TCP connector.\n\n    verify_ssl - Set to True to check ssl certifications.\n    fingerprint - Pass the binary sha256\n        digest of the expected certificate in DER format to verify\n        that the certificate the server presents matches. See also\n        https://en.wikipedia.org/wiki/HTTP_Public_Key_Pinning\n    resolver - Enable DNS lookups and use this\n        resolver\n    use_dns_cache - Use memory cache for DNS lookups.\n    ttl_dns_cache - Max seconds having cached a DNS entry, None forever.\n    family - socket address family\n    local_addr - local tuple of (host, port) to bind socket to\n\n    keepalive_timeout - (optional) Keep-alive timeout.\n    force_close - Set to True to force close and do reconnect\n        after each request (and between redirects).\n    limit - The total number of simultaneous connections.\n    limit_per_host - Number of simultaneous connections to one host.\n    enable_cleanup_closed - Enables clean-up closed ssl transports.\n                            Disabled by default.\n    happy_eyeballs_delay - This is the “Connection Attempt Delay”\n                           as defined in RFC 8305. To disable\n                           the happy eyeballs algorithm, set to None.\n    interleave - “First Address Family Count” as defined in RFC 8305\n    loop - Optional event loop.\n    \"\"\"\n\n    allowed_protocol_schema_set = HIGH_LEVEL_SCHEMA_SET | frozenset({\"tcp\"})\n    _made_ssl_context: Dict[bool, \"asyncio.Future[SSLContext]\"] = {}\n\n    def __init__(\n        self,\n        *,\n        verify_ssl: bool = True,\n        fingerprint: Optional[bytes] = None,\n        use_dns_cache: bool = True,\n        ttl_dns_cache: Optional[int] = 10,\n        family: socket.AddressFamily = socket.AddressFamily.AF_UNSPEC,\n        ssl_context: Optional[SSLContext] = None,\n        ssl: Union[bool, Fingerprint, SSLContext] = True,\n        local_addr: Optional[Tuple[str, int]] = None,\n        resolver: Optional[AbstractResolver] = None,\n        keepalive_timeout: Union[None, float, object] = sentinel,\n        force_close: bool = False,\n        limit: int = 100,\n        limit_per_host: int = 0,\n        enable_cleanup_closed: bool = False,\n        loop: Optional[asyncio.AbstractEventLoop] = None,\n        timeout_ceil_threshold: float = 5,\n        happy_eyeballs_delay: Optional[float] = 0.25,\n        interleave: Optional[int] = None,\n    ):\n        super().__init__(\n            keepalive_timeout=keepalive_timeout,\n            force_close=force_close,\n            limit=limit,\n            limit_per_host=limit_per_host,\n            enable_cleanup_closed=enable_cleanup_closed,\n            loop=loop,\n            timeout_ceil_threshold=timeout_ceil_threshold,\n        )\n\n        self._ssl = _merge_ssl_params(ssl, verify_ssl, ssl_context, fingerprint)\n        if resolver is None:\n            resolver = DefaultResolver(loop=self._loop)\n        self._resolver = resolver\n\n        self._use_dns_cache = use_dns_cache\n        self._cached_hosts = _DNSCacheTable(ttl=ttl_dns_cache)\n        self._throttle_dns_events: Dict[Tuple[str, int], EventResultOrError] = {}\n        self._family = family\n        self._local_addr_infos = aiohappyeyeballs.addr_to_addr_infos(local_addr)\n        self._happy_eyeballs_delay = happy_eyeballs_delay\n        self._interleave = interleave\n        self._resolve_host_tasks: Set[\"asyncio.Task[List[ResolveResult]]\"] = set()\n\n    def close(self) -> Awaitable[None]:\n        \"\"\"Close all ongoing DNS calls.\"\"\"\n        for ev in self._throttle_dns_events.values():\n            ev.cancel()\n\n        for t in self._resolve_host_tasks:\n            t.cancel()\n\n        return super().close()\n\n    @property\n    def family(self) -> int:\n        \"\"\"Socket family like AF_INET.\"\"\"\n        return self._family\n\n    @property\n    def use_dns_cache(self) -> bool:\n        \"\"\"True if local DNS caching is enabled.\"\"\"\n        return self._use_dns_cache\n\n    def clear_dns_cache(\n        self, host: Optional[str] = None, port: Optional[int] = None\n    ) -> None:\n        \"\"\"Remove specified host/port or clear all dns local cache.\"\"\"\n        if host is not None and port is not None:\n            self._cached_hosts.remove((host, port))\n        elif host is not None or port is not None:\n            raise ValueError(\"either both host and port \" \"or none of them are allowed\")\n        else:\n            self._cached_hosts.clear()\n\n    async def _resolve_host(\n        self, host: str, port: int, traces: Optional[Sequence[\"Trace\"]] = None\n    ) -> List[ResolveResult]:\n        \"\"\"Resolve host and return list of addresses.\"\"\"\n        if is_ip_address(host):\n            return [\n                {\n                    \"hostname\": host,\n                    \"host\": host,\n                    \"port\": port,\n                    \"family\": self._family,\n                    \"proto\": 0,\n                    \"flags\": 0,\n                }\n            ]\n\n        if not self._use_dns_cache:\n\n            if traces:\n                for trace in traces:\n                    await trace.send_dns_resolvehost_start(host)\n\n            res = await self._resolver.resolve(host, port, family=self._family)\n\n            if traces:\n                for trace in traces:\n                    await trace.send_dns_resolvehost_end(host)\n\n            return res\n\n        key = (host, port)\n        if key in self._cached_hosts and not self._cached_hosts.expired(key):\n            # get result early, before any await (#4014)\n            result = self._cached_hosts.next_addrs(key)\n\n            if traces:\n                for trace in traces:\n                    await trace.send_dns_cache_hit(host)\n            return result\n\n        #\n        # If multiple connectors are resolving the same host, we wait\n        # for the first one to resolve and then use the result for all of them.\n        # We use a throttle event to ensure that we only resolve the host once\n        # and then use the result for all the waiters.\n        #\n        # In this case we need to create a task to ensure that we can shield\n        # the task from cancellation as cancelling this lookup should not cancel\n        # the underlying lookup or else the cancel event will get broadcast to\n        # all the waiters across all connections.\n        #\n        resolved_host_task = asyncio.create_task(\n            self._resolve_host_with_throttle(key, host, port, traces)\n        )\n        self._resolve_host_tasks.add(resolved_host_task)\n        resolved_host_task.add_done_callback(self._resolve_host_tasks.discard)\n        try:\n            return await asyncio.shield(resolved_host_task)\n        except asyncio.CancelledError:\n\n            def drop_exception(fut: \"asyncio.Future[List[ResolveResult]]\") -> None:\n                with suppress(Exception, asyncio.CancelledError):\n                    fut.result()\n\n            resolved_host_task.add_done_callback(drop_exception)\n            raise\n\n    async def _resolve_host_with_throttle(\n        self,\n        key: Tuple[str, int],\n        host: str,\n        port: int,\n        traces: Optional[Sequence[\"Trace\"]],\n    ) -> List[ResolveResult]:\n        \"\"\"Resolve host with a dns events throttle.\"\"\"\n        if key in self._throttle_dns_events:\n            # get event early, before any await (#4014)\n            event = self._throttle_dns_events[key]\n            if traces:\n                for trace in traces:\n                    await trace.send_dns_cache_hit(host)\n            await event.wait()\n        else:\n            # update dict early, before any await (#4014)\n            self._throttle_dns_events[key] = EventResultOrError(self._loop)\n            if traces:\n                for trace in traces:\n                    await trace.send_dns_cache_miss(host)\n            try:\n\n                if traces:\n                    for trace in traces:\n                        await trace.send_dns_resolvehost_start(host)\n\n                addrs = await self._resolver.resolve(host, port, family=self._family)\n                if traces:\n                    for trace in traces:\n                        await trace.send_dns_resolvehost_end(host)\n\n                self._cached_hosts.add(key, addrs)\n                self._throttle_dns_events[key].set()\n            except BaseException as e:\n                # any DNS exception, independently of the implementation\n                # is set for the waiters to raise the same exception.\n                self._throttle_dns_events[key].set(exc=e)\n                raise\n            finally:\n                self._throttle_dns_events.pop(key)\n\n        return self._cached_hosts.next_addrs(key)\n\n    async def _create_connection(\n        self, req: ClientRequest, traces: List[\"Trace\"], timeout: \"ClientTimeout\"\n    ) -> ResponseHandler:\n        \"\"\"Create connection.\n\n        Has same keyword arguments as BaseEventLoop.create_connection.\n        \"\"\"\n        if req.proxy:\n            _, proto = await self._create_proxy_connection(req, traces, timeout)\n        else:\n            _, proto = await self._create_direct_connection(req, traces, timeout)\n\n        return proto\n\n    @staticmethod\n    def _make_ssl_context(verified: bool) -> SSLContext:\n        \"\"\"Create SSL context.\n\n        This method is not async-friendly and should be called from a thread\n        because it will load certificates from disk and do other blocking I/O.\n        \"\"\"\n        if verified:\n            return ssl.create_default_context()\n        sslcontext = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)\n        sslcontext.options |= ssl.OP_NO_SSLv2\n        sslcontext.options |= ssl.OP_NO_SSLv3\n        sslcontext.check_hostname = False\n        sslcontext.verify_mode = ssl.CERT_NONE\n        sslcontext.options |= ssl.OP_NO_COMPRESSION\n        sslcontext.set_default_verify_paths()\n        return sslcontext\n\n    async def _get_ssl_context(self, req: ClientRequest) -> Optional[SSLContext]:\n        \"\"\"Logic to get the correct SSL context\n\n        0. if req.ssl is false, return None\n\n        1. if ssl_context is specified in req, use it\n        2. if _ssl_context is specified in self, use it\n        3. otherwise:\n            1. if verify_ssl is not specified in req, use self.ssl_context\n               (will generate a default context according to self.verify_ssl)\n            2. if verify_ssl is True in req, generate a default SSL context\n            3. if verify_ssl is False in req, generate a SSL context that\n               won't verify\n        \"\"\"\n        if not req.is_ssl():\n            return None\n\n        if ssl is None:  # pragma: no cover\n            raise RuntimeError(\"SSL is not supported.\")\n        sslcontext = req.ssl\n        if isinstance(sslcontext, ssl.SSLContext):\n            return sslcontext\n        if sslcontext is not True:\n            # not verified or fingerprinted\n            return await self._make_or_get_ssl_context(False)\n        sslcontext = self._ssl\n        if isinstance(sslcontext, ssl.SSLContext):\n            return sslcontext\n        if sslcontext is not True:\n            # not verified or fingerprinted\n            return await self._make_or_get_ssl_context(False)\n        return await self._make_or_get_ssl_context(True)\n\n    async def _make_or_get_ssl_context(self, verified: bool) -> SSLContext:\n        \"\"\"Create or get cached SSL context.\"\"\"\n        try:\n            return await self._made_ssl_context[verified]\n        except KeyError:\n            loop = self._loop\n            future = loop.create_future()\n            self._made_ssl_context[verified] = future\n            try:\n                result = await loop.run_in_executor(\n                    None, self._make_ssl_context, verified\n                )\n            # BaseException is used since we might get CancelledError\n            except BaseException as ex:\n                del self._made_ssl_context[verified]\n                set_exception(future, ex)\n                raise\n            else:\n                set_result(future, result)\n            return result\n\n    def _get_fingerprint(self, req: ClientRequest) -> Optional[\"Fingerprint\"]:\n        ret = req.ssl\n        if isinstance(ret, Fingerprint):\n            return ret\n        ret = self._ssl\n        if isinstance(ret, Fingerprint):\n            return ret\n        return None\n\n    async def _wrap_create_connection(\n        self,\n        *args: Any,\n        addr_infos: List[aiohappyeyeballs.AddrInfoType],\n        req: ClientRequest,\n        timeout: \"ClientTimeout\",\n        client_error: Type[Exception] = ClientConnectorError,\n        **kwargs: Any,\n    ) -> Tuple[asyncio.Transport, ResponseHandler]:\n        try:\n            async with ceil_timeout(\n                timeout.sock_connect, ceil_threshold=timeout.ceil_threshold\n            ):\n                sock = await aiohappyeyeballs.start_connection(\n                    addr_infos=addr_infos,\n                    local_addr_infos=self._local_addr_infos,\n                    happy_eyeballs_delay=self._happy_eyeballs_delay,\n                    interleave=self._interleave,\n                    loop=self._loop,\n                )\n                return await self._loop.create_connection(*args, **kwargs, sock=sock)\n        except cert_errors as exc:\n            raise ClientConnectorCertificateError(req.connection_key, exc) from exc\n        except ssl_errors as exc:\n            raise ClientConnectorSSLError(req.connection_key, exc) from exc\n        except OSError as exc:\n            if exc.errno is None and isinstance(exc, asyncio.TimeoutError):\n                raise\n            raise client_error(req.connection_key, exc) from exc\n\n    async def _wrap_existing_connection(\n        self,\n        *args: Any,\n        req: ClientRequest,\n        timeout: \"ClientTimeout\",\n        client_error: Type[Exception] = ClientConnectorError,\n        **kwargs: Any,\n    ) -> Tuple[asyncio.Transport, ResponseHandler]:\n        try:\n            async with ceil_timeout(\n                timeout.sock_connect, ceil_threshold=timeout.ceil_threshold\n            ):\n                return await self._loop.create_connection(*args, **kwargs)\n        except cert_errors as exc:\n            raise ClientConnectorCertificateError(req.connection_key, exc) from exc\n        except ssl_errors as exc:\n            raise ClientConnectorSSLError(req.connection_key, exc) from exc\n        except OSError as exc:\n            if exc.errno is None and isinstance(exc, asyncio.TimeoutError):\n                raise\n            raise client_error(req.connection_key, exc) from exc\n\n    def _fail_on_no_start_tls(self, req: \"ClientRequest\") -> None:\n        \"\"\"Raise a :py:exc:`RuntimeError` on missing ``start_tls()``.\n\n        It is necessary for TLS-in-TLS so that it is possible to\n        send HTTPS queries through HTTPS proxies.\n\n        This doesn't affect regular HTTP requests, though.\n        \"\"\"\n        if not req.is_ssl():\n            return\n\n        proxy_url = req.proxy\n        assert proxy_url is not None\n        if proxy_url.scheme != \"https\":\n            return\n\n        self._check_loop_for_start_tls()\n\n    def _check_loop_for_start_tls(self) -> None:\n        try:\n            self._loop.start_tls\n        except AttributeError as attr_exc:\n            raise RuntimeError(\n                \"An HTTPS request is being sent through an HTTPS proxy. \"\n                \"This needs support for TLS in TLS but it is not implemented \"\n                \"in your runtime for the stdlib asyncio.\\n\\n\"\n                \"Please upgrade to Python 3.11 or higher. For more details, \"\n                \"please see:\\n\"\n                \"* https://bugs.python.org/issue37179\\n\"\n                \"* https://github.com/python/cpython/pull/28073\\n\"\n                \"* https://docs.aiohttp.org/en/stable/\"\n                \"client_advanced.html#proxy-support\\n\"\n                \"* https://github.com/aio-libs/aiohttp/discussions/6044\\n\",\n            ) from attr_exc\n\n    def _loop_supports_start_tls(self) -> bool:\n        try:\n            self._check_loop_for_start_tls()\n        except RuntimeError:\n            return False\n        else:\n            return True\n\n    def _warn_about_tls_in_tls(\n        self,\n        underlying_transport: asyncio.Transport,\n        req: ClientRequest,\n    ) -> None:\n        \"\"\"Issue a warning if the requested URL has HTTPS scheme.\"\"\"\n        if req.request_info.url.scheme != \"https\":\n            return\n\n        asyncio_supports_tls_in_tls = getattr(\n            underlying_transport,\n            \"_start_tls_compatible\",\n            False,\n        )\n\n        if asyncio_supports_tls_in_tls:\n            return\n\n        warnings.warn(\n            \"An HTTPS request is being sent through an HTTPS proxy. \"\n            \"This support for TLS in TLS is known to be disabled \"\n            \"in the stdlib asyncio (Python <3.11). This is why you'll probably see \"\n            \"an error in the log below.\\n\\n\"\n            \"It is possible to enable it via monkeypatching. \"\n            \"For more details, see:\\n\"\n            \"* https://bugs.python.org/issue37179\\n\"\n            \"* https://github.com/python/cpython/pull/28073\\n\\n\"\n            \"You can temporarily patch this as follows:\\n\"\n            \"* https://docs.aiohttp.org/en/stable/client_advanced.html#proxy-support\\n\"\n            \"* https://github.com/aio-libs/aiohttp/discussions/6044\\n\",\n            RuntimeWarning,\n            source=self,\n            # Why `4`? At least 3 of the calls in the stack originate\n            # from the methods in this class.\n            stacklevel=3,\n        )\n\n    async def _start_tls_connection(\n        self,\n        underlying_transport: asyncio.Transport,\n        req: ClientRequest,\n        timeout: \"ClientTimeout\",\n        client_error: Type[Exception] = ClientConnectorError,\n    ) -> Tuple[asyncio.BaseTransport, ResponseHandler]:\n        \"\"\"Wrap the raw TCP transport with TLS.\"\"\"\n        tls_proto = self._factory()  # Create a brand new proto for TLS\n\n        # Safety of the `cast()` call here is based on the fact that\n        # internally `_get_ssl_context()` only returns `None` when\n        # `req.is_ssl()` evaluates to `False` which is never gonna happen\n        # in this code path. Of course, it's rather fragile\n        # maintainability-wise but this is to be solved separately.\n        sslcontext = cast(ssl.SSLContext, await self._get_ssl_context(req))\n\n        try:\n            async with ceil_timeout(\n                timeout.sock_connect, ceil_threshold=timeout.ceil_threshold\n            ):\n                try:\n                    tls_transport = await self._loop.start_tls(\n                        underlying_transport,\n                        tls_proto,\n                        sslcontext,\n                        server_hostname=req.server_hostname or req.host,\n                        ssl_handshake_timeout=timeout.total,\n                    )\n                except BaseException:\n                    # We need to close the underlying transport since\n                    # `start_tls()` probably failed before it had a\n                    # chance to do this:\n                    underlying_transport.close()\n                    raise\n        except cert_errors as exc:\n            raise ClientConnectorCertificateError(req.connection_key, exc) from exc\n        except ssl_errors as exc:\n            raise ClientConnectorSSLError(req.connection_key, exc) from exc\n        except OSError as exc:\n            if exc.errno is None and isinstance(exc, asyncio.TimeoutError):\n                raise\n            raise client_error(req.connection_key, exc) from exc\n        except TypeError as type_err:\n            # Example cause looks like this:\n            # TypeError: transport <asyncio.sslproto._SSLProtocolTransport\n            # object at 0x7f760615e460> is not supported by start_tls()\n\n            raise ClientConnectionError(\n                \"Cannot initialize a TLS-in-TLS connection to host \"\n                f\"{req.host!s}:{req.port:d} through an underlying connection \"\n                f\"to an HTTPS proxy {req.proxy!s} ssl:{req.ssl or 'default'} \"\n                f\"[{type_err!s}]\"\n            ) from type_err\n        else:\n            if tls_transport is None:\n                msg = \"Failed to start TLS (possibly caused by closing transport)\"\n                raise client_error(req.connection_key, OSError(msg))\n            tls_proto.connection_made(\n                tls_transport\n            )  # Kick the state machine of the new TLS protocol\n\n        return tls_transport, tls_proto\n\n    def _convert_hosts_to_addr_infos(\n        self, hosts: List[ResolveResult]\n    ) -> List[aiohappyeyeballs.AddrInfoType]:\n        \"\"\"Converts the list of hosts to a list of addr_infos.\n\n        The list of hosts is the result of a DNS lookup. The list of\n        addr_infos is the result of a call to `socket.getaddrinfo()`.\n        \"\"\"\n        addr_infos: List[aiohappyeyeballs.AddrInfoType] = []\n        for hinfo in hosts:\n            host = hinfo[\"host\"]\n            is_ipv6 = \":\" in host\n            family = socket.AF_INET6 if is_ipv6 else socket.AF_INET\n            if self._family and self._family != family:\n                continue\n            addr = (host, hinfo[\"port\"], 0, 0) if is_ipv6 else (host, hinfo[\"port\"])\n            addr_infos.append(\n                (family, socket.SOCK_STREAM, socket.IPPROTO_TCP, \"\", addr)\n            )\n        return addr_infos\n\n    async def _create_direct_connection(\n        self,\n        req: ClientRequest,\n        traces: List[\"Trace\"],\n        timeout: \"ClientTimeout\",\n        *,\n        client_error: Type[Exception] = ClientConnectorError,\n    ) -> Tuple[asyncio.Transport, ResponseHandler]:\n        sslcontext = await self._get_ssl_context(req)\n        fingerprint = self._get_fingerprint(req)\n\n        host = req.url.raw_host\n        assert host is not None\n        # Replace multiple trailing dots with a single one.\n        # A trailing dot is only present for fully-qualified domain names.\n        # See https://github.com/aio-libs/aiohttp/pull/7364.\n        if host.endswith(\"..\"):\n            host = host.rstrip(\".\") + \".\"\n        port = req.port\n        assert port is not None\n        try:\n            # Cancelling this lookup should not cancel the underlying lookup\n            #  or else the cancel event will get broadcast to all the waiters\n            #  across all connections.\n            hosts = await self._resolve_host(host, port, traces=traces)\n        except OSError as exc:\n            if exc.errno is None and isinstance(exc, asyncio.TimeoutError):\n                raise\n            # in case of proxy it is not ClientProxyConnectionError\n            # it is problem of resolving proxy ip itself\n            raise ClientConnectorError(req.connection_key, exc) from exc\n\n        last_exc: Optional[Exception] = None\n        addr_infos = self._convert_hosts_to_addr_infos(hosts)\n        while addr_infos:\n            # Strip trailing dots, certificates contain FQDN without dots.\n            # See https://github.com/aio-libs/aiohttp/issues/3636\n            server_hostname = (\n                (req.server_hostname or host).rstrip(\".\") if sslcontext else None\n            )\n\n            try:\n                transp, proto = await self._wrap_create_connection(\n                    self._factory,\n                    timeout=timeout,\n                    ssl=sslcontext,\n                    addr_infos=addr_infos,\n                    server_hostname=server_hostname,\n                    req=req,\n                    client_error=client_error,\n                )\n            except ClientConnectorError as exc:\n                last_exc = exc\n                aiohappyeyeballs.pop_addr_infos_interleave(addr_infos, self._interleave)\n                continue\n\n            if req.is_ssl() and fingerprint:\n                try:\n                    fingerprint.check(transp)\n                except ServerFingerprintMismatch as exc:\n                    transp.close()\n                    if not self._cleanup_closed_disabled:\n                        self._cleanup_closed_transports.append(transp)\n                    last_exc = exc\n                    # Remove the bad peer from the list of addr_infos\n                    sock: socket.socket = transp.get_extra_info(\"socket\")\n                    bad_peer = sock.getpeername()\n                    aiohappyeyeballs.remove_addr_infos(addr_infos, bad_peer)\n                    continue\n\n            return transp, proto\n        else:\n            assert last_exc is not None\n            raise last_exc\n\n    async def _create_proxy_connection(\n        self, req: ClientRequest, traces: List[\"Trace\"], timeout: \"ClientTimeout\"\n    ) -> Tuple[asyncio.BaseTransport, ResponseHandler]:\n        self._fail_on_no_start_tls(req)\n        runtime_has_start_tls = self._loop_supports_start_tls()\n\n        headers: Dict[str, str] = {}\n        if req.proxy_headers is not None:\n            headers = req.proxy_headers  # type: ignore[assignment]\n        headers[hdrs.HOST] = req.headers[hdrs.HOST]\n\n        url = req.proxy\n        assert url is not None\n        proxy_req = ClientRequest(\n            hdrs.METH_GET,\n            url,\n            headers=headers,\n            auth=req.proxy_auth,\n            loop=self._loop,\n            ssl=req.ssl,\n        )\n\n        # create connection to proxy server\n        transport, proto = await self._create_direct_connection(\n            proxy_req, [], timeout, client_error=ClientProxyConnectionError\n        )\n\n        auth = proxy_req.headers.pop(hdrs.AUTHORIZATION, None)\n        if auth is not None:\n            if not req.is_ssl():\n                req.headers[hdrs.PROXY_AUTHORIZATION] = auth\n            else:\n                proxy_req.headers[hdrs.PROXY_AUTHORIZATION] = auth\n\n        if req.is_ssl():\n            if runtime_has_start_tls:\n                self._warn_about_tls_in_tls(transport, req)\n\n            # For HTTPS requests over HTTP proxy\n            # we must notify proxy to tunnel connection\n            # so we send CONNECT command:\n            #   CONNECT www.python.org:443 HTTP/1.1\n            #   Host: www.python.org\n            #\n            # next we must do TLS handshake and so on\n            # to do this we must wrap raw socket into secure one\n            # asyncio handles this perfectly\n            proxy_req.method = hdrs.METH_CONNECT\n            proxy_req.url = req.url\n            key = attr.evolve(\n                req.connection_key, proxy=None, proxy_auth=None, proxy_headers_hash=None\n            )\n            conn = Connection(self, key, proto, self._loop)\n            proxy_resp = await proxy_req.send(conn)\n            try:\n                protocol = conn._protocol\n                assert protocol is not None\n\n                # read_until_eof=True will ensure the connection isn't closed\n                # once the response is received and processed allowing\n                # START_TLS to work on the connection below.\n                protocol.set_response_params(\n                    read_until_eof=runtime_has_start_tls,\n                    timeout_ceil_threshold=self._timeout_ceil_threshold,\n                )\n                resp = await proxy_resp.start(conn)\n            except BaseException:\n                proxy_resp.close()\n                conn.close()\n                raise\n            else:\n                conn._protocol = None\n                conn._transport = None\n                try:\n                    if resp.status != 200:\n                        message = resp.reason\n                        if message is None:\n                            message = HTTPStatus(resp.status).phrase\n                        raise ClientHttpProxyError(\n                            proxy_resp.request_info,\n                            resp.history,\n                            status=resp.status,\n                            message=message,\n                            headers=resp.headers,\n                        )\n                    if not runtime_has_start_tls:\n                        rawsock = transport.get_extra_info(\"socket\", default=None)\n                        if rawsock is None:\n                            raise RuntimeError(\n                                \"Transport does not expose socket instance\"\n                            )\n                        # Duplicate the socket, so now we can close proxy transport\n                        rawsock = rawsock.dup()\n                except BaseException:\n                    # It shouldn't be closed in `finally` because it's fed to\n                    # `loop.start_tls()` and the docs say not to touch it after\n                    # passing there.\n                    transport.close()\n                    raise\n                finally:\n                    if not runtime_has_start_tls:\n                        transport.close()\n\n                if not runtime_has_start_tls:\n                    # HTTP proxy with support for upgrade to HTTPS\n                    sslcontext = self._get_ssl_context(req)\n                    return await self._wrap_existing_connection(\n                        self._factory,\n                        timeout=timeout,\n                        ssl=sslcontext,\n                        sock=rawsock,\n                        server_hostname=req.host,\n                        req=req,\n                    )\n\n                return await self._start_tls_connection(\n                    # Access the old transport for the last time before it's\n                    # closed and forgotten forever:\n                    transport,\n                    req=req,\n                    timeout=timeout,\n                )\n            finally:\n                proxy_resp.close()\n\n        return transport, proto",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 860,
                            "end_lineno": 925,
                            "parent": {
                                "file_name": "aiohttp/connector.py",
                                "type": "class",
                                "name": "TCPConnector",
                                "content": "class TCPConnector(BaseConnector):\n    \"\"\"TCP connector.\n\n    verify_ssl - Set to True to check ssl certifications.\n    fingerprint - Pass the binary sha256\n        digest of the expected certificate in DER format to verify\n        that the certificate the server presents matches. See also\n        https://en.wikipedia.org/wiki/HTTP_Public_Key_Pinning\n    resolver - Enable DNS lookups and use this\n        resolver\n    use_dns_cache - Use memory cache for DNS lookups.\n    ttl_dns_cache - Max seconds having cached a DNS entry, None forever.\n    family - socket address family\n    local_addr - local tuple of (host, port) to bind socket to\n\n    keepalive_timeout - (optional) Keep-alive timeout.\n    force_close - Set to True to force close and do reconnect\n        after each request (and between redirects).\n    limit - The total number of simultaneous connections.\n    limit_per_host - Number of simultaneous connections to one host.\n    enable_cleanup_closed - Enables clean-up closed ssl transports.\n                            Disabled by default.\n    happy_eyeballs_delay - This is the “Connection Attempt Delay”\n                           as defined in RFC 8305. To disable\n                           the happy eyeballs algorithm, set to None.\n    interleave - “First Address Family Count” as defined in RFC 8305\n    loop - Optional event loop.\n    \"\"\"\n\n    allowed_protocol_schema_set = HIGH_LEVEL_SCHEMA_SET | frozenset({\"tcp\"})\n    _made_ssl_context: Dict[bool, \"asyncio.Future[SSLContext]\"] = {}\n\n    def __init__(\n        self,\n        *,\n        verify_ssl: bool = True,\n        fingerprint: Optional[bytes] = None,\n        use_dns_cache: bool = True,\n        ttl_dns_cache: Optional[int] = 10,\n        family: socket.AddressFamily = socket.AddressFamily.AF_UNSPEC,\n        ssl_context: Optional[SSLContext] = None,\n        ssl: Union[bool, Fingerprint, SSLContext] = True,\n        local_addr: Optional[Tuple[str, int]] = None,\n        resolver: Optional[AbstractResolver] = None,\n        keepalive_timeout: Union[None, float, object] = sentinel,\n        force_close: bool = False,\n        limit: int = 100,\n        limit_per_host: int = 0,\n        enable_cleanup_closed: bool = False,\n        loop: Optional[asyncio.AbstractEventLoop] = None,\n        timeout_ceil_threshold: float = 5,\n        happy_eyeballs_delay: Optional[float] = 0.25,\n        interleave: Optional[int] = None,\n    ):\n        super().__init__(\n            keepalive_timeout=keepalive_timeout,\n            force_close=force_close,\n            limit=limit,\n            limit_per_host=limit_per_host,\n            enable_cleanup_closed=enable_cleanup_closed,\n            loop=loop,\n            timeout_ceil_threshold=timeout_ceil_threshold,\n        )\n\n        self._ssl = _merge_ssl_params(ssl, verify_ssl, ssl_context, fingerprint)\n        if resolver is None:\n            resolver = DefaultResolver(loop=self._loop)\n        self._resolver = resolver\n\n        self._use_dns_cache = use_dns_cache\n        self._cached_hosts = _DNSCacheTable(ttl=ttl_dns_cache)\n        self._throttle_dns_events: Dict[Tuple[str, int], EventResultOrError] = {}\n        self._family = family\n        self._local_addr_infos = aiohappyeyeballs.addr_to_addr_infos(local_addr)\n        self._happy_eyeballs_delay = happy_eyeballs_delay\n        self._interleave = interleave\n        self._resolve_host_tasks: Set[\"asyncio.Task[List[ResolveResult]]\"] = set()\n\n    def close(self) -> Awaitable[None]:\n        \"\"\"Close all ongoing DNS calls.\"\"\"\n        for ev in self._throttle_dns_events.values():\n            ev.cancel()\n\n        for t in self._resolve_host_tasks:\n            t.cancel()\n\n        return super().close()\n\n    @property\n    def family(self) -> int:\n        \"\"\"Socket family like AF_INET.\"\"\"\n        return self._family\n\n    @property\n    def use_dns_cache(self) -> bool:\n        \"\"\"True if local DNS caching is enabled.\"\"\"\n        return self._use_dns_cache\n\n    def clear_dns_cache(\n        self, host: Optional[str] = None, port: Optional[int] = None\n    ) -> None:\n        \"\"\"Remove specified host/port or clear all dns local cache.\"\"\"\n        if host is not None and port is not None:\n            self._cached_hosts.remove((host, port))\n        elif host is not None or port is not None:\n            raise ValueError(\"either both host and port \" \"or none of them are allowed\")\n        else:\n            self._cached_hosts.clear()\n\n    async def _resolve_host(\n        self, host: str, port: int, traces: Optional[Sequence[\"Trace\"]] = None\n    ) -> List[ResolveResult]:\n        \"\"\"Resolve host and return list of addresses.\"\"\"\n        if is_ip_address(host):\n            return [\n                {\n                    \"hostname\": host,\n                    \"host\": host,\n                    \"port\": port,\n                    \"family\": self._family,\n                    \"proto\": 0,\n                    \"flags\": 0,\n                }\n            ]\n\n        if not self._use_dns_cache:\n\n            if traces:\n                for trace in traces:\n                    await trace.send_dns_resolvehost_start(host)\n\n            res = await self._resolver.resolve(host, port, family=self._family)\n\n            if traces:\n                for trace in traces:\n                    await trace.send_dns_resolvehost_end(host)\n\n            return res\n\n        key = (host, port)\n        if key in self._cached_hosts and not self._cached_hosts.expired(key):\n            # get result early, before any await (#4014)\n            result = self._cached_hosts.next_addrs(key)\n\n            if traces:\n                for trace in traces:\n                    await trace.send_dns_cache_hit(host)\n            return result\n\n        #\n        # If multiple connectors are resolving the same host, we wait\n        # for the first one to resolve and then use the result for all of them.\n        # We use a throttle event to ensure that we only resolve the host once\n        # and then use the result for all the waiters.\n        #\n        # In this case we need to create a task to ensure that we can shield\n        # the task from cancellation as cancelling this lookup should not cancel\n        # the underlying lookup or else the cancel event will get broadcast to\n        # all the waiters across all connections.\n        #\n        resolved_host_task = asyncio.create_task(\n            self._resolve_host_with_throttle(key, host, port, traces)\n        )\n        self._resolve_host_tasks.add(resolved_host_task)\n        resolved_host_task.add_done_callback(self._resolve_host_tasks.discard)\n        try:\n            return await asyncio.shield(resolved_host_task)\n        except asyncio.CancelledError:\n\n            def drop_exception(fut: \"asyncio.Future[List[ResolveResult]]\") -> None:\n                with suppress(Exception, asyncio.CancelledError):\n                    fut.result()\n\n            resolved_host_task.add_done_callback(drop_exception)\n            raise\n\n    async def _resolve_host_with_throttle(\n        self,\n        key: Tuple[str, int],\n        host: str,\n        port: int,\n        traces: Optional[Sequence[\"Trace\"]],\n    ) -> List[ResolveResult]:\n        \"\"\"Resolve host with a dns events throttle.\"\"\"\n        if key in self._throttle_dns_events:\n            # get event early, before any await (#4014)\n            event = self._throttle_dns_events[key]\n            if traces:\n                for trace in traces:\n                    await trace.send_dns_cache_hit(host)\n            await event.wait()\n        else:\n            # update dict early, before any await (#4014)\n            self._throttle_dns_events[key] = EventResultOrError(self._loop)\n            if traces:\n                for trace in traces:\n                    await trace.send_dns_cache_miss(host)\n            try:\n\n                if traces:\n                    for trace in traces:\n                        await trace.send_dns_resolvehost_start(host)\n\n                addrs = await self._resolver.resolve(host, port, family=self._family)\n                if traces:\n                    for trace in traces:\n                        await trace.send_dns_resolvehost_end(host)\n\n                self._cached_hosts.add(key, addrs)\n                self._throttle_dns_events[key].set()\n            except BaseException as e:\n                # any DNS exception, independently of the implementation\n                # is set for the waiters to raise the same exception.\n                self._throttle_dns_events[key].set(exc=e)\n                raise\n            finally:\n                self._throttle_dns_events.pop(key)\n\n        return self._cached_hosts.next_addrs(key)\n\n    async def _create_connection(\n        self, req: ClientRequest, traces: List[\"Trace\"], timeout: \"ClientTimeout\"\n    ) -> ResponseHandler:\n        \"\"\"Create connection.\n\n        Has same keyword arguments as BaseEventLoop.create_connection.\n        \"\"\"\n        if req.proxy:\n            _, proto = await self._create_proxy_connection(req, traces, timeout)\n        else:\n            _, proto = await self._create_direct_connection(req, traces, timeout)\n\n        return proto\n\n    @staticmethod\n    def _make_ssl_context(verified: bool) -> SSLContext:\n        \"\"\"Create SSL context.\n\n        This method is not async-friendly and should be called from a thread\n        because it will load certificates from disk and do other blocking I/O.\n        \"\"\"\n        if verified:\n            return ssl.create_default_context()\n        sslcontext = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)\n        sslcontext.options |= ssl.OP_NO_SSLv2\n        sslcontext.options |= ssl.OP_NO_SSLv3\n        sslcontext.check_hostname = False\n        sslcontext.verify_mode = ssl.CERT_NONE\n        sslcontext.options |= ssl.OP_NO_COMPRESSION\n        sslcontext.set_default_verify_paths()\n        return sslcontext\n\n    async def _get_ssl_context(self, req: ClientRequest) -> Optional[SSLContext]:\n        \"\"\"Logic to get the correct SSL context\n\n        0. if req.ssl is false, return None\n\n        1. if ssl_context is specified in req, use it\n        2. if _ssl_context is specified in self, use it\n        3. otherwise:\n            1. if verify_ssl is not specified in req, use self.ssl_context\n               (will generate a default context according to self.verify_ssl)\n            2. if verify_ssl is True in req, generate a default SSL context\n            3. if verify_ssl is False in req, generate a SSL context that\n               won't verify\n        \"\"\"\n        if not req.is_ssl():\n            return None\n\n        if ssl is None:  # pragma: no cover\n            raise RuntimeError(\"SSL is not supported.\")\n        sslcontext = req.ssl\n        if isinstance(sslcontext, ssl.SSLContext):\n            return sslcontext\n        if sslcontext is not True:\n            # not verified or fingerprinted\n            return await self._make_or_get_ssl_context(False)\n        sslcontext = self._ssl\n        if isinstance(sslcontext, ssl.SSLContext):\n            return sslcontext\n        if sslcontext is not True:\n            # not verified or fingerprinted\n            return await self._make_or_get_ssl_context(False)\n        return await self._make_or_get_ssl_context(True)\n\n    async def _make_or_get_ssl_context(self, verified: bool) -> SSLContext:\n        \"\"\"Create or get cached SSL context.\"\"\"\n        try:\n            return await self._made_ssl_context[verified]\n        except KeyError:\n            loop = self._loop\n            future = loop.create_future()\n            self._made_ssl_context[verified] = future\n            try:\n                result = await loop.run_in_executor(\n                    None, self._make_ssl_context, verified\n                )\n            # BaseException is used since we might get CancelledError\n            except BaseException as ex:\n                del self._made_ssl_context[verified]\n                set_exception(future, ex)\n                raise\n            else:\n                set_result(future, result)\n            return result\n\n    def _get_fingerprint(self, req: ClientRequest) -> Optional[\"Fingerprint\"]:\n        ret = req.ssl\n        if isinstance(ret, Fingerprint):\n            return ret\n        ret = self._ssl\n        if isinstance(ret, Fingerprint):\n            return ret\n        return None\n\n    async def _wrap_create_connection(\n        self,\n        *args: Any,\n        addr_infos: List[aiohappyeyeballs.AddrInfoType],\n        req: ClientRequest,\n        timeout: \"ClientTimeout\",\n        client_error: Type[Exception] = ClientConnectorError,\n        **kwargs: Any,\n    ) -> Tuple[asyncio.Transport, ResponseHandler]:\n        try:\n            async with ceil_timeout(\n                timeout.sock_connect, ceil_threshold=timeout.ceil_threshold\n            ):\n                sock = await aiohappyeyeballs.start_connection(\n                    addr_infos=addr_infos,\n                    local_addr_infos=self._local_addr_infos,\n                    happy_eyeballs_delay=self._happy_eyeballs_delay,\n                    interleave=self._interleave,\n                    loop=self._loop,\n                )\n                return await self._loop.create_connection(*args, **kwargs, sock=sock)\n        except cert_errors as exc:\n            raise ClientConnectorCertificateError(req.connection_key, exc) from exc\n        except ssl_errors as exc:\n            raise ClientConnectorSSLError(req.connection_key, exc) from exc\n        except OSError as exc:\n            if exc.errno is None and isinstance(exc, asyncio.TimeoutError):\n                raise\n            raise client_error(req.connection_key, exc) from exc\n\n    async def _wrap_existing_connection(\n        self,\n        *args: Any,\n        req: ClientRequest,\n        timeout: \"ClientTimeout\",\n        client_error: Type[Exception] = ClientConnectorError,\n        **kwargs: Any,\n    ) -> Tuple[asyncio.Transport, ResponseHandler]:\n        try:\n            async with ceil_timeout(\n                timeout.sock_connect, ceil_threshold=timeout.ceil_threshold\n            ):\n                return await self._loop.create_connection(*args, **kwargs)\n        except cert_errors as exc:\n            raise ClientConnectorCertificateError(req.connection_key, exc) from exc\n        except ssl_errors as exc:\n            raise ClientConnectorSSLError(req.connection_key, exc) from exc\n        except OSError as exc:\n            if exc.errno is None and isinstance(exc, asyncio.TimeoutError):\n                raise\n            raise client_error(req.connection_key, exc) from exc\n\n    def _fail_on_no_start_tls(self, req: \"ClientRequest\") -> None:\n        \"\"\"Raise a :py:exc:`RuntimeError` on missing ``start_tls()``.\n\n        It is necessary for TLS-in-TLS so that it is possible to\n        send HTTPS queries through HTTPS proxies.\n\n        This doesn't affect regular HTTP requests, though.\n        \"\"\"\n        if not req.is_ssl():\n            return\n\n        proxy_url = req.proxy\n        assert proxy_url is not None\n        if proxy_url.scheme != \"https\":\n            return\n\n        self._check_loop_for_start_tls()\n\n    def _check_loop_for_start_tls(self) -> None:\n        try:\n            self._loop.start_tls\n        except AttributeError as attr_exc:\n            raise RuntimeError(\n                \"An HTTPS request is being sent through an HTTPS proxy. \"\n                \"This needs support for TLS in TLS but it is not implemented \"\n                \"in your runtime for the stdlib asyncio.\\n\\n\"\n                \"Please upgrade to Python 3.11 or higher. For more details, \"\n                \"please see:\\n\"\n                \"* https://bugs.python.org/issue37179\\n\"\n                \"* https://github.com/python/cpython/pull/28073\\n\"\n                \"* https://docs.aiohttp.org/en/stable/\"\n                \"client_advanced.html#proxy-support\\n\"\n                \"* https://github.com/aio-libs/aiohttp/discussions/6044\\n\",\n            ) from attr_exc\n\n    def _loop_supports_start_tls(self) -> bool:\n        try:\n            self._check_loop_for_start_tls()\n        except RuntimeError:\n            return False\n        else:\n            return True\n\n    def _warn_about_tls_in_tls(\n        self,\n        underlying_transport: asyncio.Transport,\n        req: ClientRequest,\n    ) -> None:\n        \"\"\"Issue a warning if the requested URL has HTTPS scheme.\"\"\"\n        if req.request_info.url.scheme != \"https\":\n            return\n\n        asyncio_supports_tls_in_tls = getattr(\n            underlying_transport,\n            \"_start_tls_compatible\",\n            False,\n        )\n\n        if asyncio_supports_tls_in_tls:\n            return\n\n        warnings.warn(\n            \"An HTTPS request is being sent through an HTTPS proxy. \"\n            \"This support for TLS in TLS is known to be disabled \"\n            \"in the stdlib asyncio (Python <3.11). This is why you'll probably see \"\n            \"an error in the log below.\\n\\n\"\n            \"It is possible to enable it via monkeypatching. \"\n            \"For more details, see:\\n\"\n            \"* https://bugs.python.org/issue37179\\n\"\n            \"* https://github.com/python/cpython/pull/28073\\n\\n\"\n            \"You can temporarily patch this as follows:\\n\"\n            \"* https://docs.aiohttp.org/en/stable/client_advanced.html#proxy-support\\n\"\n            \"* https://github.com/aio-libs/aiohttp/discussions/6044\\n\",\n            RuntimeWarning,\n            source=self,\n            # Why `4`? At least 3 of the calls in the stack originate\n            # from the methods in this class.\n            stacklevel=3,\n        )\n\n    async def _start_tls_connection(\n        self,\n        underlying_transport: asyncio.Transport,\n        req: ClientRequest,\n        timeout: \"ClientTimeout\",\n        client_error: Type[Exception] = ClientConnectorError,\n    ) -> Tuple[asyncio.BaseTransport, ResponseHandler]:\n        \"\"\"Wrap the raw TCP transport with TLS.\"\"\"\n        tls_proto = self._factory()  # Create a brand new proto for TLS\n\n        # Safety of the `cast()` call here is based on the fact that\n        # internally `_get_ssl_context()` only returns `None` when\n        # `req.is_ssl()` evaluates to `False` which is never gonna happen\n        # in this code path. Of course, it's rather fragile\n        # maintainability-wise but this is to be solved separately.\n        sslcontext = cast(ssl.SSLContext, await self._get_ssl_context(req))\n\n        try:\n            async with ceil_timeout(\n                timeout.sock_connect, ceil_threshold=timeout.ceil_threshold\n            ):\n                try:\n                    tls_transport = await self._loop.start_tls(\n                        underlying_transport,\n                        tls_proto,\n                        sslcontext,\n                        server_hostname=req.server_hostname or req.host,\n                        ssl_handshake_timeout=timeout.total,\n                    )\n                except BaseException:\n                    # We need to close the underlying transport since\n                    # `start_tls()` probably failed before it had a\n                    # chance to do this:\n                    underlying_transport.close()\n                    raise\n        except cert_errors as exc:\n            raise ClientConnectorCertificateError(req.connection_key, exc) from exc\n        except ssl_errors as exc:\n            raise ClientConnectorSSLError(req.connection_key, exc) from exc\n        except OSError as exc:\n            if exc.errno is None and isinstance(exc, asyncio.TimeoutError):\n                raise\n            raise client_error(req.connection_key, exc) from exc\n        except TypeError as type_err:\n            # Example cause looks like this:\n            # TypeError: transport <asyncio.sslproto._SSLProtocolTransport\n            # object at 0x7f760615e460> is not supported by start_tls()\n\n            raise ClientConnectionError(\n                \"Cannot initialize a TLS-in-TLS connection to host \"\n                f\"{req.host!s}:{req.port:d} through an underlying connection \"\n                f\"to an HTTPS proxy {req.proxy!s} ssl:{req.ssl or 'default'} \"\n                f\"[{type_err!s}]\"\n            ) from type_err\n        else:\n            if tls_transport is None:\n                msg = \"Failed to start TLS (possibly caused by closing transport)\"\n                raise client_error(req.connection_key, OSError(msg))\n            tls_proto.connection_made(\n                tls_transport\n            )  # Kick the state machine of the new TLS protocol\n\n        return tls_transport, tls_proto\n\n    def _convert_hosts_to_addr_infos(\n        self, hosts: List[ResolveResult]\n    ) -> List[aiohappyeyeballs.AddrInfoType]:\n        \"\"\"Converts the list of hosts to a list of addr_infos.\n\n        The list of hosts is the result of a DNS lookup. The list of\n        addr_infos is the result of a call to `socket.getaddrinfo()`.\n        \"\"\"\n        addr_infos: List[aiohappyeyeballs.AddrInfoType] = []\n        for hinfo in hosts:\n            host = hinfo[\"host\"]\n            is_ipv6 = \":\" in host\n            family = socket.AF_INET6 if is_ipv6 else socket.AF_INET\n            if self._family and self._family != family:\n                continue\n            addr = (host, hinfo[\"port\"], 0, 0) if is_ipv6 else (host, hinfo[\"port\"])\n            addr_infos.append(\n                (family, socket.SOCK_STREAM, socket.IPPROTO_TCP, \"\", addr)\n            )\n        return addr_infos\n\n    async def _create_direct_connection(\n        self,\n        req: ClientRequest,\n        traces: List[\"Trace\"],\n        timeout: \"ClientTimeout\",\n        *,\n        client_error: Type[Exception] = ClientConnectorError,\n    ) -> Tuple[asyncio.Transport, ResponseHandler]:\n        sslcontext = await self._get_ssl_context(req)\n        fingerprint = self._get_fingerprint(req)\n\n        host = req.url.raw_host\n        assert host is not None\n        # Replace multiple trailing dots with a single one.\n        # A trailing dot is only present for fully-qualified domain names.\n        # See https://github.com/aio-libs/aiohttp/pull/7364.\n        if host.endswith(\"..\"):\n            host = host.rstrip(\".\") + \".\"\n        port = req.port\n        assert port is not None\n        try:\n            # Cancelling this lookup should not cancel the underlying lookup\n            #  or else the cancel event will get broadcast to all the waiters\n            #  across all connections.\n            hosts = await self._resolve_host(host, port, traces=traces)\n        except OSError as exc:\n            if exc.errno is None and isinstance(exc, asyncio.TimeoutError):\n                raise\n            # in case of proxy it is not ClientProxyConnectionError\n            # it is problem of resolving proxy ip itself\n            raise ClientConnectorError(req.connection_key, exc) from exc\n\n        last_exc: Optional[Exception] = None\n        addr_infos = self._convert_hosts_to_addr_infos(hosts)\n        while addr_infos:\n            # Strip trailing dots, certificates contain FQDN without dots.\n            # See https://github.com/aio-libs/aiohttp/issues/3636\n            server_hostname = (\n                (req.server_hostname or host).rstrip(\".\") if sslcontext else None\n            )\n\n            try:\n                transp, proto = await self._wrap_create_connection(\n                    self._factory,\n                    timeout=timeout,\n                    ssl=sslcontext,\n                    addr_infos=addr_infos,\n                    server_hostname=server_hostname,\n                    req=req,\n                    client_error=client_error,\n                )\n            except ClientConnectorError as exc:\n                last_exc = exc\n                aiohappyeyeballs.pop_addr_infos_interleave(addr_infos, self._interleave)\n                continue\n\n            if req.is_ssl() and fingerprint:\n                try:\n                    fingerprint.check(transp)\n                except ServerFingerprintMismatch as exc:\n                    transp.close()\n                    if not self._cleanup_closed_disabled:\n                        self._cleanup_closed_transports.append(transp)\n                    last_exc = exc\n                    # Remove the bad peer from the list of addr_infos\n                    sock: socket.socket = transp.get_extra_info(\"socket\")\n                    bad_peer = sock.getpeername()\n                    aiohappyeyeballs.remove_addr_infos(addr_infos, bad_peer)\n                    continue\n\n            return transp, proto\n        else:\n            assert last_exc is not None\n            raise last_exc\n\n    async def _create_proxy_connection(\n        self, req: ClientRequest, traces: List[\"Trace\"], timeout: \"ClientTimeout\"\n    ) -> Tuple[asyncio.BaseTransport, ResponseHandler]:\n        self._fail_on_no_start_tls(req)\n        runtime_has_start_tls = self._loop_supports_start_tls()\n\n        headers: Dict[str, str] = {}\n        if req.proxy_headers is not None:\n            headers = req.proxy_headers  # type: ignore[assignment]\n        headers[hdrs.HOST] = req.headers[hdrs.HOST]\n\n        url = req.proxy\n        assert url is not None\n        proxy_req = ClientRequest(\n            hdrs.METH_GET,\n            url,\n            headers=headers,\n            auth=req.proxy_auth,\n            loop=self._loop,\n            ssl=req.ssl,\n        )\n\n        # create connection to proxy server\n        transport, proto = await self._create_direct_connection(\n            proxy_req, [], timeout, client_error=ClientProxyConnectionError\n        )\n\n        auth = proxy_req.headers.pop(hdrs.AUTHORIZATION, None)\n        if auth is not None:\n            if not req.is_ssl():\n                req.headers[hdrs.PROXY_AUTHORIZATION] = auth\n            else:\n                proxy_req.headers[hdrs.PROXY_AUTHORIZATION] = auth\n\n        if req.is_ssl():\n            if runtime_has_start_tls:\n                self._warn_about_tls_in_tls(transport, req)\n\n            # For HTTPS requests over HTTP proxy\n            # we must notify proxy to tunnel connection\n            # so we send CONNECT command:\n            #   CONNECT www.python.org:443 HTTP/1.1\n            #   Host: www.python.org\n            #\n            # next we must do TLS handshake and so on\n            # to do this we must wrap raw socket into secure one\n            # asyncio handles this perfectly\n            proxy_req.method = hdrs.METH_CONNECT\n            proxy_req.url = req.url\n            key = attr.evolve(\n                req.connection_key, proxy=None, proxy_auth=None, proxy_headers_hash=None\n            )\n            conn = Connection(self, key, proto, self._loop)\n            proxy_resp = await proxy_req.send(conn)\n            try:\n                protocol = conn._protocol\n                assert protocol is not None\n\n                # read_until_eof=True will ensure the connection isn't closed\n                # once the response is received and processed allowing\n                # START_TLS to work on the connection below.\n                protocol.set_response_params(\n                    read_until_eof=runtime_has_start_tls,\n                    timeout_ceil_threshold=self._timeout_ceil_threshold,\n                )\n                resp = await proxy_resp.start(conn)\n            except BaseException:\n                proxy_resp.close()\n                conn.close()\n                raise\n            else:\n                conn._protocol = None\n                conn._transport = None\n                try:\n                    if resp.status != 200:\n                        message = resp.reason\n                        if message is None:\n                            message = HTTPStatus(resp.status).phrase\n                        raise ClientHttpProxyError(\n                            proxy_resp.request_info,\n                            resp.history,\n                            status=resp.status,\n                            message=message,\n                            headers=resp.headers,\n                        )\n                    if not runtime_has_start_tls:\n                        rawsock = transport.get_extra_info(\"socket\", default=None)\n                        if rawsock is None:\n                            raise RuntimeError(\n                                \"Transport does not expose socket instance\"\n                            )\n                        # Duplicate the socket, so now we can close proxy transport\n                        rawsock = rawsock.dup()\n                except BaseException:\n                    # It shouldn't be closed in `finally` because it's fed to\n                    # `loop.start_tls()` and the docs say not to touch it after\n                    # passing there.\n                    transport.close()\n                    raise\n                finally:\n                    if not runtime_has_start_tls:\n                        transport.close()\n\n                if not runtime_has_start_tls:\n                    # HTTP proxy with support for upgrade to HTTPS\n                    sslcontext = self._get_ssl_context(req)\n                    return await self._wrap_existing_connection(\n                        self._factory,\n                        timeout=timeout,\n                        ssl=sslcontext,\n                        sock=rawsock,\n                        server_hostname=req.host,\n                        req=req,\n                    )\n\n                return await self._start_tls_connection(\n                    # Access the old transport for the last time before it's\n                    # closed and forgotten forever:\n                    transport,\n                    req=req,\n                    timeout=timeout,\n                )\n            finally:\n                proxy_resp.close()\n\n        return transport, proto",
                                "ast_type_str": "ClassDef",
                                "start_lineno": 751,
                                "end_lineno": 1483,
                                "parent": null
                            }
                        },
                        {
                            "file_name": "aiohttp/connector.py",
                            "type": "class",
                            "name": "TCPConnector",
                            "content": "class TCPConnector(BaseConnector):\n    \"\"\"TCP connector.\n\n    verify_ssl - Set to True to check ssl certifications.\n    fingerprint - Pass the binary sha256\n        digest of the expected certificate in DER format to verify\n        that the certificate the server presents matches. See also\n        https://en.wikipedia.org/wiki/HTTP_Public_Key_Pinning\n    resolver - Enable DNS lookups and use this\n        resolver\n    use_dns_cache - Use memory cache for DNS lookups.\n    ttl_dns_cache - Max seconds having cached a DNS entry, None forever.\n    family - socket address family\n    local_addr - local tuple of (host, port) to bind socket to\n\n    keepalive_timeout - (optional) Keep-alive timeout.\n    force_close - Set to True to force close and do reconnect\n        after each request (and between redirects).\n    limit - The total number of simultaneous connections.\n    limit_per_host - Number of simultaneous connections to one host.\n    enable_cleanup_closed - Enables clean-up closed ssl transports.\n                            Disabled by default.\n    happy_eyeballs_delay - This is the “Connection Attempt Delay”\n                           as defined in RFC 8305. To disable\n                           the happy eyeballs algorithm, set to None.\n    interleave - “First Address Family Count” as defined in RFC 8305\n    loop - Optional event loop.\n    \"\"\"\n\n    allowed_protocol_schema_set = HIGH_LEVEL_SCHEMA_SET | frozenset({\"tcp\"})\n    _made_ssl_context: Dict[bool, \"asyncio.Future[SSLContext]\"] = {}\n\n    def __init__(\n        self,\n        *,\n        verify_ssl: bool = True,\n        fingerprint: Optional[bytes] = None,\n        use_dns_cache: bool = True,\n        ttl_dns_cache: Optional[int] = 10,\n        family: socket.AddressFamily = socket.AddressFamily.AF_UNSPEC,\n        ssl_context: Optional[SSLContext] = None,\n        ssl: Union[bool, Fingerprint, SSLContext] = True,\n        local_addr: Optional[Tuple[str, int]] = None,\n        resolver: Optional[AbstractResolver] = None,\n        keepalive_timeout: Union[None, float, object] = sentinel,\n        force_close: bool = False,\n        limit: int = 100,\n        limit_per_host: int = 0,\n        enable_cleanup_closed: bool = False,\n        loop: Optional[asyncio.AbstractEventLoop] = None,\n        timeout_ceil_threshold: float = 5,\n        happy_eyeballs_delay: Optional[float] = 0.25,\n        interleave: Optional[int] = None,\n    ):\n        super().__init__(\n            keepalive_timeout=keepalive_timeout,\n            force_close=force_close,\n            limit=limit,\n            limit_per_host=limit_per_host,\n            enable_cleanup_closed=enable_cleanup_closed,\n            loop=loop,\n            timeout_ceil_threshold=timeout_ceil_threshold,\n        )\n\n        self._ssl = _merge_ssl_params(ssl, verify_ssl, ssl_context, fingerprint)\n        if resolver is None:\n            resolver = DefaultResolver(loop=self._loop)\n        self._resolver = resolver\n\n        self._use_dns_cache = use_dns_cache\n        self._cached_hosts = _DNSCacheTable(ttl=ttl_dns_cache)\n        self._throttle_dns_events: Dict[Tuple[str, int], EventResultOrError] = {}\n        self._family = family\n        self._local_addr_infos = aiohappyeyeballs.addr_to_addr_infos(local_addr)\n        self._happy_eyeballs_delay = happy_eyeballs_delay\n        self._interleave = interleave\n        self._resolve_host_tasks: Set[\"asyncio.Task[List[ResolveResult]]\"] = set()\n\n    def close(self) -> Awaitable[None]:\n        \"\"\"Close all ongoing DNS calls.\"\"\"\n        for ev in self._throttle_dns_events.values():\n            ev.cancel()\n\n        for t in self._resolve_host_tasks:\n            t.cancel()\n\n        return super().close()\n\n    @property\n    def family(self) -> int:\n        \"\"\"Socket family like AF_INET.\"\"\"\n        return self._family\n\n    @property\n    def use_dns_cache(self) -> bool:\n        \"\"\"True if local DNS caching is enabled.\"\"\"\n        return self._use_dns_cache\n\n    def clear_dns_cache(\n        self, host: Optional[str] = None, port: Optional[int] = None\n    ) -> None:\n        \"\"\"Remove specified host/port or clear all dns local cache.\"\"\"\n        if host is not None and port is not None:\n            self._cached_hosts.remove((host, port))\n        elif host is not None or port is not None:\n            raise ValueError(\"either both host and port \" \"or none of them are allowed\")\n        else:\n            self._cached_hosts.clear()\n\n    async def _resolve_host(\n        self, host: str, port: int, traces: Optional[Sequence[\"Trace\"]] = None\n    ) -> List[ResolveResult]:\n        \"\"\"Resolve host and return list of addresses.\"\"\"\n        if is_ip_address(host):\n            return [\n                {\n                    \"hostname\": host,\n                    \"host\": host,\n                    \"port\": port,\n                    \"family\": self._family,\n                    \"proto\": 0,\n                    \"flags\": 0,\n                }\n            ]\n\n        if not self._use_dns_cache:\n\n            if traces:\n                for trace in traces:\n                    await trace.send_dns_resolvehost_start(host)\n\n            res = await self._resolver.resolve(host, port, family=self._family)\n\n            if traces:\n                for trace in traces:\n                    await trace.send_dns_resolvehost_end(host)\n\n            return res\n\n        key = (host, port)\n        if key in self._cached_hosts and not self._cached_hosts.expired(key):\n            # get result early, before any await (#4014)\n            result = self._cached_hosts.next_addrs(key)\n\n            if traces:\n                for trace in traces:\n                    await trace.send_dns_cache_hit(host)\n            return result\n\n        #\n        # If multiple connectors are resolving the same host, we wait\n        # for the first one to resolve and then use the result for all of them.\n        # We use a throttle event to ensure that we only resolve the host once\n        # and then use the result for all the waiters.\n        #\n        # In this case we need to create a task to ensure that we can shield\n        # the task from cancellation as cancelling this lookup should not cancel\n        # the underlying lookup or else the cancel event will get broadcast to\n        # all the waiters across all connections.\n        #\n        resolved_host_task = asyncio.create_task(\n            self._resolve_host_with_throttle(key, host, port, traces)\n        )\n        self._resolve_host_tasks.add(resolved_host_task)\n        resolved_host_task.add_done_callback(self._resolve_host_tasks.discard)\n        try:\n            return await asyncio.shield(resolved_host_task)\n        except asyncio.CancelledError:\n\n            def drop_exception(fut: \"asyncio.Future[List[ResolveResult]]\") -> None:\n                with suppress(Exception, asyncio.CancelledError):\n                    fut.result()\n\n            resolved_host_task.add_done_callback(drop_exception)\n            raise\n\n    async def _resolve_host_with_throttle(\n        self,\n        key: Tuple[str, int],\n        host: str,\n        port: int,\n        traces: Optional[Sequence[\"Trace\"]],\n    ) -> List[ResolveResult]:\n        \"\"\"Resolve host with a dns events throttle.\"\"\"\n        if key in self._throttle_dns_events:\n            # get event early, before any await (#4014)\n            event = self._throttle_dns_events[key]\n            if traces:\n                for trace in traces:\n                    await trace.send_dns_cache_hit(host)\n            await event.wait()\n        else:\n            # update dict early, before any await (#4014)\n            self._throttle_dns_events[key] = EventResultOrError(self._loop)\n            if traces:\n                for trace in traces:\n                    await trace.send_dns_cache_miss(host)\n            try:\n\n                if traces:\n                    for trace in traces:\n                        await trace.send_dns_resolvehost_start(host)\n\n                addrs = await self._resolver.resolve(host, port, family=self._family)\n                if traces:\n                    for trace in traces:\n                        await trace.send_dns_resolvehost_end(host)\n\n                self._cached_hosts.add(key, addrs)\n                self._throttle_dns_events[key].set()\n            except BaseException as e:\n                # any DNS exception, independently of the implementation\n                # is set for the waiters to raise the same exception.\n                self._throttle_dns_events[key].set(exc=e)\n                raise\n            finally:\n                self._throttle_dns_events.pop(key)\n\n        return self._cached_hosts.next_addrs(key)\n\n    async def _create_connection(\n        self, req: ClientRequest, traces: List[\"Trace\"], timeout: \"ClientTimeout\"\n    ) -> ResponseHandler:\n        \"\"\"Create connection.\n\n        Has same keyword arguments as BaseEventLoop.create_connection.\n        \"\"\"\n        if req.proxy:\n            _, proto = await self._create_proxy_connection(req, traces, timeout)\n        else:\n            _, proto = await self._create_direct_connection(req, traces, timeout)\n\n        return proto\n\n    @staticmethod\n    def _make_ssl_context(verified: bool) -> SSLContext:\n        \"\"\"Create SSL context.\n\n        This method is not async-friendly and should be called from a thread\n        because it will load certificates from disk and do other blocking I/O.\n        \"\"\"\n        if verified:\n            return ssl.create_default_context()\n        sslcontext = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)\n        sslcontext.options |= ssl.OP_NO_SSLv2\n        sslcontext.options |= ssl.OP_NO_SSLv3\n        sslcontext.check_hostname = False\n        sslcontext.verify_mode = ssl.CERT_NONE\n        sslcontext.options |= ssl.OP_NO_COMPRESSION\n        sslcontext.set_default_verify_paths()\n        return sslcontext\n\n    async def _get_ssl_context(self, req: ClientRequest) -> Optional[SSLContext]:\n        \"\"\"Logic to get the correct SSL context\n\n        0. if req.ssl is false, return None\n\n        1. if ssl_context is specified in req, use it\n        2. if _ssl_context is specified in self, use it\n        3. otherwise:\n            1. if verify_ssl is not specified in req, use self.ssl_context\n               (will generate a default context according to self.verify_ssl)\n            2. if verify_ssl is True in req, generate a default SSL context\n            3. if verify_ssl is False in req, generate a SSL context that\n               won't verify\n        \"\"\"\n        if not req.is_ssl():\n            return None\n\n        if ssl is None:  # pragma: no cover\n            raise RuntimeError(\"SSL is not supported.\")\n        sslcontext = req.ssl\n        if isinstance(sslcontext, ssl.SSLContext):\n            return sslcontext\n        if sslcontext is not True:\n            # not verified or fingerprinted\n            return await self._make_or_get_ssl_context(False)\n        sslcontext = self._ssl\n        if isinstance(sslcontext, ssl.SSLContext):\n            return sslcontext\n        if sslcontext is not True:\n            # not verified or fingerprinted\n            return await self._make_or_get_ssl_context(False)\n        return await self._make_or_get_ssl_context(True)\n\n    async def _make_or_get_ssl_context(self, verified: bool) -> SSLContext:\n        \"\"\"Create or get cached SSL context.\"\"\"\n        try:\n            return await self._made_ssl_context[verified]\n        except KeyError:\n            loop = self._loop\n            future = loop.create_future()\n            self._made_ssl_context[verified] = future\n            try:\n                result = await loop.run_in_executor(\n                    None, self._make_ssl_context, verified\n                )\n            # BaseException is used since we might get CancelledError\n            except BaseException as ex:\n                del self._made_ssl_context[verified]\n                set_exception(future, ex)\n                raise\n            else:\n                set_result(future, result)\n            return result\n\n    def _get_fingerprint(self, req: ClientRequest) -> Optional[\"Fingerprint\"]:\n        ret = req.ssl\n        if isinstance(ret, Fingerprint):\n            return ret\n        ret = self._ssl\n        if isinstance(ret, Fingerprint):\n            return ret\n        return None\n\n    async def _wrap_create_connection(\n        self,\n        *args: Any,\n        addr_infos: List[aiohappyeyeballs.AddrInfoType],\n        req: ClientRequest,\n        timeout: \"ClientTimeout\",\n        client_error: Type[Exception] = ClientConnectorError,\n        **kwargs: Any,\n    ) -> Tuple[asyncio.Transport, ResponseHandler]:\n        try:\n            async with ceil_timeout(\n                timeout.sock_connect, ceil_threshold=timeout.ceil_threshold\n            ):\n                sock = await aiohappyeyeballs.start_connection(\n                    addr_infos=addr_infos,\n                    local_addr_infos=self._local_addr_infos,\n                    happy_eyeballs_delay=self._happy_eyeballs_delay,\n                    interleave=self._interleave,\n                    loop=self._loop,\n                )\n                return await self._loop.create_connection(*args, **kwargs, sock=sock)\n        except cert_errors as exc:\n            raise ClientConnectorCertificateError(req.connection_key, exc) from exc\n        except ssl_errors as exc:\n            raise ClientConnectorSSLError(req.connection_key, exc) from exc\n        except OSError as exc:\n            if exc.errno is None and isinstance(exc, asyncio.TimeoutError):\n                raise\n            raise client_error(req.connection_key, exc) from exc\n\n    async def _wrap_existing_connection(\n        self,\n        *args: Any,\n        req: ClientRequest,\n        timeout: \"ClientTimeout\",\n        client_error: Type[Exception] = ClientConnectorError,\n        **kwargs: Any,\n    ) -> Tuple[asyncio.Transport, ResponseHandler]:\n        try:\n            async with ceil_timeout(\n                timeout.sock_connect, ceil_threshold=timeout.ceil_threshold\n            ):\n                return await self._loop.create_connection(*args, **kwargs)\n        except cert_errors as exc:\n            raise ClientConnectorCertificateError(req.connection_key, exc) from exc\n        except ssl_errors as exc:\n            raise ClientConnectorSSLError(req.connection_key, exc) from exc\n        except OSError as exc:\n            if exc.errno is None and isinstance(exc, asyncio.TimeoutError):\n                raise\n            raise client_error(req.connection_key, exc) from exc\n\n    def _fail_on_no_start_tls(self, req: \"ClientRequest\") -> None:\n        \"\"\"Raise a :py:exc:`RuntimeError` on missing ``start_tls()``.\n\n        It is necessary for TLS-in-TLS so that it is possible to\n        send HTTPS queries through HTTPS proxies.\n\n        This doesn't affect regular HTTP requests, though.\n        \"\"\"\n        if not req.is_ssl():\n            return\n\n        proxy_url = req.proxy\n        assert proxy_url is not None\n        if proxy_url.scheme != \"https\":\n            return\n\n        self._check_loop_for_start_tls()\n\n    def _check_loop_for_start_tls(self) -> None:\n        try:\n            self._loop.start_tls\n        except AttributeError as attr_exc:\n            raise RuntimeError(\n                \"An HTTPS request is being sent through an HTTPS proxy. \"\n                \"This needs support for TLS in TLS but it is not implemented \"\n                \"in your runtime for the stdlib asyncio.\\n\\n\"\n                \"Please upgrade to Python 3.11 or higher. For more details, \"\n                \"please see:\\n\"\n                \"* https://bugs.python.org/issue37179\\n\"\n                \"* https://github.com/python/cpython/pull/28073\\n\"\n                \"* https://docs.aiohttp.org/en/stable/\"\n                \"client_advanced.html#proxy-support\\n\"\n                \"* https://github.com/aio-libs/aiohttp/discussions/6044\\n\",\n            ) from attr_exc\n\n    def _loop_supports_start_tls(self) -> bool:\n        try:\n            self._check_loop_for_start_tls()\n        except RuntimeError:\n            return False\n        else:\n            return True\n\n    def _warn_about_tls_in_tls(\n        self,\n        underlying_transport: asyncio.Transport,\n        req: ClientRequest,\n    ) -> None:\n        \"\"\"Issue a warning if the requested URL has HTTPS scheme.\"\"\"\n        if req.request_info.url.scheme != \"https\":\n            return\n\n        asyncio_supports_tls_in_tls = getattr(\n            underlying_transport,\n            \"_start_tls_compatible\",\n            False,\n        )\n\n        if asyncio_supports_tls_in_tls:\n            return\n\n        warnings.warn(\n            \"An HTTPS request is being sent through an HTTPS proxy. \"\n            \"This support for TLS in TLS is known to be disabled \"\n            \"in the stdlib asyncio (Python <3.11). This is why you'll probably see \"\n            \"an error in the log below.\\n\\n\"\n            \"It is possible to enable it via monkeypatching. \"\n            \"For more details, see:\\n\"\n            \"* https://bugs.python.org/issue37179\\n\"\n            \"* https://github.com/python/cpython/pull/28073\\n\\n\"\n            \"You can temporarily patch this as follows:\\n\"\n            \"* https://docs.aiohttp.org/en/stable/client_advanced.html#proxy-support\\n\"\n            \"* https://github.com/aio-libs/aiohttp/discussions/6044\\n\",\n            RuntimeWarning,\n            source=self,\n            # Why `4`? At least 3 of the calls in the stack originate\n            # from the methods in this class.\n            stacklevel=3,\n        )\n\n    async def _start_tls_connection(\n        self,\n        underlying_transport: asyncio.Transport,\n        req: ClientRequest,\n        timeout: \"ClientTimeout\",\n        client_error: Type[Exception] = ClientConnectorError,\n    ) -> Tuple[asyncio.BaseTransport, ResponseHandler]:\n        \"\"\"Wrap the raw TCP transport with TLS.\"\"\"\n        tls_proto = self._factory()  # Create a brand new proto for TLS\n\n        # Safety of the `cast()` call here is based on the fact that\n        # internally `_get_ssl_context()` only returns `None` when\n        # `req.is_ssl()` evaluates to `False` which is never gonna happen\n        # in this code path. Of course, it's rather fragile\n        # maintainability-wise but this is to be solved separately.\n        sslcontext = cast(ssl.SSLContext, await self._get_ssl_context(req))\n\n        try:\n            async with ceil_timeout(\n                timeout.sock_connect, ceil_threshold=timeout.ceil_threshold\n            ):\n                try:\n                    tls_transport = await self._loop.start_tls(\n                        underlying_transport,\n                        tls_proto,\n                        sslcontext,\n                        server_hostname=req.server_hostname or req.host,\n                        ssl_handshake_timeout=timeout.total,\n                    )\n                except BaseException:\n                    # We need to close the underlying transport since\n                    # `start_tls()` probably failed before it had a\n                    # chance to do this:\n                    underlying_transport.close()\n                    raise\n        except cert_errors as exc:\n            raise ClientConnectorCertificateError(req.connection_key, exc) from exc\n        except ssl_errors as exc:\n            raise ClientConnectorSSLError(req.connection_key, exc) from exc\n        except OSError as exc:\n            if exc.errno is None and isinstance(exc, asyncio.TimeoutError):\n                raise\n            raise client_error(req.connection_key, exc) from exc\n        except TypeError as type_err:\n            # Example cause looks like this:\n            # TypeError: transport <asyncio.sslproto._SSLProtocolTransport\n            # object at 0x7f760615e460> is not supported by start_tls()\n\n            raise ClientConnectionError(\n                \"Cannot initialize a TLS-in-TLS connection to host \"\n                f\"{req.host!s}:{req.port:d} through an underlying connection \"\n                f\"to an HTTPS proxy {req.proxy!s} ssl:{req.ssl or 'default'} \"\n                f\"[{type_err!s}]\"\n            ) from type_err\n        else:\n            if tls_transport is None:\n                msg = \"Failed to start TLS (possibly caused by closing transport)\"\n                raise client_error(req.connection_key, OSError(msg))\n            tls_proto.connection_made(\n                tls_transport\n            )  # Kick the state machine of the new TLS protocol\n\n        return tls_transport, tls_proto\n\n    def _convert_hosts_to_addr_infos(\n        self, hosts: List[ResolveResult]\n    ) -> List[aiohappyeyeballs.AddrInfoType]:\n        \"\"\"Converts the list of hosts to a list of addr_infos.\n\n        The list of hosts is the result of a DNS lookup. The list of\n        addr_infos is the result of a call to `socket.getaddrinfo()`.\n        \"\"\"\n        addr_infos: List[aiohappyeyeballs.AddrInfoType] = []\n        for hinfo in hosts:\n            host = hinfo[\"host\"]\n            is_ipv6 = \":\" in host\n            family = socket.AF_INET6 if is_ipv6 else socket.AF_INET\n            if self._family and self._family != family:\n                continue\n            addr = (host, hinfo[\"port\"], 0, 0) if is_ipv6 else (host, hinfo[\"port\"])\n            addr_infos.append(\n                (family, socket.SOCK_STREAM, socket.IPPROTO_TCP, \"\", addr)\n            )\n        return addr_infos\n\n    async def _create_direct_connection(\n        self,\n        req: ClientRequest,\n        traces: List[\"Trace\"],\n        timeout: \"ClientTimeout\",\n        *,\n        client_error: Type[Exception] = ClientConnectorError,\n    ) -> Tuple[asyncio.Transport, ResponseHandler]:\n        sslcontext = await self._get_ssl_context(req)\n        fingerprint = self._get_fingerprint(req)\n\n        host = req.url.raw_host\n        assert host is not None\n        # Replace multiple trailing dots with a single one.\n        # A trailing dot is only present for fully-qualified domain names.\n        # See https://github.com/aio-libs/aiohttp/pull/7364.\n        if host.endswith(\"..\"):\n            host = host.rstrip(\".\") + \".\"\n        port = req.port\n        assert port is not None\n        try:\n            # Cancelling this lookup should not cancel the underlying lookup\n            #  or else the cancel event will get broadcast to all the waiters\n            #  across all connections.\n            hosts = await self._resolve_host(host, port, traces=traces)\n        except OSError as exc:\n            if exc.errno is None and isinstance(exc, asyncio.TimeoutError):\n                raise\n            # in case of proxy it is not ClientProxyConnectionError\n            # it is problem of resolving proxy ip itself\n            raise ClientConnectorError(req.connection_key, exc) from exc\n\n        last_exc: Optional[Exception] = None\n        addr_infos = self._convert_hosts_to_addr_infos(hosts)\n        while addr_infos:\n            # Strip trailing dots, certificates contain FQDN without dots.\n            # See https://github.com/aio-libs/aiohttp/issues/3636\n            server_hostname = (\n                (req.server_hostname or host).rstrip(\".\") if sslcontext else None\n            )\n\n            try:\n                transp, proto = await self._wrap_create_connection(\n                    self._factory,\n                    timeout=timeout,\n                    ssl=sslcontext,\n                    addr_infos=addr_infos,\n                    server_hostname=server_hostname,\n                    req=req,\n                    client_error=client_error,\n                )\n            except ClientConnectorError as exc:\n                last_exc = exc\n                aiohappyeyeballs.pop_addr_infos_interleave(addr_infos, self._interleave)\n                continue\n\n            if req.is_ssl() and fingerprint:\n                try:\n                    fingerprint.check(transp)\n                except ServerFingerprintMismatch as exc:\n                    transp.close()\n                    if not self._cleanup_closed_disabled:\n                        self._cleanup_closed_transports.append(transp)\n                    last_exc = exc\n                    # Remove the bad peer from the list of addr_infos\n                    sock: socket.socket = transp.get_extra_info(\"socket\")\n                    bad_peer = sock.getpeername()\n                    aiohappyeyeballs.remove_addr_infos(addr_infos, bad_peer)\n                    continue\n\n            return transp, proto\n        else:\n            assert last_exc is not None\n            raise last_exc\n\n    async def _create_proxy_connection(\n        self, req: ClientRequest, traces: List[\"Trace\"], timeout: \"ClientTimeout\"\n    ) -> Tuple[asyncio.BaseTransport, ResponseHandler]:\n        self._fail_on_no_start_tls(req)\n        runtime_has_start_tls = self._loop_supports_start_tls()\n\n        headers: Dict[str, str] = {}\n        if req.proxy_headers is not None:\n            headers = req.proxy_headers  # type: ignore[assignment]\n        headers[hdrs.HOST] = req.headers[hdrs.HOST]\n\n        url = req.proxy\n        assert url is not None\n        proxy_req = ClientRequest(\n            hdrs.METH_GET,\n            url,\n            headers=headers,\n            auth=req.proxy_auth,\n            loop=self._loop,\n            ssl=req.ssl,\n        )\n\n        # create connection to proxy server\n        transport, proto = await self._create_direct_connection(\n            proxy_req, [], timeout, client_error=ClientProxyConnectionError\n        )\n\n        auth = proxy_req.headers.pop(hdrs.AUTHORIZATION, None)\n        if auth is not None:\n            if not req.is_ssl():\n                req.headers[hdrs.PROXY_AUTHORIZATION] = auth\n            else:\n                proxy_req.headers[hdrs.PROXY_AUTHORIZATION] = auth\n\n        if req.is_ssl():\n            if runtime_has_start_tls:\n                self._warn_about_tls_in_tls(transport, req)\n\n            # For HTTPS requests over HTTP proxy\n            # we must notify proxy to tunnel connection\n            # so we send CONNECT command:\n            #   CONNECT www.python.org:443 HTTP/1.1\n            #   Host: www.python.org\n            #\n            # next we must do TLS handshake and so on\n            # to do this we must wrap raw socket into secure one\n            # asyncio handles this perfectly\n            proxy_req.method = hdrs.METH_CONNECT\n            proxy_req.url = req.url\n            key = attr.evolve(\n                req.connection_key, proxy=None, proxy_auth=None, proxy_headers_hash=None\n            )\n            conn = Connection(self, key, proto, self._loop)\n            proxy_resp = await proxy_req.send(conn)\n            try:\n                protocol = conn._protocol\n                assert protocol is not None\n\n                # read_until_eof=True will ensure the connection isn't closed\n                # once the response is received and processed allowing\n                # START_TLS to work on the connection below.\n                protocol.set_response_params(\n                    read_until_eof=runtime_has_start_tls,\n                    timeout_ceil_threshold=self._timeout_ceil_threshold,\n                )\n                resp = await proxy_resp.start(conn)\n            except BaseException:\n                proxy_resp.close()\n                conn.close()\n                raise\n            else:\n                conn._protocol = None\n                conn._transport = None\n                try:\n                    if resp.status != 200:\n                        message = resp.reason\n                        if message is None:\n                            message = HTTPStatus(resp.status).phrase\n                        raise ClientHttpProxyError(\n                            proxy_resp.request_info,\n                            resp.history,\n                            status=resp.status,\n                            message=message,\n                            headers=resp.headers,\n                        )\n                    if not runtime_has_start_tls:\n                        rawsock = transport.get_extra_info(\"socket\", default=None)\n                        if rawsock is None:\n                            raise RuntimeError(\n                                \"Transport does not expose socket instance\"\n                            )\n                        # Duplicate the socket, so now we can close proxy transport\n                        rawsock = rawsock.dup()\n                except BaseException:\n                    # It shouldn't be closed in `finally` because it's fed to\n                    # `loop.start_tls()` and the docs say not to touch it after\n                    # passing there.\n                    transport.close()\n                    raise\n                finally:\n                    if not runtime_has_start_tls:\n                        transport.close()\n\n                if not runtime_has_start_tls:\n                    # HTTP proxy with support for upgrade to HTTPS\n                    sslcontext = self._get_ssl_context(req)\n                    return await self._wrap_existing_connection(\n                        self._factory,\n                        timeout=timeout,\n                        ssl=sslcontext,\n                        sock=rawsock,\n                        server_hostname=req.host,\n                        req=req,\n                    )\n\n                return await self._start_tls_connection(\n                    # Access the old transport for the last time before it's\n                    # closed and forgotten forever:\n                    transport,\n                    req=req,\n                    timeout=timeout,\n                )\n            finally:\n                proxy_resp.close()\n\n        return transport, proto",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 751,
                            "end_lineno": 1483,
                            "parent": null
                        }
                    ],
                    "added_entities": [],
                    "deleted_entities": []
                }
            ]
        },
        {
            "old_file_content": "# Tests of http client with custom Connector\n\nimport asyncio\nimport gc\nimport hashlib\nimport platform\nimport socket\nimport ssl\nimport sys\nimport uuid\nfrom collections import deque\nfrom contextlib import closing\nfrom typing import Any, List, Optional, Type\nfrom unittest import mock\n\nimport pytest\nfrom aiohappyeyeballs import AddrInfoType\nfrom yarl import URL\n\nimport aiohttp\nfrom aiohttp import client, web\nfrom aiohttp.client import ClientRequest, ClientTimeout\nfrom aiohttp.client_reqrep import ConnectionKey\nfrom aiohttp.connector import Connection, TCPConnector, _DNSCacheTable\nfrom aiohttp.locks import EventResultOrError\nfrom aiohttp.test_utils import make_mocked_coro, unused_port\nfrom aiohttp.tracing import Trace\n\n\n@pytest.fixture()\ndef key():\n    # Connection key\n    return ConnectionKey(\"localhost\", 80, False, True, None, None, None)\n\n\n@pytest.fixture\ndef key2():\n    # Connection key\n    return ConnectionKey(\"localhost\", 80, False, True, None, None, None)\n\n\n@pytest.fixture\ndef ssl_key():\n    # Connection key\n    return ConnectionKey(\"localhost\", 80, True, True, None, None, None)\n\n\n@pytest.fixture\ndef unix_server(loop, unix_sockname):\n    runners = []\n\n    async def go(app):\n        runner = web.AppRunner(app)\n        runners.append(runner)\n        await runner.setup()\n        site = web.UnixSite(runner, unix_sockname)\n        await site.start()\n\n    yield go\n\n    for runner in runners:\n        loop.run_until_complete(runner.cleanup())\n\n\n@pytest.fixture\ndef named_pipe_server(proactor_loop, pipe_name):\n    runners = []\n\n    async def go(app):\n        runner = web.AppRunner(app)\n        runners.append(runner)\n        await runner.setup()\n        site = web.NamedPipeSite(runner, pipe_name)\n        await site.start()\n\n    yield go\n\n    for runner in runners:\n        proactor_loop.run_until_complete(runner.cleanup())\n\n\ndef create_mocked_conn(conn_closing_result=None, **kwargs):\n    try:\n        loop = asyncio.get_running_loop()\n    except RuntimeError:\n        loop = asyncio.get_event_loop_policy().get_event_loop()\n\n    proto = mock.Mock(**kwargs)\n    proto.closed = loop.create_future()\n    proto.closed.set_result(conn_closing_result)\n    return proto\n\n\ndef test_connection_del(loop) -> None:\n    connector = mock.Mock()\n    key = mock.Mock()\n    protocol = mock.Mock()\n    loop.set_debug(0)\n    conn = Connection(connector, key, protocol, loop=loop)\n    exc_handler = mock.Mock()\n    loop.set_exception_handler(exc_handler)\n\n    with pytest.warns(ResourceWarning):\n        del conn\n        gc.collect()\n\n    connector._release.assert_called_with(key, protocol, should_close=True)\n    msg = {\n        \"message\": mock.ANY,\n        \"client_connection\": mock.ANY,\n    }\n    exc_handler.assert_called_with(loop, msg)\n\n\ndef test_connection_del_loop_debug(loop) -> None:\n    connector = mock.Mock()\n    key = mock.Mock()\n    protocol = mock.Mock()\n    loop.set_debug(1)\n    conn = Connection(connector, key, protocol, loop=loop)\n    exc_handler = mock.Mock()\n    loop.set_exception_handler(exc_handler)\n\n    with pytest.warns(ResourceWarning):\n        del conn\n        gc.collect()\n\n    msg = {\n        \"message\": mock.ANY,\n        \"client_connection\": mock.ANY,\n        \"source_traceback\": mock.ANY,\n    }\n    exc_handler.assert_called_with(loop, msg)\n\n\ndef test_connection_del_loop_closed(loop) -> None:\n    connector = mock.Mock()\n    key = mock.Mock()\n    protocol = mock.Mock()\n    loop.set_debug(1)\n    conn = Connection(connector, key, protocol, loop=loop)\n    exc_handler = mock.Mock()\n    loop.set_exception_handler(exc_handler)\n    loop.close()\n\n    with pytest.warns(ResourceWarning):\n        del conn\n        gc.collect()\n\n    assert not connector._release.called\n    assert not exc_handler.called\n\n\nasync def test_del(loop) -> None:\n    conn = aiohttp.BaseConnector()\n    proto = mock.Mock(should_close=False)\n    conn._release(\"a\", proto)\n    conns_impl = conn._conns\n\n    exc_handler = mock.Mock()\n    loop.set_exception_handler(exc_handler)\n\n    with pytest.warns(ResourceWarning):\n        del conn\n        gc.collect()\n\n    assert not conns_impl\n    proto.close.assert_called_with()\n    msg = {\n        \"connector\": mock.ANY,  # conn was deleted\n        \"connections\": mock.ANY,\n        \"message\": \"Unclosed connector\",\n    }\n    if loop.get_debug():\n        msg[\"source_traceback\"] = mock.ANY\n    exc_handler.assert_called_with(loop, msg)\n\n\n@pytest.mark.xfail\nasync def test_del_with_scheduled_cleanup(loop) -> None:\n    loop.set_debug(True)\n    conn = aiohttp.BaseConnector(loop=loop, keepalive_timeout=0.01)\n    transp = mock.Mock()\n    conn._conns[\"a\"] = [(transp, 123)]\n\n    conns_impl = conn._conns\n    exc_handler = mock.Mock()\n    loop.set_exception_handler(exc_handler)\n\n    with pytest.warns(ResourceWarning):\n        # obviously doesn't deletion because loop has a strong\n        # reference to connector's instance method, isn't it?\n        del conn\n        await asyncio.sleep(0.01)\n        gc.collect()\n\n    assert not conns_impl\n    transp.close.assert_called_with()\n    msg = {\"connector\": mock.ANY, \"message\": \"Unclosed connector\"}  # conn was deleted\n    if loop.get_debug():\n        msg[\"source_traceback\"] = mock.ANY\n    exc_handler.assert_called_with(loop, msg)\n\n\n@pytest.mark.skipif(\n    sys.implementation.name != \"cpython\", reason=\"CPython GC is required for the test\"\n)\ndef test_del_with_closed_loop(loop) -> None:\n    async def make_conn():\n        return aiohttp.BaseConnector()\n\n    conn = loop.run_until_complete(make_conn())\n    transp = mock.Mock()\n    conn._conns[\"a\"] = [(transp, 123)]\n\n    conns_impl = conn._conns\n    exc_handler = mock.Mock()\n    loop.set_exception_handler(exc_handler)\n    loop.close()\n\n    with pytest.warns(ResourceWarning):\n        del conn\n        gc.collect()\n\n    assert not conns_impl\n    assert not transp.close.called\n    assert exc_handler.called\n\n\nasync def test_del_empty_connector(loop) -> None:\n    conn = aiohttp.BaseConnector(loop=loop)\n\n    exc_handler = mock.Mock()\n    loop.set_exception_handler(exc_handler)\n\n    del conn\n\n    assert not exc_handler.called\n\n\nasync def test_create_conn(loop) -> None:\n    conn = aiohttp.BaseConnector(loop=loop)\n    with pytest.raises(NotImplementedError):\n        await conn._create_connection(object(), [], object())\n\n\nasync def test_connector_context_manager(loop) -> None:\n    conn = aiohttp.BaseConnector(loop=loop)\n\n    with pytest.warns(DeprecationWarning):\n        with conn as c:\n            assert conn is c\n\n    assert conn.closed\n\n    await conn.close()\n\n\nasync def test_async_context_manager(loop) -> None:\n    conn = aiohttp.BaseConnector(loop=loop)\n\n    async with conn as c:\n        assert conn is c\n\n    assert conn.closed\n\n\nasync def test_close(loop) -> None:\n    proto = mock.Mock()\n\n    conn = aiohttp.BaseConnector(loop=loop)\n    assert not conn.closed\n    conn._conns[(\"host\", 8080, False)] = [(proto, object())]\n    await conn.close()\n\n    assert not conn._conns\n    assert proto.close.called\n    assert conn.closed\n\n\nasync def test_get(loop) -> None:\n    conn = aiohttp.BaseConnector(loop=loop)\n    assert conn._get(1) is None\n\n    proto = mock.Mock()\n    conn._conns[1] = [(proto, loop.time())]\n    assert conn._get(1) == proto\n    await conn.close()\n\n\nasync def test_get_unconnected_proto(loop) -> None:\n    conn = aiohttp.BaseConnector()\n    key = ConnectionKey(\"localhost\", 80, False, None, None, None, None)\n    assert conn._get(key) is None\n\n    proto = create_mocked_conn(loop)\n    conn._conns[key] = [(proto, loop.time())]\n    assert conn._get(key) == proto\n\n    assert conn._get(key) is None\n    conn._conns[key] = [(proto, loop.time())]\n    proto.is_connected = lambda *args: False\n    assert conn._get(key) is None\n    await conn.close()\n\n\nasync def test_get_unconnected_proto_ssl(loop) -> None:\n    conn = aiohttp.BaseConnector()\n    key = ConnectionKey(\"localhost\", 80, True, None, None, None, None)\n    assert conn._get(key) is None\n\n    proto = create_mocked_conn(loop)\n    conn._conns[key] = [(proto, loop.time())]\n    assert conn._get(key) == proto\n\n    assert conn._get(key) is None\n    conn._conns[key] = [(proto, loop.time())]\n    proto.is_connected = lambda *args: False\n    assert conn._get(key) is None\n    await conn.close()\n\n\nasync def test_get_expired(loop) -> None:\n    conn = aiohttp.BaseConnector(loop=loop)\n    key = ConnectionKey(\"localhost\", 80, False, None, None, None, None)\n    assert conn._get(key) is None\n\n    proto = mock.Mock()\n    conn._conns[key] = [(proto, loop.time() - 1000)]\n    assert conn._get(key) is None\n    assert not conn._conns\n    await conn.close()\n\n\nasync def test_get_expired_ssl(loop) -> None:\n    conn = aiohttp.BaseConnector(loop=loop, enable_cleanup_closed=True)\n    key = ConnectionKey(\"localhost\", 80, True, None, None, None, None)\n    assert conn._get(key) is None\n\n    proto = mock.Mock()\n    transport = proto.transport\n    conn._conns[key] = [(proto, loop.time() - 1000)]\n    assert conn._get(key) is None\n    assert not conn._conns\n    assert conn._cleanup_closed_transports == [transport]\n    await conn.close()\n\n\nasync def test_release_acquired(loop, key) -> None:\n    proto = mock.Mock()\n    conn = aiohttp.BaseConnector(loop=loop, limit=5)\n    conn._release_waiter = mock.Mock()\n\n    conn._acquired.add(proto)\n    conn._acquired_per_host[key].add(proto)\n    conn._release_acquired(key, proto)\n    assert 0 == len(conn._acquired)\n    assert 0 == len(conn._acquired_per_host)\n    assert conn._release_waiter.called\n\n    conn._release_acquired(key, proto)\n    assert 0 == len(conn._acquired)\n    assert 0 == len(conn._acquired_per_host)\n\n    await conn.close()\n\n\nasync def test_release_acquired_closed(loop, key) -> None:\n    proto = mock.Mock()\n    conn = aiohttp.BaseConnector(loop=loop, limit=5)\n    conn._release_waiter = mock.Mock()\n\n    conn._acquired.add(proto)\n    conn._acquired_per_host[key].add(proto)\n    conn._closed = True\n    conn._release_acquired(key, proto)\n    assert 1 == len(conn._acquired)\n    assert 1 == len(conn._acquired_per_host[key])\n    assert not conn._release_waiter.called\n    await conn.close()\n\n\nasync def test_release(loop, key) -> None:\n    conn = aiohttp.BaseConnector(loop=loop)\n    conn._release_waiter = mock.Mock()\n\n    proto = mock.Mock(should_close=False)\n\n    conn._acquired.add(proto)\n    conn._acquired_per_host[key].add(proto)\n\n    conn._release(key, proto)\n    assert conn._release_waiter.called\n    assert conn._cleanup_handle is not None\n    assert conn._conns[key][0][0] == proto\n    assert conn._conns[key][0][1] == pytest.approx(loop.time(), abs=0.1)\n    assert not conn._cleanup_closed_transports\n    await conn.close()\n\n\nasync def test_release_ssl_transport(loop, ssl_key) -> None:\n    conn = aiohttp.BaseConnector(loop=loop, enable_cleanup_closed=True)\n    conn._release_waiter = mock.Mock()\n\n    proto = mock.Mock()\n    transport = proto.transport\n    conn._acquired.add(proto)\n    conn._acquired_per_host[ssl_key].add(proto)\n\n    conn._release(ssl_key, proto, should_close=True)\n    assert conn._cleanup_closed_transports == [transport]\n    await conn.close()\n\n\nasync def test_release_already_closed(loop) -> None:\n    conn = aiohttp.BaseConnector(loop=loop)\n\n    proto = mock.Mock()\n    key = 1\n    conn._acquired.add(proto)\n    await conn.close()\n\n    conn._release_waiters = mock.Mock()\n    conn._release_acquired = mock.Mock()\n\n    conn._release(key, proto)\n    assert not conn._release_waiters.called\n    assert not conn._release_acquired.called\n\n\nasync def test_release_waiter_no_limit(loop, key, key2) -> None:\n    # limit is 0\n    conn = aiohttp.BaseConnector(limit=0, loop=loop)\n    w = mock.Mock()\n    w.done.return_value = False\n    conn._waiters[key].append(w)\n    conn._release_waiter()\n    assert len(conn._waiters[key]) == 0\n    assert w.done.called\n    await conn.close()\n\n\nasync def test_release_waiter_first_available(loop, key, key2) -> None:\n    conn = aiohttp.BaseConnector(loop=loop)\n    w1, w2 = mock.Mock(), mock.Mock()\n    w1.done.return_value = False\n    w2.done.return_value = False\n    conn._waiters[key].append(w2)\n    conn._waiters[key2].append(w1)\n    conn._release_waiter()\n    assert (\n        w1.set_result.called\n        and not w2.set_result.called\n        or not w1.set_result.called\n        and w2.set_result.called\n    )\n    await conn.close()\n\n\nasync def test_release_waiter_release_first(loop, key, key2) -> None:\n    conn = aiohttp.BaseConnector(loop=loop, limit=1)\n    w1, w2 = mock.Mock(), mock.Mock()\n    w1.done.return_value = False\n    w2.done.return_value = False\n    conn._waiters[key] = deque([w1, w2])\n    conn._release_waiter()\n    assert w1.set_result.called\n    assert not w2.set_result.called\n    await conn.close()\n\n\nasync def test_release_waiter_skip_done_waiter(loop, key, key2) -> None:\n    conn = aiohttp.BaseConnector(loop=loop, limit=1)\n    w1, w2 = mock.Mock(), mock.Mock()\n    w1.done.return_value = True\n    w2.done.return_value = False\n    conn._waiters[key] = deque([w1, w2])\n    conn._release_waiter()\n    assert not w1.set_result.called\n    assert w2.set_result.called\n    await conn.close()\n\n\nasync def test_release_waiter_per_host(loop, key, key2) -> None:\n    # no limit\n    conn = aiohttp.BaseConnector(loop=loop, limit=0, limit_per_host=2)\n    w1, w2 = mock.Mock(), mock.Mock()\n    w1.done.return_value = False\n    w2.done.return_value = False\n    conn._waiters[key] = deque([w1])\n    conn._waiters[key2] = deque([w2])\n    conn._release_waiter()\n    assert (w1.set_result.called and not w2.set_result.called) or (\n        not w1.set_result.called and w2.set_result.called\n    )\n    await conn.close()\n\n\nasync def test_release_waiter_no_available(loop, key, key2) -> None:\n    # limit is 0\n    conn = aiohttp.BaseConnector(limit=0, loop=loop)\n    w = mock.Mock()\n    w.done.return_value = False\n    conn._waiters[key].append(w)\n    conn._available_connections = mock.Mock(return_value=0)\n    conn._release_waiter()\n    assert len(conn._waiters) == 1\n    assert not w.done.called\n    await conn.close()\n\n\nasync def test_release_close(loop, key) -> None:\n    conn = aiohttp.BaseConnector(loop=loop)\n    proto = mock.Mock(should_close=True)\n\n    conn._acquired.add(proto)\n    conn._release(key, proto)\n    assert not conn._conns\n    assert proto.close.called\n\n\nasync def test__drop_acquire_per_host1(loop) -> None:\n    conn = aiohttp.BaseConnector(loop=loop)\n    conn._drop_acquired_per_host(123, 456)\n    assert len(conn._acquired_per_host) == 0\n\n\nasync def test__drop_acquire_per_host2(loop) -> None:\n    conn = aiohttp.BaseConnector(loop=loop)\n    conn._acquired_per_host[123].add(456)\n    conn._drop_acquired_per_host(123, 456)\n    assert len(conn._acquired_per_host) == 0\n\n\nasync def test__drop_acquire_per_host3(loop) -> None:\n    conn = aiohttp.BaseConnector(loop=loop)\n    conn._acquired_per_host[123].add(456)\n    conn._acquired_per_host[123].add(789)\n    conn._drop_acquired_per_host(123, 456)\n    assert len(conn._acquired_per_host) == 1\n    assert conn._acquired_per_host[123] == {789}\n\n\nasync def test_tcp_connector_certificate_error(\n    loop: Any, start_connection: mock.AsyncMock\n) -> None:\n    req = ClientRequest(\"GET\", URL(\"https://127.0.0.1:443\"), loop=loop)\n\n    async def certificate_error(*args, **kwargs):\n        raise ssl.CertificateError\n\n    conn = aiohttp.TCPConnector(loop=loop)\n    conn._loop.create_connection = certificate_error\n\n    with pytest.raises(aiohttp.ClientConnectorCertificateError) as ctx:\n        await conn.connect(req, [], ClientTimeout())\n\n    assert isinstance(ctx.value, ssl.CertificateError)\n    assert isinstance(ctx.value.certificate_error, ssl.CertificateError)\n    assert isinstance(ctx.value, aiohttp.ClientSSLError)\n\n\nasync def test_tcp_connector_server_hostname_default(\n    loop: Any, start_connection: mock.AsyncMock\n) -> None:\n    conn = aiohttp.TCPConnector()\n\n    with mock.patch.object(\n        conn._loop, \"create_connection\", autospec=True, spec_set=True\n    ) as create_connection:\n        create_connection.return_value = mock.Mock(), mock.Mock()\n\n        req = ClientRequest(\"GET\", URL(\"https://127.0.0.1:443\"), loop=loop)\n\n        with closing(await conn.connect(req, [], ClientTimeout())):\n            assert create_connection.call_args.kwargs[\"server_hostname\"] == \"127.0.0.1\"\n\n\nasync def test_tcp_connector_server_hostname_override(\n    loop: Any, start_connection: mock.AsyncMock\n) -> None:\n    conn = aiohttp.TCPConnector()\n\n    with mock.patch.object(\n        conn._loop, \"create_connection\", autospec=True, spec_set=True\n    ) as create_connection:\n        create_connection.return_value = mock.Mock(), mock.Mock()\n\n        req = ClientRequest(\n            \"GET\", URL(\"https://127.0.0.1:443\"), loop=loop, server_hostname=\"localhost\"\n        )\n\n        with closing(await conn.connect(req, [], ClientTimeout())):\n            assert create_connection.call_args.kwargs[\"server_hostname\"] == \"localhost\"\n\n\nasync def test_tcp_connector_multiple_hosts_errors(loop) -> None:\n    conn = aiohttp.TCPConnector(loop=loop)\n\n    ip1 = \"192.168.1.1\"\n    ip2 = \"192.168.1.2\"\n    ip3 = \"192.168.1.3\"\n    ip4 = \"192.168.1.4\"\n    ip5 = \"192.168.1.5\"\n    ips = [ip1, ip2, ip3, ip4, ip5]\n    addrs_tried = []\n    ips_tried = []\n\n    fingerprint = hashlib.sha256(b\"foo\").digest()\n\n    req = ClientRequest(\n        \"GET\",\n        URL(\"https://mocked.host\"),\n        ssl=aiohttp.Fingerprint(fingerprint),\n        loop=loop,\n    )\n\n    async def _resolve_host(host, port, traces=None):\n        return [\n            {\n                \"hostname\": host,\n                \"host\": ip,\n                \"port\": port,\n                \"family\": socket.AF_INET,\n                \"proto\": 0,\n                \"flags\": socket.AI_NUMERICHOST,\n            }\n            for ip in ips\n        ]\n\n    conn._resolve_host = _resolve_host\n\n    os_error = certificate_error = ssl_error = fingerprint_error = False\n    connected = False\n\n    async def start_connection(*args, **kwargs):\n        addr_infos: List[AddrInfoType] = kwargs[\"addr_infos\"]\n\n        first_addr_info = addr_infos[0]\n        first_addr_info_addr = first_addr_info[-1]\n        addrs_tried.append(first_addr_info_addr)\n\n        mock_socket = mock.create_autospec(socket.socket, spec_set=True, instance=True)\n        mock_socket.getpeername.return_value = first_addr_info_addr\n        return mock_socket\n\n    async def create_connection(*args, **kwargs):\n        nonlocal os_error, certificate_error, ssl_error, fingerprint_error\n        nonlocal connected\n\n        sock = kwargs[\"sock\"]\n        addr_info = sock.getpeername()\n        ip = addr_info[0]\n\n        ips_tried.append(ip)\n\n        if ip == ip1:\n            os_error = True\n            raise OSError\n\n        if ip == ip2:\n            certificate_error = True\n            raise ssl.CertificateError\n\n        if ip == ip3:\n            ssl_error = True\n            raise ssl.SSLError\n\n        if ip == ip4:\n            sock: socket.socket = kwargs[\"sock\"]\n\n            # Close the socket since we are not actually connecting\n            # and we don't want to leak it.\n            sock.close()\n\n            fingerprint_error = True\n            tr, pr = mock.Mock(), mock.Mock()\n\n            def get_extra_info(param):\n                if param == \"sslcontext\":\n                    return True\n\n                if param == \"ssl_object\":\n                    s = mock.Mock()\n                    s.getpeercert.return_value = b\"not foo\"\n                    return s\n\n                if param == \"peername\":\n                    return (\"192.168.1.5\", 12345)\n\n                if param == \"socket\":\n                    return sock\n\n                assert False, param\n\n            tr.get_extra_info = get_extra_info\n            return tr, pr\n\n        if ip == ip5:\n            sock: socket.socket = kwargs[\"sock\"]\n\n            # Close the socket since we are not actually connecting\n            # and we don't want to leak it.\n            sock.close()\n\n            connected = True\n            tr, pr = mock.Mock(), mock.Mock()\n\n            def get_extra_info(param):\n                if param == \"sslcontext\":\n                    return True\n\n                if param == \"ssl_object\":\n                    s = mock.Mock()\n                    s.getpeercert.return_value = b\"foo\"\n                    return s\n\n                assert False\n\n            tr.get_extra_info = get_extra_info\n            return tr, pr\n\n        assert False\n\n    conn._loop.create_connection = create_connection\n\n    with mock.patch(\n        \"aiohttp.connector.aiohappyeyeballs.start_connection\", start_connection\n    ):\n        established_connection = await conn.connect(req, [], ClientTimeout())\n\n    assert ips_tried == ips\n    assert addrs_tried == [(ip, 443) for ip in ips]\n\n    assert os_error\n    assert certificate_error\n    assert ssl_error\n    assert fingerprint_error\n    assert connected\n\n    established_connection.close()\n\n\n@pytest.mark.parametrize(\n    (\"happy_eyeballs_delay\"),\n    [0.1, 0.25, None],\n)\nasync def test_tcp_connector_happy_eyeballs(\n    loop: Any, happy_eyeballs_delay: Optional[float]\n) -> None:\n    conn = aiohttp.TCPConnector(happy_eyeballs_delay=happy_eyeballs_delay)\n\n    ip1 = \"dead::beef::\"\n    ip2 = \"192.168.1.1\"\n    ips = [ip1, ip2]\n    addrs_tried = []\n\n    req = ClientRequest(\n        \"GET\",\n        URL(\"https://mocked.host\"),\n        loop=loop,\n    )\n\n    async def _resolve_host(host, port, traces=None):\n        return [\n            {\n                \"hostname\": host,\n                \"host\": ip,\n                \"port\": port,\n                \"family\": socket.AF_INET6 if \":\" in ip else socket.AF_INET,\n                \"proto\": 0,\n                \"flags\": socket.AI_NUMERICHOST,\n            }\n            for ip in ips\n        ]\n\n    conn._resolve_host = _resolve_host\n\n    os_error = False\n    connected = False\n\n    async def sock_connect(*args, **kwargs):\n        addr = args[1]\n        nonlocal os_error\n\n        addrs_tried.append(addr)\n\n        if addr[0] == ip1:\n            os_error = True\n            raise OSError\n\n    async def create_connection(*args, **kwargs):\n        sock: socket.socket = kwargs[\"sock\"]\n\n        # Close the socket since we are not actually connecting\n        # and we don't want to leak it.\n        sock.close()\n\n        nonlocal connected\n        connected = True\n        tr = create_mocked_conn(loop)\n        pr = create_mocked_conn(loop)\n        return tr, pr\n\n    conn._loop.sock_connect = sock_connect\n    conn._loop.create_connection = create_connection\n\n    established_connection = await conn.connect(req, [], ClientTimeout())\n\n    assert addrs_tried == [(ip1, 443, 0, 0), (ip2, 443)]\n\n    assert os_error\n    assert connected\n\n    established_connection.close()\n\n\nasync def test_tcp_connector_interleave(loop: Any) -> None:\n    conn = aiohttp.TCPConnector(interleave=2)\n\n    ip1 = \"192.168.1.1\"\n    ip2 = \"192.168.1.2\"\n    ip3 = \"dead::beef::\"\n    ip4 = \"aaaa::beef::\"\n    ip5 = \"192.168.1.5\"\n    ips = [ip1, ip2, ip3, ip4, ip5]\n    success_ips = []\n    interleave = None\n\n    req = ClientRequest(\n        \"GET\",\n        URL(\"https://mocked.host\"),\n        loop=loop,\n    )\n\n    async def _resolve_host(host, port, traces=None):\n        return [\n            {\n                \"hostname\": host,\n                \"host\": ip,\n                \"port\": port,\n                \"family\": socket.AF_INET6 if \":\" in ip else socket.AF_INET,\n                \"proto\": 0,\n                \"flags\": socket.AI_NUMERICHOST,\n            }\n            for ip in ips\n        ]\n\n    conn._resolve_host = _resolve_host\n\n    async def start_connection(*args, **kwargs):\n        nonlocal interleave\n        addr_infos: List[AddrInfoType] = kwargs[\"addr_infos\"]\n        interleave = kwargs[\"interleave\"]\n        # Mock the 4th host connecting successfully\n        fourth_addr_info = addr_infos[3]\n        fourth_addr_info_addr = fourth_addr_info[-1]\n        mock_socket = mock.create_autospec(socket.socket, spec_set=True, instance=True)\n        mock_socket.getpeername.return_value = fourth_addr_info_addr\n        return mock_socket\n\n    async def create_connection(*args, **kwargs):\n        sock = kwargs[\"sock\"]\n        addr_info = sock.getpeername()\n        ip = addr_info[0]\n\n        success_ips.append(ip)\n\n        sock: socket.socket = kwargs[\"sock\"]\n        # Close the socket since we are not actually connecting\n        # and we don't want to leak it.\n        sock.close()\n        tr = create_mocked_conn(loop)\n        pr = create_mocked_conn(loop)\n        return tr, pr\n\n    conn._loop.create_connection = create_connection\n\n    with mock.patch(\n        \"aiohttp.connector.aiohappyeyeballs.start_connection\", start_connection\n    ):\n        established_connection = await conn.connect(req, [], ClientTimeout())\n\n    assert success_ips == [ip4]\n    assert interleave == 2\n    established_connection.close()\n\n\nasync def test_tcp_connector_family_is_respected(loop: Any) -> None:\n    conn = aiohttp.TCPConnector(family=socket.AF_INET)\n\n    ip1 = \"dead::beef::\"\n    ip2 = \"192.168.1.1\"\n    ips = [ip1, ip2]\n    addrs_tried = []\n\n    req = ClientRequest(\n        \"GET\",\n        URL(\"https://mocked.host\"),\n        loop=loop,\n    )\n\n    async def _resolve_host(host, port, traces=None):\n        return [\n            {\n                \"hostname\": host,\n                \"host\": ip,\n                \"port\": port,\n                \"family\": socket.AF_INET6 if \":\" in ip else socket.AF_INET,\n                \"proto\": 0,\n                \"flags\": socket.AI_NUMERICHOST,\n            }\n            for ip in ips\n        ]\n\n    conn._resolve_host = _resolve_host\n    connected = False\n\n    async def sock_connect(*args, **kwargs):\n        addr = args[1]\n        addrs_tried.append(addr)\n\n    async def create_connection(*args, **kwargs):\n        sock: socket.socket = kwargs[\"sock\"]\n\n        # Close the socket since we are not actually connecting\n        # and we don't want to leak it.\n        sock.close()\n\n        nonlocal connected\n        connected = True\n        tr = create_mocked_conn(loop)\n        pr = create_mocked_conn(loop)\n        return tr, pr\n\n    conn._loop.sock_connect = sock_connect\n    conn._loop.create_connection = create_connection\n\n    established_connection = await conn.connect(req, [], ClientTimeout())\n\n    # We should only try the IPv4 address since we specified\n    # the family to be AF_INET\n    assert addrs_tried == [(ip2, 443)]\n\n    assert connected\n\n    established_connection.close()\n\n\nasync def test_tcp_connector_resolve_host(loop: Any) -> None:\n    conn = aiohttp.TCPConnector(use_dns_cache=True)\n\n    res = await conn._resolve_host(\"localhost\", 8080)\n    assert res\n    for rec in res:\n        if rec[\"family\"] == socket.AF_INET:\n            assert rec[\"host\"] == \"127.0.0.1\"\n            assert rec[\"hostname\"] == \"localhost\"\n            assert rec[\"port\"] == 8080\n        elif rec[\"family\"] == socket.AF_INET6:\n            assert rec[\"hostname\"] == \"localhost\"\n            assert rec[\"port\"] == 8080\n            if platform.system() == \"Darwin\":\n                assert rec[\"host\"] in (\"::1\", \"fe80::1\", \"fe80::1%lo0\")\n            else:\n                assert rec[\"host\"] == \"::1\"\n\n\n@pytest.fixture\ndef dns_response(loop):\n    async def coro():\n        # simulates a network operation\n        await asyncio.sleep(0)\n        return [\"127.0.0.1\"]\n\n    return coro\n\n\nasync def test_tcp_connector_dns_cache_not_expired(loop, dns_response) -> None:\n    with mock.patch(\"aiohttp.connector.DefaultResolver\") as m_resolver:\n        conn = aiohttp.TCPConnector(loop=loop, use_dns_cache=True, ttl_dns_cache=10)\n        m_resolver().resolve.return_value = dns_response()\n        await conn._resolve_host(\"localhost\", 8080)\n        await conn._resolve_host(\"localhost\", 8080)\n        m_resolver().resolve.assert_called_once_with(\"localhost\", 8080, family=0)\n\n\nasync def test_tcp_connector_dns_cache_forever(loop, dns_response) -> None:\n    with mock.patch(\"aiohttp.connector.DefaultResolver\") as m_resolver:\n        conn = aiohttp.TCPConnector(loop=loop, use_dns_cache=True, ttl_dns_cache=10)\n        m_resolver().resolve.return_value = dns_response()\n        await conn._resolve_host(\"localhost\", 8080)\n        await conn._resolve_host(\"localhost\", 8080)\n        m_resolver().resolve.assert_called_once_with(\"localhost\", 8080, family=0)\n\n\nasync def test_tcp_connector_use_dns_cache_disabled(loop, dns_response) -> None:\n    with mock.patch(\"aiohttp.connector.DefaultResolver\") as m_resolver:\n        conn = aiohttp.TCPConnector(loop=loop, use_dns_cache=False)\n        m_resolver().resolve.side_effect = [dns_response(), dns_response()]\n        await conn._resolve_host(\"localhost\", 8080)\n        await conn._resolve_host(\"localhost\", 8080)\n        m_resolver().resolve.assert_has_calls(\n            [\n                mock.call(\"localhost\", 8080, family=0),\n                mock.call(\"localhost\", 8080, family=0),\n            ]\n        )\n\n\nasync def test_tcp_connector_dns_throttle_requests(loop, dns_response) -> None:\n    with mock.patch(\"aiohttp.connector.DefaultResolver\") as m_resolver:\n        conn = aiohttp.TCPConnector(loop=loop, use_dns_cache=True, ttl_dns_cache=10)\n        m_resolver().resolve.return_value = dns_response()\n        loop.create_task(conn._resolve_host(\"localhost\", 8080))\n        loop.create_task(conn._resolve_host(\"localhost\", 8080))\n        await asyncio.sleep(0)\n        await asyncio.sleep(0)\n        m_resolver().resolve.assert_called_once_with(\"localhost\", 8080, family=0)\n\n\nasync def test_tcp_connector_dns_throttle_requests_exception_spread(loop) -> None:\n    with mock.patch(\"aiohttp.connector.DefaultResolver\") as m_resolver:\n        conn = aiohttp.TCPConnector(loop=loop, use_dns_cache=True, ttl_dns_cache=10)\n        e = Exception()\n        m_resolver().resolve.side_effect = e\n        r1 = loop.create_task(conn._resolve_host(\"localhost\", 8080))\n        r2 = loop.create_task(conn._resolve_host(\"localhost\", 8080))\n        await asyncio.sleep(0)\n        await asyncio.sleep(0)\n        await asyncio.sleep(0)\n        await asyncio.sleep(0)\n        assert r1.exception() == e\n        assert r2.exception() == e\n\n\nasync def test_tcp_connector_dns_throttle_requests_cancelled_when_close(\n    loop, dns_response\n):\n\n    with mock.patch(\"aiohttp.connector.DefaultResolver\") as m_resolver:\n        conn = aiohttp.TCPConnector(loop=loop, use_dns_cache=True, ttl_dns_cache=10)\n        m_resolver().resolve.return_value = dns_response()\n        loop.create_task(conn._resolve_host(\"localhost\", 8080))\n        f = loop.create_task(conn._resolve_host(\"localhost\", 8080))\n\n        await asyncio.sleep(0)\n        await asyncio.sleep(0)\n        await conn.close()\n\n        with pytest.raises(asyncio.CancelledError):\n            await f\n\n\n@pytest.fixture\ndef dns_response_error(loop):\n    async def coro():\n        # simulates a network operation\n        await asyncio.sleep(0)\n        raise socket.gaierror(-3, \"Temporary failure in name resolution\")\n\n    return coro\n\n\nasync def test_tcp_connector_cancel_dns_error_captured(\n    loop, dns_response_error\n) -> None:\n\n    exception_handler_called = False\n\n    def exception_handler(loop, context):\n        nonlocal exception_handler_called\n        exception_handler_called = True\n\n    loop.set_exception_handler(mock.Mock(side_effect=exception_handler))\n\n    with mock.patch(\"aiohttp.connector.DefaultResolver\") as m_resolver:\n        req = ClientRequest(\n            method=\"GET\", url=URL(\"http://temporary-failure:80\"), loop=loop\n        )\n        conn = aiohttp.TCPConnector(\n            use_dns_cache=False,\n        )\n        m_resolver().resolve.return_value = dns_response_error()\n        f = loop.create_task(conn._create_direct_connection(req, [], ClientTimeout(0)))\n\n        await asyncio.sleep(0)\n        f.cancel()\n        with pytest.raises(asyncio.CancelledError):\n            await f\n\n        gc.collect()\n        assert exception_handler_called is False\n\n\nasync def test_tcp_connector_dns_tracing(loop, dns_response) -> None:\n    session = mock.Mock()\n    trace_config_ctx = mock.Mock()\n    on_dns_resolvehost_start = mock.Mock(side_effect=make_mocked_coro(mock.Mock()))\n    on_dns_resolvehost_end = mock.Mock(side_effect=make_mocked_coro(mock.Mock()))\n    on_dns_cache_hit = mock.Mock(side_effect=make_mocked_coro(mock.Mock()))\n    on_dns_cache_miss = mock.Mock(side_effect=make_mocked_coro(mock.Mock()))\n\n    trace_config = aiohttp.TraceConfig(\n        trace_config_ctx_factory=mock.Mock(return_value=trace_config_ctx)\n    )\n    trace_config.on_dns_resolvehost_start.append(on_dns_resolvehost_start)\n    trace_config.on_dns_resolvehost_end.append(on_dns_resolvehost_end)\n    trace_config.on_dns_cache_hit.append(on_dns_cache_hit)\n    trace_config.on_dns_cache_miss.append(on_dns_cache_miss)\n    trace_config.freeze()\n    traces = [Trace(session, trace_config, trace_config.trace_config_ctx())]\n\n    with mock.patch(\"aiohttp.connector.DefaultResolver\") as m_resolver:\n        conn = aiohttp.TCPConnector(loop=loop, use_dns_cache=True, ttl_dns_cache=10)\n\n        m_resolver().resolve.return_value = dns_response()\n\n        await conn._resolve_host(\"localhost\", 8080, traces=traces)\n        on_dns_resolvehost_start.assert_called_once_with(\n            session,\n            trace_config_ctx,\n            aiohttp.TraceDnsResolveHostStartParams(\"localhost\"),\n        )\n        on_dns_resolvehost_end.assert_called_once_with(\n            session, trace_config_ctx, aiohttp.TraceDnsResolveHostEndParams(\"localhost\")\n        )\n        on_dns_cache_miss.assert_called_once_with(\n            session, trace_config_ctx, aiohttp.TraceDnsCacheMissParams(\"localhost\")\n        )\n        assert not on_dns_cache_hit.called\n\n        await conn._resolve_host(\"localhost\", 8080, traces=traces)\n        on_dns_cache_hit.assert_called_once_with(\n            session, trace_config_ctx, aiohttp.TraceDnsCacheHitParams(\"localhost\")\n        )\n\n\nasync def test_tcp_connector_dns_tracing_cache_disabled(loop, dns_response) -> None:\n    session = mock.Mock()\n    trace_config_ctx = mock.Mock()\n    on_dns_resolvehost_start = mock.Mock(side_effect=make_mocked_coro(mock.Mock()))\n    on_dns_resolvehost_end = mock.Mock(side_effect=make_mocked_coro(mock.Mock()))\n\n    trace_config = aiohttp.TraceConfig(\n        trace_config_ctx_factory=mock.Mock(return_value=trace_config_ctx)\n    )\n    trace_config.on_dns_resolvehost_start.append(on_dns_resolvehost_start)\n    trace_config.on_dns_resolvehost_end.append(on_dns_resolvehost_end)\n    trace_config.freeze()\n    traces = [Trace(session, trace_config, trace_config.trace_config_ctx())]\n\n    with mock.patch(\"aiohttp.connector.DefaultResolver\") as m_resolver:\n        conn = aiohttp.TCPConnector(loop=loop, use_dns_cache=False)\n\n        m_resolver().resolve.side_effect = [dns_response(), dns_response()]\n\n        await conn._resolve_host(\"localhost\", 8080, traces=traces)\n\n        await conn._resolve_host(\"localhost\", 8080, traces=traces)\n\n        on_dns_resolvehost_start.assert_has_calls(\n            [\n                mock.call(\n                    session,\n                    trace_config_ctx,\n                    aiohttp.TraceDnsResolveHostStartParams(\"localhost\"),\n                ),\n                mock.call(\n                    session,\n                    trace_config_ctx,\n                    aiohttp.TraceDnsResolveHostStartParams(\"localhost\"),\n                ),\n            ]\n        )\n        on_dns_resolvehost_end.assert_has_calls(\n            [\n                mock.call(\n                    session,\n                    trace_config_ctx,\n                    aiohttp.TraceDnsResolveHostEndParams(\"localhost\"),\n                ),\n                mock.call(\n                    session,\n                    trace_config_ctx,\n                    aiohttp.TraceDnsResolveHostEndParams(\"localhost\"),\n                ),\n            ]\n        )\n\n\nasync def test_tcp_connector_dns_tracing_throttle_requests(loop, dns_response) -> None:\n    session = mock.Mock()\n    trace_config_ctx = mock.Mock()\n    on_dns_cache_hit = mock.Mock(side_effect=make_mocked_coro(mock.Mock()))\n    on_dns_cache_miss = mock.Mock(side_effect=make_mocked_coro(mock.Mock()))\n\n    trace_config = aiohttp.TraceConfig(\n        trace_config_ctx_factory=mock.Mock(return_value=trace_config_ctx)\n    )\n    trace_config.on_dns_cache_hit.append(on_dns_cache_hit)\n    trace_config.on_dns_cache_miss.append(on_dns_cache_miss)\n    trace_config.freeze()\n    traces = [Trace(session, trace_config, trace_config.trace_config_ctx())]\n\n    with mock.patch(\"aiohttp.connector.DefaultResolver\") as m_resolver:\n        conn = aiohttp.TCPConnector(loop=loop, use_dns_cache=True, ttl_dns_cache=10)\n        m_resolver().resolve.return_value = dns_response()\n        loop.create_task(conn._resolve_host(\"localhost\", 8080, traces=traces))\n        loop.create_task(conn._resolve_host(\"localhost\", 8080, traces=traces))\n        await asyncio.sleep(0)\n        await asyncio.sleep(0)\n        on_dns_cache_hit.assert_called_once_with(\n            session, trace_config_ctx, aiohttp.TraceDnsCacheHitParams(\"localhost\")\n        )\n        on_dns_cache_miss.assert_called_once_with(\n            session, trace_config_ctx, aiohttp.TraceDnsCacheMissParams(\"localhost\")\n        )\n\n\nasync def test_dns_error(loop) -> None:\n    connector = aiohttp.TCPConnector(loop=loop)\n    connector._resolve_host = make_mocked_coro(\n        raise_exception=OSError(\"dont take it serious\")\n    )\n\n    req = ClientRequest(\"GET\", URL(\"http://www.python.org\"), loop=loop)\n\n    with pytest.raises(aiohttp.ClientConnectorError):\n        await connector.connect(req, [], ClientTimeout())\n\n\nasync def test_get_pop_empty_conns(loop) -> None:\n    # see issue #473\n    conn = aiohttp.BaseConnector(loop=loop)\n    key = (\"127.0.0.1\", 80, False)\n    conn._conns[key] = []\n    proto = conn._get(key)\n    assert proto is None\n    assert not conn._conns\n\n\nasync def test_release_close_do_not_add_to_pool(loop, key) -> None:\n    # see issue #473\n    conn = aiohttp.BaseConnector(loop=loop)\n\n    proto = mock.Mock(should_close=True)\n\n    conn._acquired.add(proto)\n    conn._release(key, proto)\n    assert not conn._conns\n\n\nasync def test_release_close_do_not_delete_existing_connections(key) -> None:\n    proto1 = mock.Mock()\n\n    conn = aiohttp.BaseConnector()\n    conn._conns[key] = [(proto1, 1)]\n\n    proto = mock.Mock(should_close=True)\n    conn._acquired.add(proto)\n    conn._release(key, proto)\n    assert conn._conns[key] == [(proto1, 1)]\n    assert proto.close.called\n    await conn.close()\n\n\nasync def test_release_not_started(loop) -> None:\n    conn = aiohttp.BaseConnector(loop=loop)\n    proto = mock.Mock(should_close=False)\n    key = 1\n    conn._acquired.add(proto)\n    conn._release(key, proto)\n    # assert conn._conns == {1: [(proto, 10)]}\n    rec = conn._conns[1]\n    assert rec[0][0] == proto\n    assert rec[0][1] == pytest.approx(loop.time(), abs=0.05)\n    assert not proto.close.called\n    await conn.close()\n\n\nasync def test_release_not_opened(loop, key) -> None:\n    conn = aiohttp.BaseConnector(loop=loop)\n\n    proto = mock.Mock()\n    conn._acquired.add(proto)\n    conn._release(key, proto)\n    assert proto.close.called\n\n\nasync def test_connect(loop, key) -> None:\n    proto = mock.Mock()\n    proto.is_connected.return_value = True\n\n    req = ClientRequest(\"GET\", URL(\"http://localhost:80\"), loop=loop)\n\n    conn = aiohttp.BaseConnector(loop=loop)\n    conn._conns[key] = [(proto, loop.time())]\n    conn._create_connection = mock.Mock()\n    conn._create_connection.return_value = loop.create_future()\n    conn._create_connection.return_value.set_result(proto)\n\n    connection = await conn.connect(req, [], ClientTimeout())\n    assert not conn._create_connection.called\n    assert connection._protocol is proto\n    assert connection.transport is proto.transport\n    assert isinstance(connection, Connection)\n    connection.close()\n\n\nasync def test_connect_tracing(loop) -> None:\n    session = mock.Mock()\n    trace_config_ctx = mock.Mock()\n    on_connection_create_start = mock.Mock(side_effect=make_mocked_coro(mock.Mock()))\n    on_connection_create_end = mock.Mock(side_effect=make_mocked_coro(mock.Mock()))\n\n    trace_config = aiohttp.TraceConfig(\n        trace_config_ctx_factory=mock.Mock(return_value=trace_config_ctx)\n    )\n    trace_config.on_connection_create_start.append(on_connection_create_start)\n    trace_config.on_connection_create_end.append(on_connection_create_end)\n    trace_config.freeze()\n    traces = [Trace(session, trace_config, trace_config.trace_config_ctx())]\n\n    proto = mock.Mock()\n    proto.is_connected.return_value = True\n\n    req = ClientRequest(\"GET\", URL(\"http://host:80\"), loop=loop)\n\n    conn = aiohttp.BaseConnector(loop=loop)\n    conn._create_connection = mock.Mock()\n    conn._create_connection.return_value = loop.create_future()\n    conn._create_connection.return_value.set_result(proto)\n\n    conn2 = await conn.connect(req, traces, ClientTimeout())\n    conn2.release()\n\n    on_connection_create_start.assert_called_with(\n        session, trace_config_ctx, aiohttp.TraceConnectionCreateStartParams()\n    )\n    on_connection_create_end.assert_called_with(\n        session, trace_config_ctx, aiohttp.TraceConnectionCreateEndParams()\n    )\n\n\nasync def test_close_during_connect(loop) -> None:\n    proto = mock.Mock()\n    proto.is_connected.return_value = True\n\n    fut = loop.create_future()\n    req = ClientRequest(\"GET\", URL(\"http://host:80\"), loop=loop)\n\n    conn = aiohttp.BaseConnector(loop=loop)\n    conn._create_connection = mock.Mock()\n    conn._create_connection.return_value = fut\n\n    task = loop.create_task(conn.connect(req, None, ClientTimeout()))\n    await asyncio.sleep(0)\n    await conn.close()\n\n    fut.set_result(proto)\n    with pytest.raises(aiohttp.ClientConnectionError):\n        await task\n\n    assert proto.close.called\n\n\nasync def test_ctor_cleanup() -> None:\n    loop = mock.Mock()\n    loop.time.return_value = 1.5\n    conn = aiohttp.BaseConnector(\n        loop=loop, keepalive_timeout=10, enable_cleanup_closed=True\n    )\n    assert conn._cleanup_handle is None\n    assert conn._cleanup_closed_handle is not None\n\n\nasync def test_cleanup(key) -> None:\n    testset = {\n        key: [(mock.Mock(), 10), (mock.Mock(), 300)],\n    }\n    testset[key][0][0].is_connected.return_value = True\n    testset[key][1][0].is_connected.return_value = False\n\n    loop = mock.Mock()\n    loop.time.return_value = 300\n    conn = aiohttp.BaseConnector(loop=loop)\n    conn._conns = testset\n    existing_handle = conn._cleanup_handle = mock.Mock()\n\n    conn._cleanup()\n    assert existing_handle.cancel.called\n    assert conn._conns == {}\n    assert conn._cleanup_handle is None\n\n\nasync def test_cleanup_close_ssl_transport(ssl_key) -> None:\n    proto = mock.Mock()\n    transport = proto.transport\n    testset = {ssl_key: [(proto, 10)]}\n\n    loop = mock.Mock()\n    loop.time.return_value = 300\n    conn = aiohttp.BaseConnector(loop=loop, enable_cleanup_closed=True)\n    conn._conns = testset\n    existing_handle = conn._cleanup_handle = mock.Mock()\n\n    conn._cleanup()\n    assert existing_handle.cancel.called\n    assert conn._conns == {}\n    assert conn._cleanup_closed_transports == [transport]\n\n\nasync def test_cleanup2() -> None:\n    testset = {1: [(mock.Mock(), 300)]}\n    testset[1][0][0].is_connected.return_value = True\n\n    loop = mock.Mock()\n    loop.time.return_value = 300\n\n    conn = aiohttp.BaseConnector(loop=loop, keepalive_timeout=10)\n    conn._conns = testset\n    conn._cleanup()\n    assert conn._conns == testset\n\n    assert conn._cleanup_handle is not None\n    loop.call_at.assert_called_with(310, mock.ANY, mock.ANY)\n    await conn.close()\n\n\nasync def test_cleanup3(key) -> None:\n    testset = {key: [(mock.Mock(), 290.1), (mock.Mock(), 305.1)]}\n    testset[key][0][0].is_connected.return_value = True\n\n    loop = mock.Mock()\n    loop.time.return_value = 308.5\n\n    conn = aiohttp.BaseConnector(loop=loop, keepalive_timeout=10)\n    conn._conns = testset\n\n    conn._cleanup()\n    assert conn._conns == {key: [testset[key][1]]}\n\n    assert conn._cleanup_handle is not None\n    loop.call_at.assert_called_with(319, mock.ANY, mock.ANY)\n    await conn.close()\n\n\nasync def test_cleanup_closed(loop, mocker) -> None:\n    if not hasattr(loop, \"__dict__\"):\n        pytest.skip(\"can not override loop attributes\")\n\n    mocker.spy(loop, \"call_at\")\n    conn = aiohttp.BaseConnector(loop=loop, enable_cleanup_closed=True)\n\n    tr = mock.Mock()\n    conn._cleanup_closed_handle = cleanup_closed_handle = mock.Mock()\n    conn._cleanup_closed_transports = [tr]\n    conn._cleanup_closed()\n    assert tr.abort.called\n    assert not conn._cleanup_closed_transports\n    assert loop.call_at.called\n    assert cleanup_closed_handle.cancel.called\n\n\nasync def test_cleanup_closed_disabled(loop, mocker) -> None:\n    conn = aiohttp.BaseConnector(loop=loop, enable_cleanup_closed=False)\n\n    tr = mock.Mock()\n    conn._cleanup_closed_transports = [tr]\n    conn._cleanup_closed()\n    assert tr.abort.called\n    assert not conn._cleanup_closed_transports\n\n\nasync def test_tcp_connector_ctor() -> None:\n    conn = aiohttp.TCPConnector()\n    assert conn._ssl is True\n\n    assert conn.use_dns_cache\n    assert conn.family == 0\n\n\nasync def test_tcp_connector_allowed_protocols(loop: asyncio.AbstractEventLoop) -> None:\n    conn = aiohttp.TCPConnector()\n    assert conn.allowed_protocol_schema_set == {\"\", \"tcp\", \"http\", \"https\", \"ws\", \"wss\"}\n\n\nasync def test_invalid_ssl_param() -> None:\n    with pytest.raises(TypeError):\n        aiohttp.TCPConnector(ssl=object())  # type: ignore[arg-type]\n\n\nasync def test_tcp_connector_ctor_fingerprint_valid(\n    loop: asyncio.AbstractEventLoop,\n) -> None:\n    valid = aiohttp.Fingerprint(hashlib.sha256(b\"foo\").digest())\n    conn = aiohttp.TCPConnector(ssl=valid, loop=loop)\n    assert conn._ssl is valid\n\n\nasync def test_insecure_fingerprint_md5(loop) -> None:\n    with pytest.raises(ValueError):\n        aiohttp.TCPConnector(\n            ssl=aiohttp.Fingerprint(hashlib.md5(b\"foo\").digest()), loop=loop\n        )\n\n\nasync def test_insecure_fingerprint_sha1(loop) -> None:\n    with pytest.raises(ValueError):\n        aiohttp.TCPConnector(\n            ssl=aiohttp.Fingerprint(hashlib.sha1(b\"foo\").digest()), loop=loop\n        )\n\n\nasync def test_tcp_connector_clear_dns_cache(loop) -> None:\n    conn = aiohttp.TCPConnector(loop=loop)\n    hosts = [\"a\", \"b\"]\n    conn._cached_hosts.add((\"localhost\", 123), hosts)\n    conn._cached_hosts.add((\"localhost\", 124), hosts)\n    conn.clear_dns_cache(\"localhost\", 123)\n    with pytest.raises(KeyError):\n        conn._cached_hosts.next_addrs((\"localhost\", 123))\n\n    assert conn._cached_hosts.next_addrs((\"localhost\", 124)) == hosts\n\n    # Remove removed element is OK\n    conn.clear_dns_cache(\"localhost\", 123)\n    with pytest.raises(KeyError):\n        conn._cached_hosts.next_addrs((\"localhost\", 123))\n\n    conn.clear_dns_cache()\n    with pytest.raises(KeyError):\n        conn._cached_hosts.next_addrs((\"localhost\", 124))\n\n\nasync def test_tcp_connector_clear_dns_cache_bad_args(loop) -> None:\n    conn = aiohttp.TCPConnector(loop=loop)\n    with pytest.raises(ValueError):\n        conn.clear_dns_cache(\"localhost\")\n\n\nasync def test_dont_recreate_ssl_context() -> None:\n    conn = aiohttp.TCPConnector()\n    ctx = await conn._make_or_get_ssl_context(True)\n    assert ctx is await conn._make_or_get_ssl_context(True)\n\n\nasync def test_dont_recreate_ssl_context2() -> None:\n    conn = aiohttp.TCPConnector()\n    ctx = await conn._make_or_get_ssl_context(False)\n    assert ctx is await conn._make_or_get_ssl_context(False)\n\n\nasync def test___get_ssl_context1() -> None:\n    conn = aiohttp.TCPConnector()\n    req = mock.Mock()\n    req.is_ssl.return_value = False\n    assert await conn._get_ssl_context(req) is None\n\n\nasync def test___get_ssl_context2(loop) -> None:\n    ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)\n    conn = aiohttp.TCPConnector(loop=loop)\n    req = mock.Mock()\n    req.is_ssl.return_value = True\n    req.ssl = ctx\n    assert await conn._get_ssl_context(req) is ctx\n\n\nasync def test___get_ssl_context3(loop) -> None:\n    ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)\n    conn = aiohttp.TCPConnector(loop=loop, ssl=ctx)\n    req = mock.Mock()\n    req.is_ssl.return_value = True\n    req.ssl = True\n    assert await conn._get_ssl_context(req) is ctx\n\n\nasync def test___get_ssl_context4(loop) -> None:\n    ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)\n    conn = aiohttp.TCPConnector(loop=loop, ssl=ctx)\n    req = mock.Mock()\n    req.is_ssl.return_value = True\n    req.ssl = False\n    assert await conn._get_ssl_context(req) is await conn._make_or_get_ssl_context(\n        False\n    )\n\n\nasync def test___get_ssl_context5(loop) -> None:\n    ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)\n    conn = aiohttp.TCPConnector(loop=loop, ssl=ctx)\n    req = mock.Mock()\n    req.is_ssl.return_value = True\n    req.ssl = aiohttp.Fingerprint(hashlib.sha256(b\"1\").digest())\n    assert await conn._get_ssl_context(req) is await conn._make_or_get_ssl_context(\n        False\n    )\n\n\nasync def test___get_ssl_context6() -> None:\n    conn = aiohttp.TCPConnector()\n    req = mock.Mock()\n    req.is_ssl.return_value = True\n    req.ssl = True\n    assert await conn._get_ssl_context(req) is await conn._make_or_get_ssl_context(True)\n\n\nasync def test_ssl_context_once() -> None:\n    \"\"\"Test the ssl context is created only once and shared between connectors.\"\"\"\n    conn1 = aiohttp.TCPConnector()\n    conn2 = aiohttp.TCPConnector()\n    conn3 = aiohttp.TCPConnector()\n\n    req = mock.Mock()\n    req.is_ssl.return_value = True\n    req.ssl = True\n    assert await conn1._get_ssl_context(req) is await conn1._make_or_get_ssl_context(\n        True\n    )\n    assert await conn2._get_ssl_context(req) is await conn1._make_or_get_ssl_context(\n        True\n    )\n    assert await conn3._get_ssl_context(req) is await conn1._make_or_get_ssl_context(\n        True\n    )\n    assert conn1._made_ssl_context is conn2._made_ssl_context is conn3._made_ssl_context\n    assert True in conn1._made_ssl_context\n\n\n@pytest.mark.parametrize(\"exception\", [OSError, ssl.SSLError, asyncio.CancelledError])\nasync def test_ssl_context_creation_raises(exception: Type[BaseException]) -> None:\n    \"\"\"Test that we try again if SSLContext creation fails the first time.\"\"\"\n    conn = aiohttp.TCPConnector()\n    conn._made_ssl_context.clear()\n\n    with mock.patch.object(\n        conn, \"_make_ssl_context\", side_effect=exception\n    ), pytest.raises(exception):\n        await conn._make_or_get_ssl_context(True)\n\n    assert isinstance(await conn._make_or_get_ssl_context(True), ssl.SSLContext)\n\n\nasync def test_close_twice(loop) -> None:\n    proto = mock.Mock()\n\n    conn = aiohttp.BaseConnector(loop=loop)\n    conn._conns[1] = [(proto, object())]\n    await conn.close()\n\n    assert not conn._conns\n    assert proto.close.called\n    assert conn.closed\n\n    conn._conns = \"Invalid\"  # fill with garbage\n    await conn.close()\n    assert conn.closed\n\n\nasync def test_close_cancels_cleanup_handle(loop) -> None:\n    conn = aiohttp.BaseConnector(loop=loop)\n    conn._release(1, mock.Mock(should_close=False))\n    assert conn._cleanup_handle is not None\n    await conn.close()\n    assert conn._cleanup_handle is None\n\n\nasync def test_close_abort_closed_transports(loop) -> None:\n    tr = mock.Mock()\n\n    conn = aiohttp.BaseConnector(loop=loop)\n    conn._cleanup_closed_transports.append(tr)\n    await conn.close()\n\n    assert not conn._cleanup_closed_transports\n    assert tr.abort.called\n    assert conn.closed\n\n\nasync def test_close_cancels_cleanup_closed_handle(loop) -> None:\n    conn = aiohttp.BaseConnector(loop=loop, enable_cleanup_closed=True)\n    assert conn._cleanup_closed_handle is not None\n    await conn.close()\n    assert conn._cleanup_closed_handle is None\n\n\nasync def test_ctor_with_default_loop(loop) -> None:\n    conn = aiohttp.BaseConnector()\n    assert loop is conn._loop\n\n\nasync def test_base_connector_allows_high_level_protocols(\n    loop: asyncio.AbstractEventLoop,\n) -> None:\n    conn = aiohttp.BaseConnector()\n    assert conn.allowed_protocol_schema_set == {\n        \"\",\n        \"http\",\n        \"https\",\n        \"ws\",\n        \"wss\",\n    }\n\n\nasync def test_connect_with_limit(\n    loop: asyncio.AbstractEventLoop, key: ConnectionKey\n) -> None:\n    proto = create_mocked_conn(loop)\n    proto.is_connected.return_value = True\n\n    req = ClientRequest(\n        \"GET\", URL(\"http://localhost:80\"), loop=loop, response_class=mock.Mock()\n    )\n\n    conn = aiohttp.BaseConnector(loop=loop, limit=1)\n    conn._conns[key] = [(proto, loop.time())]\n    conn._create_connection = mock.Mock()\n    conn._create_connection.return_value = loop.create_future()\n    conn._create_connection.return_value.set_result(proto)\n\n    connection1 = await conn.connect(req, None, ClientTimeout())\n    assert connection1._protocol == proto\n\n    assert 1 == len(conn._acquired)\n    assert proto in conn._acquired\n    assert key in conn._acquired_per_host\n    assert proto in conn._acquired_per_host[key]\n\n    acquired = False\n\n    async def f():\n        nonlocal acquired\n        connection2 = await conn.connect(req, None, ClientTimeout())\n        acquired = True\n        assert 1 == len(conn._acquired)\n        assert 1 == len(conn._acquired_per_host[key])\n        connection2.release()\n\n    task = loop.create_task(f())\n\n    await asyncio.sleep(0.01)\n    assert not acquired\n    connection1.release()\n    await asyncio.sleep(0)\n    assert acquired\n    await task\n    await conn.close()\n\n\nasync def test_connect_queued_operation_tracing(loop, key) -> None:\n    session = mock.Mock()\n    trace_config_ctx = mock.Mock()\n    on_connection_queued_start = mock.Mock(side_effect=make_mocked_coro(mock.Mock()))\n    on_connection_queued_end = mock.Mock(side_effect=make_mocked_coro(mock.Mock()))\n\n    trace_config = aiohttp.TraceConfig(\n        trace_config_ctx_factory=mock.Mock(return_value=trace_config_ctx)\n    )\n    trace_config.on_connection_queued_start.append(on_connection_queued_start)\n    trace_config.on_connection_queued_end.append(on_connection_queued_end)\n    trace_config.freeze()\n    traces = [Trace(session, trace_config, trace_config.trace_config_ctx())]\n\n    proto = mock.Mock()\n    proto.is_connected.return_value = True\n\n    req = ClientRequest(\n        \"GET\", URL(\"http://localhost1:80\"), loop=loop, response_class=mock.Mock()\n    )\n\n    conn = aiohttp.BaseConnector(loop=loop, limit=1)\n    conn._conns[key] = [(proto, loop.time())]\n    conn._create_connection = mock.Mock()\n    conn._create_connection.return_value = loop.create_future()\n    conn._create_connection.return_value.set_result(proto)\n\n    connection1 = await conn.connect(req, traces, ClientTimeout())\n\n    async def f():\n        connection2 = await conn.connect(req, traces, ClientTimeout())\n        on_connection_queued_start.assert_called_with(\n            session, trace_config_ctx, aiohttp.TraceConnectionQueuedStartParams()\n        )\n        on_connection_queued_end.assert_called_with(\n            session, trace_config_ctx, aiohttp.TraceConnectionQueuedEndParams()\n        )\n        connection2.release()\n\n    task = asyncio.ensure_future(f(), loop=loop)\n    await asyncio.sleep(0.01)\n    connection1.release()\n    await task\n    await conn.close()\n\n\nasync def test_connect_reuseconn_tracing(loop, key) -> None:\n    session = mock.Mock()\n    trace_config_ctx = mock.Mock()\n    on_connection_reuseconn = mock.Mock(side_effect=make_mocked_coro(mock.Mock()))\n\n    trace_config = aiohttp.TraceConfig(\n        trace_config_ctx_factory=mock.Mock(return_value=trace_config_ctx)\n    )\n    trace_config.on_connection_reuseconn.append(on_connection_reuseconn)\n    trace_config.freeze()\n    traces = [Trace(session, trace_config, trace_config.trace_config_ctx())]\n\n    proto = mock.Mock()\n    proto.is_connected.return_value = True\n\n    req = ClientRequest(\n        \"GET\", URL(\"http://localhost:80\"), loop=loop, response_class=mock.Mock()\n    )\n\n    conn = aiohttp.BaseConnector(loop=loop, limit=1)\n    conn._conns[key] = [(proto, loop.time())]\n    conn2 = await conn.connect(req, traces, ClientTimeout())\n    conn2.release()\n\n    on_connection_reuseconn.assert_called_with(\n        session, trace_config_ctx, aiohttp.TraceConnectionReuseconnParams()\n    )\n    await conn.close()\n\n\nasync def test_connect_with_limit_and_limit_per_host(loop, key) -> None:\n    proto = mock.Mock()\n    proto.is_connected.return_value = True\n\n    req = ClientRequest(\"GET\", URL(\"http://localhost:80\"), loop=loop)\n\n    conn = aiohttp.BaseConnector(loop=loop, limit=1000, limit_per_host=1)\n    conn._conns[key] = [(proto, loop.time())]\n    conn._create_connection = mock.Mock()\n    conn._create_connection.return_value = loop.create_future()\n    conn._create_connection.return_value.set_result(proto)\n\n    acquired = False\n    connection1 = await conn.connect(req, None, ClientTimeout())\n\n    async def f():\n        nonlocal acquired\n        connection2 = await conn.connect(req, None, ClientTimeout())\n        acquired = True\n        assert 1 == len(conn._acquired)\n        assert 1 == len(conn._acquired_per_host[key])\n        connection2.release()\n\n    task = loop.create_task(f())\n\n    await asyncio.sleep(0.01)\n    assert not acquired\n    connection1.release()\n    await asyncio.sleep(0)\n    assert acquired\n    await task\n    await conn.close()\n\n\nasync def test_connect_with_no_limit_and_limit_per_host(loop, key) -> None:\n    proto = mock.Mock()\n    proto.is_connected.return_value = True\n\n    req = ClientRequest(\"GET\", URL(\"http://localhost1:80\"), loop=loop)\n\n    conn = aiohttp.BaseConnector(loop=loop, limit=0, limit_per_host=1)\n    conn._conns[key] = [(proto, loop.time())]\n    conn._create_connection = mock.Mock()\n    conn._create_connection.return_value = loop.create_future()\n    conn._create_connection.return_value.set_result(proto)\n\n    acquired = False\n    connection1 = await conn.connect(req, None, ClientTimeout())\n\n    async def f():\n        nonlocal acquired\n        connection2 = await conn.connect(req, None, ClientTimeout())\n        acquired = True\n        connection2.release()\n\n    task = loop.create_task(f())\n\n    await asyncio.sleep(0.01)\n    assert not acquired\n    connection1.release()\n    await asyncio.sleep(0)\n    assert acquired\n    await task\n    await conn.close()\n\n\nasync def test_connect_with_no_limits(loop, key) -> None:\n    proto = mock.Mock()\n    proto.is_connected.return_value = True\n\n    req = ClientRequest(\"GET\", URL(\"http://localhost:80\"), loop=loop)\n\n    conn = aiohttp.BaseConnector(loop=loop, limit=0, limit_per_host=0)\n    conn._conns[key] = [(proto, loop.time())]\n    conn._create_connection = mock.Mock()\n    conn._create_connection.return_value = loop.create_future()\n    conn._create_connection.return_value.set_result(proto)\n\n    acquired = False\n    connection1 = await conn.connect(req, None, ClientTimeout())\n\n    async def f():\n        nonlocal acquired\n        connection2 = await conn.connect(req, None, ClientTimeout())\n        acquired = True\n        assert 1 == len(conn._acquired)\n        assert 1 == len(conn._acquired_per_host[key])\n        connection2.release()\n\n    task = loop.create_task(f())\n\n    await asyncio.sleep(0.01)\n    assert acquired\n    connection1.release()\n    await task\n    await conn.close()\n\n\nasync def test_connect_with_limit_cancelled(loop) -> None:\n\n    proto = mock.Mock()\n    proto.is_connected.return_value = True\n\n    req = ClientRequest(\"GET\", URL(\"http://host:80\"), loop=loop)\n\n    conn = aiohttp.BaseConnector(loop=loop, limit=1)\n    key = (\"host\", 80, False)\n    conn._conns[key] = [(proto, loop.time())]\n    conn._create_connection = mock.Mock()\n    conn._create_connection.return_value = loop.create_future()\n    conn._create_connection.return_value.set_result(proto)\n\n    connection = await conn.connect(req, None, ClientTimeout())\n    assert connection._protocol == proto\n    assert connection.transport == proto.transport\n\n    assert 1 == len(conn._acquired)\n\n    with pytest.raises(asyncio.TimeoutError):\n        # limit exhausted\n        await asyncio.wait_for(conn.connect(req, None, ClientTimeout()), 0.01)\n    connection.close()\n\n    await conn.close()\n\n\nasync def test_connect_with_capacity_release_waiters(loop) -> None:\n    def check_with_exc(err):\n        conn = aiohttp.BaseConnector(limit=1, loop=loop)\n        conn._create_connection = mock.Mock()\n        conn._create_connection.return_value = loop.create_future()\n        conn._create_connection.return_value.set_exception(err)\n\n        with pytest.raises(Exception):\n            req = mock.Mock()\n            yield from conn.connect(req, None, ClientTimeout())\n\n        assert not conn._waiters\n\n    check_with_exc(OSError(1, \"permission error\"))\n    check_with_exc(RuntimeError())\n    check_with_exc(asyncio.TimeoutError())\n\n\nasync def test_connect_with_limit_concurrent(loop) -> None:\n    proto = mock.Mock()\n    proto.should_close = False\n    proto.is_connected.return_value = True\n\n    req = ClientRequest(\"GET\", URL(\"http://host:80\"), loop=loop)\n\n    max_connections = 2\n    num_connections = 0\n\n    conn = aiohttp.BaseConnector(limit=max_connections, loop=loop)\n\n    # Use a real coroutine for _create_connection; a mock would mask\n    # problems that only happen when the method yields.\n\n    async def create_connection(req, traces, timeout):\n        nonlocal num_connections\n        num_connections += 1\n        await asyncio.sleep(0)\n\n        # Make a new transport mock each time because acquired\n        # transports are stored in a set. Reusing the same object\n        # messes with the count.\n        proto = mock.Mock(should_close=False)\n        proto.is_connected.return_value = True\n\n        return proto\n\n    conn._create_connection = create_connection\n\n    # Simulate something like a crawler. It opens a connection, does\n    # something with it, closes it, then creates tasks that make more\n    # connections and waits for them to finish. The crawler is started\n    # with multiple concurrent requests and stops when it hits a\n    # predefined maximum number of requests.\n\n    max_requests = 50\n    num_requests = 0\n    start_requests = max_connections + 1\n\n    async def f(start=True):\n        nonlocal num_requests\n        if num_requests == max_requests:\n            return\n        num_requests += 1\n        if not start:\n            connection = await conn.connect(req, None, ClientTimeout())\n            await asyncio.sleep(0)\n            connection.release()\n            await asyncio.sleep(0)\n        tasks = [loop.create_task(f(start=False)) for i in range(start_requests)]\n        await asyncio.wait(tasks)\n\n    await f()\n    await conn.close()\n\n    assert max_connections == num_connections\n\n\nasync def test_connect_waiters_cleanup(loop) -> None:\n    proto = mock.Mock()\n    proto.is_connected.return_value = True\n\n    req = ClientRequest(\"GET\", URL(\"http://host:80\"), loop=loop)\n\n    conn = aiohttp.BaseConnector(loop=loop, limit=1)\n    conn._available_connections = mock.Mock(return_value=0)\n\n    t = loop.create_task(conn.connect(req, None, ClientTimeout()))\n\n    await asyncio.sleep(0)\n    assert conn._waiters.keys()\n\n    t.cancel()\n    await asyncio.sleep(0)\n    assert not conn._waiters.keys()\n\n\nasync def test_connect_waiters_cleanup_key_error(loop) -> None:\n    proto = mock.Mock()\n    proto.is_connected.return_value = True\n\n    req = ClientRequest(\"GET\", URL(\"http://host:80\"), loop=loop)\n\n    conn = aiohttp.BaseConnector(loop=loop, limit=1)\n    conn._available_connections = mock.Mock(return_value=0)\n\n    t = loop.create_task(conn.connect(req, None, ClientTimeout()))\n\n    await asyncio.sleep(0)\n    assert conn._waiters.keys()\n\n    # we delete the entry explicitly before the\n    # canceled connection grabs the loop again, we\n    # must expect a none failure termination\n    conn._waiters.clear()\n    t.cancel()\n    await asyncio.sleep(0)\n    assert not conn._waiters.keys() == []\n\n\nasync def test_close_with_acquired_connection(loop) -> None:\n    proto = mock.Mock()\n    proto.is_connected.return_value = True\n\n    req = ClientRequest(\"GET\", URL(\"http://host:80\"), loop=loop)\n\n    conn = aiohttp.BaseConnector(loop=loop, limit=1)\n    key = (\"host\", 80, False)\n    conn._conns[key] = [(proto, loop.time())]\n    conn._create_connection = mock.Mock()\n    conn._create_connection.return_value = loop.create_future()\n    conn._create_connection.return_value.set_result(proto)\n\n    connection = await conn.connect(req, None, ClientTimeout())\n\n    assert 1 == len(conn._acquired)\n    await conn.close()\n    assert 0 == len(conn._acquired)\n    assert conn.closed\n    proto.close.assert_called_with()\n\n    assert not connection.closed\n    connection.close()\n    assert connection.closed\n\n\nasync def test_default_force_close(loop) -> None:\n    connector = aiohttp.BaseConnector(loop=loop)\n    assert not connector.force_close\n\n\nasync def test_limit_property(loop) -> None:\n    conn = aiohttp.BaseConnector(loop=loop, limit=15)\n    assert 15 == conn.limit\n\n    await conn.close()\n\n\nasync def test_limit_per_host_property(loop) -> None:\n    conn = aiohttp.BaseConnector(loop=loop, limit_per_host=15)\n    assert 15 == conn.limit_per_host\n\n    await conn.close()\n\n\nasync def test_limit_property_default(loop) -> None:\n    conn = aiohttp.BaseConnector(loop=loop)\n    assert conn.limit == 100\n    await conn.close()\n\n\nasync def test_limit_per_host_property_default(loop) -> None:\n    conn = aiohttp.BaseConnector(loop=loop)\n    assert conn.limit_per_host == 0\n    await conn.close()\n\n\nasync def test_force_close_and_explicit_keep_alive(loop) -> None:\n    with pytest.raises(ValueError):\n        aiohttp.BaseConnector(loop=loop, keepalive_timeout=30, force_close=True)\n\n    conn = aiohttp.BaseConnector(loop=loop, force_close=True, keepalive_timeout=None)\n    assert conn\n\n    conn = aiohttp.BaseConnector(loop=loop, force_close=True)\n\n    assert conn\n\n\nasync def test_error_on_connection(loop, key) -> None:\n    conn = aiohttp.BaseConnector(limit=1, loop=loop)\n\n    req = mock.Mock()\n    req.connection_key = key\n    proto = mock.Mock()\n    i = 0\n\n    fut = loop.create_future()\n    exc = OSError()\n\n    async def create_connection(req, traces, timeout):\n        nonlocal i\n        i += 1\n        if i == 1:\n            await fut\n            raise exc\n        elif i == 2:\n            return proto\n\n    conn._create_connection = create_connection\n\n    t1 = loop.create_task(conn.connect(req, None, ClientTimeout()))\n    t2 = loop.create_task(conn.connect(req, None, ClientTimeout()))\n    await asyncio.sleep(0)\n    assert not t1.done()\n    assert not t2.done()\n    assert len(conn._acquired_per_host[key]) == 1\n\n    fut.set_result(None)\n    with pytest.raises(OSError):\n        await t1\n\n    ret = await t2\n    assert len(conn._acquired_per_host[key]) == 1\n\n    assert ret._key == key\n    assert ret.protocol == proto\n    assert proto in conn._acquired\n    ret.release()\n\n\nasync def test_cancelled_waiter(loop) -> None:\n    conn = aiohttp.BaseConnector(limit=1, loop=loop)\n    req = mock.Mock()\n    req.connection_key = \"key\"\n    proto = mock.Mock()\n\n    async def create_connection(req, traces=None):\n        await asyncio.sleep(1)\n        return proto\n\n    conn._create_connection = create_connection\n\n    conn._acquired.add(proto)\n\n    conn2 = loop.create_task(conn.connect(req, None, ClientTimeout()))\n    await asyncio.sleep(0)\n    conn2.cancel()\n\n    with pytest.raises(asyncio.CancelledError):\n        await conn2\n\n\nasync def test_error_on_connection_with_cancelled_waiter(loop, key) -> None:\n    conn = aiohttp.BaseConnector(limit=1, loop=loop)\n\n    req = mock.Mock()\n    req.connection_key = key\n    proto = mock.Mock()\n    i = 0\n\n    fut1 = loop.create_future()\n    fut2 = loop.create_future()\n    exc = OSError()\n\n    async def create_connection(req, traces, timeout):\n        nonlocal i\n        i += 1\n        if i == 1:\n            await fut1\n            raise exc\n        if i == 2:\n            await fut2\n        elif i == 3:\n            return proto\n\n    conn._create_connection = create_connection\n\n    t1 = loop.create_task(conn.connect(req, None, ClientTimeout()))\n    t2 = loop.create_task(conn.connect(req, None, ClientTimeout()))\n    t3 = loop.create_task(conn.connect(req, None, ClientTimeout()))\n    await asyncio.sleep(0)\n    assert not t1.done()\n    assert not t2.done()\n    assert len(conn._acquired_per_host[key]) == 1\n\n    fut1.set_result(None)\n    fut2.cancel()\n    with pytest.raises(OSError):\n        await t1\n\n    with pytest.raises(asyncio.CancelledError):\n        await t2\n\n    ret = await t3\n    assert len(conn._acquired_per_host[key]) == 1\n\n    assert ret._key == key\n    assert ret.protocol == proto\n    assert proto in conn._acquired\n    ret.release()\n\n\nasync def test_tcp_connector(aiohttp_client, loop) -> None:\n    async def handler(request):\n        return web.Response()\n\n    app = web.Application()\n    app.router.add_get(\"/\", handler)\n    client = await aiohttp_client(app)\n\n    r = await client.get(\"/\")\n    assert r.status == 200\n\n\n@pytest.mark.skipif(not hasattr(socket, \"AF_UNIX\"), reason=\"requires UNIX sockets\")\nasync def test_unix_connector_not_found(loop) -> None:\n    connector = aiohttp.UnixConnector(\"/\" + uuid.uuid4().hex)\n\n    req = ClientRequest(\"GET\", URL(\"http://www.python.org\"), loop=loop)\n    with pytest.raises(aiohttp.ClientConnectorError):\n        await connector.connect(req, None, ClientTimeout())\n\n\n@pytest.mark.skipif(not hasattr(socket, \"AF_UNIX\"), reason=\"requires UNIX sockets\")\nasync def test_unix_connector_permission(loop) -> None:\n    loop.create_unix_connection = make_mocked_coro(raise_exception=PermissionError())\n    connector = aiohttp.UnixConnector(\"/\" + uuid.uuid4().hex, loop=loop)\n\n    req = ClientRequest(\"GET\", URL(\"http://www.python.org\"), loop=loop)\n    with pytest.raises(aiohttp.ClientConnectorError):\n        await connector.connect(req, None, ClientTimeout())\n\n\n@pytest.mark.skipif(\n    platform.system() != \"Windows\", reason=\"Proactor Event loop present only in Windows\"\n)\nasync def test_named_pipe_connector_wrong_loop(selector_loop, pipe_name) -> None:\n    with pytest.raises(RuntimeError):\n        aiohttp.NamedPipeConnector(pipe_name, loop=asyncio.get_event_loop())\n\n\n@pytest.mark.skipif(\n    platform.system() != \"Windows\", reason=\"Proactor Event loop present only in Windows\"\n)\nasync def test_named_pipe_connector_not_found(proactor_loop, pipe_name) -> None:\n    connector = aiohttp.NamedPipeConnector(pipe_name, loop=proactor_loop)\n\n    req = ClientRequest(\"GET\", URL(\"http://www.python.org\"), loop=proactor_loop)\n    with pytest.raises(aiohttp.ClientConnectorError):\n        await connector.connect(req, None, ClientTimeout())\n\n\n@pytest.mark.skipif(\n    platform.system() != \"Windows\", reason=\"Proactor Event loop present only in Windows\"\n)\nasync def test_named_pipe_connector_permission(proactor_loop, pipe_name) -> None:\n    proactor_loop.create_pipe_connection = make_mocked_coro(\n        raise_exception=PermissionError()\n    )\n    connector = aiohttp.NamedPipeConnector(pipe_name, loop=proactor_loop)\n\n    req = ClientRequest(\"GET\", URL(\"http://www.python.org\"), loop=proactor_loop)\n    with pytest.raises(aiohttp.ClientConnectorError):\n        await connector.connect(req, None, ClientTimeout())\n\n\nasync def test_default_use_dns_cache() -> None:\n    conn = aiohttp.TCPConnector()\n    assert conn.use_dns_cache\n\n\nasync def test_ssl_none() -> None:\n    conn = aiohttp.TCPConnector(ssl=None)\n    assert conn._ssl is True\n\n\nasync def test_resolver_not_called_with_address_is_ip(loop) -> None:\n    resolver = mock.MagicMock()\n    connector = aiohttp.TCPConnector(resolver=resolver)\n\n    req = ClientRequest(\n        \"GET\",\n        URL(f\"http://127.0.0.1:{unused_port()}\"),\n        loop=loop,\n        response_class=mock.Mock(),\n    )\n\n    with pytest.raises(OSError):\n        await connector.connect(req, None, ClientTimeout())\n\n    resolver.resolve.assert_not_called()\n\n\nasync def test_tcp_connector_raise_connector_ssl_error(\n    aiohttp_server,\n    ssl_ctx,\n) -> None:\n    async def handler(request):\n        return web.Response()\n\n    app = web.Application()\n    app.router.add_get(\"/\", handler)\n\n    srv = await aiohttp_server(app, ssl=ssl_ctx)\n\n    port = unused_port()\n    conn = aiohttp.TCPConnector(local_addr=(\"127.0.0.1\", port))\n\n    session = aiohttp.ClientSession(connector=conn)\n    url = srv.make_url(\"/\")\n\n    err = aiohttp.ClientConnectorCertificateError\n    with pytest.raises(err) as ctx:\n        await session.get(url)\n\n    assert isinstance(ctx.value, aiohttp.ClientConnectorCertificateError)\n    assert isinstance(ctx.value.certificate_error, ssl.SSLError)\n\n    await session.close()\n\n\n@pytest.mark.parametrize(\n    \"host\",\n    (\n        pytest.param(\"127.0.0.1\", id=\"ip address\"),\n        pytest.param(\"localhost\", id=\"domain name\"),\n        pytest.param(\"localhost.\", id=\"fully-qualified domain name\"),\n        pytest.param(\n            \"localhost...\", id=\"fully-qualified domain name with multiple trailing dots\"\n        ),\n        pytest.param(\"príklad.localhost.\", id=\"idna fully-qualified domain name\"),\n    ),\n)\nasync def test_tcp_connector_do_not_raise_connector_ssl_error(\n    aiohttp_server,\n    ssl_ctx,\n    client_ssl_ctx,\n    host,\n) -> None:\n    async def handler(request):\n        return web.Response()\n\n    app = web.Application()\n    app.router.add_get(\"/\", handler)\n\n    srv = await aiohttp_server(app, ssl=ssl_ctx)\n    port = unused_port()\n    conn = aiohttp.TCPConnector(local_addr=(\"127.0.0.1\", port))\n\n    # resolving something.localhost with the real DNS resolver does not work on macOS, so we have a stub.\n    async def _resolve_host(host, port, traces=None):\n        return [\n            {\n                \"hostname\": host,\n                \"host\": \"127.0.0.1\",\n                \"port\": port,\n                \"family\": socket.AF_INET,\n                \"proto\": 0,\n                \"flags\": socket.AI_NUMERICHOST,\n            },\n            {\n                \"hostname\": host,\n                \"host\": \"::1\",\n                \"port\": port,\n                \"family\": socket.AF_INET,\n                \"proto\": 0,\n                \"flags\": socket.AI_NUMERICHOST,\n            },\n        ]\n\n    conn._resolve_host = _resolve_host\n\n    session = aiohttp.ClientSession(connector=conn)\n    url = srv.make_url(\"/\")\n\n    r = await session.get(url.with_host(host), ssl=client_ssl_ctx)\n\n    r.release()\n    first_conn = next(iter(conn._conns.values()))[0][0]\n\n    try:\n        _sslcontext = first_conn.transport._ssl_protocol._sslcontext\n    except AttributeError:\n        _sslcontext = first_conn.transport._sslcontext\n\n    assert _sslcontext is client_ssl_ctx\n    r.close()\n\n    await session.close()\n    await conn.close()\n\n\nasync def test_tcp_connector_uses_provided_local_addr(aiohttp_server) -> None:\n    async def handler(request):\n        return web.Response()\n\n    app = web.Application()\n    app.router.add_get(\"/\", handler)\n    srv = await aiohttp_server(app)\n\n    port = unused_port()\n    conn = aiohttp.TCPConnector(local_addr=(\"127.0.0.1\", port))\n\n    session = aiohttp.ClientSession(connector=conn)\n    url = srv.make_url(\"/\")\n\n    r = await session.get(url)\n    r.release()\n\n    first_conn = next(iter(conn._conns.values()))[0][0]\n    assert first_conn.transport.get_extra_info(\"sockname\") == (\"127.0.0.1\", port)\n    r.close()\n    await session.close()\n    await conn.close()\n\n\nasync def test_unix_connector(unix_server, unix_sockname) -> None:\n    async def handler(request):\n        return web.Response()\n\n    app = web.Application()\n    app.router.add_get(\"/\", handler)\n    await unix_server(app)\n\n    url = \"http://127.0.0.1/\"\n\n    connector = aiohttp.UnixConnector(unix_sockname)\n    assert unix_sockname == connector.path\n    assert connector.allowed_protocol_schema_set == {\n        \"\",\n        \"http\",\n        \"https\",\n        \"ws\",\n        \"wss\",\n        \"unix\",\n    }\n\n    session = client.ClientSession(connector=connector)\n    r = await session.get(url)\n    assert r.status == 200\n    r.close()\n    await session.close()\n\n\n@pytest.mark.skipif(\n    platform.system() != \"Windows\", reason=\"Proactor Event loop present only in Windows\"\n)\nasync def test_named_pipe_connector(\n    proactor_loop, named_pipe_server, pipe_name\n) -> None:\n    async def handler(request):\n        return web.Response()\n\n    app = web.Application()\n    app.router.add_get(\"/\", handler)\n    await named_pipe_server(app)\n\n    url = \"http://this-does-not-matter.com\"\n\n    connector = aiohttp.NamedPipeConnector(pipe_name)\n    assert pipe_name == connector.path\n    assert connector.allowed_protocol_schema_set == {\n        \"\",\n        \"http\",\n        \"https\",\n        \"ws\",\n        \"wss\",\n        \"npipe\",\n    }\n\n    session = client.ClientSession(connector=connector)\n    r = await session.get(url)\n    assert r.status == 200\n    r.close()\n    await session.close()\n\n\nclass TestDNSCacheTable:\n    @pytest.fixture\n    def dns_cache_table(self):\n        return _DNSCacheTable()\n\n    def test_next_addrs_basic(self, dns_cache_table) -> None:\n        dns_cache_table.add(\"localhost\", [\"127.0.0.1\"])\n        dns_cache_table.add(\"foo\", [\"127.0.0.2\"])\n\n        addrs = dns_cache_table.next_addrs(\"localhost\")\n        assert addrs == [\"127.0.0.1\"]\n        addrs = dns_cache_table.next_addrs(\"foo\")\n        assert addrs == [\"127.0.0.2\"]\n        with pytest.raises(KeyError):\n            dns_cache_table.next_addrs(\"no-such-host\")\n\n    def test_remove(self, dns_cache_table) -> None:\n        dns_cache_table.add(\"localhost\", [\"127.0.0.1\"])\n        dns_cache_table.remove(\"localhost\")\n        with pytest.raises(KeyError):\n            dns_cache_table.next_addrs(\"localhost\")\n\n    def test_clear(self, dns_cache_table) -> None:\n        dns_cache_table.add(\"localhost\", [\"127.0.0.1\"])\n        dns_cache_table.clear()\n        with pytest.raises(KeyError):\n            dns_cache_table.next_addrs(\"localhost\")\n\n    def test_not_expired_ttl_None(self, dns_cache_table) -> None:\n        dns_cache_table.add(\"localhost\", [\"127.0.0.1\"])\n        assert not dns_cache_table.expired(\"localhost\")\n\n    def test_not_expired_ttl(self) -> None:\n        dns_cache_table = _DNSCacheTable(ttl=0.1)\n        dns_cache_table.add(\"localhost\", [\"127.0.0.1\"])\n        assert not dns_cache_table.expired(\"localhost\")\n\n    def test_expired_ttl(self, monkeypatch: pytest.MonkeyPatch) -> None:\n        dns_cache_table = _DNSCacheTable(ttl=1)\n        monkeypatch.setattr(\"aiohttp.connector.monotonic\", lambda: 1)\n        dns_cache_table.add(\"localhost\", [\"127.0.0.1\"])\n        monkeypatch.setattr(\"aiohttp.connector.monotonic\", lambda: 2)\n        assert not dns_cache_table.expired(\"localhost\")\n        monkeypatch.setattr(\"aiohttp.connector.monotonic\", lambda: 3)\n        assert dns_cache_table.expired(\"localhost\")\n\n    def test_never_expire(self, monkeypatch: pytest.MonkeyPatch) -> None:\n        dns_cache_table = _DNSCacheTable(ttl=None)\n        monkeypatch.setattr(\"aiohttp.connector.monotonic\", lambda: 1)\n        dns_cache_table.add(\"localhost\", [\"127.0.0.1\"])\n        monkeypatch.setattr(\"aiohttp.connector.monotonic\", lambda: 10000000)\n        assert not dns_cache_table.expired(\"localhost\")\n\n    def test_always_expire(self, monkeypatch: pytest.MonkeyPatch) -> None:\n        dns_cache_table = _DNSCacheTable(ttl=0)\n        monkeypatch.setattr(\"aiohttp.connector.monotonic\", lambda: 1)\n        dns_cache_table.add(\"localhost\", [\"127.0.0.1\"])\n        monkeypatch.setattr(\"aiohttp.connector.monotonic\", lambda: 1.00001)\n        assert dns_cache_table.expired(\"localhost\")\n\n    def test_next_addrs(self, dns_cache_table) -> None:\n        dns_cache_table.add(\"foo\", [\"127.0.0.1\", \"127.0.0.2\", \"127.0.0.3\"])\n\n        # Each calls to next_addrs return the hosts using\n        # a round robin strategy.\n        addrs = dns_cache_table.next_addrs(\"foo\")\n        assert addrs == [\"127.0.0.1\", \"127.0.0.2\", \"127.0.0.3\"]\n\n        addrs = dns_cache_table.next_addrs(\"foo\")\n        assert addrs == [\"127.0.0.2\", \"127.0.0.3\", \"127.0.0.1\"]\n\n        addrs = dns_cache_table.next_addrs(\"foo\")\n        assert addrs == [\"127.0.0.3\", \"127.0.0.1\", \"127.0.0.2\"]\n\n        addrs = dns_cache_table.next_addrs(\"foo\")\n        assert addrs == [\"127.0.0.1\", \"127.0.0.2\", \"127.0.0.3\"]\n\n    def test_next_addrs_single(self, dns_cache_table) -> None:\n        dns_cache_table.add(\"foo\", [\"127.0.0.1\"])\n\n        addrs = dns_cache_table.next_addrs(\"foo\")\n        assert addrs == [\"127.0.0.1\"]\n\n        addrs = dns_cache_table.next_addrs(\"foo\")\n        assert addrs == [\"127.0.0.1\"]\n\n\nasync def test_connector_cache_trace_race():\n    class DummyTracer:\n        async def send_dns_cache_hit(self, *args, **kwargs):\n            connector._cached_hosts.remove((\"\", 0))\n\n    token = object()\n    connector = TCPConnector()\n    connector._cached_hosts.add((\"\", 0), [token])\n\n    traces = [DummyTracer()]\n    assert await connector._resolve_host(\"\", 0, traces) == [token]\n\n\nasync def test_connector_throttle_trace_race(loop):\n    key = (\"\", 0)\n    token = object()\n\n    class DummyTracer:\n        async def send_dns_cache_hit(self, *args, **kwargs):\n            event = connector._throttle_dns_events.pop(key)\n            event.set()\n            connector._cached_hosts.add(key, [token])\n\n    connector = TCPConnector()\n    connector._throttle_dns_events[key] = EventResultOrError(loop)\n    traces = [DummyTracer()]\n    assert await connector._resolve_host(\"\", 0, traces) == [token]\n\n\nasync def test_connector_does_not_remove_needed_waiters(loop, key) -> None:\n    proto = create_mocked_conn(loop)\n    proto.is_connected.return_value = True\n\n    req = ClientRequest(\"GET\", URL(\"https://localhost:80\"), loop=loop)\n    connection_key = req.connection_key\n\n    connector = aiohttp.BaseConnector()\n    connector._available_connections = mock.Mock(return_value=0)\n    connector._conns[key] = [(proto, loop.time())]\n    connector._create_connection = create_mocked_conn(loop)\n    connector._create_connection.return_value = loop.create_future()\n    connector._create_connection.return_value.set_result(proto)\n\n    dummy_waiter = loop.create_future()\n\n    async def await_connection_and_check_waiters():\n        connection = await connector.connect(req, [], ClientTimeout())\n        try:\n            assert connection_key in connector._waiters\n            assert dummy_waiter in connector._waiters[connection_key]\n        finally:\n            connection.close()\n\n    async def allow_connection_and_add_dummy_waiter():\n        # `asyncio.gather` may execute coroutines not in order.\n        # Skip one event loop run cycle in such a case.\n        if connection_key not in connector._waiters:\n            await asyncio.sleep(0)\n        connector._waiters[connection_key].popleft().set_result(None)\n        del connector._waiters[connection_key]\n        connector._waiters[connection_key].append(dummy_waiter)\n\n    await asyncio.gather(\n        await_connection_and_check_waiters(),\n        allow_connection_and_add_dummy_waiter(),\n    )\n\n    await connector.close()\n",
            "new_file_content": "# Tests of http client with custom Connector\n\nimport asyncio\nimport gc\nimport hashlib\nimport platform\nimport socket\nimport ssl\nimport sys\nimport uuid\nfrom collections import deque\nfrom contextlib import closing, suppress\nfrom typing import Any, List, Optional, Type\nfrom unittest import mock\n\nimport pytest\nfrom aiohappyeyeballs import AddrInfoType\nfrom yarl import URL\n\nimport aiohttp\nfrom aiohttp import client, web\nfrom aiohttp.client import ClientRequest, ClientTimeout\nfrom aiohttp.client_reqrep import ConnectionKey\nfrom aiohttp.connector import Connection, TCPConnector, _DNSCacheTable\nfrom aiohttp.locks import EventResultOrError\nfrom aiohttp.test_utils import make_mocked_coro, unused_port\nfrom aiohttp.tracing import Trace\n\n\n@pytest.fixture()\ndef key():\n    # Connection key\n    return ConnectionKey(\"localhost\", 80, False, True, None, None, None)\n\n\n@pytest.fixture\ndef key2():\n    # Connection key\n    return ConnectionKey(\"localhost\", 80, False, True, None, None, None)\n\n\n@pytest.fixture\ndef ssl_key():\n    # Connection key\n    return ConnectionKey(\"localhost\", 80, True, True, None, None, None)\n\n\n@pytest.fixture\ndef unix_server(loop, unix_sockname):\n    runners = []\n\n    async def go(app):\n        runner = web.AppRunner(app)\n        runners.append(runner)\n        await runner.setup()\n        site = web.UnixSite(runner, unix_sockname)\n        await site.start()\n\n    yield go\n\n    for runner in runners:\n        loop.run_until_complete(runner.cleanup())\n\n\n@pytest.fixture\ndef named_pipe_server(proactor_loop, pipe_name):\n    runners = []\n\n    async def go(app):\n        runner = web.AppRunner(app)\n        runners.append(runner)\n        await runner.setup()\n        site = web.NamedPipeSite(runner, pipe_name)\n        await site.start()\n\n    yield go\n\n    for runner in runners:\n        proactor_loop.run_until_complete(runner.cleanup())\n\n\ndef create_mocked_conn(conn_closing_result=None, **kwargs):\n    try:\n        loop = asyncio.get_running_loop()\n    except RuntimeError:\n        loop = asyncio.get_event_loop_policy().get_event_loop()\n\n    proto = mock.Mock(**kwargs)\n    proto.closed = loop.create_future()\n    proto.closed.set_result(conn_closing_result)\n    return proto\n\n\ndef test_connection_del(loop) -> None:\n    connector = mock.Mock()\n    key = mock.Mock()\n    protocol = mock.Mock()\n    loop.set_debug(0)\n    conn = Connection(connector, key, protocol, loop=loop)\n    exc_handler = mock.Mock()\n    loop.set_exception_handler(exc_handler)\n\n    with pytest.warns(ResourceWarning):\n        del conn\n        gc.collect()\n\n    connector._release.assert_called_with(key, protocol, should_close=True)\n    msg = {\n        \"message\": mock.ANY,\n        \"client_connection\": mock.ANY,\n    }\n    exc_handler.assert_called_with(loop, msg)\n\n\ndef test_connection_del_loop_debug(loop) -> None:\n    connector = mock.Mock()\n    key = mock.Mock()\n    protocol = mock.Mock()\n    loop.set_debug(1)\n    conn = Connection(connector, key, protocol, loop=loop)\n    exc_handler = mock.Mock()\n    loop.set_exception_handler(exc_handler)\n\n    with pytest.warns(ResourceWarning):\n        del conn\n        gc.collect()\n\n    msg = {\n        \"message\": mock.ANY,\n        \"client_connection\": mock.ANY,\n        \"source_traceback\": mock.ANY,\n    }\n    exc_handler.assert_called_with(loop, msg)\n\n\ndef test_connection_del_loop_closed(loop) -> None:\n    connector = mock.Mock()\n    key = mock.Mock()\n    protocol = mock.Mock()\n    loop.set_debug(1)\n    conn = Connection(connector, key, protocol, loop=loop)\n    exc_handler = mock.Mock()\n    loop.set_exception_handler(exc_handler)\n    loop.close()\n\n    with pytest.warns(ResourceWarning):\n        del conn\n        gc.collect()\n\n    assert not connector._release.called\n    assert not exc_handler.called\n\n\nasync def test_del(loop) -> None:\n    conn = aiohttp.BaseConnector()\n    proto = mock.Mock(should_close=False)\n    conn._release(\"a\", proto)\n    conns_impl = conn._conns\n\n    exc_handler = mock.Mock()\n    loop.set_exception_handler(exc_handler)\n\n    with pytest.warns(ResourceWarning):\n        del conn\n        gc.collect()\n\n    assert not conns_impl\n    proto.close.assert_called_with()\n    msg = {\n        \"connector\": mock.ANY,  # conn was deleted\n        \"connections\": mock.ANY,\n        \"message\": \"Unclosed connector\",\n    }\n    if loop.get_debug():\n        msg[\"source_traceback\"] = mock.ANY\n    exc_handler.assert_called_with(loop, msg)\n\n\n@pytest.mark.xfail\nasync def test_del_with_scheduled_cleanup(loop) -> None:\n    loop.set_debug(True)\n    conn = aiohttp.BaseConnector(loop=loop, keepalive_timeout=0.01)\n    transp = mock.Mock()\n    conn._conns[\"a\"] = [(transp, 123)]\n\n    conns_impl = conn._conns\n    exc_handler = mock.Mock()\n    loop.set_exception_handler(exc_handler)\n\n    with pytest.warns(ResourceWarning):\n        # obviously doesn't deletion because loop has a strong\n        # reference to connector's instance method, isn't it?\n        del conn\n        await asyncio.sleep(0.01)\n        gc.collect()\n\n    assert not conns_impl\n    transp.close.assert_called_with()\n    msg = {\"connector\": mock.ANY, \"message\": \"Unclosed connector\"}  # conn was deleted\n    if loop.get_debug():\n        msg[\"source_traceback\"] = mock.ANY\n    exc_handler.assert_called_with(loop, msg)\n\n\n@pytest.mark.skipif(\n    sys.implementation.name != \"cpython\", reason=\"CPython GC is required for the test\"\n)\ndef test_del_with_closed_loop(loop) -> None:\n    async def make_conn():\n        return aiohttp.BaseConnector()\n\n    conn = loop.run_until_complete(make_conn())\n    transp = mock.Mock()\n    conn._conns[\"a\"] = [(transp, 123)]\n\n    conns_impl = conn._conns\n    exc_handler = mock.Mock()\n    loop.set_exception_handler(exc_handler)\n    loop.close()\n\n    with pytest.warns(ResourceWarning):\n        del conn\n        gc.collect()\n\n    assert not conns_impl\n    assert not transp.close.called\n    assert exc_handler.called\n\n\nasync def test_del_empty_connector(loop) -> None:\n    conn = aiohttp.BaseConnector(loop=loop)\n\n    exc_handler = mock.Mock()\n    loop.set_exception_handler(exc_handler)\n\n    del conn\n\n    assert not exc_handler.called\n\n\nasync def test_create_conn(loop) -> None:\n    conn = aiohttp.BaseConnector(loop=loop)\n    with pytest.raises(NotImplementedError):\n        await conn._create_connection(object(), [], object())\n\n\nasync def test_connector_context_manager(loop) -> None:\n    conn = aiohttp.BaseConnector(loop=loop)\n\n    with pytest.warns(DeprecationWarning):\n        with conn as c:\n            assert conn is c\n\n    assert conn.closed\n\n    await conn.close()\n\n\nasync def test_async_context_manager(loop) -> None:\n    conn = aiohttp.BaseConnector(loop=loop)\n\n    async with conn as c:\n        assert conn is c\n\n    assert conn.closed\n\n\nasync def test_close(loop) -> None:\n    proto = mock.Mock()\n\n    conn = aiohttp.BaseConnector(loop=loop)\n    assert not conn.closed\n    conn._conns[(\"host\", 8080, False)] = [(proto, object())]\n    await conn.close()\n\n    assert not conn._conns\n    assert proto.close.called\n    assert conn.closed\n\n\nasync def test_get(loop) -> None:\n    conn = aiohttp.BaseConnector(loop=loop)\n    assert conn._get(1) is None\n\n    proto = mock.Mock()\n    conn._conns[1] = [(proto, loop.time())]\n    assert conn._get(1) == proto\n    await conn.close()\n\n\nasync def test_get_unconnected_proto(loop) -> None:\n    conn = aiohttp.BaseConnector()\n    key = ConnectionKey(\"localhost\", 80, False, None, None, None, None)\n    assert conn._get(key) is None\n\n    proto = create_mocked_conn(loop)\n    conn._conns[key] = [(proto, loop.time())]\n    assert conn._get(key) == proto\n\n    assert conn._get(key) is None\n    conn._conns[key] = [(proto, loop.time())]\n    proto.is_connected = lambda *args: False\n    assert conn._get(key) is None\n    await conn.close()\n\n\nasync def test_get_unconnected_proto_ssl(loop) -> None:\n    conn = aiohttp.BaseConnector()\n    key = ConnectionKey(\"localhost\", 80, True, None, None, None, None)\n    assert conn._get(key) is None\n\n    proto = create_mocked_conn(loop)\n    conn._conns[key] = [(proto, loop.time())]\n    assert conn._get(key) == proto\n\n    assert conn._get(key) is None\n    conn._conns[key] = [(proto, loop.time())]\n    proto.is_connected = lambda *args: False\n    assert conn._get(key) is None\n    await conn.close()\n\n\nasync def test_get_expired(loop) -> None:\n    conn = aiohttp.BaseConnector(loop=loop)\n    key = ConnectionKey(\"localhost\", 80, False, None, None, None, None)\n    assert conn._get(key) is None\n\n    proto = mock.Mock()\n    conn._conns[key] = [(proto, loop.time() - 1000)]\n    assert conn._get(key) is None\n    assert not conn._conns\n    await conn.close()\n\n\nasync def test_get_expired_ssl(loop) -> None:\n    conn = aiohttp.BaseConnector(loop=loop, enable_cleanup_closed=True)\n    key = ConnectionKey(\"localhost\", 80, True, None, None, None, None)\n    assert conn._get(key) is None\n\n    proto = mock.Mock()\n    transport = proto.transport\n    conn._conns[key] = [(proto, loop.time() - 1000)]\n    assert conn._get(key) is None\n    assert not conn._conns\n    assert conn._cleanup_closed_transports == [transport]\n    await conn.close()\n\n\nasync def test_release_acquired(loop, key) -> None:\n    proto = mock.Mock()\n    conn = aiohttp.BaseConnector(loop=loop, limit=5)\n    conn._release_waiter = mock.Mock()\n\n    conn._acquired.add(proto)\n    conn._acquired_per_host[key].add(proto)\n    conn._release_acquired(key, proto)\n    assert 0 == len(conn._acquired)\n    assert 0 == len(conn._acquired_per_host)\n    assert conn._release_waiter.called\n\n    conn._release_acquired(key, proto)\n    assert 0 == len(conn._acquired)\n    assert 0 == len(conn._acquired_per_host)\n\n    await conn.close()\n\n\nasync def test_release_acquired_closed(loop, key) -> None:\n    proto = mock.Mock()\n    conn = aiohttp.BaseConnector(loop=loop, limit=5)\n    conn._release_waiter = mock.Mock()\n\n    conn._acquired.add(proto)\n    conn._acquired_per_host[key].add(proto)\n    conn._closed = True\n    conn._release_acquired(key, proto)\n    assert 1 == len(conn._acquired)\n    assert 1 == len(conn._acquired_per_host[key])\n    assert not conn._release_waiter.called\n    await conn.close()\n\n\nasync def test_release(loop, key) -> None:\n    conn = aiohttp.BaseConnector(loop=loop)\n    conn._release_waiter = mock.Mock()\n\n    proto = mock.Mock(should_close=False)\n\n    conn._acquired.add(proto)\n    conn._acquired_per_host[key].add(proto)\n\n    conn._release(key, proto)\n    assert conn._release_waiter.called\n    assert conn._cleanup_handle is not None\n    assert conn._conns[key][0][0] == proto\n    assert conn._conns[key][0][1] == pytest.approx(loop.time(), abs=0.1)\n    assert not conn._cleanup_closed_transports\n    await conn.close()\n\n\nasync def test_release_ssl_transport(loop, ssl_key) -> None:\n    conn = aiohttp.BaseConnector(loop=loop, enable_cleanup_closed=True)\n    conn._release_waiter = mock.Mock()\n\n    proto = mock.Mock()\n    transport = proto.transport\n    conn._acquired.add(proto)\n    conn._acquired_per_host[ssl_key].add(proto)\n\n    conn._release(ssl_key, proto, should_close=True)\n    assert conn._cleanup_closed_transports == [transport]\n    await conn.close()\n\n\nasync def test_release_already_closed(loop) -> None:\n    conn = aiohttp.BaseConnector(loop=loop)\n\n    proto = mock.Mock()\n    key = 1\n    conn._acquired.add(proto)\n    await conn.close()\n\n    conn._release_waiters = mock.Mock()\n    conn._release_acquired = mock.Mock()\n\n    conn._release(key, proto)\n    assert not conn._release_waiters.called\n    assert not conn._release_acquired.called\n\n\nasync def test_release_waiter_no_limit(loop, key, key2) -> None:\n    # limit is 0\n    conn = aiohttp.BaseConnector(limit=0, loop=loop)\n    w = mock.Mock()\n    w.done.return_value = False\n    conn._waiters[key].append(w)\n    conn._release_waiter()\n    assert len(conn._waiters[key]) == 0\n    assert w.done.called\n    await conn.close()\n\n\nasync def test_release_waiter_first_available(loop, key, key2) -> None:\n    conn = aiohttp.BaseConnector(loop=loop)\n    w1, w2 = mock.Mock(), mock.Mock()\n    w1.done.return_value = False\n    w2.done.return_value = False\n    conn._waiters[key].append(w2)\n    conn._waiters[key2].append(w1)\n    conn._release_waiter()\n    assert (\n        w1.set_result.called\n        and not w2.set_result.called\n        or not w1.set_result.called\n        and w2.set_result.called\n    )\n    await conn.close()\n\n\nasync def test_release_waiter_release_first(loop, key, key2) -> None:\n    conn = aiohttp.BaseConnector(loop=loop, limit=1)\n    w1, w2 = mock.Mock(), mock.Mock()\n    w1.done.return_value = False\n    w2.done.return_value = False\n    conn._waiters[key] = deque([w1, w2])\n    conn._release_waiter()\n    assert w1.set_result.called\n    assert not w2.set_result.called\n    await conn.close()\n\n\nasync def test_release_waiter_skip_done_waiter(loop, key, key2) -> None:\n    conn = aiohttp.BaseConnector(loop=loop, limit=1)\n    w1, w2 = mock.Mock(), mock.Mock()\n    w1.done.return_value = True\n    w2.done.return_value = False\n    conn._waiters[key] = deque([w1, w2])\n    conn._release_waiter()\n    assert not w1.set_result.called\n    assert w2.set_result.called\n    await conn.close()\n\n\nasync def test_release_waiter_per_host(loop, key, key2) -> None:\n    # no limit\n    conn = aiohttp.BaseConnector(loop=loop, limit=0, limit_per_host=2)\n    w1, w2 = mock.Mock(), mock.Mock()\n    w1.done.return_value = False\n    w2.done.return_value = False\n    conn._waiters[key] = deque([w1])\n    conn._waiters[key2] = deque([w2])\n    conn._release_waiter()\n    assert (w1.set_result.called and not w2.set_result.called) or (\n        not w1.set_result.called and w2.set_result.called\n    )\n    await conn.close()\n\n\nasync def test_release_waiter_no_available(loop, key, key2) -> None:\n    # limit is 0\n    conn = aiohttp.BaseConnector(limit=0, loop=loop)\n    w = mock.Mock()\n    w.done.return_value = False\n    conn._waiters[key].append(w)\n    conn._available_connections = mock.Mock(return_value=0)\n    conn._release_waiter()\n    assert len(conn._waiters) == 1\n    assert not w.done.called\n    await conn.close()\n\n\nasync def test_release_close(loop, key) -> None:\n    conn = aiohttp.BaseConnector(loop=loop)\n    proto = mock.Mock(should_close=True)\n\n    conn._acquired.add(proto)\n    conn._release(key, proto)\n    assert not conn._conns\n    assert proto.close.called\n\n\nasync def test__drop_acquire_per_host1(loop) -> None:\n    conn = aiohttp.BaseConnector(loop=loop)\n    conn._drop_acquired_per_host(123, 456)\n    assert len(conn._acquired_per_host) == 0\n\n\nasync def test__drop_acquire_per_host2(loop) -> None:\n    conn = aiohttp.BaseConnector(loop=loop)\n    conn._acquired_per_host[123].add(456)\n    conn._drop_acquired_per_host(123, 456)\n    assert len(conn._acquired_per_host) == 0\n\n\nasync def test__drop_acquire_per_host3(loop) -> None:\n    conn = aiohttp.BaseConnector(loop=loop)\n    conn._acquired_per_host[123].add(456)\n    conn._acquired_per_host[123].add(789)\n    conn._drop_acquired_per_host(123, 456)\n    assert len(conn._acquired_per_host) == 1\n    assert conn._acquired_per_host[123] == {789}\n\n\nasync def test_tcp_connector_certificate_error(\n    loop: Any, start_connection: mock.AsyncMock\n) -> None:\n    req = ClientRequest(\"GET\", URL(\"https://127.0.0.1:443\"), loop=loop)\n\n    async def certificate_error(*args, **kwargs):\n        raise ssl.CertificateError\n\n    conn = aiohttp.TCPConnector(loop=loop)\n    conn._loop.create_connection = certificate_error\n\n    with pytest.raises(aiohttp.ClientConnectorCertificateError) as ctx:\n        await conn.connect(req, [], ClientTimeout())\n\n    assert isinstance(ctx.value, ssl.CertificateError)\n    assert isinstance(ctx.value.certificate_error, ssl.CertificateError)\n    assert isinstance(ctx.value, aiohttp.ClientSSLError)\n\n\nasync def test_tcp_connector_server_hostname_default(\n    loop: Any, start_connection: mock.AsyncMock\n) -> None:\n    conn = aiohttp.TCPConnector()\n\n    with mock.patch.object(\n        conn._loop, \"create_connection\", autospec=True, spec_set=True\n    ) as create_connection:\n        create_connection.return_value = mock.Mock(), mock.Mock()\n\n        req = ClientRequest(\"GET\", URL(\"https://127.0.0.1:443\"), loop=loop)\n\n        with closing(await conn.connect(req, [], ClientTimeout())):\n            assert create_connection.call_args.kwargs[\"server_hostname\"] == \"127.0.0.1\"\n\n\nasync def test_tcp_connector_server_hostname_override(\n    loop: Any, start_connection: mock.AsyncMock\n) -> None:\n    conn = aiohttp.TCPConnector()\n\n    with mock.patch.object(\n        conn._loop, \"create_connection\", autospec=True, spec_set=True\n    ) as create_connection:\n        create_connection.return_value = mock.Mock(), mock.Mock()\n\n        req = ClientRequest(\n            \"GET\", URL(\"https://127.0.0.1:443\"), loop=loop, server_hostname=\"localhost\"\n        )\n\n        with closing(await conn.connect(req, [], ClientTimeout())):\n            assert create_connection.call_args.kwargs[\"server_hostname\"] == \"localhost\"\n\n\nasync def test_tcp_connector_multiple_hosts_errors(loop) -> None:\n    conn = aiohttp.TCPConnector(loop=loop)\n\n    ip1 = \"192.168.1.1\"\n    ip2 = \"192.168.1.2\"\n    ip3 = \"192.168.1.3\"\n    ip4 = \"192.168.1.4\"\n    ip5 = \"192.168.1.5\"\n    ips = [ip1, ip2, ip3, ip4, ip5]\n    addrs_tried = []\n    ips_tried = []\n\n    fingerprint = hashlib.sha256(b\"foo\").digest()\n\n    req = ClientRequest(\n        \"GET\",\n        URL(\"https://mocked.host\"),\n        ssl=aiohttp.Fingerprint(fingerprint),\n        loop=loop,\n    )\n\n    async def _resolve_host(host, port, traces=None):\n        return [\n            {\n                \"hostname\": host,\n                \"host\": ip,\n                \"port\": port,\n                \"family\": socket.AF_INET,\n                \"proto\": 0,\n                \"flags\": socket.AI_NUMERICHOST,\n            }\n            for ip in ips\n        ]\n\n    conn._resolve_host = _resolve_host\n\n    os_error = certificate_error = ssl_error = fingerprint_error = False\n    connected = False\n\n    async def start_connection(*args, **kwargs):\n        addr_infos: List[AddrInfoType] = kwargs[\"addr_infos\"]\n\n        first_addr_info = addr_infos[0]\n        first_addr_info_addr = first_addr_info[-1]\n        addrs_tried.append(first_addr_info_addr)\n\n        mock_socket = mock.create_autospec(socket.socket, spec_set=True, instance=True)\n        mock_socket.getpeername.return_value = first_addr_info_addr\n        return mock_socket\n\n    async def create_connection(*args, **kwargs):\n        nonlocal os_error, certificate_error, ssl_error, fingerprint_error\n        nonlocal connected\n\n        sock = kwargs[\"sock\"]\n        addr_info = sock.getpeername()\n        ip = addr_info[0]\n\n        ips_tried.append(ip)\n\n        if ip == ip1:\n            os_error = True\n            raise OSError\n\n        if ip == ip2:\n            certificate_error = True\n            raise ssl.CertificateError\n\n        if ip == ip3:\n            ssl_error = True\n            raise ssl.SSLError\n\n        if ip == ip4:\n            sock: socket.socket = kwargs[\"sock\"]\n\n            # Close the socket since we are not actually connecting\n            # and we don't want to leak it.\n            sock.close()\n\n            fingerprint_error = True\n            tr, pr = mock.Mock(), mock.Mock()\n\n            def get_extra_info(param):\n                if param == \"sslcontext\":\n                    return True\n\n                if param == \"ssl_object\":\n                    s = mock.Mock()\n                    s.getpeercert.return_value = b\"not foo\"\n                    return s\n\n                if param == \"peername\":\n                    return (\"192.168.1.5\", 12345)\n\n                if param == \"socket\":\n                    return sock\n\n                assert False, param\n\n            tr.get_extra_info = get_extra_info\n            return tr, pr\n\n        if ip == ip5:\n            sock: socket.socket = kwargs[\"sock\"]\n\n            # Close the socket since we are not actually connecting\n            # and we don't want to leak it.\n            sock.close()\n\n            connected = True\n            tr, pr = mock.Mock(), mock.Mock()\n\n            def get_extra_info(param):\n                if param == \"sslcontext\":\n                    return True\n\n                if param == \"ssl_object\":\n                    s = mock.Mock()\n                    s.getpeercert.return_value = b\"foo\"\n                    return s\n\n                assert False\n\n            tr.get_extra_info = get_extra_info\n            return tr, pr\n\n        assert False\n\n    conn._loop.create_connection = create_connection\n\n    with mock.patch(\n        \"aiohttp.connector.aiohappyeyeballs.start_connection\", start_connection\n    ):\n        established_connection = await conn.connect(req, [], ClientTimeout())\n\n    assert ips_tried == ips\n    assert addrs_tried == [(ip, 443) for ip in ips]\n\n    assert os_error\n    assert certificate_error\n    assert ssl_error\n    assert fingerprint_error\n    assert connected\n\n    established_connection.close()\n\n\n@pytest.mark.parametrize(\n    (\"happy_eyeballs_delay\"),\n    [0.1, 0.25, None],\n)\nasync def test_tcp_connector_happy_eyeballs(\n    loop: Any, happy_eyeballs_delay: Optional[float]\n) -> None:\n    conn = aiohttp.TCPConnector(happy_eyeballs_delay=happy_eyeballs_delay)\n\n    ip1 = \"dead::beef::\"\n    ip2 = \"192.168.1.1\"\n    ips = [ip1, ip2]\n    addrs_tried = []\n\n    req = ClientRequest(\n        \"GET\",\n        URL(\"https://mocked.host\"),\n        loop=loop,\n    )\n\n    async def _resolve_host(host, port, traces=None):\n        return [\n            {\n                \"hostname\": host,\n                \"host\": ip,\n                \"port\": port,\n                \"family\": socket.AF_INET6 if \":\" in ip else socket.AF_INET,\n                \"proto\": 0,\n                \"flags\": socket.AI_NUMERICHOST,\n            }\n            for ip in ips\n        ]\n\n    conn._resolve_host = _resolve_host\n\n    os_error = False\n    connected = False\n\n    async def sock_connect(*args, **kwargs):\n        addr = args[1]\n        nonlocal os_error\n\n        addrs_tried.append(addr)\n\n        if addr[0] == ip1:\n            os_error = True\n            raise OSError\n\n    async def create_connection(*args, **kwargs):\n        sock: socket.socket = kwargs[\"sock\"]\n\n        # Close the socket since we are not actually connecting\n        # and we don't want to leak it.\n        sock.close()\n\n        nonlocal connected\n        connected = True\n        tr = create_mocked_conn(loop)\n        pr = create_mocked_conn(loop)\n        return tr, pr\n\n    conn._loop.sock_connect = sock_connect\n    conn._loop.create_connection = create_connection\n\n    established_connection = await conn.connect(req, [], ClientTimeout())\n\n    assert addrs_tried == [(ip1, 443, 0, 0), (ip2, 443)]\n\n    assert os_error\n    assert connected\n\n    established_connection.close()\n\n\nasync def test_tcp_connector_interleave(loop: Any) -> None:\n    conn = aiohttp.TCPConnector(interleave=2)\n\n    ip1 = \"192.168.1.1\"\n    ip2 = \"192.168.1.2\"\n    ip3 = \"dead::beef::\"\n    ip4 = \"aaaa::beef::\"\n    ip5 = \"192.168.1.5\"\n    ips = [ip1, ip2, ip3, ip4, ip5]\n    success_ips = []\n    interleave = None\n\n    req = ClientRequest(\n        \"GET\",\n        URL(\"https://mocked.host\"),\n        loop=loop,\n    )\n\n    async def _resolve_host(host, port, traces=None):\n        return [\n            {\n                \"hostname\": host,\n                \"host\": ip,\n                \"port\": port,\n                \"family\": socket.AF_INET6 if \":\" in ip else socket.AF_INET,\n                \"proto\": 0,\n                \"flags\": socket.AI_NUMERICHOST,\n            }\n            for ip in ips\n        ]\n\n    conn._resolve_host = _resolve_host\n\n    async def start_connection(*args, **kwargs):\n        nonlocal interleave\n        addr_infos: List[AddrInfoType] = kwargs[\"addr_infos\"]\n        interleave = kwargs[\"interleave\"]\n        # Mock the 4th host connecting successfully\n        fourth_addr_info = addr_infos[3]\n        fourth_addr_info_addr = fourth_addr_info[-1]\n        mock_socket = mock.create_autospec(socket.socket, spec_set=True, instance=True)\n        mock_socket.getpeername.return_value = fourth_addr_info_addr\n        return mock_socket\n\n    async def create_connection(*args, **kwargs):\n        sock = kwargs[\"sock\"]\n        addr_info = sock.getpeername()\n        ip = addr_info[0]\n\n        success_ips.append(ip)\n\n        sock: socket.socket = kwargs[\"sock\"]\n        # Close the socket since we are not actually connecting\n        # and we don't want to leak it.\n        sock.close()\n        tr = create_mocked_conn(loop)\n        pr = create_mocked_conn(loop)\n        return tr, pr\n\n    conn._loop.create_connection = create_connection\n\n    with mock.patch(\n        \"aiohttp.connector.aiohappyeyeballs.start_connection\", start_connection\n    ):\n        established_connection = await conn.connect(req, [], ClientTimeout())\n\n    assert success_ips == [ip4]\n    assert interleave == 2\n    established_connection.close()\n\n\nasync def test_tcp_connector_family_is_respected(loop: Any) -> None:\n    conn = aiohttp.TCPConnector(family=socket.AF_INET)\n\n    ip1 = \"dead::beef::\"\n    ip2 = \"192.168.1.1\"\n    ips = [ip1, ip2]\n    addrs_tried = []\n\n    req = ClientRequest(\n        \"GET\",\n        URL(\"https://mocked.host\"),\n        loop=loop,\n    )\n\n    async def _resolve_host(host, port, traces=None):\n        return [\n            {\n                \"hostname\": host,\n                \"host\": ip,\n                \"port\": port,\n                \"family\": socket.AF_INET6 if \":\" in ip else socket.AF_INET,\n                \"proto\": 0,\n                \"flags\": socket.AI_NUMERICHOST,\n            }\n            for ip in ips\n        ]\n\n    conn._resolve_host = _resolve_host\n    connected = False\n\n    async def sock_connect(*args, **kwargs):\n        addr = args[1]\n        addrs_tried.append(addr)\n\n    async def create_connection(*args, **kwargs):\n        sock: socket.socket = kwargs[\"sock\"]\n\n        # Close the socket since we are not actually connecting\n        # and we don't want to leak it.\n        sock.close()\n\n        nonlocal connected\n        connected = True\n        tr = create_mocked_conn(loop)\n        pr = create_mocked_conn(loop)\n        return tr, pr\n\n    conn._loop.sock_connect = sock_connect\n    conn._loop.create_connection = create_connection\n\n    established_connection = await conn.connect(req, [], ClientTimeout())\n\n    # We should only try the IPv4 address since we specified\n    # the family to be AF_INET\n    assert addrs_tried == [(ip2, 443)]\n\n    assert connected\n\n    established_connection.close()\n\n\nasync def test_tcp_connector_resolve_host(loop: Any) -> None:\n    conn = aiohttp.TCPConnector(use_dns_cache=True)\n\n    res = await conn._resolve_host(\"localhost\", 8080)\n    assert res\n    for rec in res:\n        if rec[\"family\"] == socket.AF_INET:\n            assert rec[\"host\"] == \"127.0.0.1\"\n            assert rec[\"hostname\"] == \"localhost\"\n            assert rec[\"port\"] == 8080\n        elif rec[\"family\"] == socket.AF_INET6:\n            assert rec[\"hostname\"] == \"localhost\"\n            assert rec[\"port\"] == 8080\n            if platform.system() == \"Darwin\":\n                assert rec[\"host\"] in (\"::1\", \"fe80::1\", \"fe80::1%lo0\")\n            else:\n                assert rec[\"host\"] == \"::1\"\n\n\n@pytest.fixture\ndef dns_response(loop):\n    async def coro():\n        # simulates a network operation\n        await asyncio.sleep(0)\n        return [\"127.0.0.1\"]\n\n    return coro\n\n\nasync def test_tcp_connector_dns_cache_not_expired(loop, dns_response) -> None:\n    with mock.patch(\"aiohttp.connector.DefaultResolver\") as m_resolver:\n        conn = aiohttp.TCPConnector(loop=loop, use_dns_cache=True, ttl_dns_cache=10)\n        m_resolver().resolve.return_value = dns_response()\n        await conn._resolve_host(\"localhost\", 8080)\n        await conn._resolve_host(\"localhost\", 8080)\n        m_resolver().resolve.assert_called_once_with(\"localhost\", 8080, family=0)\n\n\nasync def test_tcp_connector_dns_cache_forever(loop, dns_response) -> None:\n    with mock.patch(\"aiohttp.connector.DefaultResolver\") as m_resolver:\n        conn = aiohttp.TCPConnector(loop=loop, use_dns_cache=True, ttl_dns_cache=10)\n        m_resolver().resolve.return_value = dns_response()\n        await conn._resolve_host(\"localhost\", 8080)\n        await conn._resolve_host(\"localhost\", 8080)\n        m_resolver().resolve.assert_called_once_with(\"localhost\", 8080, family=0)\n\n\nasync def test_tcp_connector_use_dns_cache_disabled(loop, dns_response) -> None:\n    with mock.patch(\"aiohttp.connector.DefaultResolver\") as m_resolver:\n        conn = aiohttp.TCPConnector(loop=loop, use_dns_cache=False)\n        m_resolver().resolve.side_effect = [dns_response(), dns_response()]\n        await conn._resolve_host(\"localhost\", 8080)\n        await conn._resolve_host(\"localhost\", 8080)\n        m_resolver().resolve.assert_has_calls(\n            [\n                mock.call(\"localhost\", 8080, family=0),\n                mock.call(\"localhost\", 8080, family=0),\n            ]\n        )\n\n\nasync def test_tcp_connector_dns_throttle_requests(loop, dns_response) -> None:\n    with mock.patch(\"aiohttp.connector.DefaultResolver\") as m_resolver:\n        conn = aiohttp.TCPConnector(loop=loop, use_dns_cache=True, ttl_dns_cache=10)\n        m_resolver().resolve.return_value = dns_response()\n        loop.create_task(conn._resolve_host(\"localhost\", 8080))\n        loop.create_task(conn._resolve_host(\"localhost\", 8080))\n        await asyncio.sleep(0)\n        await asyncio.sleep(0)\n        m_resolver().resolve.assert_called_once_with(\"localhost\", 8080, family=0)\n\n\nasync def test_tcp_connector_dns_throttle_requests_exception_spread(loop) -> None:\n    with mock.patch(\"aiohttp.connector.DefaultResolver\") as m_resolver:\n        conn = aiohttp.TCPConnector(loop=loop, use_dns_cache=True, ttl_dns_cache=10)\n        e = Exception()\n        m_resolver().resolve.side_effect = e\n        r1 = loop.create_task(conn._resolve_host(\"localhost\", 8080))\n        r2 = loop.create_task(conn._resolve_host(\"localhost\", 8080))\n        await asyncio.sleep(0)\n        await asyncio.sleep(0)\n        await asyncio.sleep(0)\n        await asyncio.sleep(0)\n        assert r1.exception() == e\n        assert r2.exception() == e\n\n\nasync def test_tcp_connector_dns_throttle_requests_cancelled_when_close(\n    loop, dns_response\n):\n\n    with mock.patch(\"aiohttp.connector.DefaultResolver\") as m_resolver:\n        conn = aiohttp.TCPConnector(loop=loop, use_dns_cache=True, ttl_dns_cache=10)\n        m_resolver().resolve.return_value = dns_response()\n        loop.create_task(conn._resolve_host(\"localhost\", 8080))\n        f = loop.create_task(conn._resolve_host(\"localhost\", 8080))\n\n        await asyncio.sleep(0)\n        await asyncio.sleep(0)\n        await conn.close()\n\n        with pytest.raises(asyncio.CancelledError):\n            await f\n\n\n@pytest.fixture\ndef dns_response_error(loop):\n    async def coro():\n        # simulates a network operation\n        await asyncio.sleep(0)\n        raise socket.gaierror(-3, \"Temporary failure in name resolution\")\n\n    return coro\n\n\nasync def test_tcp_connector_cancel_dns_error_captured(\n    loop, dns_response_error\n) -> None:\n\n    exception_handler_called = False\n\n    def exception_handler(loop, context):\n        nonlocal exception_handler_called\n        exception_handler_called = True\n\n    loop.set_exception_handler(mock.Mock(side_effect=exception_handler))\n\n    with mock.patch(\"aiohttp.connector.DefaultResolver\") as m_resolver:\n        req = ClientRequest(\n            method=\"GET\", url=URL(\"http://temporary-failure:80\"), loop=loop\n        )\n        conn = aiohttp.TCPConnector(\n            use_dns_cache=False,\n        )\n        m_resolver().resolve.return_value = dns_response_error()\n        f = loop.create_task(conn._create_direct_connection(req, [], ClientTimeout(0)))\n\n        await asyncio.sleep(0)\n        f.cancel()\n        with pytest.raises(asyncio.CancelledError):\n            await f\n\n        gc.collect()\n        assert exception_handler_called is False\n\n\nasync def test_tcp_connector_dns_tracing(loop, dns_response) -> None:\n    session = mock.Mock()\n    trace_config_ctx = mock.Mock()\n    on_dns_resolvehost_start = mock.Mock(side_effect=make_mocked_coro(mock.Mock()))\n    on_dns_resolvehost_end = mock.Mock(side_effect=make_mocked_coro(mock.Mock()))\n    on_dns_cache_hit = mock.Mock(side_effect=make_mocked_coro(mock.Mock()))\n    on_dns_cache_miss = mock.Mock(side_effect=make_mocked_coro(mock.Mock()))\n\n    trace_config = aiohttp.TraceConfig(\n        trace_config_ctx_factory=mock.Mock(return_value=trace_config_ctx)\n    )\n    trace_config.on_dns_resolvehost_start.append(on_dns_resolvehost_start)\n    trace_config.on_dns_resolvehost_end.append(on_dns_resolvehost_end)\n    trace_config.on_dns_cache_hit.append(on_dns_cache_hit)\n    trace_config.on_dns_cache_miss.append(on_dns_cache_miss)\n    trace_config.freeze()\n    traces = [Trace(session, trace_config, trace_config.trace_config_ctx())]\n\n    with mock.patch(\"aiohttp.connector.DefaultResolver\") as m_resolver:\n        conn = aiohttp.TCPConnector(loop=loop, use_dns_cache=True, ttl_dns_cache=10)\n\n        m_resolver().resolve.return_value = dns_response()\n\n        await conn._resolve_host(\"localhost\", 8080, traces=traces)\n        on_dns_resolvehost_start.assert_called_once_with(\n            session,\n            trace_config_ctx,\n            aiohttp.TraceDnsResolveHostStartParams(\"localhost\"),\n        )\n        on_dns_resolvehost_end.assert_called_once_with(\n            session, trace_config_ctx, aiohttp.TraceDnsResolveHostEndParams(\"localhost\")\n        )\n        on_dns_cache_miss.assert_called_once_with(\n            session, trace_config_ctx, aiohttp.TraceDnsCacheMissParams(\"localhost\")\n        )\n        assert not on_dns_cache_hit.called\n\n        await conn._resolve_host(\"localhost\", 8080, traces=traces)\n        on_dns_cache_hit.assert_called_once_with(\n            session, trace_config_ctx, aiohttp.TraceDnsCacheHitParams(\"localhost\")\n        )\n\n\nasync def test_tcp_connector_dns_tracing_cache_disabled(loop, dns_response) -> None:\n    session = mock.Mock()\n    trace_config_ctx = mock.Mock()\n    on_dns_resolvehost_start = mock.Mock(side_effect=make_mocked_coro(mock.Mock()))\n    on_dns_resolvehost_end = mock.Mock(side_effect=make_mocked_coro(mock.Mock()))\n\n    trace_config = aiohttp.TraceConfig(\n        trace_config_ctx_factory=mock.Mock(return_value=trace_config_ctx)\n    )\n    trace_config.on_dns_resolvehost_start.append(on_dns_resolvehost_start)\n    trace_config.on_dns_resolvehost_end.append(on_dns_resolvehost_end)\n    trace_config.freeze()\n    traces = [Trace(session, trace_config, trace_config.trace_config_ctx())]\n\n    with mock.patch(\"aiohttp.connector.DefaultResolver\") as m_resolver:\n        conn = aiohttp.TCPConnector(loop=loop, use_dns_cache=False)\n\n        m_resolver().resolve.side_effect = [dns_response(), dns_response()]\n\n        await conn._resolve_host(\"localhost\", 8080, traces=traces)\n\n        await conn._resolve_host(\"localhost\", 8080, traces=traces)\n\n        on_dns_resolvehost_start.assert_has_calls(\n            [\n                mock.call(\n                    session,\n                    trace_config_ctx,\n                    aiohttp.TraceDnsResolveHostStartParams(\"localhost\"),\n                ),\n                mock.call(\n                    session,\n                    trace_config_ctx,\n                    aiohttp.TraceDnsResolveHostStartParams(\"localhost\"),\n                ),\n            ]\n        )\n        on_dns_resolvehost_end.assert_has_calls(\n            [\n                mock.call(\n                    session,\n                    trace_config_ctx,\n                    aiohttp.TraceDnsResolveHostEndParams(\"localhost\"),\n                ),\n                mock.call(\n                    session,\n                    trace_config_ctx,\n                    aiohttp.TraceDnsResolveHostEndParams(\"localhost\"),\n                ),\n            ]\n        )\n\n\nasync def test_tcp_connector_dns_tracing_throttle_requests(loop, dns_response) -> None:\n    session = mock.Mock()\n    trace_config_ctx = mock.Mock()\n    on_dns_cache_hit = mock.Mock(side_effect=make_mocked_coro(mock.Mock()))\n    on_dns_cache_miss = mock.Mock(side_effect=make_mocked_coro(mock.Mock()))\n\n    trace_config = aiohttp.TraceConfig(\n        trace_config_ctx_factory=mock.Mock(return_value=trace_config_ctx)\n    )\n    trace_config.on_dns_cache_hit.append(on_dns_cache_hit)\n    trace_config.on_dns_cache_miss.append(on_dns_cache_miss)\n    trace_config.freeze()\n    traces = [Trace(session, trace_config, trace_config.trace_config_ctx())]\n\n    with mock.patch(\"aiohttp.connector.DefaultResolver\") as m_resolver:\n        conn = aiohttp.TCPConnector(loop=loop, use_dns_cache=True, ttl_dns_cache=10)\n        m_resolver().resolve.return_value = dns_response()\n        loop.create_task(conn._resolve_host(\"localhost\", 8080, traces=traces))\n        loop.create_task(conn._resolve_host(\"localhost\", 8080, traces=traces))\n        await asyncio.sleep(0)\n        await asyncio.sleep(0)\n        on_dns_cache_hit.assert_called_once_with(\n            session, trace_config_ctx, aiohttp.TraceDnsCacheHitParams(\"localhost\")\n        )\n        on_dns_cache_miss.assert_called_once_with(\n            session, trace_config_ctx, aiohttp.TraceDnsCacheMissParams(\"localhost\")\n        )\n\n\nasync def test_dns_error(loop) -> None:\n    connector = aiohttp.TCPConnector(loop=loop)\n    connector._resolve_host = make_mocked_coro(\n        raise_exception=OSError(\"dont take it serious\")\n    )\n\n    req = ClientRequest(\"GET\", URL(\"http://www.python.org\"), loop=loop)\n\n    with pytest.raises(aiohttp.ClientConnectorError):\n        await connector.connect(req, [], ClientTimeout())\n\n\nasync def test_get_pop_empty_conns(loop) -> None:\n    # see issue #473\n    conn = aiohttp.BaseConnector(loop=loop)\n    key = (\"127.0.0.1\", 80, False)\n    conn._conns[key] = []\n    proto = conn._get(key)\n    assert proto is None\n    assert not conn._conns\n\n\nasync def test_release_close_do_not_add_to_pool(loop, key) -> None:\n    # see issue #473\n    conn = aiohttp.BaseConnector(loop=loop)\n\n    proto = mock.Mock(should_close=True)\n\n    conn._acquired.add(proto)\n    conn._release(key, proto)\n    assert not conn._conns\n\n\nasync def test_release_close_do_not_delete_existing_connections(key) -> None:\n    proto1 = mock.Mock()\n\n    conn = aiohttp.BaseConnector()\n    conn._conns[key] = [(proto1, 1)]\n\n    proto = mock.Mock(should_close=True)\n    conn._acquired.add(proto)\n    conn._release(key, proto)\n    assert conn._conns[key] == [(proto1, 1)]\n    assert proto.close.called\n    await conn.close()\n\n\nasync def test_release_not_started(loop) -> None:\n    conn = aiohttp.BaseConnector(loop=loop)\n    proto = mock.Mock(should_close=False)\n    key = 1\n    conn._acquired.add(proto)\n    conn._release(key, proto)\n    # assert conn._conns == {1: [(proto, 10)]}\n    rec = conn._conns[1]\n    assert rec[0][0] == proto\n    assert rec[0][1] == pytest.approx(loop.time(), abs=0.05)\n    assert not proto.close.called\n    await conn.close()\n\n\nasync def test_release_not_opened(loop, key) -> None:\n    conn = aiohttp.BaseConnector(loop=loop)\n\n    proto = mock.Mock()\n    conn._acquired.add(proto)\n    conn._release(key, proto)\n    assert proto.close.called\n\n\nasync def test_connect(loop, key) -> None:\n    proto = mock.Mock()\n    proto.is_connected.return_value = True\n\n    req = ClientRequest(\"GET\", URL(\"http://localhost:80\"), loop=loop)\n\n    conn = aiohttp.BaseConnector(loop=loop)\n    conn._conns[key] = [(proto, loop.time())]\n    conn._create_connection = mock.Mock()\n    conn._create_connection.return_value = loop.create_future()\n    conn._create_connection.return_value.set_result(proto)\n\n    connection = await conn.connect(req, [], ClientTimeout())\n    assert not conn._create_connection.called\n    assert connection._protocol is proto\n    assert connection.transport is proto.transport\n    assert isinstance(connection, Connection)\n    connection.close()\n\n\nasync def test_connect_tracing(loop) -> None:\n    session = mock.Mock()\n    trace_config_ctx = mock.Mock()\n    on_connection_create_start = mock.Mock(side_effect=make_mocked_coro(mock.Mock()))\n    on_connection_create_end = mock.Mock(side_effect=make_mocked_coro(mock.Mock()))\n\n    trace_config = aiohttp.TraceConfig(\n        trace_config_ctx_factory=mock.Mock(return_value=trace_config_ctx)\n    )\n    trace_config.on_connection_create_start.append(on_connection_create_start)\n    trace_config.on_connection_create_end.append(on_connection_create_end)\n    trace_config.freeze()\n    traces = [Trace(session, trace_config, trace_config.trace_config_ctx())]\n\n    proto = mock.Mock()\n    proto.is_connected.return_value = True\n\n    req = ClientRequest(\"GET\", URL(\"http://host:80\"), loop=loop)\n\n    conn = aiohttp.BaseConnector(loop=loop)\n    conn._create_connection = mock.Mock()\n    conn._create_connection.return_value = loop.create_future()\n    conn._create_connection.return_value.set_result(proto)\n\n    conn2 = await conn.connect(req, traces, ClientTimeout())\n    conn2.release()\n\n    on_connection_create_start.assert_called_with(\n        session, trace_config_ctx, aiohttp.TraceConnectionCreateStartParams()\n    )\n    on_connection_create_end.assert_called_with(\n        session, trace_config_ctx, aiohttp.TraceConnectionCreateEndParams()\n    )\n\n\nasync def test_close_during_connect(loop) -> None:\n    proto = mock.Mock()\n    proto.is_connected.return_value = True\n\n    fut = loop.create_future()\n    req = ClientRequest(\"GET\", URL(\"http://host:80\"), loop=loop)\n\n    conn = aiohttp.BaseConnector(loop=loop)\n    conn._create_connection = mock.Mock()\n    conn._create_connection.return_value = fut\n\n    task = loop.create_task(conn.connect(req, None, ClientTimeout()))\n    await asyncio.sleep(0)\n    await conn.close()\n\n    fut.set_result(proto)\n    with pytest.raises(aiohttp.ClientConnectionError):\n        await task\n\n    assert proto.close.called\n\n\nasync def test_ctor_cleanup() -> None:\n    loop = mock.Mock()\n    loop.time.return_value = 1.5\n    conn = aiohttp.BaseConnector(\n        loop=loop, keepalive_timeout=10, enable_cleanup_closed=True\n    )\n    assert conn._cleanup_handle is None\n    assert conn._cleanup_closed_handle is not None\n\n\nasync def test_cleanup(key) -> None:\n    testset = {\n        key: [(mock.Mock(), 10), (mock.Mock(), 300)],\n    }\n    testset[key][0][0].is_connected.return_value = True\n    testset[key][1][0].is_connected.return_value = False\n\n    loop = mock.Mock()\n    loop.time.return_value = 300\n    conn = aiohttp.BaseConnector(loop=loop)\n    conn._conns = testset\n    existing_handle = conn._cleanup_handle = mock.Mock()\n\n    conn._cleanup()\n    assert existing_handle.cancel.called\n    assert conn._conns == {}\n    assert conn._cleanup_handle is None\n\n\nasync def test_cleanup_close_ssl_transport(ssl_key) -> None:\n    proto = mock.Mock()\n    transport = proto.transport\n    testset = {ssl_key: [(proto, 10)]}\n\n    loop = mock.Mock()\n    loop.time.return_value = 300\n    conn = aiohttp.BaseConnector(loop=loop, enable_cleanup_closed=True)\n    conn._conns = testset\n    existing_handle = conn._cleanup_handle = mock.Mock()\n\n    conn._cleanup()\n    assert existing_handle.cancel.called\n    assert conn._conns == {}\n    assert conn._cleanup_closed_transports == [transport]\n\n\nasync def test_cleanup2() -> None:\n    testset = {1: [(mock.Mock(), 300)]}\n    testset[1][0][0].is_connected.return_value = True\n\n    loop = mock.Mock()\n    loop.time.return_value = 300\n\n    conn = aiohttp.BaseConnector(loop=loop, keepalive_timeout=10)\n    conn._conns = testset\n    conn._cleanup()\n    assert conn._conns == testset\n\n    assert conn._cleanup_handle is not None\n    loop.call_at.assert_called_with(310, mock.ANY, mock.ANY)\n    await conn.close()\n\n\nasync def test_cleanup3(key) -> None:\n    testset = {key: [(mock.Mock(), 290.1), (mock.Mock(), 305.1)]}\n    testset[key][0][0].is_connected.return_value = True\n\n    loop = mock.Mock()\n    loop.time.return_value = 308.5\n\n    conn = aiohttp.BaseConnector(loop=loop, keepalive_timeout=10)\n    conn._conns = testset\n\n    conn._cleanup()\n    assert conn._conns == {key: [testset[key][1]]}\n\n    assert conn._cleanup_handle is not None\n    loop.call_at.assert_called_with(319, mock.ANY, mock.ANY)\n    await conn.close()\n\n\nasync def test_cleanup_closed(loop, mocker) -> None:\n    if not hasattr(loop, \"__dict__\"):\n        pytest.skip(\"can not override loop attributes\")\n\n    mocker.spy(loop, \"call_at\")\n    conn = aiohttp.BaseConnector(loop=loop, enable_cleanup_closed=True)\n\n    tr = mock.Mock()\n    conn._cleanup_closed_handle = cleanup_closed_handle = mock.Mock()\n    conn._cleanup_closed_transports = [tr]\n    conn._cleanup_closed()\n    assert tr.abort.called\n    assert not conn._cleanup_closed_transports\n    assert loop.call_at.called\n    assert cleanup_closed_handle.cancel.called\n\n\nasync def test_cleanup_closed_disabled(loop, mocker) -> None:\n    conn = aiohttp.BaseConnector(loop=loop, enable_cleanup_closed=False)\n\n    tr = mock.Mock()\n    conn._cleanup_closed_transports = [tr]\n    conn._cleanup_closed()\n    assert tr.abort.called\n    assert not conn._cleanup_closed_transports\n\n\nasync def test_tcp_connector_ctor() -> None:\n    conn = aiohttp.TCPConnector()\n    assert conn._ssl is True\n\n    assert conn.use_dns_cache\n    assert conn.family == 0\n\n\nasync def test_tcp_connector_allowed_protocols(loop: asyncio.AbstractEventLoop) -> None:\n    conn = aiohttp.TCPConnector()\n    assert conn.allowed_protocol_schema_set == {\"\", \"tcp\", \"http\", \"https\", \"ws\", \"wss\"}\n\n\nasync def test_invalid_ssl_param() -> None:\n    with pytest.raises(TypeError):\n        aiohttp.TCPConnector(ssl=object())  # type: ignore[arg-type]\n\n\nasync def test_tcp_connector_ctor_fingerprint_valid(\n    loop: asyncio.AbstractEventLoop,\n) -> None:\n    valid = aiohttp.Fingerprint(hashlib.sha256(b\"foo\").digest())\n    conn = aiohttp.TCPConnector(ssl=valid, loop=loop)\n    assert conn._ssl is valid\n\n\nasync def test_insecure_fingerprint_md5(loop) -> None:\n    with pytest.raises(ValueError):\n        aiohttp.TCPConnector(\n            ssl=aiohttp.Fingerprint(hashlib.md5(b\"foo\").digest()), loop=loop\n        )\n\n\nasync def test_insecure_fingerprint_sha1(loop) -> None:\n    with pytest.raises(ValueError):\n        aiohttp.TCPConnector(\n            ssl=aiohttp.Fingerprint(hashlib.sha1(b\"foo\").digest()), loop=loop\n        )\n\n\nasync def test_tcp_connector_clear_dns_cache(loop) -> None:\n    conn = aiohttp.TCPConnector(loop=loop)\n    hosts = [\"a\", \"b\"]\n    conn._cached_hosts.add((\"localhost\", 123), hosts)\n    conn._cached_hosts.add((\"localhost\", 124), hosts)\n    conn.clear_dns_cache(\"localhost\", 123)\n    with pytest.raises(KeyError):\n        conn._cached_hosts.next_addrs((\"localhost\", 123))\n\n    assert conn._cached_hosts.next_addrs((\"localhost\", 124)) == hosts\n\n    # Remove removed element is OK\n    conn.clear_dns_cache(\"localhost\", 123)\n    with pytest.raises(KeyError):\n        conn._cached_hosts.next_addrs((\"localhost\", 123))\n\n    conn.clear_dns_cache()\n    with pytest.raises(KeyError):\n        conn._cached_hosts.next_addrs((\"localhost\", 124))\n\n\nasync def test_tcp_connector_clear_dns_cache_bad_args(loop) -> None:\n    conn = aiohttp.TCPConnector(loop=loop)\n    with pytest.raises(ValueError):\n        conn.clear_dns_cache(\"localhost\")\n\n\nasync def test_dont_recreate_ssl_context() -> None:\n    conn = aiohttp.TCPConnector()\n    ctx = await conn._make_or_get_ssl_context(True)\n    assert ctx is await conn._make_or_get_ssl_context(True)\n\n\nasync def test_dont_recreate_ssl_context2() -> None:\n    conn = aiohttp.TCPConnector()\n    ctx = await conn._make_or_get_ssl_context(False)\n    assert ctx is await conn._make_or_get_ssl_context(False)\n\n\nasync def test___get_ssl_context1() -> None:\n    conn = aiohttp.TCPConnector()\n    req = mock.Mock()\n    req.is_ssl.return_value = False\n    assert await conn._get_ssl_context(req) is None\n\n\nasync def test___get_ssl_context2(loop) -> None:\n    ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)\n    conn = aiohttp.TCPConnector(loop=loop)\n    req = mock.Mock()\n    req.is_ssl.return_value = True\n    req.ssl = ctx\n    assert await conn._get_ssl_context(req) is ctx\n\n\nasync def test___get_ssl_context3(loop) -> None:\n    ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)\n    conn = aiohttp.TCPConnector(loop=loop, ssl=ctx)\n    req = mock.Mock()\n    req.is_ssl.return_value = True\n    req.ssl = True\n    assert await conn._get_ssl_context(req) is ctx\n\n\nasync def test___get_ssl_context4(loop) -> None:\n    ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)\n    conn = aiohttp.TCPConnector(loop=loop, ssl=ctx)\n    req = mock.Mock()\n    req.is_ssl.return_value = True\n    req.ssl = False\n    assert await conn._get_ssl_context(req) is await conn._make_or_get_ssl_context(\n        False\n    )\n\n\nasync def test___get_ssl_context5(loop) -> None:\n    ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)\n    conn = aiohttp.TCPConnector(loop=loop, ssl=ctx)\n    req = mock.Mock()\n    req.is_ssl.return_value = True\n    req.ssl = aiohttp.Fingerprint(hashlib.sha256(b\"1\").digest())\n    assert await conn._get_ssl_context(req) is await conn._make_or_get_ssl_context(\n        False\n    )\n\n\nasync def test___get_ssl_context6() -> None:\n    conn = aiohttp.TCPConnector()\n    req = mock.Mock()\n    req.is_ssl.return_value = True\n    req.ssl = True\n    assert await conn._get_ssl_context(req) is await conn._make_or_get_ssl_context(True)\n\n\nasync def test_ssl_context_once() -> None:\n    \"\"\"Test the ssl context is created only once and shared between connectors.\"\"\"\n    conn1 = aiohttp.TCPConnector()\n    conn2 = aiohttp.TCPConnector()\n    conn3 = aiohttp.TCPConnector()\n\n    req = mock.Mock()\n    req.is_ssl.return_value = True\n    req.ssl = True\n    assert await conn1._get_ssl_context(req) is await conn1._make_or_get_ssl_context(\n        True\n    )\n    assert await conn2._get_ssl_context(req) is await conn1._make_or_get_ssl_context(\n        True\n    )\n    assert await conn3._get_ssl_context(req) is await conn1._make_or_get_ssl_context(\n        True\n    )\n    assert conn1._made_ssl_context is conn2._made_ssl_context is conn3._made_ssl_context\n    assert True in conn1._made_ssl_context\n\n\n@pytest.mark.parametrize(\"exception\", [OSError, ssl.SSLError, asyncio.CancelledError])\nasync def test_ssl_context_creation_raises(exception: Type[BaseException]) -> None:\n    \"\"\"Test that we try again if SSLContext creation fails the first time.\"\"\"\n    conn = aiohttp.TCPConnector()\n    conn._made_ssl_context.clear()\n\n    with mock.patch.object(\n        conn, \"_make_ssl_context\", side_effect=exception\n    ), pytest.raises(exception):\n        await conn._make_or_get_ssl_context(True)\n\n    assert isinstance(await conn._make_or_get_ssl_context(True), ssl.SSLContext)\n\n\nasync def test_close_twice(loop) -> None:\n    proto = mock.Mock()\n\n    conn = aiohttp.BaseConnector(loop=loop)\n    conn._conns[1] = [(proto, object())]\n    await conn.close()\n\n    assert not conn._conns\n    assert proto.close.called\n    assert conn.closed\n\n    conn._conns = \"Invalid\"  # fill with garbage\n    await conn.close()\n    assert conn.closed\n\n\nasync def test_close_cancels_cleanup_handle(loop) -> None:\n    conn = aiohttp.BaseConnector(loop=loop)\n    conn._release(1, mock.Mock(should_close=False))\n    assert conn._cleanup_handle is not None\n    await conn.close()\n    assert conn._cleanup_handle is None\n\n\nasync def test_close_cancels_resolve_host(loop: asyncio.AbstractEventLoop) -> None:\n    cancelled = False\n\n    async def delay_resolve_host(*args: object) -> None:\n        \"\"\"Delay _resolve_host() task in order to test cancellation.\"\"\"\n        nonlocal cancelled\n        try:\n            await asyncio.sleep(10)\n        except asyncio.CancelledError:\n            cancelled = True\n            raise\n\n    conn = aiohttp.TCPConnector()\n    req = ClientRequest(\n        \"GET\", URL(\"http://localhost:80\"), loop=loop, response_class=mock.Mock()\n    )\n    with mock.patch.object(conn, \"_resolve_host_with_throttle\", delay_resolve_host):\n        t = asyncio.create_task(conn.connect(req, [], ClientTimeout()))\n        # Let it create the internal task\n        await asyncio.sleep(0)\n        # Let that task start running\n        await asyncio.sleep(0)\n\n        # We now have a task being tracked and can ensure that .close() cancels it.\n        assert len(conn._resolve_host_tasks) == 1\n        await conn.close()\n        await asyncio.sleep(0.01)\n        assert cancelled\n        assert len(conn._resolve_host_tasks) == 0\n\n        with suppress(asyncio.CancelledError):\n            await t\n\n\nasync def test_close_abort_closed_transports(loop: asyncio.AbstractEventLoop) -> None:\n    tr = mock.Mock()\n\n    conn = aiohttp.BaseConnector(loop=loop)\n    conn._cleanup_closed_transports.append(tr)\n    await conn.close()\n\n    assert not conn._cleanup_closed_transports\n    assert tr.abort.called\n    assert conn.closed\n\n\nasync def test_close_cancels_cleanup_closed_handle(loop) -> None:\n    conn = aiohttp.BaseConnector(loop=loop, enable_cleanup_closed=True)\n    assert conn._cleanup_closed_handle is not None\n    await conn.close()\n    assert conn._cleanup_closed_handle is None\n\n\nasync def test_ctor_with_default_loop(loop) -> None:\n    conn = aiohttp.BaseConnector()\n    assert loop is conn._loop\n\n\nasync def test_base_connector_allows_high_level_protocols(\n    loop: asyncio.AbstractEventLoop,\n) -> None:\n    conn = aiohttp.BaseConnector()\n    assert conn.allowed_protocol_schema_set == {\n        \"\",\n        \"http\",\n        \"https\",\n        \"ws\",\n        \"wss\",\n    }\n\n\nasync def test_connect_with_limit(\n    loop: asyncio.AbstractEventLoop, key: ConnectionKey\n) -> None:\n    proto = create_mocked_conn(loop)\n    proto.is_connected.return_value = True\n\n    req = ClientRequest(\n        \"GET\", URL(\"http://localhost:80\"), loop=loop, response_class=mock.Mock()\n    )\n\n    conn = aiohttp.BaseConnector(loop=loop, limit=1)\n    conn._conns[key] = [(proto, loop.time())]\n    conn._create_connection = mock.Mock()\n    conn._create_connection.return_value = loop.create_future()\n    conn._create_connection.return_value.set_result(proto)\n\n    connection1 = await conn.connect(req, None, ClientTimeout())\n    assert connection1._protocol == proto\n\n    assert 1 == len(conn._acquired)\n    assert proto in conn._acquired\n    assert key in conn._acquired_per_host\n    assert proto in conn._acquired_per_host[key]\n\n    acquired = False\n\n    async def f():\n        nonlocal acquired\n        connection2 = await conn.connect(req, None, ClientTimeout())\n        acquired = True\n        assert 1 == len(conn._acquired)\n        assert 1 == len(conn._acquired_per_host[key])\n        connection2.release()\n\n    task = loop.create_task(f())\n\n    await asyncio.sleep(0.01)\n    assert not acquired\n    connection1.release()\n    await asyncio.sleep(0)\n    assert acquired\n    await task\n    await conn.close()\n\n\nasync def test_connect_queued_operation_tracing(loop, key) -> None:\n    session = mock.Mock()\n    trace_config_ctx = mock.Mock()\n    on_connection_queued_start = mock.Mock(side_effect=make_mocked_coro(mock.Mock()))\n    on_connection_queued_end = mock.Mock(side_effect=make_mocked_coro(mock.Mock()))\n\n    trace_config = aiohttp.TraceConfig(\n        trace_config_ctx_factory=mock.Mock(return_value=trace_config_ctx)\n    )\n    trace_config.on_connection_queued_start.append(on_connection_queued_start)\n    trace_config.on_connection_queued_end.append(on_connection_queued_end)\n    trace_config.freeze()\n    traces = [Trace(session, trace_config, trace_config.trace_config_ctx())]\n\n    proto = mock.Mock()\n    proto.is_connected.return_value = True\n\n    req = ClientRequest(\n        \"GET\", URL(\"http://localhost1:80\"), loop=loop, response_class=mock.Mock()\n    )\n\n    conn = aiohttp.BaseConnector(loop=loop, limit=1)\n    conn._conns[key] = [(proto, loop.time())]\n    conn._create_connection = mock.Mock()\n    conn._create_connection.return_value = loop.create_future()\n    conn._create_connection.return_value.set_result(proto)\n\n    connection1 = await conn.connect(req, traces, ClientTimeout())\n\n    async def f():\n        connection2 = await conn.connect(req, traces, ClientTimeout())\n        on_connection_queued_start.assert_called_with(\n            session, trace_config_ctx, aiohttp.TraceConnectionQueuedStartParams()\n        )\n        on_connection_queued_end.assert_called_with(\n            session, trace_config_ctx, aiohttp.TraceConnectionQueuedEndParams()\n        )\n        connection2.release()\n\n    task = asyncio.ensure_future(f(), loop=loop)\n    await asyncio.sleep(0.01)\n    connection1.release()\n    await task\n    await conn.close()\n\n\nasync def test_connect_reuseconn_tracing(loop, key) -> None:\n    session = mock.Mock()\n    trace_config_ctx = mock.Mock()\n    on_connection_reuseconn = mock.Mock(side_effect=make_mocked_coro(mock.Mock()))\n\n    trace_config = aiohttp.TraceConfig(\n        trace_config_ctx_factory=mock.Mock(return_value=trace_config_ctx)\n    )\n    trace_config.on_connection_reuseconn.append(on_connection_reuseconn)\n    trace_config.freeze()\n    traces = [Trace(session, trace_config, trace_config.trace_config_ctx())]\n\n    proto = mock.Mock()\n    proto.is_connected.return_value = True\n\n    req = ClientRequest(\n        \"GET\", URL(\"http://localhost:80\"), loop=loop, response_class=mock.Mock()\n    )\n\n    conn = aiohttp.BaseConnector(loop=loop, limit=1)\n    conn._conns[key] = [(proto, loop.time())]\n    conn2 = await conn.connect(req, traces, ClientTimeout())\n    conn2.release()\n\n    on_connection_reuseconn.assert_called_with(\n        session, trace_config_ctx, aiohttp.TraceConnectionReuseconnParams()\n    )\n    await conn.close()\n\n\nasync def test_connect_with_limit_and_limit_per_host(loop, key) -> None:\n    proto = mock.Mock()\n    proto.is_connected.return_value = True\n\n    req = ClientRequest(\"GET\", URL(\"http://localhost:80\"), loop=loop)\n\n    conn = aiohttp.BaseConnector(loop=loop, limit=1000, limit_per_host=1)\n    conn._conns[key] = [(proto, loop.time())]\n    conn._create_connection = mock.Mock()\n    conn._create_connection.return_value = loop.create_future()\n    conn._create_connection.return_value.set_result(proto)\n\n    acquired = False\n    connection1 = await conn.connect(req, None, ClientTimeout())\n\n    async def f():\n        nonlocal acquired\n        connection2 = await conn.connect(req, None, ClientTimeout())\n        acquired = True\n        assert 1 == len(conn._acquired)\n        assert 1 == len(conn._acquired_per_host[key])\n        connection2.release()\n\n    task = loop.create_task(f())\n\n    await asyncio.sleep(0.01)\n    assert not acquired\n    connection1.release()\n    await asyncio.sleep(0)\n    assert acquired\n    await task\n    await conn.close()\n\n\nasync def test_connect_with_no_limit_and_limit_per_host(loop, key) -> None:\n    proto = mock.Mock()\n    proto.is_connected.return_value = True\n\n    req = ClientRequest(\"GET\", URL(\"http://localhost1:80\"), loop=loop)\n\n    conn = aiohttp.BaseConnector(loop=loop, limit=0, limit_per_host=1)\n    conn._conns[key] = [(proto, loop.time())]\n    conn._create_connection = mock.Mock()\n    conn._create_connection.return_value = loop.create_future()\n    conn._create_connection.return_value.set_result(proto)\n\n    acquired = False\n    connection1 = await conn.connect(req, None, ClientTimeout())\n\n    async def f():\n        nonlocal acquired\n        connection2 = await conn.connect(req, None, ClientTimeout())\n        acquired = True\n        connection2.release()\n\n    task = loop.create_task(f())\n\n    await asyncio.sleep(0.01)\n    assert not acquired\n    connection1.release()\n    await asyncio.sleep(0)\n    assert acquired\n    await task\n    await conn.close()\n\n\nasync def test_connect_with_no_limits(loop, key) -> None:\n    proto = mock.Mock()\n    proto.is_connected.return_value = True\n\n    req = ClientRequest(\"GET\", URL(\"http://localhost:80\"), loop=loop)\n\n    conn = aiohttp.BaseConnector(loop=loop, limit=0, limit_per_host=0)\n    conn._conns[key] = [(proto, loop.time())]\n    conn._create_connection = mock.Mock()\n    conn._create_connection.return_value = loop.create_future()\n    conn._create_connection.return_value.set_result(proto)\n\n    acquired = False\n    connection1 = await conn.connect(req, None, ClientTimeout())\n\n    async def f():\n        nonlocal acquired\n        connection2 = await conn.connect(req, None, ClientTimeout())\n        acquired = True\n        assert 1 == len(conn._acquired)\n        assert 1 == len(conn._acquired_per_host[key])\n        connection2.release()\n\n    task = loop.create_task(f())\n\n    await asyncio.sleep(0.01)\n    assert acquired\n    connection1.release()\n    await task\n    await conn.close()\n\n\nasync def test_connect_with_limit_cancelled(loop) -> None:\n\n    proto = mock.Mock()\n    proto.is_connected.return_value = True\n\n    req = ClientRequest(\"GET\", URL(\"http://host:80\"), loop=loop)\n\n    conn = aiohttp.BaseConnector(loop=loop, limit=1)\n    key = (\"host\", 80, False)\n    conn._conns[key] = [(proto, loop.time())]\n    conn._create_connection = mock.Mock()\n    conn._create_connection.return_value = loop.create_future()\n    conn._create_connection.return_value.set_result(proto)\n\n    connection = await conn.connect(req, None, ClientTimeout())\n    assert connection._protocol == proto\n    assert connection.transport == proto.transport\n\n    assert 1 == len(conn._acquired)\n\n    with pytest.raises(asyncio.TimeoutError):\n        # limit exhausted\n        await asyncio.wait_for(conn.connect(req, None, ClientTimeout()), 0.01)\n    connection.close()\n\n    await conn.close()\n\n\nasync def test_connect_with_capacity_release_waiters(loop) -> None:\n    def check_with_exc(err):\n        conn = aiohttp.BaseConnector(limit=1, loop=loop)\n        conn._create_connection = mock.Mock()\n        conn._create_connection.return_value = loop.create_future()\n        conn._create_connection.return_value.set_exception(err)\n\n        with pytest.raises(Exception):\n            req = mock.Mock()\n            yield from conn.connect(req, None, ClientTimeout())\n\n        assert not conn._waiters\n\n    check_with_exc(OSError(1, \"permission error\"))\n    check_with_exc(RuntimeError())\n    check_with_exc(asyncio.TimeoutError())\n\n\nasync def test_connect_with_limit_concurrent(loop) -> None:\n    proto = mock.Mock()\n    proto.should_close = False\n    proto.is_connected.return_value = True\n\n    req = ClientRequest(\"GET\", URL(\"http://host:80\"), loop=loop)\n\n    max_connections = 2\n    num_connections = 0\n\n    conn = aiohttp.BaseConnector(limit=max_connections, loop=loop)\n\n    # Use a real coroutine for _create_connection; a mock would mask\n    # problems that only happen when the method yields.\n\n    async def create_connection(req, traces, timeout):\n        nonlocal num_connections\n        num_connections += 1\n        await asyncio.sleep(0)\n\n        # Make a new transport mock each time because acquired\n        # transports are stored in a set. Reusing the same object\n        # messes with the count.\n        proto = mock.Mock(should_close=False)\n        proto.is_connected.return_value = True\n\n        return proto\n\n    conn._create_connection = create_connection\n\n    # Simulate something like a crawler. It opens a connection, does\n    # something with it, closes it, then creates tasks that make more\n    # connections and waits for them to finish. The crawler is started\n    # with multiple concurrent requests and stops when it hits a\n    # predefined maximum number of requests.\n\n    max_requests = 50\n    num_requests = 0\n    start_requests = max_connections + 1\n\n    async def f(start=True):\n        nonlocal num_requests\n        if num_requests == max_requests:\n            return\n        num_requests += 1\n        if not start:\n            connection = await conn.connect(req, None, ClientTimeout())\n            await asyncio.sleep(0)\n            connection.release()\n            await asyncio.sleep(0)\n        tasks = [loop.create_task(f(start=False)) for i in range(start_requests)]\n        await asyncio.wait(tasks)\n\n    await f()\n    await conn.close()\n\n    assert max_connections == num_connections\n\n\nasync def test_connect_waiters_cleanup(loop) -> None:\n    proto = mock.Mock()\n    proto.is_connected.return_value = True\n\n    req = ClientRequest(\"GET\", URL(\"http://host:80\"), loop=loop)\n\n    conn = aiohttp.BaseConnector(loop=loop, limit=1)\n    conn._available_connections = mock.Mock(return_value=0)\n\n    t = loop.create_task(conn.connect(req, None, ClientTimeout()))\n\n    await asyncio.sleep(0)\n    assert conn._waiters.keys()\n\n    t.cancel()\n    await asyncio.sleep(0)\n    assert not conn._waiters.keys()\n\n\nasync def test_connect_waiters_cleanup_key_error(loop) -> None:\n    proto = mock.Mock()\n    proto.is_connected.return_value = True\n\n    req = ClientRequest(\"GET\", URL(\"http://host:80\"), loop=loop)\n\n    conn = aiohttp.BaseConnector(loop=loop, limit=1)\n    conn._available_connections = mock.Mock(return_value=0)\n\n    t = loop.create_task(conn.connect(req, None, ClientTimeout()))\n\n    await asyncio.sleep(0)\n    assert conn._waiters.keys()\n\n    # we delete the entry explicitly before the\n    # canceled connection grabs the loop again, we\n    # must expect a none failure termination\n    conn._waiters.clear()\n    t.cancel()\n    await asyncio.sleep(0)\n    assert not conn._waiters.keys() == []\n\n\nasync def test_close_with_acquired_connection(loop) -> None:\n    proto = mock.Mock()\n    proto.is_connected.return_value = True\n\n    req = ClientRequest(\"GET\", URL(\"http://host:80\"), loop=loop)\n\n    conn = aiohttp.BaseConnector(loop=loop, limit=1)\n    key = (\"host\", 80, False)\n    conn._conns[key] = [(proto, loop.time())]\n    conn._create_connection = mock.Mock()\n    conn._create_connection.return_value = loop.create_future()\n    conn._create_connection.return_value.set_result(proto)\n\n    connection = await conn.connect(req, None, ClientTimeout())\n\n    assert 1 == len(conn._acquired)\n    await conn.close()\n    assert 0 == len(conn._acquired)\n    assert conn.closed\n    proto.close.assert_called_with()\n\n    assert not connection.closed\n    connection.close()\n    assert connection.closed\n\n\nasync def test_default_force_close(loop) -> None:\n    connector = aiohttp.BaseConnector(loop=loop)\n    assert not connector.force_close\n\n\nasync def test_limit_property(loop) -> None:\n    conn = aiohttp.BaseConnector(loop=loop, limit=15)\n    assert 15 == conn.limit\n\n    await conn.close()\n\n\nasync def test_limit_per_host_property(loop) -> None:\n    conn = aiohttp.BaseConnector(loop=loop, limit_per_host=15)\n    assert 15 == conn.limit_per_host\n\n    await conn.close()\n\n\nasync def test_limit_property_default(loop) -> None:\n    conn = aiohttp.BaseConnector(loop=loop)\n    assert conn.limit == 100\n    await conn.close()\n\n\nasync def test_limit_per_host_property_default(loop) -> None:\n    conn = aiohttp.BaseConnector(loop=loop)\n    assert conn.limit_per_host == 0\n    await conn.close()\n\n\nasync def test_force_close_and_explicit_keep_alive(loop) -> None:\n    with pytest.raises(ValueError):\n        aiohttp.BaseConnector(loop=loop, keepalive_timeout=30, force_close=True)\n\n    conn = aiohttp.BaseConnector(loop=loop, force_close=True, keepalive_timeout=None)\n    assert conn\n\n    conn = aiohttp.BaseConnector(loop=loop, force_close=True)\n\n    assert conn\n\n\nasync def test_error_on_connection(loop, key) -> None:\n    conn = aiohttp.BaseConnector(limit=1, loop=loop)\n\n    req = mock.Mock()\n    req.connection_key = key\n    proto = mock.Mock()\n    i = 0\n\n    fut = loop.create_future()\n    exc = OSError()\n\n    async def create_connection(req, traces, timeout):\n        nonlocal i\n        i += 1\n        if i == 1:\n            await fut\n            raise exc\n        elif i == 2:\n            return proto\n\n    conn._create_connection = create_connection\n\n    t1 = loop.create_task(conn.connect(req, None, ClientTimeout()))\n    t2 = loop.create_task(conn.connect(req, None, ClientTimeout()))\n    await asyncio.sleep(0)\n    assert not t1.done()\n    assert not t2.done()\n    assert len(conn._acquired_per_host[key]) == 1\n\n    fut.set_result(None)\n    with pytest.raises(OSError):\n        await t1\n\n    ret = await t2\n    assert len(conn._acquired_per_host[key]) == 1\n\n    assert ret._key == key\n    assert ret.protocol == proto\n    assert proto in conn._acquired\n    ret.release()\n\n\nasync def test_cancelled_waiter(loop) -> None:\n    conn = aiohttp.BaseConnector(limit=1, loop=loop)\n    req = mock.Mock()\n    req.connection_key = \"key\"\n    proto = mock.Mock()\n\n    async def create_connection(req, traces=None):\n        await asyncio.sleep(1)\n        return proto\n\n    conn._create_connection = create_connection\n\n    conn._acquired.add(proto)\n\n    conn2 = loop.create_task(conn.connect(req, None, ClientTimeout()))\n    await asyncio.sleep(0)\n    conn2.cancel()\n\n    with pytest.raises(asyncio.CancelledError):\n        await conn2\n\n\nasync def test_error_on_connection_with_cancelled_waiter(loop, key) -> None:\n    conn = aiohttp.BaseConnector(limit=1, loop=loop)\n\n    req = mock.Mock()\n    req.connection_key = key\n    proto = mock.Mock()\n    i = 0\n\n    fut1 = loop.create_future()\n    fut2 = loop.create_future()\n    exc = OSError()\n\n    async def create_connection(req, traces, timeout):\n        nonlocal i\n        i += 1\n        if i == 1:\n            await fut1\n            raise exc\n        if i == 2:\n            await fut2\n        elif i == 3:\n            return proto\n\n    conn._create_connection = create_connection\n\n    t1 = loop.create_task(conn.connect(req, None, ClientTimeout()))\n    t2 = loop.create_task(conn.connect(req, None, ClientTimeout()))\n    t3 = loop.create_task(conn.connect(req, None, ClientTimeout()))\n    await asyncio.sleep(0)\n    assert not t1.done()\n    assert not t2.done()\n    assert len(conn._acquired_per_host[key]) == 1\n\n    fut1.set_result(None)\n    fut2.cancel()\n    with pytest.raises(OSError):\n        await t1\n\n    with pytest.raises(asyncio.CancelledError):\n        await t2\n\n    ret = await t3\n    assert len(conn._acquired_per_host[key]) == 1\n\n    assert ret._key == key\n    assert ret.protocol == proto\n    assert proto in conn._acquired\n    ret.release()\n\n\nasync def test_tcp_connector(aiohttp_client, loop) -> None:\n    async def handler(request):\n        return web.Response()\n\n    app = web.Application()\n    app.router.add_get(\"/\", handler)\n    client = await aiohttp_client(app)\n\n    r = await client.get(\"/\")\n    assert r.status == 200\n\n\n@pytest.mark.skipif(not hasattr(socket, \"AF_UNIX\"), reason=\"requires UNIX sockets\")\nasync def test_unix_connector_not_found(loop) -> None:\n    connector = aiohttp.UnixConnector(\"/\" + uuid.uuid4().hex)\n\n    req = ClientRequest(\"GET\", URL(\"http://www.python.org\"), loop=loop)\n    with pytest.raises(aiohttp.ClientConnectorError):\n        await connector.connect(req, None, ClientTimeout())\n\n\n@pytest.mark.skipif(not hasattr(socket, \"AF_UNIX\"), reason=\"requires UNIX sockets\")\nasync def test_unix_connector_permission(loop) -> None:\n    loop.create_unix_connection = make_mocked_coro(raise_exception=PermissionError())\n    connector = aiohttp.UnixConnector(\"/\" + uuid.uuid4().hex, loop=loop)\n\n    req = ClientRequest(\"GET\", URL(\"http://www.python.org\"), loop=loop)\n    with pytest.raises(aiohttp.ClientConnectorError):\n        await connector.connect(req, None, ClientTimeout())\n\n\n@pytest.mark.skipif(\n    platform.system() != \"Windows\", reason=\"Proactor Event loop present only in Windows\"\n)\nasync def test_named_pipe_connector_wrong_loop(selector_loop, pipe_name) -> None:\n    with pytest.raises(RuntimeError):\n        aiohttp.NamedPipeConnector(pipe_name, loop=asyncio.get_event_loop())\n\n\n@pytest.mark.skipif(\n    platform.system() != \"Windows\", reason=\"Proactor Event loop present only in Windows\"\n)\nasync def test_named_pipe_connector_not_found(proactor_loop, pipe_name) -> None:\n    connector = aiohttp.NamedPipeConnector(pipe_name, loop=proactor_loop)\n\n    req = ClientRequest(\"GET\", URL(\"http://www.python.org\"), loop=proactor_loop)\n    with pytest.raises(aiohttp.ClientConnectorError):\n        await connector.connect(req, None, ClientTimeout())\n\n\n@pytest.mark.skipif(\n    platform.system() != \"Windows\", reason=\"Proactor Event loop present only in Windows\"\n)\nasync def test_named_pipe_connector_permission(proactor_loop, pipe_name) -> None:\n    proactor_loop.create_pipe_connection = make_mocked_coro(\n        raise_exception=PermissionError()\n    )\n    connector = aiohttp.NamedPipeConnector(pipe_name, loop=proactor_loop)\n\n    req = ClientRequest(\"GET\", URL(\"http://www.python.org\"), loop=proactor_loop)\n    with pytest.raises(aiohttp.ClientConnectorError):\n        await connector.connect(req, None, ClientTimeout())\n\n\nasync def test_default_use_dns_cache() -> None:\n    conn = aiohttp.TCPConnector()\n    assert conn.use_dns_cache\n\n\nasync def test_ssl_none() -> None:\n    conn = aiohttp.TCPConnector(ssl=None)\n    assert conn._ssl is True\n\n\nasync def test_resolver_not_called_with_address_is_ip(loop) -> None:\n    resolver = mock.MagicMock()\n    connector = aiohttp.TCPConnector(resolver=resolver)\n\n    req = ClientRequest(\n        \"GET\",\n        URL(f\"http://127.0.0.1:{unused_port()}\"),\n        loop=loop,\n        response_class=mock.Mock(),\n    )\n\n    with pytest.raises(OSError):\n        await connector.connect(req, None, ClientTimeout())\n\n    resolver.resolve.assert_not_called()\n\n\nasync def test_tcp_connector_raise_connector_ssl_error(\n    aiohttp_server,\n    ssl_ctx,\n) -> None:\n    async def handler(request):\n        return web.Response()\n\n    app = web.Application()\n    app.router.add_get(\"/\", handler)\n\n    srv = await aiohttp_server(app, ssl=ssl_ctx)\n\n    port = unused_port()\n    conn = aiohttp.TCPConnector(local_addr=(\"127.0.0.1\", port))\n\n    session = aiohttp.ClientSession(connector=conn)\n    url = srv.make_url(\"/\")\n\n    err = aiohttp.ClientConnectorCertificateError\n    with pytest.raises(err) as ctx:\n        await session.get(url)\n\n    assert isinstance(ctx.value, aiohttp.ClientConnectorCertificateError)\n    assert isinstance(ctx.value.certificate_error, ssl.SSLError)\n\n    await session.close()\n\n\n@pytest.mark.parametrize(\n    \"host\",\n    (\n        pytest.param(\"127.0.0.1\", id=\"ip address\"),\n        pytest.param(\"localhost\", id=\"domain name\"),\n        pytest.param(\"localhost.\", id=\"fully-qualified domain name\"),\n        pytest.param(\n            \"localhost...\", id=\"fully-qualified domain name with multiple trailing dots\"\n        ),\n        pytest.param(\"príklad.localhost.\", id=\"idna fully-qualified domain name\"),\n    ),\n)\nasync def test_tcp_connector_do_not_raise_connector_ssl_error(\n    aiohttp_server,\n    ssl_ctx,\n    client_ssl_ctx,\n    host,\n) -> None:\n    async def handler(request):\n        return web.Response()\n\n    app = web.Application()\n    app.router.add_get(\"/\", handler)\n\n    srv = await aiohttp_server(app, ssl=ssl_ctx)\n    port = unused_port()\n    conn = aiohttp.TCPConnector(local_addr=(\"127.0.0.1\", port))\n\n    # resolving something.localhost with the real DNS resolver does not work on macOS, so we have a stub.\n    async def _resolve_host(host, port, traces=None):\n        return [\n            {\n                \"hostname\": host,\n                \"host\": \"127.0.0.1\",\n                \"port\": port,\n                \"family\": socket.AF_INET,\n                \"proto\": 0,\n                \"flags\": socket.AI_NUMERICHOST,\n            },\n            {\n                \"hostname\": host,\n                \"host\": \"::1\",\n                \"port\": port,\n                \"family\": socket.AF_INET,\n                \"proto\": 0,\n                \"flags\": socket.AI_NUMERICHOST,\n            },\n        ]\n\n    conn._resolve_host = _resolve_host\n\n    session = aiohttp.ClientSession(connector=conn)\n    url = srv.make_url(\"/\")\n\n    r = await session.get(url.with_host(host), ssl=client_ssl_ctx)\n\n    r.release()\n    first_conn = next(iter(conn._conns.values()))[0][0]\n\n    try:\n        _sslcontext = first_conn.transport._ssl_protocol._sslcontext\n    except AttributeError:\n        _sslcontext = first_conn.transport._sslcontext\n\n    assert _sslcontext is client_ssl_ctx\n    r.close()\n\n    await session.close()\n    await conn.close()\n\n\nasync def test_tcp_connector_uses_provided_local_addr(aiohttp_server) -> None:\n    async def handler(request):\n        return web.Response()\n\n    app = web.Application()\n    app.router.add_get(\"/\", handler)\n    srv = await aiohttp_server(app)\n\n    port = unused_port()\n    conn = aiohttp.TCPConnector(local_addr=(\"127.0.0.1\", port))\n\n    session = aiohttp.ClientSession(connector=conn)\n    url = srv.make_url(\"/\")\n\n    r = await session.get(url)\n    r.release()\n\n    first_conn = next(iter(conn._conns.values()))[0][0]\n    assert first_conn.transport.get_extra_info(\"sockname\") == (\"127.0.0.1\", port)\n    r.close()\n    await session.close()\n    await conn.close()\n\n\nasync def test_unix_connector(unix_server, unix_sockname) -> None:\n    async def handler(request):\n        return web.Response()\n\n    app = web.Application()\n    app.router.add_get(\"/\", handler)\n    await unix_server(app)\n\n    url = \"http://127.0.0.1/\"\n\n    connector = aiohttp.UnixConnector(unix_sockname)\n    assert unix_sockname == connector.path\n    assert connector.allowed_protocol_schema_set == {\n        \"\",\n        \"http\",\n        \"https\",\n        \"ws\",\n        \"wss\",\n        \"unix\",\n    }\n\n    session = client.ClientSession(connector=connector)\n    r = await session.get(url)\n    assert r.status == 200\n    r.close()\n    await session.close()\n\n\n@pytest.mark.skipif(\n    platform.system() != \"Windows\", reason=\"Proactor Event loop present only in Windows\"\n)\nasync def test_named_pipe_connector(\n    proactor_loop, named_pipe_server, pipe_name\n) -> None:\n    async def handler(request):\n        return web.Response()\n\n    app = web.Application()\n    app.router.add_get(\"/\", handler)\n    await named_pipe_server(app)\n\n    url = \"http://this-does-not-matter.com\"\n\n    connector = aiohttp.NamedPipeConnector(pipe_name)\n    assert pipe_name == connector.path\n    assert connector.allowed_protocol_schema_set == {\n        \"\",\n        \"http\",\n        \"https\",\n        \"ws\",\n        \"wss\",\n        \"npipe\",\n    }\n\n    session = client.ClientSession(connector=connector)\n    r = await session.get(url)\n    assert r.status == 200\n    r.close()\n    await session.close()\n\n\nclass TestDNSCacheTable:\n    @pytest.fixture\n    def dns_cache_table(self):\n        return _DNSCacheTable()\n\n    def test_next_addrs_basic(self, dns_cache_table) -> None:\n        dns_cache_table.add(\"localhost\", [\"127.0.0.1\"])\n        dns_cache_table.add(\"foo\", [\"127.0.0.2\"])\n\n        addrs = dns_cache_table.next_addrs(\"localhost\")\n        assert addrs == [\"127.0.0.1\"]\n        addrs = dns_cache_table.next_addrs(\"foo\")\n        assert addrs == [\"127.0.0.2\"]\n        with pytest.raises(KeyError):\n            dns_cache_table.next_addrs(\"no-such-host\")\n\n    def test_remove(self, dns_cache_table) -> None:\n        dns_cache_table.add(\"localhost\", [\"127.0.0.1\"])\n        dns_cache_table.remove(\"localhost\")\n        with pytest.raises(KeyError):\n            dns_cache_table.next_addrs(\"localhost\")\n\n    def test_clear(self, dns_cache_table) -> None:\n        dns_cache_table.add(\"localhost\", [\"127.0.0.1\"])\n        dns_cache_table.clear()\n        with pytest.raises(KeyError):\n            dns_cache_table.next_addrs(\"localhost\")\n\n    def test_not_expired_ttl_None(self, dns_cache_table) -> None:\n        dns_cache_table.add(\"localhost\", [\"127.0.0.1\"])\n        assert not dns_cache_table.expired(\"localhost\")\n\n    def test_not_expired_ttl(self) -> None:\n        dns_cache_table = _DNSCacheTable(ttl=0.1)\n        dns_cache_table.add(\"localhost\", [\"127.0.0.1\"])\n        assert not dns_cache_table.expired(\"localhost\")\n\n    def test_expired_ttl(self, monkeypatch: pytest.MonkeyPatch) -> None:\n        dns_cache_table = _DNSCacheTable(ttl=1)\n        monkeypatch.setattr(\"aiohttp.connector.monotonic\", lambda: 1)\n        dns_cache_table.add(\"localhost\", [\"127.0.0.1\"])\n        monkeypatch.setattr(\"aiohttp.connector.monotonic\", lambda: 2)\n        assert not dns_cache_table.expired(\"localhost\")\n        monkeypatch.setattr(\"aiohttp.connector.monotonic\", lambda: 3)\n        assert dns_cache_table.expired(\"localhost\")\n\n    def test_never_expire(self, monkeypatch: pytest.MonkeyPatch) -> None:\n        dns_cache_table = _DNSCacheTable(ttl=None)\n        monkeypatch.setattr(\"aiohttp.connector.monotonic\", lambda: 1)\n        dns_cache_table.add(\"localhost\", [\"127.0.0.1\"])\n        monkeypatch.setattr(\"aiohttp.connector.monotonic\", lambda: 10000000)\n        assert not dns_cache_table.expired(\"localhost\")\n\n    def test_always_expire(self, monkeypatch: pytest.MonkeyPatch) -> None:\n        dns_cache_table = _DNSCacheTable(ttl=0)\n        monkeypatch.setattr(\"aiohttp.connector.monotonic\", lambda: 1)\n        dns_cache_table.add(\"localhost\", [\"127.0.0.1\"])\n        monkeypatch.setattr(\"aiohttp.connector.monotonic\", lambda: 1.00001)\n        assert dns_cache_table.expired(\"localhost\")\n\n    def test_next_addrs(self, dns_cache_table) -> None:\n        dns_cache_table.add(\"foo\", [\"127.0.0.1\", \"127.0.0.2\", \"127.0.0.3\"])\n\n        # Each calls to next_addrs return the hosts using\n        # a round robin strategy.\n        addrs = dns_cache_table.next_addrs(\"foo\")\n        assert addrs == [\"127.0.0.1\", \"127.0.0.2\", \"127.0.0.3\"]\n\n        addrs = dns_cache_table.next_addrs(\"foo\")\n        assert addrs == [\"127.0.0.2\", \"127.0.0.3\", \"127.0.0.1\"]\n\n        addrs = dns_cache_table.next_addrs(\"foo\")\n        assert addrs == [\"127.0.0.3\", \"127.0.0.1\", \"127.0.0.2\"]\n\n        addrs = dns_cache_table.next_addrs(\"foo\")\n        assert addrs == [\"127.0.0.1\", \"127.0.0.2\", \"127.0.0.3\"]\n\n    def test_next_addrs_single(self, dns_cache_table) -> None:\n        dns_cache_table.add(\"foo\", [\"127.0.0.1\"])\n\n        addrs = dns_cache_table.next_addrs(\"foo\")\n        assert addrs == [\"127.0.0.1\"]\n\n        addrs = dns_cache_table.next_addrs(\"foo\")\n        assert addrs == [\"127.0.0.1\"]\n\n\nasync def test_connector_cache_trace_race():\n    class DummyTracer:\n        async def send_dns_cache_hit(self, *args, **kwargs):\n            connector._cached_hosts.remove((\"\", 0))\n\n    token = object()\n    connector = TCPConnector()\n    connector._cached_hosts.add((\"\", 0), [token])\n\n    traces = [DummyTracer()]\n    assert await connector._resolve_host(\"\", 0, traces) == [token]\n\n\nasync def test_connector_throttle_trace_race(loop):\n    key = (\"\", 0)\n    token = object()\n\n    class DummyTracer:\n        async def send_dns_cache_hit(self, *args, **kwargs):\n            event = connector._throttle_dns_events.pop(key)\n            event.set()\n            connector._cached_hosts.add(key, [token])\n\n    connector = TCPConnector()\n    connector._throttle_dns_events[key] = EventResultOrError(loop)\n    traces = [DummyTracer()]\n    assert await connector._resolve_host(\"\", 0, traces) == [token]\n\n\nasync def test_connector_does_not_remove_needed_waiters(loop, key) -> None:\n    proto = create_mocked_conn(loop)\n    proto.is_connected.return_value = True\n\n    req = ClientRequest(\"GET\", URL(\"https://localhost:80\"), loop=loop)\n    connection_key = req.connection_key\n\n    connector = aiohttp.BaseConnector()\n    connector._available_connections = mock.Mock(return_value=0)\n    connector._conns[key] = [(proto, loop.time())]\n    connector._create_connection = create_mocked_conn(loop)\n    connector._create_connection.return_value = loop.create_future()\n    connector._create_connection.return_value.set_result(proto)\n\n    dummy_waiter = loop.create_future()\n\n    async def await_connection_and_check_waiters():\n        connection = await connector.connect(req, [], ClientTimeout())\n        try:\n            assert connection_key in connector._waiters\n            assert dummy_waiter in connector._waiters[connection_key]\n        finally:\n            connection.close()\n\n    async def allow_connection_and_add_dummy_waiter():\n        # `asyncio.gather` may execute coroutines not in order.\n        # Skip one event loop run cycle in such a case.\n        if connection_key not in connector._waiters:\n            await asyncio.sleep(0)\n        connector._waiters[connection_key].popleft().set_result(None)\n        del connector._waiters[connection_key]\n        connector._waiters[connection_key].append(dummy_waiter)\n\n    await asyncio.gather(\n        await_connection_and_check_waiters(),\n        allow_connection_and_add_dummy_waiter(),\n    )\n\n    await connector.close()\n",
            "header": {
                "file": {
                    "path": "tests/test_connector.py"
                },
                "misc_line": null
            },
            "index_line": {
                "old_commit_hash": "8dd7a294",
                "new_commit_hash": "0129f0cc",
                "mode": "100644"
            },
            "is_binary_file": false,
            "binary_line": null,
            "minus_file": {
                "path": "a/tests/test_connector.py"
            },
            "plus_file": {
                "path": "b/tests/test_connector.py"
            },
            "hunks": [
                {
                    "descriptor": {
                        "old_range": {
                            "start": 9,
                            "length": 7
                        },
                        "new_range": {
                            "start": 9,
                            "length": 7
                        },
                        "section": "import ssl"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "import sys",
                                "type": "context"
                            },
                            {
                                "content": "import uuid",
                                "type": "context"
                            },
                            {
                                "content": "from collections import deque",
                                "type": "context"
                            },
                            {
                                "content": "from contextlib import closing",
                                "type": "deleted"
                            },
                            {
                                "content": "from contextlib import closing, suppress",
                                "type": "added"
                            },
                            {
                                "content": "from typing import Any, List, Optional, Type",
                                "type": "context"
                            },
                            {
                                "content": "from unittest import mock",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [],
                    "added_entities": [
                        {
                            "file_name": "tests/test_connector.py",
                            "type": "statement",
                            "name": "",
                            "content": "from contextlib import closing, suppress",
                            "ast_type_str": "ImportFrom",
                            "start_lineno": 12,
                            "end_lineno": 12,
                            "parent": null
                        }
                    ],
                    "deleted_entities": [
                        {
                            "file_name": "tests/test_connector.py",
                            "type": "statement",
                            "name": "",
                            "content": "from contextlib import closing",
                            "ast_type_str": "ImportFrom",
                            "start_lineno": 12,
                            "end_lineno": 12,
                            "parent": null
                        }
                    ]
                },
                {
                    "descriptor": {
                        "old_range": {
                            "start": 1667,
                            "length": 7
                        },
                        "new_range": {
                            "start": 1667,
                            "length": 41
                        },
                        "section": "async def test_close_cancels_cleanup_handle(loop) -> None:"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "    assert conn._cleanup_handle is None",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "async def test_close_abort_closed_transports(loop) -> None:",
                                "type": "deleted"
                            },
                            {
                                "content": "async def test_close_cancels_resolve_host(loop: asyncio.AbstractEventLoop) -> None:",
                                "type": "added"
                            },
                            {
                                "content": "    cancelled = False",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "    async def delay_resolve_host(*args: object) -> None:",
                                "type": "added"
                            },
                            {
                                "content": "        \"\"\"Delay _resolve_host() task in order to test cancellation.\"\"\"",
                                "type": "added"
                            },
                            {
                                "content": "        nonlocal cancelled",
                                "type": "added"
                            },
                            {
                                "content": "        try:",
                                "type": "added"
                            },
                            {
                                "content": "            await asyncio.sleep(10)",
                                "type": "added"
                            },
                            {
                                "content": "        except asyncio.CancelledError:",
                                "type": "added"
                            },
                            {
                                "content": "            cancelled = True",
                                "type": "added"
                            },
                            {
                                "content": "            raise",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "    conn = aiohttp.TCPConnector()",
                                "type": "added"
                            },
                            {
                                "content": "    req = ClientRequest(",
                                "type": "added"
                            },
                            {
                                "content": "        \"GET\", URL(\"http://localhost:80\"), loop=loop, response_class=mock.Mock()",
                                "type": "added"
                            },
                            {
                                "content": "    )",
                                "type": "added"
                            },
                            {
                                "content": "    with mock.patch.object(conn, \"_resolve_host_with_throttle\", delay_resolve_host):",
                                "type": "added"
                            },
                            {
                                "content": "        t = asyncio.create_task(conn.connect(req, [], ClientTimeout()))",
                                "type": "added"
                            },
                            {
                                "content": "        # Let it create the internal task",
                                "type": "added"
                            },
                            {
                                "content": "        await asyncio.sleep(0)",
                                "type": "added"
                            },
                            {
                                "content": "        # Let that task start running",
                                "type": "added"
                            },
                            {
                                "content": "        await asyncio.sleep(0)",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "        # We now have a task being tracked and can ensure that .close() cancels it.",
                                "type": "added"
                            },
                            {
                                "content": "        assert len(conn._resolve_host_tasks) == 1",
                                "type": "added"
                            },
                            {
                                "content": "        await conn.close()",
                                "type": "added"
                            },
                            {
                                "content": "        await asyncio.sleep(0.01)",
                                "type": "added"
                            },
                            {
                                "content": "        assert cancelled",
                                "type": "added"
                            },
                            {
                                "content": "        assert len(conn._resolve_host_tasks) == 0",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "        with suppress(asyncio.CancelledError):",
                                "type": "added"
                            },
                            {
                                "content": "            await t",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "async def test_close_abort_closed_transports(loop: asyncio.AbstractEventLoop) -> None:",
                                "type": "added"
                            },
                            {
                                "content": "    tr = mock.Mock()",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "    conn = aiohttp.BaseConnector(loop=loop)",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [
                        {
                            "file_name": "tests/test_connector.py",
                            "type": "function",
                            "name": "test_close_abort_closed_transports",
                            "content": "async def test_close_abort_closed_transports(loop) -> None:\n    tr = mock.Mock()\n\n    conn = aiohttp.BaseConnector(loop=loop)\n    conn._cleanup_closed_transports.append(tr)\n    await conn.close()\n\n    assert not conn._cleanup_closed_transports\n    assert tr.abort.called\n    assert conn.closed",
                            "ast_type_str": "AsyncFunctionDef",
                            "start_lineno": 1670,
                            "end_lineno": 1679,
                            "parent": null
                        }
                    ],
                    "added_entities": [
                        {
                            "file_name": "tests/test_connector.py",
                            "type": "function",
                            "name": "test_close_cancels_resolve_host",
                            "content": "async def test_close_cancels_resolve_host(loop: asyncio.AbstractEventLoop) -> None:\n    cancelled = False\n\n    async def delay_resolve_host(*args: object) -> None:\n        \"\"\"Delay _resolve_host() task in order to test cancellation.\"\"\"\n        nonlocal cancelled\n        try:\n            await asyncio.sleep(10)\n        except asyncio.CancelledError:\n            cancelled = True\n            raise\n\n    conn = aiohttp.TCPConnector()\n    req = ClientRequest(\n        \"GET\", URL(\"http://localhost:80\"), loop=loop, response_class=mock.Mock()\n    )\n    with mock.patch.object(conn, \"_resolve_host_with_throttle\", delay_resolve_host):\n        t = asyncio.create_task(conn.connect(req, [], ClientTimeout()))\n        # Let it create the internal task\n        await asyncio.sleep(0)\n        # Let that task start running\n        await asyncio.sleep(0)\n\n        # We now have a task being tracked and can ensure that .close() cancels it.\n        assert len(conn._resolve_host_tasks) == 1\n        await conn.close()\n        await asyncio.sleep(0.01)\n        assert cancelled\n        assert len(conn._resolve_host_tasks) == 0\n\n        with suppress(asyncio.CancelledError):\n            await t",
                            "ast_type_str": "AsyncFunctionDef",
                            "start_lineno": 1670,
                            "end_lineno": 1701,
                            "parent": null
                        }
                    ],
                    "deleted_entities": []
                }
            ]
        }
    ],
    "old_commit_hash": "ea316336f0b247bb85fd7ee0e4e41f5eac682228^",
    "new_commit_hash": "ea316336f0b247bb85fd7ee0e4e41f5eac682228",
    "commit_message": "Fix resolve_host \"Task was destroyed but it is pending\" errors (#8967) (#8980)\n\n(cherry picked from commit cd761a347be2609deca503646b9b5fb3585b2fda)",
    "commit_date": "2024-09-02T02:20:25+01:00",
    "metadata": {}
}
{
    "repo_name": "aiohttp",
    "new_commit_hash": "ea316336f0b247bb85fd7ee0e4e41f5eac682228",
    "test_file_codes": [
        "# Tests of http client with custom Connector\n\nimport asyncio\nimport gc\nimport hashlib\nimport platform\nimport socket\nimport ssl\nimport sys\nimport uuid\nfrom collections import deque\nfrom contextlib import closing, suppress\nfrom typing import Any, List, Optional, Type\nfrom unittest import mock\n\nimport pytest\nfrom aiohappyeyeballs import AddrInfoType\nfrom yarl import URL\n\nimport aiohttp\nfrom aiohttp import client, web\nfrom aiohttp.client import ClientRequest, ClientTimeout\nfrom aiohttp.client_reqrep import ConnectionKey\nfrom aiohttp.connector import Connection, TCPConnector, _DNSCacheTable\nfrom aiohttp.locks import EventResultOrError\nfrom aiohttp.test_utils import make_mocked_coro, unused_port\nfrom aiohttp.tracing import Trace\n\n\n@pytest.fixture()\ndef key():\n    # Connection key\n    return ConnectionKey(\"localhost\", 80, False, True, None, None, None)\n\n\n@pytest.fixture\ndef key2():\n    # Connection key\n    return ConnectionKey(\"localhost\", 80, False, True, None, None, None)\n\n\n@pytest.fixture\ndef ssl_key():\n    # Connection key\n    return ConnectionKey(\"localhost\", 80, True, True, None, None, None)\n\n\n@pytest.fixture\ndef unix_server(loop, unix_sockname):\n    runners = []\n\n    async def go(app):\n        runner = web.AppRunner(app)\n        runners.append(runner)\n        await runner.setup()\n        site = web.UnixSite(runner, unix_sockname)\n        await site.start()\n\n    yield go\n\n    for runner in runners:\n        loop.run_until_complete(runner.cleanup())\n\n\n@pytest.fixture\ndef named_pipe_server(proactor_loop, pipe_name):\n    runners = []\n\n    async def go(app):\n        runner = web.AppRunner(app)\n        runners.append(runner)\n        await runner.setup()\n        site = web.NamedPipeSite(runner, pipe_name)\n        await site.start()\n\n    yield go\n\n    for runner in runners:\n        proactor_loop.run_until_complete(runner.cleanup())\n\n\ndef create_mocked_conn(conn_closing_result=None, **kwargs):\n    try:\n        loop = asyncio.get_running_loop()\n    except RuntimeError:\n        loop = asyncio.get_event_loop_policy().get_event_loop()\n\n    proto = mock.Mock(**kwargs)\n    proto.closed = loop.create_future()\n    proto.closed.set_result(conn_closing_result)\n    return proto\n\n\ndef test_connection_del(loop) -> None:\n    connector = mock.Mock()\n    key = mock.Mock()\n    protocol = mock.Mock()\n    loop.set_debug(0)\n    conn = Connection(connector, key, protocol, loop=loop)\n    exc_handler = mock.Mock()\n    loop.set_exception_handler(exc_handler)\n\n    with pytest.warns(ResourceWarning):\n        del conn\n        gc.collect()\n\n    connector._release.assert_called_with(key, protocol, should_close=True)\n    msg = {\n        \"message\": mock.ANY,\n        \"client_connection\": mock.ANY,\n    }\n    exc_handler.assert_called_with(loop, msg)\n\n\ndef test_connection_del_loop_debug(loop) -> None:\n    connector = mock.Mock()\n    key = mock.Mock()\n    protocol = mock.Mock()\n    loop.set_debug(1)\n    conn = Connection(connector, key, protocol, loop=loop)\n    exc_handler = mock.Mock()\n    loop.set_exception_handler(exc_handler)\n\n    with pytest.warns(ResourceWarning):\n        del conn\n        gc.collect()\n\n    msg = {\n        \"message\": mock.ANY,\n        \"client_connection\": mock.ANY,\n        \"source_traceback\": mock.ANY,\n    }\n    exc_handler.assert_called_with(loop, msg)\n\n\ndef test_connection_del_loop_closed(loop) -> None:\n    connector = mock.Mock()\n    key = mock.Mock()\n    protocol = mock.Mock()\n    loop.set_debug(1)\n    conn = Connection(connector, key, protocol, loop=loop)\n    exc_handler = mock.Mock()\n    loop.set_exception_handler(exc_handler)\n    loop.close()\n\n    with pytest.warns(ResourceWarning):\n        del conn\n        gc.collect()\n\n    assert not connector._release.called\n    assert not exc_handler.called\n\n\nasync def test_del(loop) -> None:\n    conn = aiohttp.BaseConnector()\n    proto = mock.Mock(should_close=False)\n    conn._release(\"a\", proto)\n    conns_impl = conn._conns\n\n    exc_handler = mock.Mock()\n    loop.set_exception_handler(exc_handler)\n\n    with pytest.warns(ResourceWarning):\n        del conn\n        gc.collect()\n\n    assert not conns_impl\n    proto.close.assert_called_with()\n    msg = {\n        \"connector\": mock.ANY,  # conn was deleted\n        \"connections\": mock.ANY,\n        \"message\": \"Unclosed connector\",\n    }\n    if loop.get_debug():\n        msg[\"source_traceback\"] = mock.ANY\n    exc_handler.assert_called_with(loop, msg)\n\n\n@pytest.mark.xfail\nasync def test_del_with_scheduled_cleanup(loop) -> None:\n    loop.set_debug(True)\n    conn = aiohttp.BaseConnector(loop=loop, keepalive_timeout=0.01)\n    transp = mock.Mock()\n    conn._conns[\"a\"] = [(transp, 123)]\n\n    conns_impl = conn._conns\n    exc_handler = mock.Mock()\n    loop.set_exception_handler(exc_handler)\n\n    with pytest.warns(ResourceWarning):\n        # obviously doesn't deletion because loop has a strong\n        # reference to connector's instance method, isn't it?\n        del conn\n        await asyncio.sleep(0.01)\n        gc.collect()\n\n    assert not conns_impl\n    transp.close.assert_called_with()\n    msg = {\"connector\": mock.ANY, \"message\": \"Unclosed connector\"}  # conn was deleted\n    if loop.get_debug():\n        msg[\"source_traceback\"] = mock.ANY\n    exc_handler.assert_called_with(loop, msg)\n\n\n@pytest.mark.skipif(\n    sys.implementation.name != \"cpython\", reason=\"CPython GC is required for the test\"\n)\ndef test_del_with_closed_loop(loop) -> None:\n    async def make_conn():\n        return aiohttp.BaseConnector()\n\n    conn = loop.run_until_complete(make_conn())\n    transp = mock.Mock()\n    conn._conns[\"a\"] = [(transp, 123)]\n\n    conns_impl = conn._conns\n    exc_handler = mock.Mock()\n    loop.set_exception_handler(exc_handler)\n    loop.close()\n\n    with pytest.warns(ResourceWarning):\n        del conn\n        gc.collect()\n\n    assert not conns_impl\n    assert not transp.close.called\n    assert exc_handler.called\n\n\nasync def test_del_empty_connector(loop) -> None:\n    conn = aiohttp.BaseConnector(loop=loop)\n\n    exc_handler = mock.Mock()\n    loop.set_exception_handler(exc_handler)\n\n    del conn\n\n    assert not exc_handler.called\n\n\nasync def test_create_conn(loop) -> None:\n    conn = aiohttp.BaseConnector(loop=loop)\n    with pytest.raises(NotImplementedError):\n        await conn._create_connection(object(), [], object())\n\n\nasync def test_connector_context_manager(loop) -> None:\n    conn = aiohttp.BaseConnector(loop=loop)\n\n    with pytest.warns(DeprecationWarning):\n        with conn as c:\n            assert conn is c\n\n    assert conn.closed\n\n    await conn.close()\n\n\nasync def test_async_context_manager(loop) -> None:\n    conn = aiohttp.BaseConnector(loop=loop)\n\n    async with conn as c:\n        assert conn is c\n\n    assert conn.closed\n\n\nasync def test_close(loop) -> None:\n    proto = mock.Mock()\n\n    conn = aiohttp.BaseConnector(loop=loop)\n    assert not conn.closed\n    conn._conns[(\"host\", 8080, False)] = [(proto, object())]\n    await conn.close()\n\n    assert not conn._conns\n    assert proto.close.called\n    assert conn.closed\n\n\nasync def test_get(loop) -> None:\n    conn = aiohttp.BaseConnector(loop=loop)\n    assert conn._get(1) is None\n\n    proto = mock.Mock()\n    conn._conns[1] = [(proto, loop.time())]\n    assert conn._get(1) == proto\n    await conn.close()\n\n\nasync def test_get_unconnected_proto(loop) -> None:\n    conn = aiohttp.BaseConnector()\n    key = ConnectionKey(\"localhost\", 80, False, None, None, None, None)\n    assert conn._get(key) is None\n\n    proto = create_mocked_conn(loop)\n    conn._conns[key] = [(proto, loop.time())]\n    assert conn._get(key) == proto\n\n    assert conn._get(key) is None\n    conn._conns[key] = [(proto, loop.time())]\n    proto.is_connected = lambda *args: False\n    assert conn._get(key) is None\n    await conn.close()\n\n\nasync def test_get_unconnected_proto_ssl(loop) -> None:\n    conn = aiohttp.BaseConnector()\n    key = ConnectionKey(\"localhost\", 80, True, None, None, None, None)\n    assert conn._get(key) is None\n\n    proto = create_mocked_conn(loop)\n    conn._conns[key] = [(proto, loop.time())]\n    assert conn._get(key) == proto\n\n    assert conn._get(key) is None\n    conn._conns[key] = [(proto, loop.time())]\n    proto.is_connected = lambda *args: False\n    assert conn._get(key) is None\n    await conn.close()\n\n\nasync def test_get_expired(loop) -> None:\n    conn = aiohttp.BaseConnector(loop=loop)\n    key = ConnectionKey(\"localhost\", 80, False, None, None, None, None)\n    assert conn._get(key) is None\n\n    proto = mock.Mock()\n    conn._conns[key] = [(proto, loop.time() - 1000)]\n    assert conn._get(key) is None\n    assert not conn._conns\n    await conn.close()\n\n\nasync def test_get_expired_ssl(loop) -> None:\n    conn = aiohttp.BaseConnector(loop=loop, enable_cleanup_closed=True)\n    key = ConnectionKey(\"localhost\", 80, True, None, None, None, None)\n    assert conn._get(key) is None\n\n    proto = mock.Mock()\n    transport = proto.transport\n    conn._conns[key] = [(proto, loop.time() - 1000)]\n    assert conn._get(key) is None\n    assert not conn._conns\n    assert conn._cleanup_closed_transports == [transport]\n    await conn.close()\n\n\nasync def test_release_acquired(loop, key) -> None:\n    proto = mock.Mock()\n    conn = aiohttp.BaseConnector(loop=loop, limit=5)\n    conn._release_waiter = mock.Mock()\n\n    conn._acquired.add(proto)\n    conn._acquired_per_host[key].add(proto)\n    conn._release_acquired(key, proto)\n    assert 0 == len(conn._acquired)\n    assert 0 == len(conn._acquired_per_host)\n    assert conn._release_waiter.called\n\n    conn._release_acquired(key, proto)\n    assert 0 == len(conn._acquired)\n    assert 0 == len(conn._acquired_per_host)\n\n    await conn.close()\n\n\nasync def test_release_acquired_closed(loop, key) -> None:\n    proto = mock.Mock()\n    conn = aiohttp.BaseConnector(loop=loop, limit=5)\n    conn._release_waiter = mock.Mock()\n\n    conn._acquired.add(proto)\n    conn._acquired_per_host[key].add(proto)\n    conn._closed = True\n    conn._release_acquired(key, proto)\n    assert 1 == len(conn._acquired)\n    assert 1 == len(conn._acquired_per_host[key])\n    assert not conn._release_waiter.called\n    await conn.close()\n\n\nasync def test_release(loop, key) -> None:\n    conn = aiohttp.BaseConnector(loop=loop)\n    conn._release_waiter = mock.Mock()\n\n    proto = mock.Mock(should_close=False)\n\n    conn._acquired.add(proto)\n    conn._acquired_per_host[key].add(proto)\n\n    conn._release(key, proto)\n    assert conn._release_waiter.called\n    assert conn._cleanup_handle is not None\n    assert conn._conns[key][0][0] == proto\n    assert conn._conns[key][0][1] == pytest.approx(loop.time(), abs=0.1)\n    assert not conn._cleanup_closed_transports\n    await conn.close()\n\n\nasync def test_release_ssl_transport(loop, ssl_key) -> None:\n    conn = aiohttp.BaseConnector(loop=loop, enable_cleanup_closed=True)\n    conn._release_waiter = mock.Mock()\n\n    proto = mock.Mock()\n    transport = proto.transport\n    conn._acquired.add(proto)\n    conn._acquired_per_host[ssl_key].add(proto)\n\n    conn._release(ssl_key, proto, should_close=True)\n    assert conn._cleanup_closed_transports == [transport]\n    await conn.close()\n\n\nasync def test_release_already_closed(loop) -> None:\n    conn = aiohttp.BaseConnector(loop=loop)\n\n    proto = mock.Mock()\n    key = 1\n    conn._acquired.add(proto)\n    await conn.close()\n\n    conn._release_waiters = mock.Mock()\n    conn._release_acquired = mock.Mock()\n\n    conn._release(key, proto)\n    assert not conn._release_waiters.called\n    assert not conn._release_acquired.called\n\n\nasync def test_release_waiter_no_limit(loop, key, key2) -> None:\n    # limit is 0\n    conn = aiohttp.BaseConnector(limit=0, loop=loop)\n    w = mock.Mock()\n    w.done.return_value = False\n    conn._waiters[key].append(w)\n    conn._release_waiter()\n    assert len(conn._waiters[key]) == 0\n    assert w.done.called\n    await conn.close()\n\n\nasync def test_release_waiter_first_available(loop, key, key2) -> None:\n    conn = aiohttp.BaseConnector(loop=loop)\n    w1, w2 = mock.Mock(), mock.Mock()\n    w1.done.return_value = False\n    w2.done.return_value = False\n    conn._waiters[key].append(w2)\n    conn._waiters[key2].append(w1)\n    conn._release_waiter()\n    assert (\n        w1.set_result.called\n        and not w2.set_result.called\n        or not w1.set_result.called\n        and w2.set_result.called\n    )\n    await conn.close()\n\n\nasync def test_release_waiter_release_first(loop, key, key2) -> None:\n    conn = aiohttp.BaseConnector(loop=loop, limit=1)\n    w1, w2 = mock.Mock(), mock.Mock()\n    w1.done.return_value = False\n    w2.done.return_value = False\n    conn._waiters[key] = deque([w1, w2])\n    conn._release_waiter()\n    assert w1.set_result.called\n    assert not w2.set_result.called\n    await conn.close()\n\n\nasync def test_release_waiter_skip_done_waiter(loop, key, key2) -> None:\n    conn = aiohttp.BaseConnector(loop=loop, limit=1)\n    w1, w2 = mock.Mock(), mock.Mock()\n    w1.done.return_value = True\n    w2.done.return_value = False\n    conn._waiters[key] = deque([w1, w2])\n    conn._release_waiter()\n    assert not w1.set_result.called\n    assert w2.set_result.called\n    await conn.close()\n\n\nasync def test_release_waiter_per_host(loop, key, key2) -> None:\n    # no limit\n    conn = aiohttp.BaseConnector(loop=loop, limit=0, limit_per_host=2)\n    w1, w2 = mock.Mock(), mock.Mock()\n    w1.done.return_value = False\n    w2.done.return_value = False\n    conn._waiters[key] = deque([w1])\n    conn._waiters[key2] = deque([w2])\n    conn._release_waiter()\n    assert (w1.set_result.called and not w2.set_result.called) or (\n        not w1.set_result.called and w2.set_result.called\n    )\n    await conn.close()\n\n\nasync def test_release_waiter_no_available(loop, key, key2) -> None:\n    # limit is 0\n    conn = aiohttp.BaseConnector(limit=0, loop=loop)\n    w = mock.Mock()\n    w.done.return_value = False\n    conn._waiters[key].append(w)\n    conn._available_connections = mock.Mock(return_value=0)\n    conn._release_waiter()\n    assert len(conn._waiters) == 1\n    assert not w.done.called\n    await conn.close()\n\n\nasync def test_release_close(loop, key) -> None:\n    conn = aiohttp.BaseConnector(loop=loop)\n    proto = mock.Mock(should_close=True)\n\n    conn._acquired.add(proto)\n    conn._release(key, proto)\n    assert not conn._conns\n    assert proto.close.called\n\n\nasync def test__drop_acquire_per_host1(loop) -> None:\n    conn = aiohttp.BaseConnector(loop=loop)\n    conn._drop_acquired_per_host(123, 456)\n    assert len(conn._acquired_per_host) == 0\n\n\nasync def test__drop_acquire_per_host2(loop) -> None:\n    conn = aiohttp.BaseConnector(loop=loop)\n    conn._acquired_per_host[123].add(456)\n    conn._drop_acquired_per_host(123, 456)\n    assert len(conn._acquired_per_host) == 0\n\n\nasync def test__drop_acquire_per_host3(loop) -> None:\n    conn = aiohttp.BaseConnector(loop=loop)\n    conn._acquired_per_host[123].add(456)\n    conn._acquired_per_host[123].add(789)\n    conn._drop_acquired_per_host(123, 456)\n    assert len(conn._acquired_per_host) == 1\n    assert conn._acquired_per_host[123] == {789}\n\n\nasync def test_tcp_connector_certificate_error(\n    loop: Any, start_connection: mock.AsyncMock\n) -> None:\n    req = ClientRequest(\"GET\", URL(\"https://127.0.0.1:443\"), loop=loop)\n\n    async def certificate_error(*args, **kwargs):\n        raise ssl.CertificateError\n\n    conn = aiohttp.TCPConnector(loop=loop)\n    conn._loop.create_connection = certificate_error\n\n    with pytest.raises(aiohttp.ClientConnectorCertificateError) as ctx:\n        await conn.connect(req, [], ClientTimeout())\n\n    assert isinstance(ctx.value, ssl.CertificateError)\n    assert isinstance(ctx.value.certificate_error, ssl.CertificateError)\n    assert isinstance(ctx.value, aiohttp.ClientSSLError)\n\n\nasync def test_tcp_connector_server_hostname_default(\n    loop: Any, start_connection: mock.AsyncMock\n) -> None:\n    conn = aiohttp.TCPConnector()\n\n    with mock.patch.object(\n        conn._loop, \"create_connection\", autospec=True, spec_set=True\n    ) as create_connection:\n        create_connection.return_value = mock.Mock(), mock.Mock()\n\n        req = ClientRequest(\"GET\", URL(\"https://127.0.0.1:443\"), loop=loop)\n\n        with closing(await conn.connect(req, [], ClientTimeout())):\n            assert create_connection.call_args.kwargs[\"server_hostname\"] == \"127.0.0.1\"\n\n\nasync def test_tcp_connector_server_hostname_override(\n    loop: Any, start_connection: mock.AsyncMock\n) -> None:\n    conn = aiohttp.TCPConnector()\n\n    with mock.patch.object(\n        conn._loop, \"create_connection\", autospec=True, spec_set=True\n    ) as create_connection:\n        create_connection.return_value = mock.Mock(), mock.Mock()\n\n        req = ClientRequest(\n            \"GET\", URL(\"https://127.0.0.1:443\"), loop=loop, server_hostname=\"localhost\"\n        )\n\n        with closing(await conn.connect(req, [], ClientTimeout())):\n            assert create_connection.call_args.kwargs[\"server_hostname\"] == \"localhost\"\n\n\nasync def test_tcp_connector_multiple_hosts_errors(loop) -> None:\n    conn = aiohttp.TCPConnector(loop=loop)\n\n    ip1 = \"192.168.1.1\"\n    ip2 = \"192.168.1.2\"\n    ip3 = \"192.168.1.3\"\n    ip4 = \"192.168.1.4\"\n    ip5 = \"192.168.1.5\"\n    ips = [ip1, ip2, ip3, ip4, ip5]\n    addrs_tried = []\n    ips_tried = []\n\n    fingerprint = hashlib.sha256(b\"foo\").digest()\n\n    req = ClientRequest(\n        \"GET\",\n        URL(\"https://mocked.host\"),\n        ssl=aiohttp.Fingerprint(fingerprint),\n        loop=loop,\n    )\n\n    async def _resolve_host(host, port, traces=None):\n        return [\n            {\n                \"hostname\": host,\n                \"host\": ip,\n                \"port\": port,\n                \"family\": socket.AF_INET,\n                \"proto\": 0,\n                \"flags\": socket.AI_NUMERICHOST,\n            }\n            for ip in ips\n        ]\n\n    conn._resolve_host = _resolve_host\n\n    os_error = certificate_error = ssl_error = fingerprint_error = False\n    connected = False\n\n    async def start_connection(*args, **kwargs):\n        addr_infos: List[AddrInfoType] = kwargs[\"addr_infos\"]\n\n        first_addr_info = addr_infos[0]\n        first_addr_info_addr = first_addr_info[-1]\n        addrs_tried.append(first_addr_info_addr)\n\n        mock_socket = mock.create_autospec(socket.socket, spec_set=True, instance=True)\n        mock_socket.getpeername.return_value = first_addr_info_addr\n        return mock_socket\n\n    async def create_connection(*args, **kwargs):\n        nonlocal os_error, certificate_error, ssl_error, fingerprint_error\n        nonlocal connected\n\n        sock = kwargs[\"sock\"]\n        addr_info = sock.getpeername()\n        ip = addr_info[0]\n\n        ips_tried.append(ip)\n\n        if ip == ip1:\n            os_error = True\n            raise OSError\n\n        if ip == ip2:\n            certificate_error = True\n            raise ssl.CertificateError\n\n        if ip == ip3:\n            ssl_error = True\n            raise ssl.SSLError\n\n        if ip == ip4:\n            sock: socket.socket = kwargs[\"sock\"]\n\n            # Close the socket since we are not actually connecting\n            # and we don't want to leak it.\n            sock.close()\n\n            fingerprint_error = True\n            tr, pr = mock.Mock(), mock.Mock()\n\n            def get_extra_info(param):\n                if param == \"sslcontext\":\n                    return True\n\n                if param == \"ssl_object\":\n                    s = mock.Mock()\n                    s.getpeercert.return_value = b\"not foo\"\n                    return s\n\n                if param == \"peername\":\n                    return (\"192.168.1.5\", 12345)\n\n                if param == \"socket\":\n                    return sock\n\n                assert False, param\n\n            tr.get_extra_info = get_extra_info\n            return tr, pr\n\n        if ip == ip5:\n            sock: socket.socket = kwargs[\"sock\"]\n\n            # Close the socket since we are not actually connecting\n            # and we don't want to leak it.\n            sock.close()\n\n            connected = True\n            tr, pr = mock.Mock(), mock.Mock()\n\n            def get_extra_info(param):\n                if param == \"sslcontext\":\n                    return True\n\n                if param == \"ssl_object\":\n                    s = mock.Mock()\n                    s.getpeercert.return_value = b\"foo\"\n                    return s\n\n                assert False\n\n            tr.get_extra_info = get_extra_info\n            return tr, pr\n\n        assert False\n\n    conn._loop.create_connection = create_connection\n\n    with mock.patch(\n        \"aiohttp.connector.aiohappyeyeballs.start_connection\", start_connection\n    ):\n        established_connection = await conn.connect(req, [], ClientTimeout())\n\n    assert ips_tried == ips\n    assert addrs_tried == [(ip, 443) for ip in ips]\n\n    assert os_error\n    assert certificate_error\n    assert ssl_error\n    assert fingerprint_error\n    assert connected\n\n    established_connection.close()\n\n\n@pytest.mark.parametrize(\n    (\"happy_eyeballs_delay\"),\n    [0.1, 0.25, None],\n)\nasync def test_tcp_connector_happy_eyeballs(\n    loop: Any, happy_eyeballs_delay: Optional[float]\n) -> None:\n    conn = aiohttp.TCPConnector(happy_eyeballs_delay=happy_eyeballs_delay)\n\n    ip1 = \"dead::beef::\"\n    ip2 = \"192.168.1.1\"\n    ips = [ip1, ip2]\n    addrs_tried = []\n\n    req = ClientRequest(\n        \"GET\",\n        URL(\"https://mocked.host\"),\n        loop=loop,\n    )\n\n    async def _resolve_host(host, port, traces=None):\n        return [\n            {\n                \"hostname\": host,\n                \"host\": ip,\n                \"port\": port,\n                \"family\": socket.AF_INET6 if \":\" in ip else socket.AF_INET,\n                \"proto\": 0,\n                \"flags\": socket.AI_NUMERICHOST,\n            }\n            for ip in ips\n        ]\n\n    conn._resolve_host = _resolve_host\n\n    os_error = False\n    connected = False\n\n    async def sock_connect(*args, **kwargs):\n        addr = args[1]\n        nonlocal os_error\n\n        addrs_tried.append(addr)\n\n        if addr[0] == ip1:\n            os_error = True\n            raise OSError\n\n    async def create_connection(*args, **kwargs):\n        sock: socket.socket = kwargs[\"sock\"]\n\n        # Close the socket since we are not actually connecting\n        # and we don't want to leak it.\n        sock.close()\n\n        nonlocal connected\n        connected = True\n        tr = create_mocked_conn(loop)\n        pr = create_mocked_conn(loop)\n        return tr, pr\n\n    conn._loop.sock_connect = sock_connect\n    conn._loop.create_connection = create_connection\n\n    established_connection = await conn.connect(req, [], ClientTimeout())\n\n    assert addrs_tried == [(ip1, 443, 0, 0), (ip2, 443)]\n\n    assert os_error\n    assert connected\n\n    established_connection.close()\n\n\nasync def test_tcp_connector_interleave(loop: Any) -> None:\n    conn = aiohttp.TCPConnector(interleave=2)\n\n    ip1 = \"192.168.1.1\"\n    ip2 = \"192.168.1.2\"\n    ip3 = \"dead::beef::\"\n    ip4 = \"aaaa::beef::\"\n    ip5 = \"192.168.1.5\"\n    ips = [ip1, ip2, ip3, ip4, ip5]\n    success_ips = []\n    interleave = None\n\n    req = ClientRequest(\n        \"GET\",\n        URL(\"https://mocked.host\"),\n        loop=loop,\n    )\n\n    async def _resolve_host(host, port, traces=None):\n        return [\n            {\n                \"hostname\": host,\n                \"host\": ip,\n                \"port\": port,\n                \"family\": socket.AF_INET6 if \":\" in ip else socket.AF_INET,\n                \"proto\": 0,\n                \"flags\": socket.AI_NUMERICHOST,\n            }\n            for ip in ips\n        ]\n\n    conn._resolve_host = _resolve_host\n\n    async def start_connection(*args, **kwargs):\n        nonlocal interleave\n        addr_infos: List[AddrInfoType] = kwargs[\"addr_infos\"]\n        interleave = kwargs[\"interleave\"]\n        # Mock the 4th host connecting successfully\n        fourth_addr_info = addr_infos[3]\n        fourth_addr_info_addr = fourth_addr_info[-1]\n        mock_socket = mock.create_autospec(socket.socket, spec_set=True, instance=True)\n        mock_socket.getpeername.return_value = fourth_addr_info_addr\n        return mock_socket\n\n    async def create_connection(*args, **kwargs):\n        sock = kwargs[\"sock\"]\n        addr_info = sock.getpeername()\n        ip = addr_info[0]\n\n        success_ips.append(ip)\n\n        sock: socket.socket = kwargs[\"sock\"]\n        # Close the socket since we are not actually connecting\n        # and we don't want to leak it.\n        sock.close()\n        tr = create_mocked_conn(loop)\n        pr = create_mocked_conn(loop)\n        return tr, pr\n\n    conn._loop.create_connection = create_connection\n\n    with mock.patch(\n        \"aiohttp.connector.aiohappyeyeballs.start_connection\", start_connection\n    ):\n        established_connection = await conn.connect(req, [], ClientTimeout())\n\n    assert success_ips == [ip4]\n    assert interleave == 2\n    established_connection.close()\n\n\nasync def test_tcp_connector_family_is_respected(loop: Any) -> None:\n    conn = aiohttp.TCPConnector(family=socket.AF_INET)\n\n    ip1 = \"dead::beef::\"\n    ip2 = \"192.168.1.1\"\n    ips = [ip1, ip2]\n    addrs_tried = []\n\n    req = ClientRequest(\n        \"GET\",\n        URL(\"https://mocked.host\"),\n        loop=loop,\n    )\n\n    async def _resolve_host(host, port, traces=None):\n        return [\n            {\n                \"hostname\": host,\n                \"host\": ip,\n                \"port\": port,\n                \"family\": socket.AF_INET6 if \":\" in ip else socket.AF_INET,\n                \"proto\": 0,\n                \"flags\": socket.AI_NUMERICHOST,\n            }\n            for ip in ips\n        ]\n\n    conn._resolve_host = _resolve_host\n    connected = False\n\n    async def sock_connect(*args, **kwargs):\n        addr = args[1]\n        addrs_tried.append(addr)\n\n    async def create_connection(*args, **kwargs):\n        sock: socket.socket = kwargs[\"sock\"]\n\n        # Close the socket since we are not actually connecting\n        # and we don't want to leak it.\n        sock.close()\n\n        nonlocal connected\n        connected = True\n        tr = create_mocked_conn(loop)\n        pr = create_mocked_conn(loop)\n        return tr, pr\n\n    conn._loop.sock_connect = sock_connect\n    conn._loop.create_connection = create_connection\n\n    established_connection = await conn.connect(req, [], ClientTimeout())\n\n    # We should only try the IPv4 address since we specified\n    # the family to be AF_INET\n    assert addrs_tried == [(ip2, 443)]\n\n    assert connected\n\n    established_connection.close()\n\n\nasync def test_tcp_connector_resolve_host(loop: Any) -> None:\n    conn = aiohttp.TCPConnector(use_dns_cache=True)\n\n    res = await conn._resolve_host(\"localhost\", 8080)\n    assert res\n    for rec in res:\n        if rec[\"family\"] == socket.AF_INET:\n            assert rec[\"host\"] == \"127.0.0.1\"\n            assert rec[\"hostname\"] == \"localhost\"\n            assert rec[\"port\"] == 8080\n        elif rec[\"family\"] == socket.AF_INET6:\n            assert rec[\"hostname\"] == \"localhost\"\n            assert rec[\"port\"] == 8080\n            if platform.system() == \"Darwin\":\n                assert rec[\"host\"] in (\"::1\", \"fe80::1\", \"fe80::1%lo0\")\n            else:\n                assert rec[\"host\"] == \"::1\"\n\n\n@pytest.fixture\ndef dns_response(loop):\n    async def coro():\n        # simulates a network operation\n        await asyncio.sleep(0)\n        return [\"127.0.0.1\"]\n\n    return coro\n\n\nasync def test_tcp_connector_dns_cache_not_expired(loop, dns_response) -> None:\n    with mock.patch(\"aiohttp.connector.DefaultResolver\") as m_resolver:\n        conn = aiohttp.TCPConnector(loop=loop, use_dns_cache=True, ttl_dns_cache=10)\n        m_resolver().resolve.return_value = dns_response()\n        await conn._resolve_host(\"localhost\", 8080)\n        await conn._resolve_host(\"localhost\", 8080)\n        m_resolver().resolve.assert_called_once_with(\"localhost\", 8080, family=0)\n\n\nasync def test_tcp_connector_dns_cache_forever(loop, dns_response) -> None:\n    with mock.patch(\"aiohttp.connector.DefaultResolver\") as m_resolver:\n        conn = aiohttp.TCPConnector(loop=loop, use_dns_cache=True, ttl_dns_cache=10)\n        m_resolver().resolve.return_value = dns_response()\n        await conn._resolve_host(\"localhost\", 8080)\n        await conn._resolve_host(\"localhost\", 8080)\n        m_resolver().resolve.assert_called_once_with(\"localhost\", 8080, family=0)\n\n\nasync def test_tcp_connector_use_dns_cache_disabled(loop, dns_response) -> None:\n    with mock.patch(\"aiohttp.connector.DefaultResolver\") as m_resolver:\n        conn = aiohttp.TCPConnector(loop=loop, use_dns_cache=False)\n        m_resolver().resolve.side_effect = [dns_response(), dns_response()]\n        await conn._resolve_host(\"localhost\", 8080)\n        await conn._resolve_host(\"localhost\", 8080)\n        m_resolver().resolve.assert_has_calls(\n            [\n                mock.call(\"localhost\", 8080, family=0),\n                mock.call(\"localhost\", 8080, family=0),\n            ]\n        )\n\n\nasync def test_tcp_connector_dns_throttle_requests(loop, dns_response) -> None:\n    with mock.patch(\"aiohttp.connector.DefaultResolver\") as m_resolver:\n        conn = aiohttp.TCPConnector(loop=loop, use_dns_cache=True, ttl_dns_cache=10)\n        m_resolver().resolve.return_value = dns_response()\n        loop.create_task(conn._resolve_host(\"localhost\", 8080))\n        loop.create_task(conn._resolve_host(\"localhost\", 8080))\n        await asyncio.sleep(0)\n        await asyncio.sleep(0)\n        m_resolver().resolve.assert_called_once_with(\"localhost\", 8080, family=0)\n\n\nasync def test_tcp_connector_dns_throttle_requests_exception_spread(loop) -> None:\n    with mock.patch(\"aiohttp.connector.DefaultResolver\") as m_resolver:\n        conn = aiohttp.TCPConnector(loop=loop, use_dns_cache=True, ttl_dns_cache=10)\n        e = Exception()\n        m_resolver().resolve.side_effect = e\n        r1 = loop.create_task(conn._resolve_host(\"localhost\", 8080))\n        r2 = loop.create_task(conn._resolve_host(\"localhost\", 8080))\n        await asyncio.sleep(0)\n        await asyncio.sleep(0)\n        await asyncio.sleep(0)\n        await asyncio.sleep(0)\n        assert r1.exception() == e\n        assert r2.exception() == e\n\n\nasync def test_tcp_connector_dns_throttle_requests_cancelled_when_close(\n    loop, dns_response\n):\n\n    with mock.patch(\"aiohttp.connector.DefaultResolver\") as m_resolver:\n        conn = aiohttp.TCPConnector(loop=loop, use_dns_cache=True, ttl_dns_cache=10)\n        m_resolver().resolve.return_value = dns_response()\n        loop.create_task(conn._resolve_host(\"localhost\", 8080))\n        f = loop.create_task(conn._resolve_host(\"localhost\", 8080))\n\n        await asyncio.sleep(0)\n        await asyncio.sleep(0)\n        await conn.close()\n\n        with pytest.raises(asyncio.CancelledError):\n            await f\n\n\n@pytest.fixture\ndef dns_response_error(loop):\n    async def coro():\n        # simulates a network operation\n        await asyncio.sleep(0)\n        raise socket.gaierror(-3, \"Temporary failure in name resolution\")\n\n    return coro\n\n\nasync def test_tcp_connector_cancel_dns_error_captured(\n    loop, dns_response_error\n) -> None:\n\n    exception_handler_called = False\n\n    def exception_handler(loop, context):\n        nonlocal exception_handler_called\n        exception_handler_called = True\n\n    loop.set_exception_handler(mock.Mock(side_effect=exception_handler))\n\n    with mock.patch(\"aiohttp.connector.DefaultResolver\") as m_resolver:\n        req = ClientRequest(\n            method=\"GET\", url=URL(\"http://temporary-failure:80\"), loop=loop\n        )\n        conn = aiohttp.TCPConnector(\n            use_dns_cache=False,\n        )\n        m_resolver().resolve.return_value = dns_response_error()\n        f = loop.create_task(conn._create_direct_connection(req, [], ClientTimeout(0)))\n\n        await asyncio.sleep(0)\n        f.cancel()\n        with pytest.raises(asyncio.CancelledError):\n            await f\n\n        gc.collect()\n        assert exception_handler_called is False\n\n\nasync def test_tcp_connector_dns_tracing(loop, dns_response) -> None:\n    session = mock.Mock()\n    trace_config_ctx = mock.Mock()\n    on_dns_resolvehost_start = mock.Mock(side_effect=make_mocked_coro(mock.Mock()))\n    on_dns_resolvehost_end = mock.Mock(side_effect=make_mocked_coro(mock.Mock()))\n    on_dns_cache_hit = mock.Mock(side_effect=make_mocked_coro(mock.Mock()))\n    on_dns_cache_miss = mock.Mock(side_effect=make_mocked_coro(mock.Mock()))\n\n    trace_config = aiohttp.TraceConfig(\n        trace_config_ctx_factory=mock.Mock(return_value=trace_config_ctx)\n    )\n    trace_config.on_dns_resolvehost_start.append(on_dns_resolvehost_start)\n    trace_config.on_dns_resolvehost_end.append(on_dns_resolvehost_end)\n    trace_config.on_dns_cache_hit.append(on_dns_cache_hit)\n    trace_config.on_dns_cache_miss.append(on_dns_cache_miss)\n    trace_config.freeze()\n    traces = [Trace(session, trace_config, trace_config.trace_config_ctx())]\n\n    with mock.patch(\"aiohttp.connector.DefaultResolver\") as m_resolver:\n        conn = aiohttp.TCPConnector(loop=loop, use_dns_cache=True, ttl_dns_cache=10)\n\n        m_resolver().resolve.return_value = dns_response()\n\n        await conn._resolve_host(\"localhost\", 8080, traces=traces)\n        on_dns_resolvehost_start.assert_called_once_with(\n            session,\n            trace_config_ctx,\n            aiohttp.TraceDnsResolveHostStartParams(\"localhost\"),\n        )\n        on_dns_resolvehost_end.assert_called_once_with(\n            session, trace_config_ctx, aiohttp.TraceDnsResolveHostEndParams(\"localhost\")\n        )\n        on_dns_cache_miss.assert_called_once_with(\n            session, trace_config_ctx, aiohttp.TraceDnsCacheMissParams(\"localhost\")\n        )\n        assert not on_dns_cache_hit.called\n\n        await conn._resolve_host(\"localhost\", 8080, traces=traces)\n        on_dns_cache_hit.assert_called_once_with(\n            session, trace_config_ctx, aiohttp.TraceDnsCacheHitParams(\"localhost\")\n        )\n\n\nasync def test_tcp_connector_dns_tracing_cache_disabled(loop, dns_response) -> None:\n    session = mock.Mock()\n    trace_config_ctx = mock.Mock()\n    on_dns_resolvehost_start = mock.Mock(side_effect=make_mocked_coro(mock.Mock()))\n    on_dns_resolvehost_end = mock.Mock(side_effect=make_mocked_coro(mock.Mock()))\n\n    trace_config = aiohttp.TraceConfig(\n        trace_config_ctx_factory=mock.Mock(return_value=trace_config_ctx)\n    )\n    trace_config.on_dns_resolvehost_start.append(on_dns_resolvehost_start)\n    trace_config.on_dns_resolvehost_end.append(on_dns_resolvehost_end)\n    trace_config.freeze()\n    traces = [Trace(session, trace_config, trace_config.trace_config_ctx())]\n\n    with mock.patch(\"aiohttp.connector.DefaultResolver\") as m_resolver:\n        conn = aiohttp.TCPConnector(loop=loop, use_dns_cache=False)\n\n        m_resolver().resolve.side_effect = [dns_response(), dns_response()]\n\n        await conn._resolve_host(\"localhost\", 8080, traces=traces)\n\n        await conn._resolve_host(\"localhost\", 8080, traces=traces)\n\n        on_dns_resolvehost_start.assert_has_calls(\n            [\n                mock.call(\n                    session,\n                    trace_config_ctx,\n                    aiohttp.TraceDnsResolveHostStartParams(\"localhost\"),\n                ),\n                mock.call(\n                    session,\n                    trace_config_ctx,\n                    aiohttp.TraceDnsResolveHostStartParams(\"localhost\"),\n                ),\n            ]\n        )\n        on_dns_resolvehost_end.assert_has_calls(\n            [\n                mock.call(\n                    session,\n                    trace_config_ctx,\n                    aiohttp.TraceDnsResolveHostEndParams(\"localhost\"),\n                ),\n                mock.call(\n                    session,\n                    trace_config_ctx,\n                    aiohttp.TraceDnsResolveHostEndParams(\"localhost\"),\n                ),\n            ]\n        )\n\n\nasync def test_tcp_connector_dns_tracing_throttle_requests(loop, dns_response) -> None:\n    session = mock.Mock()\n    trace_config_ctx = mock.Mock()\n    on_dns_cache_hit = mock.Mock(side_effect=make_mocked_coro(mock.Mock()))\n    on_dns_cache_miss = mock.Mock(side_effect=make_mocked_coro(mock.Mock()))\n\n    trace_config = aiohttp.TraceConfig(\n        trace_config_ctx_factory=mock.Mock(return_value=trace_config_ctx)\n    )\n    trace_config.on_dns_cache_hit.append(on_dns_cache_hit)\n    trace_config.on_dns_cache_miss.append(on_dns_cache_miss)\n    trace_config.freeze()\n    traces = [Trace(session, trace_config, trace_config.trace_config_ctx())]\n\n    with mock.patch(\"aiohttp.connector.DefaultResolver\") as m_resolver:\n        conn = aiohttp.TCPConnector(loop=loop, use_dns_cache=True, ttl_dns_cache=10)\n        m_resolver().resolve.return_value = dns_response()\n        loop.create_task(conn._resolve_host(\"localhost\", 8080, traces=traces))\n        loop.create_task(conn._resolve_host(\"localhost\", 8080, traces=traces))\n        await asyncio.sleep(0)\n        await asyncio.sleep(0)\n        on_dns_cache_hit.assert_called_once_with(\n            session, trace_config_ctx, aiohttp.TraceDnsCacheHitParams(\"localhost\")\n        )\n        on_dns_cache_miss.assert_called_once_with(\n            session, trace_config_ctx, aiohttp.TraceDnsCacheMissParams(\"localhost\")\n        )\n\n\nasync def test_dns_error(loop) -> None:\n    connector = aiohttp.TCPConnector(loop=loop)\n    connector._resolve_host = make_mocked_coro(\n        raise_exception=OSError(\"dont take it serious\")\n    )\n\n    req = ClientRequest(\"GET\", URL(\"http://www.python.org\"), loop=loop)\n\n    with pytest.raises(aiohttp.ClientConnectorError):\n        await connector.connect(req, [], ClientTimeout())\n\n\nasync def test_get_pop_empty_conns(loop) -> None:\n    # see issue #473\n    conn = aiohttp.BaseConnector(loop=loop)\n    key = (\"127.0.0.1\", 80, False)\n    conn._conns[key] = []\n    proto = conn._get(key)\n    assert proto is None\n    assert not conn._conns\n\n\nasync def test_release_close_do_not_add_to_pool(loop, key) -> None:\n    # see issue #473\n    conn = aiohttp.BaseConnector(loop=loop)\n\n    proto = mock.Mock(should_close=True)\n\n    conn._acquired.add(proto)\n    conn._release(key, proto)\n    assert not conn._conns\n\n\nasync def test_release_close_do_not_delete_existing_connections(key) -> None:\n    proto1 = mock.Mock()\n\n    conn = aiohttp.BaseConnector()\n    conn._conns[key] = [(proto1, 1)]\n\n    proto = mock.Mock(should_close=True)\n    conn._acquired.add(proto)\n    conn._release(key, proto)\n    assert conn._conns[key] == [(proto1, 1)]\n    assert proto.close.called\n    await conn.close()\n\n\nasync def test_release_not_started(loop) -> None:\n    conn = aiohttp.BaseConnector(loop=loop)\n    proto = mock.Mock(should_close=False)\n    key = 1\n    conn._acquired.add(proto)\n    conn._release(key, proto)\n    # assert conn._conns == {1: [(proto, 10)]}\n    rec = conn._conns[1]\n    assert rec[0][0] == proto\n    assert rec[0][1] == pytest.approx(loop.time(), abs=0.05)\n    assert not proto.close.called\n    await conn.close()\n\n\nasync def test_release_not_opened(loop, key) -> None:\n    conn = aiohttp.BaseConnector(loop=loop)\n\n    proto = mock.Mock()\n    conn._acquired.add(proto)\n    conn._release(key, proto)\n    assert proto.close.called\n\n\nasync def test_connect(loop, key) -> None:\n    proto = mock.Mock()\n    proto.is_connected.return_value = True\n\n    req = ClientRequest(\"GET\", URL(\"http://localhost:80\"), loop=loop)\n\n    conn = aiohttp.BaseConnector(loop=loop)\n    conn._conns[key] = [(proto, loop.time())]\n    conn._create_connection = mock.Mock()\n    conn._create_connection.return_value = loop.create_future()\n    conn._create_connection.return_value.set_result(proto)\n\n    connection = await conn.connect(req, [], ClientTimeout())\n    assert not conn._create_connection.called\n    assert connection._protocol is proto\n    assert connection.transport is proto.transport\n    assert isinstance(connection, Connection)\n    connection.close()\n\n\nasync def test_connect_tracing(loop) -> None:\n    session = mock.Mock()\n    trace_config_ctx = mock.Mock()\n    on_connection_create_start = mock.Mock(side_effect=make_mocked_coro(mock.Mock()))\n    on_connection_create_end = mock.Mock(side_effect=make_mocked_coro(mock.Mock()))\n\n    trace_config = aiohttp.TraceConfig(\n        trace_config_ctx_factory=mock.Mock(return_value=trace_config_ctx)\n    )\n    trace_config.on_connection_create_start.append(on_connection_create_start)\n    trace_config.on_connection_create_end.append(on_connection_create_end)\n    trace_config.freeze()\n    traces = [Trace(session, trace_config, trace_config.trace_config_ctx())]\n\n    proto = mock.Mock()\n    proto.is_connected.return_value = True\n\n    req = ClientRequest(\"GET\", URL(\"http://host:80\"), loop=loop)\n\n    conn = aiohttp.BaseConnector(loop=loop)\n    conn._create_connection = mock.Mock()\n    conn._create_connection.return_value = loop.create_future()\n    conn._create_connection.return_value.set_result(proto)\n\n    conn2 = await conn.connect(req, traces, ClientTimeout())\n    conn2.release()\n\n    on_connection_create_start.assert_called_with(\n        session, trace_config_ctx, aiohttp.TraceConnectionCreateStartParams()\n    )\n    on_connection_create_end.assert_called_with(\n        session, trace_config_ctx, aiohttp.TraceConnectionCreateEndParams()\n    )\n\n\nasync def test_close_during_connect(loop) -> None:\n    proto = mock.Mock()\n    proto.is_connected.return_value = True\n\n    fut = loop.create_future()\n    req = ClientRequest(\"GET\", URL(\"http://host:80\"), loop=loop)\n\n    conn = aiohttp.BaseConnector(loop=loop)\n    conn._create_connection = mock.Mock()\n    conn._create_connection.return_value = fut\n\n    task = loop.create_task(conn.connect(req, None, ClientTimeout()))\n    await asyncio.sleep(0)\n    await conn.close()\n\n    fut.set_result(proto)\n    with pytest.raises(aiohttp.ClientConnectionError):\n        await task\n\n    assert proto.close.called\n\n\nasync def test_ctor_cleanup() -> None:\n    loop = mock.Mock()\n    loop.time.return_value = 1.5\n    conn = aiohttp.BaseConnector(\n        loop=loop, keepalive_timeout=10, enable_cleanup_closed=True\n    )\n    assert conn._cleanup_handle is None\n    assert conn._cleanup_closed_handle is not None\n\n\nasync def test_cleanup(key) -> None:\n    testset = {\n        key: [(mock.Mock(), 10), (mock.Mock(), 300)],\n    }\n    testset[key][0][0].is_connected.return_value = True\n    testset[key][1][0].is_connected.return_value = False\n\n    loop = mock.Mock()\n    loop.time.return_value = 300\n    conn = aiohttp.BaseConnector(loop=loop)\n    conn._conns = testset\n    existing_handle = conn._cleanup_handle = mock.Mock()\n\n    conn._cleanup()\n    assert existing_handle.cancel.called\n    assert conn._conns == {}\n    assert conn._cleanup_handle is None\n\n\nasync def test_cleanup_close_ssl_transport(ssl_key) -> None:\n    proto = mock.Mock()\n    transport = proto.transport\n    testset = {ssl_key: [(proto, 10)]}\n\n    loop = mock.Mock()\n    loop.time.return_value = 300\n    conn = aiohttp.BaseConnector(loop=loop, enable_cleanup_closed=True)\n    conn._conns = testset\n    existing_handle = conn._cleanup_handle = mock.Mock()\n\n    conn._cleanup()\n    assert existing_handle.cancel.called\n    assert conn._conns == {}\n    assert conn._cleanup_closed_transports == [transport]\n\n\nasync def test_cleanup2() -> None:\n    testset = {1: [(mock.Mock(), 300)]}\n    testset[1][0][0].is_connected.return_value = True\n\n    loop = mock.Mock()\n    loop.time.return_value = 300\n\n    conn = aiohttp.BaseConnector(loop=loop, keepalive_timeout=10)\n    conn._conns = testset\n    conn._cleanup()\n    assert conn._conns == testset\n\n    assert conn._cleanup_handle is not None\n    loop.call_at.assert_called_with(310, mock.ANY, mock.ANY)\n    await conn.close()\n\n\nasync def test_cleanup3(key) -> None:\n    testset = {key: [(mock.Mock(), 290.1), (mock.Mock(), 305.1)]}\n    testset[key][0][0].is_connected.return_value = True\n\n    loop = mock.Mock()\n    loop.time.return_value = 308.5\n\n    conn = aiohttp.BaseConnector(loop=loop, keepalive_timeout=10)\n    conn._conns = testset\n\n    conn._cleanup()\n    assert conn._conns == {key: [testset[key][1]]}\n\n    assert conn._cleanup_handle is not None\n    loop.call_at.assert_called_with(319, mock.ANY, mock.ANY)\n    await conn.close()\n\n\nasync def test_cleanup_closed(loop, mocker) -> None:\n    if not hasattr(loop, \"__dict__\"):\n        pytest.skip(\"can not override loop attributes\")\n\n    mocker.spy(loop, \"call_at\")\n    conn = aiohttp.BaseConnector(loop=loop, enable_cleanup_closed=True)\n\n    tr = mock.Mock()\n    conn._cleanup_closed_handle = cleanup_closed_handle = mock.Mock()\n    conn._cleanup_closed_transports = [tr]\n    conn._cleanup_closed()\n    assert tr.abort.called\n    assert not conn._cleanup_closed_transports\n    assert loop.call_at.called\n    assert cleanup_closed_handle.cancel.called\n\n\nasync def test_cleanup_closed_disabled(loop, mocker) -> None:\n    conn = aiohttp.BaseConnector(loop=loop, enable_cleanup_closed=False)\n\n    tr = mock.Mock()\n    conn._cleanup_closed_transports = [tr]\n    conn._cleanup_closed()\n    assert tr.abort.called\n    assert not conn._cleanup_closed_transports\n\n\nasync def test_tcp_connector_ctor() -> None:\n    conn = aiohttp.TCPConnector()\n    assert conn._ssl is True\n\n    assert conn.use_dns_cache\n    assert conn.family == 0\n\n\nasync def test_tcp_connector_allowed_protocols(loop: asyncio.AbstractEventLoop) -> None:\n    conn = aiohttp.TCPConnector()\n    assert conn.allowed_protocol_schema_set == {\"\", \"tcp\", \"http\", \"https\", \"ws\", \"wss\"}\n\n\nasync def test_invalid_ssl_param() -> None:\n    with pytest.raises(TypeError):\n        aiohttp.TCPConnector(ssl=object())  # type: ignore[arg-type]\n\n\nasync def test_tcp_connector_ctor_fingerprint_valid(\n    loop: asyncio.AbstractEventLoop,\n) -> None:\n    valid = aiohttp.Fingerprint(hashlib.sha256(b\"foo\").digest())\n    conn = aiohttp.TCPConnector(ssl=valid, loop=loop)\n    assert conn._ssl is valid\n\n\nasync def test_insecure_fingerprint_md5(loop) -> None:\n    with pytest.raises(ValueError):\n        aiohttp.TCPConnector(\n            ssl=aiohttp.Fingerprint(hashlib.md5(b\"foo\").digest()), loop=loop\n        )\n\n\nasync def test_insecure_fingerprint_sha1(loop) -> None:\n    with pytest.raises(ValueError):\n        aiohttp.TCPConnector(\n            ssl=aiohttp.Fingerprint(hashlib.sha1(b\"foo\").digest()), loop=loop\n        )\n\n\nasync def test_tcp_connector_clear_dns_cache(loop) -> None:\n    conn = aiohttp.TCPConnector(loop=loop)\n    hosts = [\"a\", \"b\"]\n    conn._cached_hosts.add((\"localhost\", 123), hosts)\n    conn._cached_hosts.add((\"localhost\", 124), hosts)\n    conn.clear_dns_cache(\"localhost\", 123)\n    with pytest.raises(KeyError):\n        conn._cached_hosts.next_addrs((\"localhost\", 123))\n\n    assert conn._cached_hosts.next_addrs((\"localhost\", 124)) == hosts\n\n    # Remove removed element is OK\n    conn.clear_dns_cache(\"localhost\", 123)\n    with pytest.raises(KeyError):\n        conn._cached_hosts.next_addrs((\"localhost\", 123))\n\n    conn.clear_dns_cache()\n    with pytest.raises(KeyError):\n        conn._cached_hosts.next_addrs((\"localhost\", 124))\n\n\nasync def test_tcp_connector_clear_dns_cache_bad_args(loop) -> None:\n    conn = aiohttp.TCPConnector(loop=loop)\n    with pytest.raises(ValueError):\n        conn.clear_dns_cache(\"localhost\")\n\n\nasync def test_dont_recreate_ssl_context() -> None:\n    conn = aiohttp.TCPConnector()\n    ctx = await conn._make_or_get_ssl_context(True)\n    assert ctx is await conn._make_or_get_ssl_context(True)\n\n\nasync def test_dont_recreate_ssl_context2() -> None:\n    conn = aiohttp.TCPConnector()\n    ctx = await conn._make_or_get_ssl_context(False)\n    assert ctx is await conn._make_or_get_ssl_context(False)\n\n\nasync def test___get_ssl_context1() -> None:\n    conn = aiohttp.TCPConnector()\n    req = mock.Mock()\n    req.is_ssl.return_value = False\n    assert await conn._get_ssl_context(req) is None\n\n\nasync def test___get_ssl_context2(loop) -> None:\n    ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)\n    conn = aiohttp.TCPConnector(loop=loop)\n    req = mock.Mock()\n    req.is_ssl.return_value = True\n    req.ssl = ctx\n    assert await conn._get_ssl_context(req) is ctx\n\n\nasync def test___get_ssl_context3(loop) -> None:\n    ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)\n    conn = aiohttp.TCPConnector(loop=loop, ssl=ctx)\n    req = mock.Mock()\n    req.is_ssl.return_value = True\n    req.ssl = True\n    assert await conn._get_ssl_context(req) is ctx\n\n\nasync def test___get_ssl_context4(loop) -> None:\n    ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)\n    conn = aiohttp.TCPConnector(loop=loop, ssl=ctx)\n    req = mock.Mock()\n    req.is_ssl.return_value = True\n    req.ssl = False\n    assert await conn._get_ssl_context(req) is await conn._make_or_get_ssl_context(\n        False\n    )\n\n\nasync def test___get_ssl_context5(loop) -> None:\n    ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)\n    conn = aiohttp.TCPConnector(loop=loop, ssl=ctx)\n    req = mock.Mock()\n    req.is_ssl.return_value = True\n    req.ssl = aiohttp.Fingerprint(hashlib.sha256(b\"1\").digest())\n    assert await conn._get_ssl_context(req) is await conn._make_or_get_ssl_context(\n        False\n    )\n\n\nasync def test___get_ssl_context6() -> None:\n    conn = aiohttp.TCPConnector()\n    req = mock.Mock()\n    req.is_ssl.return_value = True\n    req.ssl = True\n    assert await conn._get_ssl_context(req) is await conn._make_or_get_ssl_context(True)\n\n\nasync def test_ssl_context_once() -> None:\n    \"\"\"Test the ssl context is created only once and shared between connectors.\"\"\"\n    conn1 = aiohttp.TCPConnector()\n    conn2 = aiohttp.TCPConnector()\n    conn3 = aiohttp.TCPConnector()\n\n    req = mock.Mock()\n    req.is_ssl.return_value = True\n    req.ssl = True\n    assert await conn1._get_ssl_context(req) is await conn1._make_or_get_ssl_context(\n        True\n    )\n    assert await conn2._get_ssl_context(req) is await conn1._make_or_get_ssl_context(\n        True\n    )\n    assert await conn3._get_ssl_context(req) is await conn1._make_or_get_ssl_context(\n        True\n    )\n    assert conn1._made_ssl_context is conn2._made_ssl_context is conn3._made_ssl_context\n    assert True in conn1._made_ssl_context\n\n\n@pytest.mark.parametrize(\"exception\", [OSError, ssl.SSLError, asyncio.CancelledError])\nasync def test_ssl_context_creation_raises(exception: Type[BaseException]) -> None:\n    \"\"\"Test that we try again if SSLContext creation fails the first time.\"\"\"\n    conn = aiohttp.TCPConnector()\n    conn._made_ssl_context.clear()\n\n    with mock.patch.object(\n        conn, \"_make_ssl_context\", side_effect=exception\n    ), pytest.raises(exception):\n        await conn._make_or_get_ssl_context(True)\n\n    assert isinstance(await conn._make_or_get_ssl_context(True), ssl.SSLContext)\n\n\nasync def test_close_twice(loop) -> None:\n    proto = mock.Mock()\n\n    conn = aiohttp.BaseConnector(loop=loop)\n    conn._conns[1] = [(proto, object())]\n    await conn.close()\n\n    assert not conn._conns\n    assert proto.close.called\n    assert conn.closed\n\n    conn._conns = \"Invalid\"  # fill with garbage\n    await conn.close()\n    assert conn.closed\n\n\nasync def test_close_cancels_cleanup_handle(loop) -> None:\n    conn = aiohttp.BaseConnector(loop=loop)\n    conn._release(1, mock.Mock(should_close=False))\n    assert conn._cleanup_handle is not None\n    await conn.close()\n    assert conn._cleanup_handle is None\n\n\nasync def test_close_cancels_resolve_host(loop: asyncio.AbstractEventLoop) -> None:\n    cancelled = False\n\n    async def delay_resolve_host(*args: object) -> None:\n        \"\"\"Delay _resolve_host() task in order to test cancellation.\"\"\"\n        nonlocal cancelled\n        try:\n            await asyncio.sleep(10)\n        except asyncio.CancelledError:\n            cancelled = True\n            raise\n\n    conn = aiohttp.TCPConnector()\n    req = ClientRequest(\n        \"GET\", URL(\"http://localhost:80\"), loop=loop, response_class=mock.Mock()\n    )\n    with mock.patch.object(conn, \"_resolve_host_with_throttle\", delay_resolve_host):\n        t = asyncio.create_task(conn.connect(req, [], ClientTimeout()))\n        # Let it create the internal task\n        await asyncio.sleep(0)\n        # Let that task start running\n        await asyncio.sleep(0)\n\n        # We now have a task being tracked and can ensure that .close() cancels it.\n        assert len(conn._resolve_host_tasks) == 1\n        await conn.close()\n        await asyncio.sleep(0.01)\n        assert cancelled\n        assert len(conn._resolve_host_tasks) == 0\n\n        with suppress(asyncio.CancelledError):\n            await t\n\n\nasync def test_close_abort_closed_transports(loop: asyncio.AbstractEventLoop) -> None:\n    tr = mock.Mock()\n\n    conn = aiohttp.BaseConnector(loop=loop)\n    conn._cleanup_closed_transports.append(tr)\n    await conn.close()\n\n    assert not conn._cleanup_closed_transports\n    assert tr.abort.called\n    assert conn.closed\n\n\nasync def test_close_cancels_cleanup_closed_handle(loop) -> None:\n    conn = aiohttp.BaseConnector(loop=loop, enable_cleanup_closed=True)\n    assert conn._cleanup_closed_handle is not None\n    await conn.close()\n    assert conn._cleanup_closed_handle is None\n\n\nasync def test_ctor_with_default_loop(loop) -> None:\n    conn = aiohttp.BaseConnector()\n    assert loop is conn._loop\n\n\nasync def test_base_connector_allows_high_level_protocols(\n    loop: asyncio.AbstractEventLoop,\n) -> None:\n    conn = aiohttp.BaseConnector()\n    assert conn.allowed_protocol_schema_set == {\n        \"\",\n        \"http\",\n        \"https\",\n        \"ws\",\n        \"wss\",\n    }\n\n\nasync def test_connect_with_limit(\n    loop: asyncio.AbstractEventLoop, key: ConnectionKey\n) -> None:\n    proto = create_mocked_conn(loop)\n    proto.is_connected.return_value = True\n\n    req = ClientRequest(\n        \"GET\", URL(\"http://localhost:80\"), loop=loop, response_class=mock.Mock()\n    )\n\n    conn = aiohttp.BaseConnector(loop=loop, limit=1)\n    conn._conns[key] = [(proto, loop.time())]\n    conn._create_connection = mock.Mock()\n    conn._create_connection.return_value = loop.create_future()\n    conn._create_connection.return_value.set_result(proto)\n\n    connection1 = await conn.connect(req, None, ClientTimeout())\n    assert connection1._protocol == proto\n\n    assert 1 == len(conn._acquired)\n    assert proto in conn._acquired\n    assert key in conn._acquired_per_host\n    assert proto in conn._acquired_per_host[key]\n\n    acquired = False\n\n    async def f():\n        nonlocal acquired\n        connection2 = await conn.connect(req, None, ClientTimeout())\n        acquired = True\n        assert 1 == len(conn._acquired)\n        assert 1 == len(conn._acquired_per_host[key])\n        connection2.release()\n\n    task = loop.create_task(f())\n\n    await asyncio.sleep(0.01)\n    assert not acquired\n    connection1.release()\n    await asyncio.sleep(0)\n    assert acquired\n    await task\n    await conn.close()\n\n\nasync def test_connect_queued_operation_tracing(loop, key) -> None:\n    session = mock.Mock()\n    trace_config_ctx = mock.Mock()\n    on_connection_queued_start = mock.Mock(side_effect=make_mocked_coro(mock.Mock()))\n    on_connection_queued_end = mock.Mock(side_effect=make_mocked_coro(mock.Mock()))\n\n    trace_config = aiohttp.TraceConfig(\n        trace_config_ctx_factory=mock.Mock(return_value=trace_config_ctx)\n    )\n    trace_config.on_connection_queued_start.append(on_connection_queued_start)\n    trace_config.on_connection_queued_end.append(on_connection_queued_end)\n    trace_config.freeze()\n    traces = [Trace(session, trace_config, trace_config.trace_config_ctx())]\n\n    proto = mock.Mock()\n    proto.is_connected.return_value = True\n\n    req = ClientRequest(\n        \"GET\", URL(\"http://localhost1:80\"), loop=loop, response_class=mock.Mock()\n    )\n\n    conn = aiohttp.BaseConnector(loop=loop, limit=1)\n    conn._conns[key] = [(proto, loop.time())]\n    conn._create_connection = mock.Mock()\n    conn._create_connection.return_value = loop.create_future()\n    conn._create_connection.return_value.set_result(proto)\n\n    connection1 = await conn.connect(req, traces, ClientTimeout())\n\n    async def f():\n        connection2 = await conn.connect(req, traces, ClientTimeout())\n        on_connection_queued_start.assert_called_with(\n            session, trace_config_ctx, aiohttp.TraceConnectionQueuedStartParams()\n        )\n        on_connection_queued_end.assert_called_with(\n            session, trace_config_ctx, aiohttp.TraceConnectionQueuedEndParams()\n        )\n        connection2.release()\n\n    task = asyncio.ensure_future(f(), loop=loop)\n    await asyncio.sleep(0.01)\n    connection1.release()\n    await task\n    await conn.close()\n\n\nasync def test_connect_reuseconn_tracing(loop, key) -> None:\n    session = mock.Mock()\n    trace_config_ctx = mock.Mock()\n    on_connection_reuseconn = mock.Mock(side_effect=make_mocked_coro(mock.Mock()))\n\n    trace_config = aiohttp.TraceConfig(\n        trace_config_ctx_factory=mock.Mock(return_value=trace_config_ctx)\n    )\n    trace_config.on_connection_reuseconn.append(on_connection_reuseconn)\n    trace_config.freeze()\n    traces = [Trace(session, trace_config, trace_config.trace_config_ctx())]\n\n    proto = mock.Mock()\n    proto.is_connected.return_value = True\n\n    req = ClientRequest(\n        \"GET\", URL(\"http://localhost:80\"), loop=loop, response_class=mock.Mock()\n    )\n\n    conn = aiohttp.BaseConnector(loop=loop, limit=1)\n    conn._conns[key] = [(proto, loop.time())]\n    conn2 = await conn.connect(req, traces, ClientTimeout())\n    conn2.release()\n\n    on_connection_reuseconn.assert_called_with(\n        session, trace_config_ctx, aiohttp.TraceConnectionReuseconnParams()\n    )\n    await conn.close()\n\n\nasync def test_connect_with_limit_and_limit_per_host(loop, key) -> None:\n    proto = mock.Mock()\n    proto.is_connected.return_value = True\n\n    req = ClientRequest(\"GET\", URL(\"http://localhost:80\"), loop=loop)\n\n    conn = aiohttp.BaseConnector(loop=loop, limit=1000, limit_per_host=1)\n    conn._conns[key] = [(proto, loop.time())]\n    conn._create_connection = mock.Mock()\n    conn._create_connection.return_value = loop.create_future()\n    conn._create_connection.return_value.set_result(proto)\n\n    acquired = False\n    connection1 = await conn.connect(req, None, ClientTimeout())\n\n    async def f():\n        nonlocal acquired\n        connection2 = await conn.connect(req, None, ClientTimeout())\n        acquired = True\n        assert 1 == len(conn._acquired)\n        assert 1 == len(conn._acquired_per_host[key])\n        connection2.release()\n\n    task = loop.create_task(f())\n\n    await asyncio.sleep(0.01)\n    assert not acquired\n    connection1.release()\n    await asyncio.sleep(0)\n    assert acquired\n    await task\n    await conn.close()\n\n\nasync def test_connect_with_no_limit_and_limit_per_host(loop, key) -> None:\n    proto = mock.Mock()\n    proto.is_connected.return_value = True\n\n    req = ClientRequest(\"GET\", URL(\"http://localhost1:80\"), loop=loop)\n\n    conn = aiohttp.BaseConnector(loop=loop, limit=0, limit_per_host=1)\n    conn._conns[key] = [(proto, loop.time())]\n    conn._create_connection = mock.Mock()\n    conn._create_connection.return_value = loop.create_future()\n    conn._create_connection.return_value.set_result(proto)\n\n    acquired = False\n    connection1 = await conn.connect(req, None, ClientTimeout())\n\n    async def f():\n        nonlocal acquired\n        connection2 = await conn.connect(req, None, ClientTimeout())\n        acquired = True\n        connection2.release()\n\n    task = loop.create_task(f())\n\n    await asyncio.sleep(0.01)\n    assert not acquired\n    connection1.release()\n    await asyncio.sleep(0)\n    assert acquired\n    await task\n    await conn.close()\n\n\nasync def test_connect_with_no_limits(loop, key) -> None:\n    proto = mock.Mock()\n    proto.is_connected.return_value = True\n\n    req = ClientRequest(\"GET\", URL(\"http://localhost:80\"), loop=loop)\n\n    conn = aiohttp.BaseConnector(loop=loop, limit=0, limit_per_host=0)\n    conn._conns[key] = [(proto, loop.time())]\n    conn._create_connection = mock.Mock()\n    conn._create_connection.return_value = loop.create_future()\n    conn._create_connection.return_value.set_result(proto)\n\n    acquired = False\n    connection1 = await conn.connect(req, None, ClientTimeout())\n\n    async def f():\n        nonlocal acquired\n        connection2 = await conn.connect(req, None, ClientTimeout())\n        acquired = True\n        assert 1 == len(conn._acquired)\n        assert 1 == len(conn._acquired_per_host[key])\n        connection2.release()\n\n    task = loop.create_task(f())\n\n    await asyncio.sleep(0.01)\n    assert acquired\n    connection1.release()\n    await task\n    await conn.close()\n\n\nasync def test_connect_with_limit_cancelled(loop) -> None:\n\n    proto = mock.Mock()\n    proto.is_connected.return_value = True\n\n    req = ClientRequest(\"GET\", URL(\"http://host:80\"), loop=loop)\n\n    conn = aiohttp.BaseConnector(loop=loop, limit=1)\n    key = (\"host\", 80, False)\n    conn._conns[key] = [(proto, loop.time())]\n    conn._create_connection = mock.Mock()\n    conn._create_connection.return_value = loop.create_future()\n    conn._create_connection.return_value.set_result(proto)\n\n    connection = await conn.connect(req, None, ClientTimeout())\n    assert connection._protocol == proto\n    assert connection.transport == proto.transport\n\n    assert 1 == len(conn._acquired)\n\n    with pytest.raises(asyncio.TimeoutError):\n        # limit exhausted\n        await asyncio.wait_for(conn.connect(req, None, ClientTimeout()), 0.01)\n    connection.close()\n\n    await conn.close()\n\n\nasync def test_connect_with_capacity_release_waiters(loop) -> None:\n    def check_with_exc(err):\n        conn = aiohttp.BaseConnector(limit=1, loop=loop)\n        conn._create_connection = mock.Mock()\n        conn._create_connection.return_value = loop.create_future()\n        conn._create_connection.return_value.set_exception(err)\n\n        with pytest.raises(Exception):\n            req = mock.Mock()\n            yield from conn.connect(req, None, ClientTimeout())\n\n        assert not conn._waiters\n\n    check_with_exc(OSError(1, \"permission error\"))\n    check_with_exc(RuntimeError())\n    check_with_exc(asyncio.TimeoutError())\n\n\nasync def test_connect_with_limit_concurrent(loop) -> None:\n    proto = mock.Mock()\n    proto.should_close = False\n    proto.is_connected.return_value = True\n\n    req = ClientRequest(\"GET\", URL(\"http://host:80\"), loop=loop)\n\n    max_connections = 2\n    num_connections = 0\n\n    conn = aiohttp.BaseConnector(limit=max_connections, loop=loop)\n\n    # Use a real coroutine for _create_connection; a mock would mask\n    # problems that only happen when the method yields.\n\n    async def create_connection(req, traces, timeout):\n        nonlocal num_connections\n        num_connections += 1\n        await asyncio.sleep(0)\n\n        # Make a new transport mock each time because acquired\n        # transports are stored in a set. Reusing the same object\n        # messes with the count.\n        proto = mock.Mock(should_close=False)\n        proto.is_connected.return_value = True\n\n        return proto\n\n    conn._create_connection = create_connection\n\n    # Simulate something like a crawler. It opens a connection, does\n    # something with it, closes it, then creates tasks that make more\n    # connections and waits for them to finish. The crawler is started\n    # with multiple concurrent requests and stops when it hits a\n    # predefined maximum number of requests.\n\n    max_requests = 50\n    num_requests = 0\n    start_requests = max_connections + 1\n\n    async def f(start=True):\n        nonlocal num_requests\n        if num_requests == max_requests:\n            return\n        num_requests += 1\n        if not start:\n            connection = await conn.connect(req, None, ClientTimeout())\n            await asyncio.sleep(0)\n            connection.release()\n            await asyncio.sleep(0)\n        tasks = [loop.create_task(f(start=False)) for i in range(start_requests)]\n        await asyncio.wait(tasks)\n\n    await f()\n    await conn.close()\n\n    assert max_connections == num_connections\n\n\nasync def test_connect_waiters_cleanup(loop) -> None:\n    proto = mock.Mock()\n    proto.is_connected.return_value = True\n\n    req = ClientRequest(\"GET\", URL(\"http://host:80\"), loop=loop)\n\n    conn = aiohttp.BaseConnector(loop=loop, limit=1)\n    conn._available_connections = mock.Mock(return_value=0)\n\n    t = loop.create_task(conn.connect(req, None, ClientTimeout()))\n\n    await asyncio.sleep(0)\n    assert conn._waiters.keys()\n\n    t.cancel()\n    await asyncio.sleep(0)\n    assert not conn._waiters.keys()\n\n\nasync def test_connect_waiters_cleanup_key_error(loop) -> None:\n    proto = mock.Mock()\n    proto.is_connected.return_value = True\n\n    req = ClientRequest(\"GET\", URL(\"http://host:80\"), loop=loop)\n\n    conn = aiohttp.BaseConnector(loop=loop, limit=1)\n    conn._available_connections = mock.Mock(return_value=0)\n\n    t = loop.create_task(conn.connect(req, None, ClientTimeout()))\n\n    await asyncio.sleep(0)\n    assert conn._waiters.keys()\n\n    # we delete the entry explicitly before the\n    # canceled connection grabs the loop again, we\n    # must expect a none failure termination\n    conn._waiters.clear()\n    t.cancel()\n    await asyncio.sleep(0)\n    assert not conn._waiters.keys() == []\n\n\nasync def test_close_with_acquired_connection(loop) -> None:\n    proto = mock.Mock()\n    proto.is_connected.return_value = True\n\n    req = ClientRequest(\"GET\", URL(\"http://host:80\"), loop=loop)\n\n    conn = aiohttp.BaseConnector(loop=loop, limit=1)\n    key = (\"host\", 80, False)\n    conn._conns[key] = [(proto, loop.time())]\n    conn._create_connection = mock.Mock()\n    conn._create_connection.return_value = loop.create_future()\n    conn._create_connection.return_value.set_result(proto)\n\n    connection = await conn.connect(req, None, ClientTimeout())\n\n    assert 1 == len(conn._acquired)\n    await conn.close()\n    assert 0 == len(conn._acquired)\n    assert conn.closed\n    proto.close.assert_called_with()\n\n    assert not connection.closed\n    connection.close()\n    assert connection.closed\n\n\nasync def test_default_force_close(loop) -> None:\n    connector = aiohttp.BaseConnector(loop=loop)\n    assert not connector.force_close\n\n\nasync def test_limit_property(loop) -> None:\n    conn = aiohttp.BaseConnector(loop=loop, limit=15)\n    assert 15 == conn.limit\n\n    await conn.close()\n\n\nasync def test_limit_per_host_property(loop) -> None:\n    conn = aiohttp.BaseConnector(loop=loop, limit_per_host=15)\n    assert 15 == conn.limit_per_host\n\n    await conn.close()\n\n\nasync def test_limit_property_default(loop) -> None:\n    conn = aiohttp.BaseConnector(loop=loop)\n    assert conn.limit == 100\n    await conn.close()\n\n\nasync def test_limit_per_host_property_default(loop) -> None:\n    conn = aiohttp.BaseConnector(loop=loop)\n    assert conn.limit_per_host == 0\n    await conn.close()\n\n\nasync def test_force_close_and_explicit_keep_alive(loop) -> None:\n    with pytest.raises(ValueError):\n        aiohttp.BaseConnector(loop=loop, keepalive_timeout=30, force_close=True)\n\n    conn = aiohttp.BaseConnector(loop=loop, force_close=True, keepalive_timeout=None)\n    assert conn\n\n    conn = aiohttp.BaseConnector(loop=loop, force_close=True)\n\n    assert conn\n\n\nasync def test_error_on_connection(loop, key) -> None:\n    conn = aiohttp.BaseConnector(limit=1, loop=loop)\n\n    req = mock.Mock()\n    req.connection_key = key\n    proto = mock.Mock()\n    i = 0\n\n    fut = loop.create_future()\n    exc = OSError()\n\n    async def create_connection(req, traces, timeout):\n        nonlocal i\n        i += 1\n        if i == 1:\n            await fut\n            raise exc\n        elif i == 2:\n            return proto\n\n    conn._create_connection = create_connection\n\n    t1 = loop.create_task(conn.connect(req, None, ClientTimeout()))\n    t2 = loop.create_task(conn.connect(req, None, ClientTimeout()))\n    await asyncio.sleep(0)\n    assert not t1.done()\n    assert not t2.done()\n    assert len(conn._acquired_per_host[key]) == 1\n\n    fut.set_result(None)\n    with pytest.raises(OSError):\n        await t1\n\n    ret = await t2\n    assert len(conn._acquired_per_host[key]) == 1\n\n    assert ret._key == key\n    assert ret.protocol == proto\n    assert proto in conn._acquired\n    ret.release()\n\n\nasync def test_cancelled_waiter(loop) -> None:\n    conn = aiohttp.BaseConnector(limit=1, loop=loop)\n    req = mock.Mock()\n    req.connection_key = \"key\"\n    proto = mock.Mock()\n\n    async def create_connection(req, traces=None):\n        await asyncio.sleep(1)\n        return proto\n\n    conn._create_connection = create_connection\n\n    conn._acquired.add(proto)\n\n    conn2 = loop.create_task(conn.connect(req, None, ClientTimeout()))\n    await asyncio.sleep(0)\n    conn2.cancel()\n\n    with pytest.raises(asyncio.CancelledError):\n        await conn2\n\n\nasync def test_error_on_connection_with_cancelled_waiter(loop, key) -> None:\n    conn = aiohttp.BaseConnector(limit=1, loop=loop)\n\n    req = mock.Mock()\n    req.connection_key = key\n    proto = mock.Mock()\n    i = 0\n\n    fut1 = loop.create_future()\n    fut2 = loop.create_future()\n    exc = OSError()\n\n    async def create_connection(req, traces, timeout):\n        nonlocal i\n        i += 1\n        if i == 1:\n            await fut1\n            raise exc\n        if i == 2:\n            await fut2\n        elif i == 3:\n            return proto\n\n    conn._create_connection = create_connection\n\n    t1 = loop.create_task(conn.connect(req, None, ClientTimeout()))\n    t2 = loop.create_task(conn.connect(req, None, ClientTimeout()))\n    t3 = loop.create_task(conn.connect(req, None, ClientTimeout()))\n    await asyncio.sleep(0)\n    assert not t1.done()\n    assert not t2.done()\n    assert len(conn._acquired_per_host[key]) == 1\n\n    fut1.set_result(None)\n    fut2.cancel()\n    with pytest.raises(OSError):\n        await t1\n\n    with pytest.raises(asyncio.CancelledError):\n        await t2\n\n    ret = await t3\n    assert len(conn._acquired_per_host[key]) == 1\n\n    assert ret._key == key\n    assert ret.protocol == proto\n    assert proto in conn._acquired\n    ret.release()\n\n\nasync def test_tcp_connector(aiohttp_client, loop) -> None:\n    async def handler(request):\n        return web.Response()\n\n    app = web.Application()\n    app.router.add_get(\"/\", handler)\n    client = await aiohttp_client(app)\n\n    r = await client.get(\"/\")\n    assert r.status == 200\n\n\n@pytest.mark.skipif(not hasattr(socket, \"AF_UNIX\"), reason=\"requires UNIX sockets\")\nasync def test_unix_connector_not_found(loop) -> None:\n    connector = aiohttp.UnixConnector(\"/\" + uuid.uuid4().hex)\n\n    req = ClientRequest(\"GET\", URL(\"http://www.python.org\"), loop=loop)\n    with pytest.raises(aiohttp.ClientConnectorError):\n        await connector.connect(req, None, ClientTimeout())\n\n\n@pytest.mark.skipif(not hasattr(socket, \"AF_UNIX\"), reason=\"requires UNIX sockets\")\nasync def test_unix_connector_permission(loop) -> None:\n    loop.create_unix_connection = make_mocked_coro(raise_exception=PermissionError())\n    connector = aiohttp.UnixConnector(\"/\" + uuid.uuid4().hex, loop=loop)\n\n    req = ClientRequest(\"GET\", URL(\"http://www.python.org\"), loop=loop)\n    with pytest.raises(aiohttp.ClientConnectorError):\n        await connector.connect(req, None, ClientTimeout())\n\n\n@pytest.mark.skipif(\n    platform.system() != \"Windows\", reason=\"Proactor Event loop present only in Windows\"\n)\nasync def test_named_pipe_connector_wrong_loop(selector_loop, pipe_name) -> None:\n    with pytest.raises(RuntimeError):\n        aiohttp.NamedPipeConnector(pipe_name, loop=asyncio.get_event_loop())\n\n\n@pytest.mark.skipif(\n    platform.system() != \"Windows\", reason=\"Proactor Event loop present only in Windows\"\n)\nasync def test_named_pipe_connector_not_found(proactor_loop, pipe_name) -> None:\n    connector = aiohttp.NamedPipeConnector(pipe_name, loop=proactor_loop)\n\n    req = ClientRequest(\"GET\", URL(\"http://www.python.org\"), loop=proactor_loop)\n    with pytest.raises(aiohttp.ClientConnectorError):\n        await connector.connect(req, None, ClientTimeout())\n\n\n@pytest.mark.skipif(\n    platform.system() != \"Windows\", reason=\"Proactor Event loop present only in Windows\"\n)\nasync def test_named_pipe_connector_permission(proactor_loop, pipe_name) -> None:\n    proactor_loop.create_pipe_connection = make_mocked_coro(\n        raise_exception=PermissionError()\n    )\n    connector = aiohttp.NamedPipeConnector(pipe_name, loop=proactor_loop)\n\n    req = ClientRequest(\"GET\", URL(\"http://www.python.org\"), loop=proactor_loop)\n    with pytest.raises(aiohttp.ClientConnectorError):\n        await connector.connect(req, None, ClientTimeout())\n\n\nasync def test_default_use_dns_cache() -> None:\n    conn = aiohttp.TCPConnector()\n    assert conn.use_dns_cache\n\n\nasync def test_ssl_none() -> None:\n    conn = aiohttp.TCPConnector(ssl=None)\n    assert conn._ssl is True\n\n\nasync def test_resolver_not_called_with_address_is_ip(loop) -> None:\n    resolver = mock.MagicMock()\n    connector = aiohttp.TCPConnector(resolver=resolver)\n\n    req = ClientRequest(\n        \"GET\",\n        URL(f\"http://127.0.0.1:{unused_port()}\"),\n        loop=loop,\n        response_class=mock.Mock(),\n    )\n\n    with pytest.raises(OSError):\n        await connector.connect(req, None, ClientTimeout())\n\n    resolver.resolve.assert_not_called()\n\n\nasync def test_tcp_connector_raise_connector_ssl_error(\n    aiohttp_server,\n    ssl_ctx,\n) -> None:\n    async def handler(request):\n        return web.Response()\n\n    app = web.Application()\n    app.router.add_get(\"/\", handler)\n\n    srv = await aiohttp_server(app, ssl=ssl_ctx)\n\n    port = unused_port()\n    conn = aiohttp.TCPConnector(local_addr=(\"127.0.0.1\", port))\n\n    session = aiohttp.ClientSession(connector=conn)\n    url = srv.make_url(\"/\")\n\n    err = aiohttp.ClientConnectorCertificateError\n    with pytest.raises(err) as ctx:\n        await session.get(url)\n\n    assert isinstance(ctx.value, aiohttp.ClientConnectorCertificateError)\n    assert isinstance(ctx.value.certificate_error, ssl.SSLError)\n\n    await session.close()\n\n\n@pytest.mark.parametrize(\n    \"host\",\n    (\n        pytest.param(\"127.0.0.1\", id=\"ip address\"),\n        pytest.param(\"localhost\", id=\"domain name\"),\n        pytest.param(\"localhost.\", id=\"fully-qualified domain name\"),\n        pytest.param(\n            \"localhost...\", id=\"fully-qualified domain name with multiple trailing dots\"\n        ),\n        pytest.param(\"príklad.localhost.\", id=\"idna fully-qualified domain name\"),\n    ),\n)\nasync def test_tcp_connector_do_not_raise_connector_ssl_error(\n    aiohttp_server,\n    ssl_ctx,\n    client_ssl_ctx,\n    host,\n) -> None:\n    async def handler(request):\n        return web.Response()\n\n    app = web.Application()\n    app.router.add_get(\"/\", handler)\n\n    srv = await aiohttp_server(app, ssl=ssl_ctx)\n    port = unused_port()\n    conn = aiohttp.TCPConnector(local_addr=(\"127.0.0.1\", port))\n\n    # resolving something.localhost with the real DNS resolver does not work on macOS, so we have a stub.\n    async def _resolve_host(host, port, traces=None):\n        return [\n            {\n                \"hostname\": host,\n                \"host\": \"127.0.0.1\",\n                \"port\": port,\n                \"family\": socket.AF_INET,\n                \"proto\": 0,\n                \"flags\": socket.AI_NUMERICHOST,\n            },\n            {\n                \"hostname\": host,\n                \"host\": \"::1\",\n                \"port\": port,\n                \"family\": socket.AF_INET,\n                \"proto\": 0,\n                \"flags\": socket.AI_NUMERICHOST,\n            },\n        ]\n\n    conn._resolve_host = _resolve_host\n\n    session = aiohttp.ClientSession(connector=conn)\n    url = srv.make_url(\"/\")\n\n    r = await session.get(url.with_host(host), ssl=client_ssl_ctx)\n\n    r.release()\n    first_conn = next(iter(conn._conns.values()))[0][0]\n\n    try:\n        _sslcontext = first_conn.transport._ssl_protocol._sslcontext\n    except AttributeError:\n        _sslcontext = first_conn.transport._sslcontext\n\n    assert _sslcontext is client_ssl_ctx\n    r.close()\n\n    await session.close()\n    await conn.close()\n\n\nasync def test_tcp_connector_uses_provided_local_addr(aiohttp_server) -> None:\n    async def handler(request):\n        return web.Response()\n\n    app = web.Application()\n    app.router.add_get(\"/\", handler)\n    srv = await aiohttp_server(app)\n\n    port = unused_port()\n    conn = aiohttp.TCPConnector(local_addr=(\"127.0.0.1\", port))\n\n    session = aiohttp.ClientSession(connector=conn)\n    url = srv.make_url(\"/\")\n\n    r = await session.get(url)\n    r.release()\n\n    first_conn = next(iter(conn._conns.values()))[0][0]\n    assert first_conn.transport.get_extra_info(\"sockname\") == (\"127.0.0.1\", port)\n    r.close()\n    await session.close()\n    await conn.close()\n\n\nasync def test_unix_connector(unix_server, unix_sockname) -> None:\n    async def handler(request):\n        return web.Response()\n\n    app = web.Application()\n    app.router.add_get(\"/\", handler)\n    await unix_server(app)\n\n    url = \"http://127.0.0.1/\"\n\n    connector = aiohttp.UnixConnector(unix_sockname)\n    assert unix_sockname == connector.path\n    assert connector.allowed_protocol_schema_set == {\n        \"\",\n        \"http\",\n        \"https\",\n        \"ws\",\n        \"wss\",\n        \"unix\",\n    }\n\n    session = client.ClientSession(connector=connector)\n    r = await session.get(url)\n    assert r.status == 200\n    r.close()\n    await session.close()\n\n\n@pytest.mark.skipif(\n    platform.system() != \"Windows\", reason=\"Proactor Event loop present only in Windows\"\n)\nasync def test_named_pipe_connector(\n    proactor_loop, named_pipe_server, pipe_name\n) -> None:\n    async def handler(request):\n        return web.Response()\n\n    app = web.Application()\n    app.router.add_get(\"/\", handler)\n    await named_pipe_server(app)\n\n    url = \"http://this-does-not-matter.com\"\n\n    connector = aiohttp.NamedPipeConnector(pipe_name)\n    assert pipe_name == connector.path\n    assert connector.allowed_protocol_schema_set == {\n        \"\",\n        \"http\",\n        \"https\",\n        \"ws\",\n        \"wss\",\n        \"npipe\",\n    }\n\n    session = client.ClientSession(connector=connector)\n    r = await session.get(url)\n    assert r.status == 200\n    r.close()\n    await session.close()\n\n\nclass TestDNSCacheTable:\n    @pytest.fixture\n    def dns_cache_table(self):\n        return _DNSCacheTable()\n\n    def test_next_addrs_basic(self, dns_cache_table) -> None:\n        dns_cache_table.add(\"localhost\", [\"127.0.0.1\"])\n        dns_cache_table.add(\"foo\", [\"127.0.0.2\"])\n\n        addrs = dns_cache_table.next_addrs(\"localhost\")\n        assert addrs == [\"127.0.0.1\"]\n        addrs = dns_cache_table.next_addrs(\"foo\")\n        assert addrs == [\"127.0.0.2\"]\n        with pytest.raises(KeyError):\n            dns_cache_table.next_addrs(\"no-such-host\")\n\n    def test_remove(self, dns_cache_table) -> None:\n        dns_cache_table.add(\"localhost\", [\"127.0.0.1\"])\n        dns_cache_table.remove(\"localhost\")\n        with pytest.raises(KeyError):\n            dns_cache_table.next_addrs(\"localhost\")\n\n    def test_clear(self, dns_cache_table) -> None:\n        dns_cache_table.add(\"localhost\", [\"127.0.0.1\"])\n        dns_cache_table.clear()\n        with pytest.raises(KeyError):\n            dns_cache_table.next_addrs(\"localhost\")\n\n    def test_not_expired_ttl_None(self, dns_cache_table) -> None:\n        dns_cache_table.add(\"localhost\", [\"127.0.0.1\"])\n        assert not dns_cache_table.expired(\"localhost\")\n\n    def test_not_expired_ttl(self) -> None:\n        dns_cache_table = _DNSCacheTable(ttl=0.1)\n        dns_cache_table.add(\"localhost\", [\"127.0.0.1\"])\n        assert not dns_cache_table.expired(\"localhost\")\n\n    def test_expired_ttl(self, monkeypatch: pytest.MonkeyPatch) -> None:\n        dns_cache_table = _DNSCacheTable(ttl=1)\n        monkeypatch.setattr(\"aiohttp.connector.monotonic\", lambda: 1)\n        dns_cache_table.add(\"localhost\", [\"127.0.0.1\"])\n        monkeypatch.setattr(\"aiohttp.connector.monotonic\", lambda: 2)\n        assert not dns_cache_table.expired(\"localhost\")\n        monkeypatch.setattr(\"aiohttp.connector.monotonic\", lambda: 3)\n        assert dns_cache_table.expired(\"localhost\")\n\n    def test_never_expire(self, monkeypatch: pytest.MonkeyPatch) -> None:\n        dns_cache_table = _DNSCacheTable(ttl=None)\n        monkeypatch.setattr(\"aiohttp.connector.monotonic\", lambda: 1)\n        dns_cache_table.add(\"localhost\", [\"127.0.0.1\"])\n        monkeypatch.setattr(\"aiohttp.connector.monotonic\", lambda: 10000000)\n        assert not dns_cache_table.expired(\"localhost\")\n\n    def test_always_expire(self, monkeypatch: pytest.MonkeyPatch) -> None:\n        dns_cache_table = _DNSCacheTable(ttl=0)\n        monkeypatch.setattr(\"aiohttp.connector.monotonic\", lambda: 1)\n        dns_cache_table.add(\"localhost\", [\"127.0.0.1\"])\n        monkeypatch.setattr(\"aiohttp.connector.monotonic\", lambda: 1.00001)\n        assert dns_cache_table.expired(\"localhost\")\n\n    def test_next_addrs(self, dns_cache_table) -> None:\n        dns_cache_table.add(\"foo\", [\"127.0.0.1\", \"127.0.0.2\", \"127.0.0.3\"])\n\n        # Each calls to next_addrs return the hosts using\n        # a round robin strategy.\n        addrs = dns_cache_table.next_addrs(\"foo\")\n        assert addrs == [\"127.0.0.1\", \"127.0.0.2\", \"127.0.0.3\"]\n\n        addrs = dns_cache_table.next_addrs(\"foo\")\n        assert addrs == [\"127.0.0.2\", \"127.0.0.3\", \"127.0.0.1\"]\n\n        addrs = dns_cache_table.next_addrs(\"foo\")\n        assert addrs == [\"127.0.0.3\", \"127.0.0.1\", \"127.0.0.2\"]\n\n        addrs = dns_cache_table.next_addrs(\"foo\")\n        assert addrs == [\"127.0.0.1\", \"127.0.0.2\", \"127.0.0.3\"]\n\n    def test_next_addrs_single(self, dns_cache_table) -> None:\n        dns_cache_table.add(\"foo\", [\"127.0.0.1\"])\n\n        addrs = dns_cache_table.next_addrs(\"foo\")\n        assert addrs == [\"127.0.0.1\"]\n\n        addrs = dns_cache_table.next_addrs(\"foo\")\n        assert addrs == [\"127.0.0.1\"]\n\n\nasync def test_connector_cache_trace_race():\n    class DummyTracer:\n        async def send_dns_cache_hit(self, *args, **kwargs):\n            connector._cached_hosts.remove((\"\", 0))\n\n    token = object()\n    connector = TCPConnector()\n    connector._cached_hosts.add((\"\", 0), [token])\n\n    traces = [DummyTracer()]\n    assert await connector._resolve_host(\"\", 0, traces) == [token]\n\n\nasync def test_connector_throttle_trace_race(loop):\n    key = (\"\", 0)\n    token = object()\n\n    class DummyTracer:\n        async def send_dns_cache_hit(self, *args, **kwargs):\n            event = connector._throttle_dns_events.pop(key)\n            event.set()\n            connector._cached_hosts.add(key, [token])\n\n    connector = TCPConnector()\n    connector._throttle_dns_events[key] = EventResultOrError(loop)\n    traces = [DummyTracer()]\n    assert await connector._resolve_host(\"\", 0, traces) == [token]\n\n\nasync def test_connector_does_not_remove_needed_waiters(loop, key) -> None:\n    proto = create_mocked_conn(loop)\n    proto.is_connected.return_value = True\n\n    req = ClientRequest(\"GET\", URL(\"https://localhost:80\"), loop=loop)\n    connection_key = req.connection_key\n\n    connector = aiohttp.BaseConnector()\n    connector._available_connections = mock.Mock(return_value=0)\n    connector._conns[key] = [(proto, loop.time())]\n    connector._create_connection = create_mocked_conn(loop)\n    connector._create_connection.return_value = loop.create_future()\n    connector._create_connection.return_value.set_result(proto)\n\n    dummy_waiter = loop.create_future()\n\n    async def await_connection_and_check_waiters():\n        connection = await connector.connect(req, [], ClientTimeout())\n        try:\n            assert connection_key in connector._waiters\n            assert dummy_waiter in connector._waiters[connection_key]\n        finally:\n            connection.close()\n\n    async def allow_connection_and_add_dummy_waiter():\n        # `asyncio.gather` may execute coroutines not in order.\n        # Skip one event loop run cycle in such a case.\n        if connection_key not in connector._waiters:\n            await asyncio.sleep(0)\n        connector._waiters[connection_key].popleft().set_result(None)\n        del connector._waiters[connection_key]\n        connector._waiters[connection_key].append(dummy_waiter)\n\n    await asyncio.gather(\n        await_connection_and_check_waiters(),\n        allow_connection_and_add_dummy_waiter(),\n    )\n\n    await connector.close()\n",
        "import asyncio\nimport base64\nimport os\nimport socket\nimport ssl\nimport sys\nfrom hashlib import md5, sha1, sha256\nfrom pathlib import Path\nfrom tempfile import TemporaryDirectory\nfrom typing import Any\nfrom unittest import mock\nfrom uuid import uuid4\n\nimport pytest\n\nfrom aiohttp.http import WS_KEY\nfrom aiohttp.test_utils import loop_context\n\ntry:\n    import trustme\n\n    # Check if the CA is available in runtime, MacOS on Py3.10 fails somehow\n    trustme.CA()\n\n    TRUSTME: bool = True\nexcept ImportError:\n    TRUSTME = False\n\npytest_plugins = [\"aiohttp.pytest_plugin\", \"pytester\"]\n\nIS_HPUX = sys.platform.startswith(\"hp-ux\")\nIS_LINUX = sys.platform.startswith(\"linux\")\n\n\n@pytest.fixture\ndef tls_certificate_authority():\n    if not TRUSTME:\n        pytest.xfail(\"trustme is not supported\")\n    return trustme.CA()\n\n\n@pytest.fixture\ndef tls_certificate(tls_certificate_authority):\n    return tls_certificate_authority.issue_cert(\n        \"localhost\",\n        \"xn--prklad-4va.localhost\",\n        \"127.0.0.1\",\n        \"::1\",\n    )\n\n\n@pytest.fixture\ndef ssl_ctx(tls_certificate):\n    ssl_ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)\n    tls_certificate.configure_cert(ssl_ctx)\n    return ssl_ctx\n\n\n@pytest.fixture\ndef client_ssl_ctx(tls_certificate_authority):\n    ssl_ctx = ssl.create_default_context(purpose=ssl.Purpose.SERVER_AUTH)\n    tls_certificate_authority.configure_trust(ssl_ctx)\n    return ssl_ctx\n\n\n@pytest.fixture\ndef tls_ca_certificate_pem_path(tls_certificate_authority):\n    with tls_certificate_authority.cert_pem.tempfile() as ca_cert_pem:\n        yield ca_cert_pem\n\n\n@pytest.fixture\ndef tls_certificate_pem_path(tls_certificate):\n    with tls_certificate.private_key_and_cert_chain_pem.tempfile() as cert_pem:\n        yield cert_pem\n\n\n@pytest.fixture\ndef tls_certificate_pem_bytes(tls_certificate):\n    return tls_certificate.cert_chain_pems[0].bytes()\n\n\n@pytest.fixture\ndef tls_certificate_fingerprint_sha256(tls_certificate_pem_bytes):\n    tls_cert_der = ssl.PEM_cert_to_DER_cert(tls_certificate_pem_bytes.decode())\n    return sha256(tls_cert_der).digest()\n\n\n@pytest.fixture\ndef unix_sockname(tmp_path, tmp_path_factory):\n    \"\"\"Generate an fs path to the UNIX domain socket for testing.\n\n    N.B. Different OS kernels have different fs path length limitations\n    for it. For Linux, it's 108, for HP-UX it's 92 (or higher) depending\n    on its version. For for most of the BSDs (Open, Free, macOS) it's\n    mostly 104 but sometimes it can be down to 100.\n\n    Ref: https://github.com/aio-libs/aiohttp/issues/3572\n    \"\"\"\n    if not hasattr(socket, \"AF_UNIX\"):\n        pytest.skip(\"requires UNIX sockets\")\n\n    max_sock_len = 92 if IS_HPUX else 108 if IS_LINUX else 100\n    \"\"\"Amount of bytes allocated for the UNIX socket path by OS kernel.\n\n    Ref: https://unix.stackexchange.com/a/367012/27133\n    \"\"\"\n\n    sock_file_name = \"unix.sock\"\n    unique_prefix = f\"{uuid4()!s}-\"\n    unique_prefix_len = len(unique_prefix.encode())\n\n    root_tmp_dir = Path(\"/tmp\").resolve()\n    os_tmp_dir = Path(os.getenv(\"TMPDIR\", \"/tmp\")).resolve()\n    original_base_tmp_path = Path(\n        str(tmp_path_factory.getbasetemp()),\n    ).resolve()\n\n    original_base_tmp_path_hash = md5(\n        str(original_base_tmp_path).encode(),\n    ).hexdigest()\n\n    def make_tmp_dir(base_tmp_dir):\n        return TemporaryDirectory(\n            dir=str(base_tmp_dir),\n            prefix=\"pt-\",\n            suffix=f\"-{original_base_tmp_path_hash!s}\",\n        )\n\n    def assert_sock_fits(sock_path):\n        sock_path_len = len(sock_path.encode())\n        # exit-check to verify that it's correct and simplify debugging\n        # in the future\n        assert sock_path_len <= max_sock_len, (\n            \"Suggested UNIX socket ({sock_path}) is {sock_path_len} bytes \"\n            \"long but the current kernel only has {max_sock_len} bytes \"\n            \"allocated to hold it so it must be shorter. \"\n            \"See https://github.com/aio-libs/aiohttp/issues/3572 \"\n            \"for more info.\"\n        ).format_map(locals())\n\n    paths = original_base_tmp_path, os_tmp_dir, root_tmp_dir\n    unique_paths = [p for n, p in enumerate(paths) if p not in paths[:n]]\n    paths_num = len(unique_paths)\n\n    for num, tmp_dir_path in enumerate(paths, 1):\n        with make_tmp_dir(tmp_dir_path) as tmpd:\n            tmpd = Path(tmpd).resolve()\n            sock_path = str(tmpd / sock_file_name)\n            sock_path_len = len(sock_path.encode())\n\n            if num >= paths_num:\n                # exit-check to verify that it's correct and simplify\n                # debugging in the future\n                assert_sock_fits(sock_path)\n\n            if sock_path_len <= max_sock_len:\n                if max_sock_len - sock_path_len >= unique_prefix_len:\n                    # If we're lucky to have extra space in the path,\n                    # let's also make it more unique\n                    sock_path = str(tmpd / \"\".join((unique_prefix, sock_file_name)))\n                    # Double-checking it:\n                    assert_sock_fits(sock_path)\n                yield sock_path\n                return\n\n\n@pytest.fixture\ndef pipe_name():\n    name = rf\"\\\\.\\pipe\\{uuid4().hex}\"\n    return name\n\n\n@pytest.fixture\ndef create_mocked_conn(loop: Any):\n    def _proto_factory(conn_closing_result=None, **kwargs):\n        proto = mock.Mock(**kwargs)\n        proto.closed = loop.create_future()\n        proto.closed.set_result(conn_closing_result)\n        return proto\n\n    yield _proto_factory\n\n\n@pytest.fixture\ndef selector_loop():\n    policy = asyncio.WindowsSelectorEventLoopPolicy()\n    asyncio.set_event_loop_policy(policy)\n\n    with loop_context(policy.new_event_loop) as _loop:\n        asyncio.set_event_loop(_loop)\n        yield _loop\n\n\n@pytest.fixture\ndef netrc_contents(\n    tmp_path: Path,\n    monkeypatch: pytest.MonkeyPatch,\n    request: pytest.FixtureRequest,\n):\n    \"\"\"\n    Prepare :file:`.netrc` with given contents.\n\n    Monkey-patches :envvar:`NETRC` to point to created file.\n    \"\"\"\n    netrc_contents = getattr(request, \"param\", None)\n\n    netrc_file_path = tmp_path / \".netrc\"\n    if netrc_contents is not None:\n        netrc_file_path.write_text(netrc_contents)\n\n    monkeypatch.setenv(\"NETRC\", str(netrc_file_path))\n\n    return netrc_file_path\n\n\n@pytest.fixture\ndef start_connection():\n    with mock.patch(\n        \"aiohttp.connector.aiohappyeyeballs.start_connection\",\n        autospec=True,\n        spec_set=True,\n    ) as start_connection_mock:\n        yield start_connection_mock\n\n\n@pytest.fixture\ndef key_data():\n    return os.urandom(16)\n\n\n@pytest.fixture\ndef key(key_data: Any):\n    return base64.b64encode(key_data)\n\n\n@pytest.fixture\ndef ws_key(key: Any):\n    return base64.b64encode(sha1(key + WS_KEY).digest()).decode()\n"
    ],
    "test_file_names": [
        "test_1.py",
        "conftest.py"
    ],
    "setup_res_code": 0,
    "setup_res_stdout": "re-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_ea316336f0b247bb85fd7ee0e4e41f5eac682228/requirements/cython.txt\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_ea316336f0b247bb85fd7ee0e4e41f5eac682228/tools/gen.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_ea316336f0b247bb85fd7ee0e4e41f5eac682228/aiohttp/hdrs.py\n./tools/gen.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_ea316336f0b247bb85fd7ee0e4e41f5eac682228/aiohttp/_helpers.pyx\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_ea316336f0b247bb85fd7ee0e4e41f5eac682228/aiohttp/_http_parser.pyx\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_ea316336f0b247bb85fd7ee0e4e41f5eac682228/aiohttp/_http_writer.pyx\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_ea316336f0b247bb85fd7ee0e4e41f5eac682228/aiohttp/_websocket.pyx\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_ea316336f0b247bb85fd7ee0e4e41f5eac682228/aiohttp/_helpers.pyi\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_ea316336f0b247bb85fd7ee0e4e41f5eac682228/aiohttp/_cparser.pxd\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_ea316336f0b247bb85fd7ee0e4e41f5eac682228/aiohttp/_find_header.pxd\ncython -3 -o aiohttp/_helpers.c aiohttp/_helpers.pyx -I aiohttp -Werror\ncython -3 -o aiohttp/_http_parser.c aiohttp/_http_parser.pyx -I aiohttp -Werror\ncython -3 -o aiohttp/_http_writer.c aiohttp/_http_writer.pyx -I aiohttp -Werror\ncython -3 -o aiohttp/_websocket.c aiohttp/_websocket.pyx -I aiohttp -Werror\ncd vendor/llhttp; npm ci\n\n> llhttp@9.2.1 prepare\n> npm run clean && npm run build-ts\n\n\n> llhttp@9.2.1 clean\n> rm -rf lib && rm -rf test/tmp\n\n\n> llhttp@9.2.1 build-ts\n> tsc\n\n\nadded 213 packages, and audited 214 packages in 5s\n\n41 packages are looking for funding\n  run `npm fund` for details\n\n5 vulnerabilities (3 moderate, 2 high)\n\nTo address issues that do not require attention, run:\n  npm audit fix\n\nSome issues need review, and may require choosing\na different dependency.\n\nRun `npm audit` for details.\nmake -C vendor/llhttp generate\nmake[1]: Entering directory '/home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_ea316336f0b247bb85fd7ee0e4e41f5eac682228/vendor/llhttp'\nnpx ts-node bin/generate.ts\nmake[1]: Leaving directory '/home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_ea316336f0b247bb85fd7ee0e4e41f5eac682228/vendor/llhttp'\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_ea316336f0b247bb85fd7ee0e4e41f5eac682228/aiohttp/__init__.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_ea316336f0b247bb85fd7ee0e4e41f5eac682228/aiohttp/abc.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_ea316336f0b247bb85fd7ee0e4e41f5eac682228/aiohttp/base_protocol.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_ea316336f0b247bb85fd7ee0e4e41f5eac682228/aiohttp/client.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_ea316336f0b247bb85fd7ee0e4e41f5eac682228/aiohttp/client_exceptions.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_ea316336f0b247bb85fd7ee0e4e41f5eac682228/aiohttp/client_proto.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_ea316336f0b247bb85fd7ee0e4e41f5eac682228/aiohttp/client_reqrep.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_ea316336f0b247bb85fd7ee0e4e41f5eac682228/aiohttp/client_ws.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_ea316336f0b247bb85fd7ee0e4e41f5eac682228/aiohttp/compression_utils.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_ea316336f0b247bb85fd7ee0e4e41f5eac682228/aiohttp/connector.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_ea316336f0b247bb85fd7ee0e4e41f5eac682228/aiohttp/cookiejar.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_ea316336f0b247bb85fd7ee0e4e41f5eac682228/aiohttp/formdata.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_ea316336f0b247bb85fd7ee0e4e41f5eac682228/aiohttp/helpers.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_ea316336f0b247bb85fd7ee0e4e41f5eac682228/aiohttp/http.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_ea316336f0b247bb85fd7ee0e4e41f5eac682228/aiohttp/http_exceptions.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_ea316336f0b247bb85fd7ee0e4e41f5eac682228/aiohttp/http_parser.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_ea316336f0b247bb85fd7ee0e4e41f5eac682228/aiohttp/http_websocket.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_ea316336f0b247bb85fd7ee0e4e41f5eac682228/aiohttp/http_writer.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_ea316336f0b247bb85fd7ee0e4e41f5eac682228/aiohttp/locks.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_ea316336f0b247bb85fd7ee0e4e41f5eac682228/aiohttp/log.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_ea316336f0b247bb85fd7ee0e4e41f5eac682228/aiohttp/multipart.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_ea316336f0b247bb85fd7ee0e4e41f5eac682228/aiohttp/payload.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_ea316336f0b247bb85fd7ee0e4e41f5eac682228/aiohttp/payload_streamer.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_ea316336f0b247bb85fd7ee0e4e41f5eac682228/aiohttp/pytest_plugin.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_ea316336f0b247bb85fd7ee0e4e41f5eac682228/aiohttp/resolver.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_ea316336f0b247bb85fd7ee0e4e41f5eac682228/aiohttp/streams.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_ea316336f0b247bb85fd7ee0e4e41f5eac682228/aiohttp/tcp_helpers.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_ea316336f0b247bb85fd7ee0e4e41f5eac682228/aiohttp/test_utils.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_ea316336f0b247bb85fd7ee0e4e41f5eac682228/aiohttp/tracing.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_ea316336f0b247bb85fd7ee0e4e41f5eac682228/aiohttp/typedefs.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_ea316336f0b247bb85fd7ee0e4e41f5eac682228/aiohttp/web.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_ea316336f0b247bb85fd7ee0e4e41f5eac682228/aiohttp/web_app.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_ea316336f0b247bb85fd7ee0e4e41f5eac682228/aiohttp/web_exceptions.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_ea316336f0b247bb85fd7ee0e4e41f5eac682228/aiohttp/web_fileresponse.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_ea316336f0b247bb85fd7ee0e4e41f5eac682228/aiohttp/web_log.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_ea316336f0b247bb85fd7ee0e4e41f5eac682228/aiohttp/web_middlewares.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_ea316336f0b247bb85fd7ee0e4e41f5eac682228/aiohttp/web_protocol.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_ea316336f0b247bb85fd7ee0e4e41f5eac682228/aiohttp/web_request.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_ea316336f0b247bb85fd7ee0e4e41f5eac682228/aiohttp/web_response.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_ea316336f0b247bb85fd7ee0e4e41f5eac682228/aiohttp/web_routedef.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_ea316336f0b247bb85fd7ee0e4e41f5eac682228/aiohttp/web_runner.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_ea316336f0b247bb85fd7ee0e4e41f5eac682228/aiohttp/web_server.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_ea316336f0b247bb85fd7ee0e4e41f5eac682228/aiohttp/web_urldispatcher.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_ea316336f0b247bb85fd7ee0e4e41f5eac682228/aiohttp/web_ws.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_ea316336f0b247bb85fd7ee0e4e41f5eac682228/aiohttp/worker.py\nuv pip install -e . -c requirements/runtime-deps.txt\n",
    "setup_res_stderr": "Using CPython 3.9.21\nCreating virtual environment at: .venv\nActivate with: source .venv/bin/activate\nResolved 1 package in 2ms\nPrepared 1 package in 0.30ms\nInstalled 1 package in 17ms\n + pip==24.3.1\nResolved 2 packages in 10ms\nInstalled 2 packages in 11ms\n + cython==3.0.11\n + multidict==6.0.5\nResolved 100 packages in 52ms\nUninstalled 1 package in 20ms\nInstalled 99 packages in 177ms\n + aiodns==3.2.0\n + aiohappyeyeballs==2.4.0\n + aiohttp-theme==0.1.6\n + aioredis==2.0.1\n + aiosignal==1.3.1\n + alabaster==0.7.13\n + annotated-types==0.7.0\n + async-timeout==4.0.3\n + attrs==24.2.0\n + babel==2.16.0\n + blockdiag==3.0.0\n + brotli==1.1.0\n + build==1.2.1\n + certifi==2024.8.30\n + cffi==1.17.0\n + cfgv==3.4.0\n + charset-normalizer==3.3.2\n + cherry-picker==2.2.0\n + click==8.1.7\n + coverage==7.6.1\n + cryptography==43.0.0\n + distlib==0.3.8\n + docutils==0.20.1\n + exceptiongroup==1.2.2\n + filelock==3.15.4\n + freezegun==1.5.1\n + frozenlist==1.4.1\n + funcparserlib==1.0.1\n + gidgethub==5.3.0\n + gunicorn==23.0.0\n + identify==2.6.0\n + idna==3.4\n + imagesize==1.4.1\n + importlib-metadata==8.4.0\n + importlib-resources==6.4.4\n + incremental==24.7.2\n + iniconfig==2.0.0\n + jinja2==3.1.4\n + markdown-it-py==3.0.0\n + markupsafe==2.1.5\n + mdurl==0.1.2\n + mypy==1.11.2\n + mypy-extensions==1.0.0\n + nodeenv==1.9.1\n + packaging==24.1\n + pillow==9.5.0\n - pip==24.3.1\n + pip==24.2\n + pip-tools==7.4.1\n + platformdirs==4.2.2\n + pluggy==1.5.0\n + pre-commit==3.5.0\n + proxy-py==2.4.7\n + pycares==4.4.0\n + pycparser==2.22\n + pydantic==2.8.2\n + pydantic-core==2.20.1\n + pygments==2.18.0\n + pyjwt==2.8.0\n + pyproject-hooks==1.1.0\n + pytest==8.3.2\n + pytest-cov==5.0.0\n + pytest-mock==3.14.0\n + python-dateutil==2.9.0.post0\n + python-on-whales==0.72.0\n + pyyaml==6.0.2\n + re-assert==1.1.0\n + regex==2024.7.24\n + requests==2.32.3\n + rich==13.8.0\n + setuptools==74.0.0\n + setuptools-git==1.2\n + shellingham==1.5.4\n + six==1.16.0\n + slotscheck==0.19.0\n + snowballstemmer==2.2.0\n + sphinx==7.1.2\n + sphinxcontrib-applehelp==1.0.4\n + sphinxcontrib-blockdiag==3.0.0\n + sphinxcontrib-devhelp==1.0.2\n + sphinxcontrib-htmlhelp==2.0.1\n + sphinxcontrib-jsmath==1.0.1\n + sphinxcontrib-qthelp==1.0.3\n + sphinxcontrib-serializinghtml==1.1.5\n + sphinxcontrib-towncrier==0.4.0a0\n + tomli==2.0.1\n + towncrier==23.11.0\n + tqdm==4.66.5\n + trustme==1.1.0\n + typer==0.12.5\n + typing-extensions==4.12.2\n + uritemplate==4.1.1\n + urllib3==2.2.2\n + uvloop==0.20.0\n + virtualenv==20.26.3\n + wait-for-it==2.2.2\n + webcolors==24.8.0\n + wheel==0.44.0\n + yarl==1.9.6\n + zipp==3.20.1\nwarning: `yarl==1.9.6` is yanked (reason: \"Performance regression: https://github.com/aio-libs/yarl/pull/1198\")\nResolved 9 packages in 1.74s\nPrepared 1 package in 17.26s\nInstalled 1 package in 0.55ms\n + aiohttp==3.11.0.dev0 (from file:///home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_ea316336f0b247bb85fd7ee0e4e41f5eac682228)\nResolved 24 packages in 16ms\nInstalled 5 packages in 5ms\n + async-generator==1.10\n + brotlipy==0.7.0\n + chardet==5.2.0\n + multdict==0.0.5\n + pytest-asyncio==0.25.1\n",
    "new_commit_res_code": 0,
    "new_commit_res_stdout": "============================= test session starts ==============================\nplatform linux -- Python 3.9.21, pytest-8.3.2, pluggy-1.5.0 -- /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_ea316336f0b247bb85fd7ee0e4e41f5eac682228/.venv/bin/python\ncachedir: .pytest_cache\nrootdir: /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_ea316336f0b247bb85fd7ee0e4e41f5eac682228\nconfigfile: setup.cfg\nplugins: cov-5.0.0, mock-3.14.0, asyncio-0.25.1\nasyncio: mode=strict, asyncio_default_fixture_loop_scope=None\ncollecting ... collected 146 items\n\nr2e_tests/test_1.py::test_connection_del[pyloop] PASSED                  [  0%]\nr2e_tests/test_1.py::test_connection_del_loop_debug[pyloop] PASSED       [  1%]\nr2e_tests/test_1.py::test_connection_del_loop_closed[pyloop] PASSED      [  2%]\nr2e_tests/test_1.py::test_del[pyloop] PASSED                             [  2%]\nr2e_tests/test_1.py::test_del_with_scheduled_cleanup[pyloop] XFAIL       [  3%]\nr2e_tests/test_1.py::test_del_with_closed_loop[pyloop] PASSED            [  4%]\nr2e_tests/test_1.py::test_del_empty_connector[pyloop] PASSED             [  4%]\nr2e_tests/test_1.py::test_create_conn[pyloop] PASSED                     [  5%]\nr2e_tests/test_1.py::test_connector_context_manager[pyloop] PASSED       [  6%]\nr2e_tests/test_1.py::test_async_context_manager[pyloop] PASSED           [  6%]\nr2e_tests/test_1.py::test_close[pyloop] PASSED                           [  7%]\nr2e_tests/test_1.py::test_get[pyloop] PASSED                             [  8%]\nr2e_tests/test_1.py::test_get_unconnected_proto[pyloop] PASSED           [  8%]\nr2e_tests/test_1.py::test_get_unconnected_proto_ssl[pyloop] PASSED       [  9%]\nr2e_tests/test_1.py::test_get_expired[pyloop] PASSED                     [ 10%]\nr2e_tests/test_1.py::test_get_expired_ssl[pyloop] PASSED                 [ 10%]\nr2e_tests/test_1.py::test_release_acquired[pyloop] PASSED                [ 11%]\nr2e_tests/test_1.py::test_release_acquired_closed[pyloop] PASSED         [ 12%]\nr2e_tests/test_1.py::test_release[pyloop] PASSED                         [ 13%]\nr2e_tests/test_1.py::test_release_ssl_transport[pyloop] PASSED           [ 13%]\nr2e_tests/test_1.py::test_release_already_closed[pyloop] PASSED          [ 14%]\nr2e_tests/test_1.py::test_release_waiter_no_limit[pyloop] PASSED         [ 15%]\nr2e_tests/test_1.py::test_release_waiter_first_available[pyloop] PASSED  [ 15%]\nr2e_tests/test_1.py::test_release_waiter_release_first[pyloop] PASSED    [ 16%]\nr2e_tests/test_1.py::test_release_waiter_skip_done_waiter[pyloop] PASSED [ 17%]\nr2e_tests/test_1.py::test_release_waiter_per_host[pyloop] PASSED         [ 17%]\nr2e_tests/test_1.py::test_release_waiter_no_available[pyloop] PASSED     [ 18%]\nr2e_tests/test_1.py::test_release_close[pyloop] PASSED                   [ 19%]\nr2e_tests/test_1.py::test__drop_acquire_per_host1[pyloop] PASSED         [ 19%]\nr2e_tests/test_1.py::test__drop_acquire_per_host2[pyloop] PASSED         [ 20%]\nr2e_tests/test_1.py::test__drop_acquire_per_host3[pyloop] PASSED         [ 21%]\nr2e_tests/test_1.py::test_tcp_connector_certificate_error[pyloop] PASSED [ 21%]\nr2e_tests/test_1.py::test_tcp_connector_server_hostname_default[pyloop] PASSED [ 22%]\nr2e_tests/test_1.py::test_tcp_connector_server_hostname_override[pyloop] PASSED [ 23%]\nr2e_tests/test_1.py::test_tcp_connector_multiple_hosts_errors[pyloop] PASSED [ 23%]\nr2e_tests/test_1.py::test_tcp_connector_happy_eyeballs[pyloop-0.1] PASSED [ 24%]\nr2e_tests/test_1.py::test_tcp_connector_happy_eyeballs[pyloop-0.25] PASSED [ 25%]\nr2e_tests/test_1.py::test_tcp_connector_happy_eyeballs[pyloop-None] PASSED [ 26%]\nr2e_tests/test_1.py::test_tcp_connector_interleave[pyloop] PASSED        [ 26%]\nr2e_tests/test_1.py::test_tcp_connector_family_is_respected[pyloop] PASSED [ 27%]\nr2e_tests/test_1.py::test_tcp_connector_resolve_host[pyloop] PASSED      [ 28%]\nr2e_tests/test_1.py::test_tcp_connector_dns_cache_not_expired[pyloop] PASSED [ 28%]\nr2e_tests/test_1.py::test_tcp_connector_dns_cache_forever[pyloop] PASSED [ 29%]\nr2e_tests/test_1.py::test_tcp_connector_use_dns_cache_disabled[pyloop] PASSED [ 30%]\nr2e_tests/test_1.py::test_tcp_connector_dns_throttle_requests[pyloop] PASSED [ 30%]\nr2e_tests/test_1.py::test_tcp_connector_dns_throttle_requests_exception_spread[pyloop] PASSED [ 31%]\nr2e_tests/test_1.py::test_tcp_connector_dns_throttle_requests_cancelled_when_close[pyloop] PASSED [ 32%]\nr2e_tests/test_1.py::test_tcp_connector_cancel_dns_error_captured[pyloop] PASSED [ 32%]\nr2e_tests/test_1.py::test_tcp_connector_dns_tracing[pyloop] PASSED       [ 33%]\nr2e_tests/test_1.py::test_tcp_connector_dns_tracing_cache_disabled[pyloop] PASSED [ 34%]\nr2e_tests/test_1.py::test_tcp_connector_dns_tracing_throttle_requests[pyloop] PASSED [ 34%]\nr2e_tests/test_1.py::test_dns_error[pyloop] PASSED                       [ 35%]\nr2e_tests/test_1.py::test_get_pop_empty_conns[pyloop] PASSED             [ 36%]\nr2e_tests/test_1.py::test_release_close_do_not_add_to_pool[pyloop] PASSED [ 36%]\nr2e_tests/test_1.py::test_release_close_do_not_delete_existing_connections PASSED [ 37%]\nr2e_tests/test_1.py::test_release_not_started[pyloop] PASSED             [ 38%]\nr2e_tests/test_1.py::test_release_not_opened[pyloop] PASSED              [ 39%]\nr2e_tests/test_1.py::test_connect[pyloop] PASSED                         [ 39%]\nr2e_tests/test_1.py::test_connect_tracing[pyloop] PASSED                 [ 40%]\nr2e_tests/test_1.py::test_close_during_connect[pyloop] PASSED            [ 41%]\nr2e_tests/test_1.py::test_ctor_cleanup PASSED                            [ 41%]\nr2e_tests/test_1.py::test_cleanup PASSED                                 [ 42%]\nr2e_tests/test_1.py::test_cleanup_close_ssl_transport PASSED             [ 43%]\nr2e_tests/test_1.py::test_cleanup2 PASSED                                [ 43%]\nr2e_tests/test_1.py::test_cleanup3 PASSED                                [ 44%]\nr2e_tests/test_1.py::test_cleanup_closed[pyloop] PASSED                  [ 45%]\nr2e_tests/test_1.py::test_cleanup_closed_disabled[pyloop] PASSED         [ 45%]\nr2e_tests/test_1.py::test_tcp_connector_ctor PASSED                      [ 46%]\nr2e_tests/test_1.py::test_tcp_connector_allowed_protocols[pyloop] PASSED [ 47%]\nr2e_tests/test_1.py::test_invalid_ssl_param PASSED                       [ 47%]\nr2e_tests/test_1.py::test_tcp_connector_ctor_fingerprint_valid[pyloop] PASSED [ 48%]\nr2e_tests/test_1.py::test_insecure_fingerprint_md5[pyloop] PASSED        [ 49%]\nr2e_tests/test_1.py::test_insecure_fingerprint_sha1[pyloop] PASSED       [ 50%]\nr2e_tests/test_1.py::test_tcp_connector_clear_dns_cache[pyloop] PASSED   [ 50%]\nr2e_tests/test_1.py::test_tcp_connector_clear_dns_cache_bad_args[pyloop] PASSED [ 51%]\nr2e_tests/test_1.py::test_dont_recreate_ssl_context PASSED               [ 52%]\nr2e_tests/test_1.py::test_dont_recreate_ssl_context2 PASSED              [ 52%]\nr2e_tests/test_1.py::test___get_ssl_context1 PASSED                      [ 53%]\nr2e_tests/test_1.py::test___get_ssl_context2[pyloop] PASSED              [ 54%]\nr2e_tests/test_1.py::test___get_ssl_context3[pyloop] PASSED              [ 54%]\nr2e_tests/test_1.py::test___get_ssl_context4[pyloop] PASSED              [ 55%]\nr2e_tests/test_1.py::test___get_ssl_context5[pyloop] PASSED              [ 56%]\nr2e_tests/test_1.py::test___get_ssl_context6 PASSED                      [ 56%]\nr2e_tests/test_1.py::test_ssl_context_once PASSED                        [ 57%]\nr2e_tests/test_1.py::test_ssl_context_creation_raises[OSError] PASSED    [ 58%]\nr2e_tests/test_1.py::test_ssl_context_creation_raises[SSLError] PASSED   [ 58%]\nr2e_tests/test_1.py::test_ssl_context_creation_raises[CancelledError] PASSED [ 59%]\nr2e_tests/test_1.py::test_close_twice[pyloop] PASSED                     [ 60%]\nr2e_tests/test_1.py::test_close_cancels_cleanup_handle[pyloop] PASSED    [ 60%]\nr2e_tests/test_1.py::test_close_cancels_resolve_host[pyloop] PASSED      [ 61%]\nr2e_tests/test_1.py::test_close_abort_closed_transports[pyloop] PASSED   [ 62%]\nr2e_tests/test_1.py::test_close_cancels_cleanup_closed_handle[pyloop] PASSED [ 63%]\nr2e_tests/test_1.py::test_ctor_with_default_loop[pyloop] PASSED          [ 63%]\nr2e_tests/test_1.py::test_base_connector_allows_high_level_protocols[pyloop] PASSED [ 64%]\nr2e_tests/test_1.py::test_connect_with_limit[pyloop] PASSED              [ 65%]\nr2e_tests/test_1.py::test_connect_queued_operation_tracing[pyloop] PASSED [ 65%]\nr2e_tests/test_1.py::test_connect_reuseconn_tracing[pyloop] PASSED       [ 66%]\nr2e_tests/test_1.py::test_connect_with_limit_and_limit_per_host[pyloop] PASSED [ 67%]\nr2e_tests/test_1.py::test_connect_with_no_limit_and_limit_per_host[pyloop] PASSED [ 67%]\nr2e_tests/test_1.py::test_connect_with_no_limits[pyloop] PASSED          [ 68%]\nr2e_tests/test_1.py::test_connect_with_limit_cancelled[pyloop] PASSED    [ 69%]\nr2e_tests/test_1.py::test_connect_with_capacity_release_waiters[pyloop] PASSED [ 69%]\nr2e_tests/test_1.py::test_connect_with_limit_concurrent[pyloop] PASSED   [ 70%]\nr2e_tests/test_1.py::test_connect_waiters_cleanup[pyloop] PASSED         [ 71%]\nr2e_tests/test_1.py::test_connect_waiters_cleanup_key_error[pyloop] PASSED [ 71%]\nr2e_tests/test_1.py::test_close_with_acquired_connection[pyloop] PASSED  [ 72%]\nr2e_tests/test_1.py::test_default_force_close[pyloop] PASSED             [ 73%]\nr2e_tests/test_1.py::test_limit_property[pyloop] PASSED                  [ 73%]\nr2e_tests/test_1.py::test_limit_per_host_property[pyloop] PASSED         [ 74%]\nr2e_tests/test_1.py::test_limit_property_default[pyloop] PASSED          [ 75%]\nr2e_tests/test_1.py::test_limit_per_host_property_default[pyloop] PASSED [ 76%]\nr2e_tests/test_1.py::test_force_close_and_explicit_keep_alive[pyloop] PASSED [ 76%]\nr2e_tests/test_1.py::test_error_on_connection[pyloop] PASSED             [ 77%]\nr2e_tests/test_1.py::test_cancelled_waiter[pyloop] PASSED                [ 78%]\nr2e_tests/test_1.py::test_error_on_connection_with_cancelled_waiter[pyloop] PASSED [ 78%]\nr2e_tests/test_1.py::test_tcp_connector[pyloop] PASSED                   [ 79%]\nr2e_tests/test_1.py::test_unix_connector_not_found[pyloop] PASSED        [ 80%]\nr2e_tests/test_1.py::test_unix_connector_permission[pyloop] PASSED       [ 80%]\nr2e_tests/test_1.py::test_named_pipe_connector_wrong_loop SKIPPED (P...) [ 81%]\nr2e_tests/test_1.py::test_named_pipe_connector_not_found SKIPPED (Pr...) [ 82%]\nr2e_tests/test_1.py::test_named_pipe_connector_permission SKIPPED (P...) [ 82%]\nr2e_tests/test_1.py::test_default_use_dns_cache PASSED                   [ 83%]\nr2e_tests/test_1.py::test_ssl_none PASSED                                [ 84%]\nr2e_tests/test_1.py::test_resolver_not_called_with_address_is_ip[pyloop] PASSED [ 84%]\nr2e_tests/test_1.py::test_tcp_connector_raise_connector_ssl_error[pyloop] PASSED [ 85%]\nr2e_tests/test_1.py::test_tcp_connector_do_not_raise_connector_ssl_error[pyloop-ip address] PASSED [ 86%]\nr2e_tests/test_1.py::test_tcp_connector_do_not_raise_connector_ssl_error[pyloop-domain name] PASSED [ 86%]\nr2e_tests/test_1.py::test_tcp_connector_do_not_raise_connector_ssl_error[pyloop-fully-qualified domain name] PASSED [ 87%]\nr2e_tests/test_1.py::test_tcp_connector_do_not_raise_connector_ssl_error[pyloop-fully-qualified domain name with multiple trailing dots] PASSED [ 88%]\nr2e_tests/test_1.py::test_tcp_connector_do_not_raise_connector_ssl_error[pyloop-idna fully-qualified domain name] PASSED [ 89%]\nr2e_tests/test_1.py::test_tcp_connector_uses_provided_local_addr[pyloop] PASSED [ 89%]\nr2e_tests/test_1.py::test_unix_connector[pyloop] PASSED                  [ 90%]\nr2e_tests/test_1.py::test_named_pipe_connector SKIPPED (Proactor Eve...) [ 91%]\nr2e_tests/test_1.py::TestDNSCacheTable::test_next_addrs_basic PASSED     [ 91%]\nr2e_tests/test_1.py::TestDNSCacheTable::test_remove PASSED               [ 92%]\nr2e_tests/test_1.py::TestDNSCacheTable::test_clear PASSED                [ 93%]\nr2e_tests/test_1.py::TestDNSCacheTable::test_not_expired_ttl_None PASSED [ 93%]\nr2e_tests/test_1.py::TestDNSCacheTable::test_not_expired_ttl PASSED      [ 94%]\nr2e_tests/test_1.py::TestDNSCacheTable::test_expired_ttl PASSED          [ 95%]\nr2e_tests/test_1.py::TestDNSCacheTable::test_never_expire PASSED         [ 95%]\nr2e_tests/test_1.py::TestDNSCacheTable::test_always_expire PASSED        [ 96%]\nr2e_tests/test_1.py::TestDNSCacheTable::test_next_addrs PASSED           [ 97%]\nr2e_tests/test_1.py::TestDNSCacheTable::test_next_addrs_single PASSED    [ 97%]\nr2e_tests/test_1.py::test_connector_cache_trace_race PASSED              [ 98%]\nr2e_tests/test_1.py::test_connector_throttle_trace_race[pyloop] PASSED   [ 99%]\nr2e_tests/test_1.py::test_connector_does_not_remove_needed_waiters[pyloop] PASSED [100%]\n\n==================================== PASSES ====================================\n---------------------------- Captured log teardown -----------------------------\nERROR    asyncio:base_events.py:1753 Task was destroyed but it is pending!\ntask: <Task pending name='Task-54' coro=<TCPConnector._resolve_host() running at /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_ea316336f0b247bb85fd7ee0e4e41f5eac682228/aiohttp/connector.py:917> wait_for=<Future finished result=['127.0.0.1']>>\nERROR    asyncio:base_events.py:1753 Task was destroyed but it is pending!\ntask: <Task pending name='Task-55' coro=<TCPConnector._resolve_host() done, defined at /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_ea316336f0b247bb85fd7ee0e4e41f5eac682228/aiohttp/connector.py:860> wait_for=<Future pending cb=[shield.<locals>._outer_done_callback() at /home/gcpuser/.local/share/uv/python/cpython-3.9.21-linux-x86_64-gnu/lib/python3.9/asyncio/tasks.py:907, <TaskWakeupMethWrapper object at 0x7fa549f0b7f0>()]>>\n---------------------------- Captured log teardown -----------------------------\nERROR    asyncio:base_events.py:1753 Task was destroyed but it is pending!\ntask: <Task pending name='Task-76' coro=<TCPConnector._resolve_host() running at /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_ea316336f0b247bb85fd7ee0e4e41f5eac682228/aiohttp/connector.py:917> wait_for=<Future finished result=['127.0.0.1']>>\nERROR    asyncio:base_events.py:1753 Task was destroyed but it is pending!\ntask: <Task pending name='Task-77' coro=<TCPConnector._resolve_host() done, defined at /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_ea316336f0b247bb85fd7ee0e4e41f5eac682228/aiohttp/connector.py:860> wait_for=<Future pending cb=[shield.<locals>._outer_done_callback() at /home/gcpuser/.local/share/uv/python/cpython-3.9.21-linux-x86_64-gnu/lib/python3.9/asyncio/tasks.py:907, <TaskWakeupMethWrapper object at 0x7fa549f0bf70>()]>>\n__________________ test_ssl_context_creation_raises[OSError] ___________________\n------------------------------ Captured log call -------------------------------\nERROR    asyncio:base_events.py:1753 Future exception was never retrieved\nfuture: <Future finished exception=OSError()>\nTraceback (most recent call last):\n  File \"/home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_ea316336f0b247bb85fd7ee0e4e41f5eac682228/aiohttp/connector.py\", line 1039, in _make_or_get_ssl_context\n    return await self._made_ssl_context[verified]\nKeyError: True\n\nDuring handling of the above exception, another exception occurred:\n\nTraceback (most recent call last):\n  File \"/home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_ea316336f0b247bb85fd7ee0e4e41f5eac682228/r2e_tests/test_1.py\", line 1641, in test_ssl_context_creation_raises\n    await conn._make_or_get_ssl_context(True)\n  File \"/home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_ea316336f0b247bb85fd7ee0e4e41f5eac682228/aiohttp/connector.py\", line 1045, in _make_or_get_ssl_context\n    result = await loop.run_in_executor(\n  File \"/home/gcpuser/.local/share/uv/python/cpython-3.9.21-linux-x86_64-gnu/lib/python3.9/concurrent/futures/thread.py\", line 58, in run\n    result = self.fn(*self.args, **self.kwargs)\n  File \"/home/gcpuser/.local/share/uv/python/cpython-3.9.21-linux-x86_64-gnu/lib/python3.9/unittest/mock.py\", line 1092, in __call__\n    return self._mock_call(*args, **kwargs)\n  File \"/home/gcpuser/.local/share/uv/python/cpython-3.9.21-linux-x86_64-gnu/lib/python3.9/unittest/mock.py\", line 1096, in _mock_call\n    return self._execute_mock_call(*args, **kwargs)\n  File \"/home/gcpuser/.local/share/uv/python/cpython-3.9.21-linux-x86_64-gnu/lib/python3.9/unittest/mock.py\", line 1151, in _execute_mock_call\n    raise effect\nOSError\n__________________ test_ssl_context_creation_raises[SSLError] __________________\n------------------------------ Captured log call -------------------------------\nERROR    asyncio:base_events.py:1753 Future exception was never retrieved\nfuture: <Future finished exception=SSLError()>\nTraceback (most recent call last):\n  File \"/home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_ea316336f0b247bb85fd7ee0e4e41f5eac682228/aiohttp/connector.py\", line 1039, in _make_or_get_ssl_context\n    return await self._made_ssl_context[verified]\nKeyError: True\n\nDuring handling of the above exception, another exception occurred:\n\nTraceback (most recent call last):\n  File \"/home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_ea316336f0b247bb85fd7ee0e4e41f5eac682228/r2e_tests/test_1.py\", line 1641, in test_ssl_context_creation_raises\n    await conn._make_or_get_ssl_context(True)\n  File \"/home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_ea316336f0b247bb85fd7ee0e4e41f5eac682228/aiohttp/connector.py\", line 1045, in _make_or_get_ssl_context\n    result = await loop.run_in_executor(\n  File \"/home/gcpuser/.local/share/uv/python/cpython-3.9.21-linux-x86_64-gnu/lib/python3.9/concurrent/futures/thread.py\", line 58, in run\n    result = self.fn(*self.args, **self.kwargs)\n  File \"/home/gcpuser/.local/share/uv/python/cpython-3.9.21-linux-x86_64-gnu/lib/python3.9/unittest/mock.py\", line 1092, in __call__\n    return self._mock_call(*args, **kwargs)\n  File \"/home/gcpuser/.local/share/uv/python/cpython-3.9.21-linux-x86_64-gnu/lib/python3.9/unittest/mock.py\", line 1096, in _mock_call\n    return self._execute_mock_call(*args, **kwargs)\n  File \"/home/gcpuser/.local/share/uv/python/cpython-3.9.21-linux-x86_64-gnu/lib/python3.9/unittest/mock.py\", line 1151, in _execute_mock_call\n    raise effect\nssl.SSLError: ()\n_______________ test_ssl_context_creation_raises[CancelledError] _______________\n------------------------------ Captured log call -------------------------------\nERROR    asyncio:base_events.py:1753 Future exception was never retrieved\nfuture: <Future finished exception=CancelledError()>\nTraceback (most recent call last):\n  File \"/home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_ea316336f0b247bb85fd7ee0e4e41f5eac682228/aiohttp/connector.py\", line 1039, in _make_or_get_ssl_context\n    return await self._made_ssl_context[verified]\nKeyError: True\n\nDuring handling of the above exception, another exception occurred:\n\nTraceback (most recent call last):\n  File \"/home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_ea316336f0b247bb85fd7ee0e4e41f5eac682228/r2e_tests/test_1.py\", line 1641, in test_ssl_context_creation_raises\n    await conn._make_or_get_ssl_context(True)\n  File \"/home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_ea316336f0b247bb85fd7ee0e4e41f5eac682228/aiohttp/connector.py\", line 1045, in _make_or_get_ssl_context\n    result = await loop.run_in_executor(\n  File \"/home/gcpuser/.local/share/uv/python/cpython-3.9.21-linux-x86_64-gnu/lib/python3.9/concurrent/futures/thread.py\", line 58, in run\n    result = self.fn(*self.args, **self.kwargs)\n  File \"/home/gcpuser/.local/share/uv/python/cpython-3.9.21-linux-x86_64-gnu/lib/python3.9/unittest/mock.py\", line 1092, in __call__\n    return self._mock_call(*args, **kwargs)\n  File \"/home/gcpuser/.local/share/uv/python/cpython-3.9.21-linux-x86_64-gnu/lib/python3.9/unittest/mock.py\", line 1096, in _mock_call\n    return self._execute_mock_call(*args, **kwargs)\n  File \"/home/gcpuser/.local/share/uv/python/cpython-3.9.21-linux-x86_64-gnu/lib/python3.9/unittest/mock.py\", line 1151, in _execute_mock_call\n    raise effect\nasyncio.exceptions.CancelledError\n\n---------- coverage: platform linux, python 3.9.21-final-0 -----------\nName                                     Stmts   Miss Branch BrPart  Cover\n--------------------------------------------------------------------------\naiohttp/__init__.py                         27      8      2      1    69%\naiohttp/abc.py                              97      2      0      0    98%\naiohttp/base_protocol.py                    67     36     22      3    38%\naiohttp/client.py                          554    260    202     51    47%\naiohttp/client_exceptions.py               154     50     20      1    60%\naiohttp/client_proto.py                    163     53     56     19    60%\naiohttp/client_reqrep.py                   695    286    300     69    51%\naiohttp/client_ws.py                       264    211     82      1    16%\naiohttp/compression_utils.py                70     36     14      0    40%\naiohttp/connector.py                       774    147    321     19    79%\naiohttp/cookiejar.py                       255    173    118      8    25%\naiohttp/formdata.py                         97     79     46      0    13%\naiohttp/hdrs.py                             90      0      0      0   100%\naiohttp/helpers.py                         501    251    172     20    43%\naiohttp/http.py                             11      0      2      0   100%\naiohttp/http_exceptions.py                  50     20      4      0    56%\naiohttp/http_parser.py                     504    404    208      1    14%\naiohttp/http_websocket.py                  393    287    152      0    20%\naiohttp/http_writer.py                     118     44     50     13    53%\naiohttp/locks.py                            24      1      4      1    93%\naiohttp/log.py                               7      0      0      0   100%\naiohttp/multipart.py                       623    508    266      1    13%\naiohttp/payload.py                         237    113     58      1    44%\naiohttp/payload_streamer.py                 31     11      4      0    69%\naiohttp/pytest_plugin.py                   162     49     42      6    67%\naiohttp/resolver.py                         78     42     26      4    40%\naiohttp/streams.py                         398    250    146     11    29%\naiohttp/tcp_helpers.py                      19      1      6      2    88%\naiohttp/test_utils.py                      315    111     50     13    61%\naiohttp/tracing.py                         191     14     32      0    94%\naiohttp/typedefs.py                         23      0      0      0   100%\naiohttp/web.py                             122     84     52      0    23%\naiohttp/web_app.py                         282    101     74     19    57%\naiohttp/web_exceptions.py                  157     25      8      0    80%\naiohttp/web_fileresponse.py                160    126     52      0    18%\naiohttp/web_log.py                         102     37     20      1    59%\naiohttp/web_middlewares.py                  55     37     20      0    24%\naiohttp/web_protocol.py                    354    130    155     43    55%\naiohttp/web_request.py                     441    251    134      8    35%\naiohttp/web_response.py                    479    258    220     33    36%\naiohttp/web_routedef.py                    100     44     10      0    55%\naiohttp/web_runner.py                      213     65     36     11    65%\naiohttp/web_server.py                       42      5     12      1    85%\naiohttp/web_urldispatcher.py               742    386    161     21    42%\naiohttp/web_ws.py                          382    310    132      1    15%\naiohttp/worker.py                          126    126     30      0     0%\ntests/conftest.py                          130    130     16      0     0%\ntests/test_base_protocol.py                198    198      2      0     0%\ntests/test_circular_imports.py              29     29     13      0     0%\ntests/test_classbasedview.py                39     39      0      0     0%\ntests/test_client_connection.py             94     94      2      0     0%\ntests/test_client_exceptions.py            199    199     14      0     0%\ntests/test_client_fingerprint.py            59     59      0      0     0%\ntests/test_client_functional.py           2507   2507     86      0     0%\ntests/test_client_proto.py                  99     99      0      0     0%\ntests/test_client_request.py               808    808     18      0     0%\ntests/test_client_response.py              466    466      4      0     0%\ntests/test_client_session.py               556    556     29      0     0%\ntests/test_client_ws.py                    487    487      2      0     0%\ntests/test_client_ws_functional.py         788    788     32      0     0%\ntests/test_connector.py                   1697   1697     82      0     0%\ntests/test_cookiejar.py                    350    350     24      0     0%\ntests/test_flowcontrol_streams.py          100    100      0      0     0%\ntests/test_formdata.py                      81     81      6      0     0%\ntests/test_helpers.py                      470    470     24      0     0%\ntests/test_http_exceptions.py              109    109     10      0     0%\ntests/test_http_parser.py                 1088   1088     66      0     0%\ntests/test_http_writer.py                  182    182     10      0     0%\ntests/test_imports.py                       34     34      6      0     0%\ntests/test_locks.py                         39     39      0      0     0%\ntests/test_loop.py                          36     36      0      0     0%\ntests/test_multipart.py                    826    826     32      0     0%\ntests/test_multipart_helpers.py            446    446      0      0     0%\ntests/test_payload.py                       95     95      0      0     0%\ntests/test_proxy.py                        301    301      0      0     0%\ntests/test_proxy_functional.py             459    459     18      0     0%\ntests/test_pytest_plugin.py                 27     27      0      0     0%\ntests/test_resolver.py                     191    191     20      0     0%\ntests/test_route_def.py                    210    210      0      0     0%\ntests/test_run_app.py                      563    563     30      0     0%\ntests/test_streams.py                     1076   1076     38      0     0%\ntests/test_tcp_helpers.py                   52     52      2      0     0%\ntests/test_test_utils.py                   244    244      6      0     0%\ntests/test_tracing.py                       48     48      0      0     0%\ntests/test_urldispatch.py                  851    851     24      0     0%\ntests/test_web_app.py                      454    454      6      0     0%\ntests/test_web_cli.py                       75     75      0      0     0%\ntests/test_web_exceptions.py               176    176     22      0     0%\ntests/test_web_functional.py              1552   1552     34      0     0%\ntests/test_web_log.py                      116    116      2      0     0%\ntests/test_web_middleware.py               266    266     12      0     0%\ntests/test_web_request.py                  490    490      8      0     0%\ntests/test_web_request_handler.py           42     42      0      0     0%\ntests/test_web_response.py                 885    885      6      0     0%\ntests/test_web_runner.py                   151    151      4      0     0%\ntests/test_web_sendfile.py                  84     84      0      0     0%\ntests/test_web_sendfile_functional.py      655    655     18      0     0%\ntests/test_web_server.py                   162    162      0      0     0%\ntests/test_web_urldispatcher.py            517    517     24      0     0%\ntests/test_web_websocket.py                401    401      8      0     0%\ntests/test_web_websocket_functional.py     769    769     28      0     0%\ntests/test_websocket_handshake.py          152    152     12      0     0%\ntests/test_websocket_parser.py             300    300     12      0     0%\ntests/test_websocket_writer.py              95     95      6      0     0%\ntests/test_worker.py                       191    191      2      0     0%\n--------------------------------------------------------------------------\nTOTAL                                    34316  28999   4341    383    16%\n\n============================= slowest 10 durations =============================\n0.07s call     r2e_tests/test_1.py::test_tcp_connector_multiple_hosts_errors[pyloop]\n0.06s setup    r2e_tests/test_1.py::test_tcp_connector_raise_connector_ssl_error[pyloop]\n0.04s call     r2e_tests/test_1.py::test_ssl_context_creation_raises[OSError]\n0.04s call     r2e_tests/test_1.py::test_ssl_context_creation_raises[CancelledError]\n0.04s call     r2e_tests/test_1.py::test_ssl_context_creation_raises[SSLError]\n0.04s teardown r2e_tests/test_1.py::test_close_with_acquired_connection[pyloop]\n0.04s call     r2e_tests/test_1.py::test_del_with_scheduled_cleanup[pyloop]\n0.04s teardown r2e_tests/test_1.py::test_release_waiter_no_limit[pyloop]\n0.03s teardown r2e_tests/test_1.py::test_connect_waiters_cleanup_key_error[pyloop]\n0.03s teardown r2e_tests/test_1.py::test_tcp_connector_do_not_raise_connector_ssl_error[pyloop-idna fully-qualified domain name]\n=========================== short test summary info ============================\nPASSED r2e_tests/test_1.py::test_connection_del[pyloop]\nPASSED r2e_tests/test_1.py::test_connection_del_loop_debug[pyloop]\nPASSED r2e_tests/test_1.py::test_connection_del_loop_closed[pyloop]\nPASSED r2e_tests/test_1.py::test_del[pyloop]\nPASSED r2e_tests/test_1.py::test_del_with_closed_loop[pyloop]\nPASSED r2e_tests/test_1.py::test_del_empty_connector[pyloop]\nPASSED r2e_tests/test_1.py::test_create_conn[pyloop]\nPASSED r2e_tests/test_1.py::test_connector_context_manager[pyloop]\nPASSED r2e_tests/test_1.py::test_async_context_manager[pyloop]\nPASSED r2e_tests/test_1.py::test_close[pyloop]\nPASSED r2e_tests/test_1.py::test_get[pyloop]\nPASSED r2e_tests/test_1.py::test_get_unconnected_proto[pyloop]\nPASSED r2e_tests/test_1.py::test_get_unconnected_proto_ssl[pyloop]\nPASSED r2e_tests/test_1.py::test_get_expired[pyloop]\nPASSED r2e_tests/test_1.py::test_get_expired_ssl[pyloop]\nPASSED r2e_tests/test_1.py::test_release_acquired[pyloop]\nPASSED r2e_tests/test_1.py::test_release_acquired_closed[pyloop]\nPASSED r2e_tests/test_1.py::test_release[pyloop]\nPASSED r2e_tests/test_1.py::test_release_ssl_transport[pyloop]\nPASSED r2e_tests/test_1.py::test_release_already_closed[pyloop]\nPASSED r2e_tests/test_1.py::test_release_waiter_no_limit[pyloop]\nPASSED r2e_tests/test_1.py::test_release_waiter_first_available[pyloop]\nPASSED r2e_tests/test_1.py::test_release_waiter_release_first[pyloop]\nPASSED r2e_tests/test_1.py::test_release_waiter_skip_done_waiter[pyloop]\nPASSED r2e_tests/test_1.py::test_release_waiter_per_host[pyloop]\nPASSED r2e_tests/test_1.py::test_release_waiter_no_available[pyloop]\nPASSED r2e_tests/test_1.py::test_release_close[pyloop]\nPASSED r2e_tests/test_1.py::test__drop_acquire_per_host1[pyloop]\nPASSED r2e_tests/test_1.py::test__drop_acquire_per_host2[pyloop]\nPASSED r2e_tests/test_1.py::test__drop_acquire_per_host3[pyloop]\nPASSED r2e_tests/test_1.py::test_tcp_connector_certificate_error[pyloop]\nPASSED r2e_tests/test_1.py::test_tcp_connector_server_hostname_default[pyloop]\nPASSED r2e_tests/test_1.py::test_tcp_connector_server_hostname_override[pyloop]\nPASSED r2e_tests/test_1.py::test_tcp_connector_multiple_hosts_errors[pyloop]\nPASSED r2e_tests/test_1.py::test_tcp_connector_happy_eyeballs[pyloop-0.1]\nPASSED r2e_tests/test_1.py::test_tcp_connector_happy_eyeballs[pyloop-0.25]\nPASSED r2e_tests/test_1.py::test_tcp_connector_happy_eyeballs[pyloop-None]\nPASSED r2e_tests/test_1.py::test_tcp_connector_interleave[pyloop]\nPASSED r2e_tests/test_1.py::test_tcp_connector_family_is_respected[pyloop]\nPASSED r2e_tests/test_1.py::test_tcp_connector_resolve_host[pyloop]\nPASSED r2e_tests/test_1.py::test_tcp_connector_dns_cache_not_expired[pyloop]\nPASSED r2e_tests/test_1.py::test_tcp_connector_dns_cache_forever[pyloop]\nPASSED r2e_tests/test_1.py::test_tcp_connector_use_dns_cache_disabled[pyloop]\nPASSED r2e_tests/test_1.py::test_tcp_connector_dns_throttle_requests[pyloop]\nPASSED r2e_tests/test_1.py::test_tcp_connector_dns_throttle_requests_exception_spread[pyloop]\nPASSED r2e_tests/test_1.py::test_tcp_connector_dns_throttle_requests_cancelled_when_close[pyloop]\nPASSED r2e_tests/test_1.py::test_tcp_connector_cancel_dns_error_captured[pyloop]\nPASSED r2e_tests/test_1.py::test_tcp_connector_dns_tracing[pyloop]\nPASSED r2e_tests/test_1.py::test_tcp_connector_dns_tracing_cache_disabled[pyloop]\nPASSED r2e_tests/test_1.py::test_tcp_connector_dns_tracing_throttle_requests[pyloop]\nPASSED r2e_tests/test_1.py::test_dns_error[pyloop]\nPASSED r2e_tests/test_1.py::test_get_pop_empty_conns[pyloop]\nPASSED r2e_tests/test_1.py::test_release_close_do_not_add_to_pool[pyloop]\nPASSED r2e_tests/test_1.py::test_release_close_do_not_delete_existing_connections\nPASSED r2e_tests/test_1.py::test_release_not_started[pyloop]\nPASSED r2e_tests/test_1.py::test_release_not_opened[pyloop]\nPASSED r2e_tests/test_1.py::test_connect[pyloop]\nPASSED r2e_tests/test_1.py::test_connect_tracing[pyloop]\nPASSED r2e_tests/test_1.py::test_close_during_connect[pyloop]\nPASSED r2e_tests/test_1.py::test_ctor_cleanup\nPASSED r2e_tests/test_1.py::test_cleanup\nPASSED r2e_tests/test_1.py::test_cleanup_close_ssl_transport\nPASSED r2e_tests/test_1.py::test_cleanup2\nPASSED r2e_tests/test_1.py::test_cleanup3\nPASSED r2e_tests/test_1.py::test_cleanup_closed[pyloop]\nPASSED r2e_tests/test_1.py::test_cleanup_closed_disabled[pyloop]\nPASSED r2e_tests/test_1.py::test_tcp_connector_ctor\nPASSED r2e_tests/test_1.py::test_tcp_connector_allowed_protocols[pyloop]\nPASSED r2e_tests/test_1.py::test_invalid_ssl_param\nPASSED r2e_tests/test_1.py::test_tcp_connector_ctor_fingerprint_valid[pyloop]\nPASSED r2e_tests/test_1.py::test_insecure_fingerprint_md5[pyloop]\nPASSED r2e_tests/test_1.py::test_insecure_fingerprint_sha1[pyloop]\nPASSED r2e_tests/test_1.py::test_tcp_connector_clear_dns_cache[pyloop]\nPASSED r2e_tests/test_1.py::test_tcp_connector_clear_dns_cache_bad_args[pyloop]\nPASSED r2e_tests/test_1.py::test_dont_recreate_ssl_context\nPASSED r2e_tests/test_1.py::test_dont_recreate_ssl_context2\nPASSED r2e_tests/test_1.py::test___get_ssl_context1\nPASSED r2e_tests/test_1.py::test___get_ssl_context2[pyloop]\nPASSED r2e_tests/test_1.py::test___get_ssl_context3[pyloop]\nPASSED r2e_tests/test_1.py::test___get_ssl_context4[pyloop]\nPASSED r2e_tests/test_1.py::test___get_ssl_context5[pyloop]\nPASSED r2e_tests/test_1.py::test___get_ssl_context6\nPASSED r2e_tests/test_1.py::test_ssl_context_once\nPASSED r2e_tests/test_1.py::test_ssl_context_creation_raises[OSError]\nPASSED r2e_tests/test_1.py::test_ssl_context_creation_raises[SSLError]\nPASSED r2e_tests/test_1.py::test_ssl_context_creation_raises[CancelledError]\nPASSED r2e_tests/test_1.py::test_close_twice[pyloop]\nPASSED r2e_tests/test_1.py::test_close_cancels_cleanup_handle[pyloop]\nPASSED r2e_tests/test_1.py::test_close_cancels_resolve_host[pyloop]\nPASSED r2e_tests/test_1.py::test_close_abort_closed_transports[pyloop]\nPASSED r2e_tests/test_1.py::test_close_cancels_cleanup_closed_handle[pyloop]\nPASSED r2e_tests/test_1.py::test_ctor_with_default_loop[pyloop]\nPASSED r2e_tests/test_1.py::test_base_connector_allows_high_level_protocols[pyloop]\nPASSED r2e_tests/test_1.py::test_connect_with_limit[pyloop]\nPASSED r2e_tests/test_1.py::test_connect_queued_operation_tracing[pyloop]\nPASSED r2e_tests/test_1.py::test_connect_reuseconn_tracing[pyloop]\nPASSED r2e_tests/test_1.py::test_connect_with_limit_and_limit_per_host[pyloop]\nPASSED r2e_tests/test_1.py::test_connect_with_no_limit_and_limit_per_host[pyloop]\nPASSED r2e_tests/test_1.py::test_connect_with_no_limits[pyloop]\nPASSED r2e_tests/test_1.py::test_connect_with_limit_cancelled[pyloop]\nPASSED r2e_tests/test_1.py::test_connect_with_capacity_release_waiters[pyloop]\nPASSED r2e_tests/test_1.py::test_connect_with_limit_concurrent[pyloop]\nPASSED r2e_tests/test_1.py::test_connect_waiters_cleanup[pyloop]\nPASSED r2e_tests/test_1.py::test_connect_waiters_cleanup_key_error[pyloop]\nPASSED r2e_tests/test_1.py::test_close_with_acquired_connection[pyloop]\nPASSED r2e_tests/test_1.py::test_default_force_close[pyloop]\nPASSED r2e_tests/test_1.py::test_limit_property[pyloop]\nPASSED r2e_tests/test_1.py::test_limit_per_host_property[pyloop]\nPASSED r2e_tests/test_1.py::test_limit_property_default[pyloop]\nPASSED r2e_tests/test_1.py::test_limit_per_host_property_default[pyloop]\nPASSED r2e_tests/test_1.py::test_force_close_and_explicit_keep_alive[pyloop]\nPASSED r2e_tests/test_1.py::test_error_on_connection[pyloop]\nPASSED r2e_tests/test_1.py::test_cancelled_waiter[pyloop]\nPASSED r2e_tests/test_1.py::test_error_on_connection_with_cancelled_waiter[pyloop]\nPASSED r2e_tests/test_1.py::test_tcp_connector[pyloop]\nPASSED r2e_tests/test_1.py::test_unix_connector_not_found[pyloop]\nPASSED r2e_tests/test_1.py::test_unix_connector_permission[pyloop]\nPASSED r2e_tests/test_1.py::test_default_use_dns_cache\nPASSED r2e_tests/test_1.py::test_ssl_none\nPASSED r2e_tests/test_1.py::test_resolver_not_called_with_address_is_ip[pyloop]\nPASSED r2e_tests/test_1.py::test_tcp_connector_raise_connector_ssl_error[pyloop]\nPASSED r2e_tests/test_1.py::test_tcp_connector_do_not_raise_connector_ssl_error[pyloop-ip address]\nPASSED r2e_tests/test_1.py::test_tcp_connector_do_not_raise_connector_ssl_error[pyloop-domain name]\nPASSED r2e_tests/test_1.py::test_tcp_connector_do_not_raise_connector_ssl_error[pyloop-fully-qualified domain name]\nPASSED r2e_tests/test_1.py::test_tcp_connector_do_not_raise_connector_ssl_error[pyloop-fully-qualified domain name with multiple trailing dots]\nPASSED r2e_tests/test_1.py::test_tcp_connector_do_not_raise_connector_ssl_error[pyloop-idna fully-qualified domain name]\nPASSED r2e_tests/test_1.py::test_tcp_connector_uses_provided_local_addr[pyloop]\nPASSED r2e_tests/test_1.py::test_unix_connector[pyloop]\nPASSED r2e_tests/test_1.py::TestDNSCacheTable::test_next_addrs_basic\nPASSED r2e_tests/test_1.py::TestDNSCacheTable::test_remove\nPASSED r2e_tests/test_1.py::TestDNSCacheTable::test_clear\nPASSED r2e_tests/test_1.py::TestDNSCacheTable::test_not_expired_ttl_None\nPASSED r2e_tests/test_1.py::TestDNSCacheTable::test_not_expired_ttl\nPASSED r2e_tests/test_1.py::TestDNSCacheTable::test_expired_ttl\nPASSED r2e_tests/test_1.py::TestDNSCacheTable::test_never_expire\nPASSED r2e_tests/test_1.py::TestDNSCacheTable::test_always_expire\nPASSED r2e_tests/test_1.py::TestDNSCacheTable::test_next_addrs\nPASSED r2e_tests/test_1.py::TestDNSCacheTable::test_next_addrs_single\nPASSED r2e_tests/test_1.py::test_connector_cache_trace_race\nPASSED r2e_tests/test_1.py::test_connector_throttle_trace_race[pyloop]\nPASSED r2e_tests/test_1.py::test_connector_does_not_remove_needed_waiters[pyloop]\nSKIPPED [1] r2e_tests/test_1.py:2321: Proactor Event loop present only in Windows\nSKIPPED [1] r2e_tests/test_1.py:2329: Proactor Event loop present only in Windows\nSKIPPED [1] r2e_tests/test_1.py:2340: Proactor Event loop present only in Windows\nSKIPPED [1] r2e_tests/test_1.py:2532: Proactor Event loop present only in Windows\nXFAIL r2e_tests/test_1.py::test_del_with_scheduled_cleanup[pyloop]\n================== 141 passed, 4 skipped, 1 xfailed in 8.55s ===================\n",
    "new_commit_res_stderr": "/home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_ea316336f0b247bb85fd7ee0e4e41f5eac682228/.venv/lib/python3.9/site-packages/pytest_asyncio/plugin.py:207: PytestDeprecationWarning: The configuration option \"asyncio_default_fixture_loop_scope\" is unset.\nThe event loop scope for asynchronous fixtures will default to the fixture caching scope. Future versions of pytest-asyncio will default the loop scope for asynchronous fixtures to function scope. Set the default fixture loop scope explicitly in order to avoid unexpected behavior in the future. Valid fixture loop scopes are: \"function\", \"class\", \"module\", \"package\", \"session\"\n\n  warnings.warn(PytestDeprecationWarning(_DEFAULT_FIXTURE_LOOP_SCOPE_UNSET))\n",
    "old_commit_res_code": 1,
    "old_commit_res_stdout": "============================= test session starts ==============================\nplatform linux -- Python 3.9.21, pytest-8.3.2, pluggy-1.5.0 -- /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_ea316336f0b247bb85fd7ee0e4e41f5eac682228/.venv/bin/python\ncachedir: .pytest_cache\nrootdir: /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_ea316336f0b247bb85fd7ee0e4e41f5eac682228\nconfigfile: setup.cfg\nplugins: cov-5.0.0, mock-3.14.0, asyncio-0.25.1\nasyncio: mode=strict, asyncio_default_fixture_loop_scope=None\ncollecting ... collected 146 items\n\nr2e_tests/test_1.py::test_connection_del[pyloop] PASSED                  [  0%]\nr2e_tests/test_1.py::test_connection_del_loop_debug[pyloop] PASSED       [  1%]\nr2e_tests/test_1.py::test_connection_del_loop_closed[pyloop] PASSED      [  2%]\nr2e_tests/test_1.py::test_del[pyloop] PASSED                             [  2%]\nr2e_tests/test_1.py::test_del_with_scheduled_cleanup[pyloop] XFAIL       [  3%]\nr2e_tests/test_1.py::test_del_with_closed_loop[pyloop] PASSED            [  4%]\nr2e_tests/test_1.py::test_del_empty_connector[pyloop] PASSED             [  4%]\nr2e_tests/test_1.py::test_create_conn[pyloop] PASSED                     [  5%]\nr2e_tests/test_1.py::test_connector_context_manager[pyloop] PASSED       [  6%]\nr2e_tests/test_1.py::test_async_context_manager[pyloop] PASSED           [  6%]\nr2e_tests/test_1.py::test_close[pyloop] PASSED                           [  7%]\nr2e_tests/test_1.py::test_get[pyloop] PASSED                             [  8%]\nr2e_tests/test_1.py::test_get_unconnected_proto[pyloop] PASSED           [  8%]\nr2e_tests/test_1.py::test_get_unconnected_proto_ssl[pyloop] PASSED       [  9%]\nr2e_tests/test_1.py::test_get_expired[pyloop] PASSED                     [ 10%]\nr2e_tests/test_1.py::test_get_expired_ssl[pyloop] PASSED                 [ 10%]\nr2e_tests/test_1.py::test_release_acquired[pyloop] PASSED                [ 11%]\nr2e_tests/test_1.py::test_release_acquired_closed[pyloop] PASSED         [ 12%]\nr2e_tests/test_1.py::test_release[pyloop] PASSED                         [ 13%]\nr2e_tests/test_1.py::test_release_ssl_transport[pyloop] PASSED           [ 13%]\nr2e_tests/test_1.py::test_release_already_closed[pyloop] PASSED          [ 14%]\nr2e_tests/test_1.py::test_release_waiter_no_limit[pyloop] PASSED         [ 15%]\nr2e_tests/test_1.py::test_release_waiter_first_available[pyloop] PASSED  [ 15%]\nr2e_tests/test_1.py::test_release_waiter_release_first[pyloop] PASSED    [ 16%]\nr2e_tests/test_1.py::test_release_waiter_skip_done_waiter[pyloop] PASSED [ 17%]\nr2e_tests/test_1.py::test_release_waiter_per_host[pyloop] PASSED         [ 17%]\nr2e_tests/test_1.py::test_release_waiter_no_available[pyloop] PASSED     [ 18%]\nr2e_tests/test_1.py::test_release_close[pyloop] PASSED                   [ 19%]\nr2e_tests/test_1.py::test__drop_acquire_per_host1[pyloop] PASSED         [ 19%]\nr2e_tests/test_1.py::test__drop_acquire_per_host2[pyloop] PASSED         [ 20%]\nr2e_tests/test_1.py::test__drop_acquire_per_host3[pyloop] PASSED         [ 21%]\nr2e_tests/test_1.py::test_tcp_connector_certificate_error[pyloop] PASSED [ 21%]\nr2e_tests/test_1.py::test_tcp_connector_server_hostname_default[pyloop] PASSED [ 22%]\nr2e_tests/test_1.py::test_tcp_connector_server_hostname_override[pyloop] PASSED [ 23%]\nr2e_tests/test_1.py::test_tcp_connector_multiple_hosts_errors[pyloop] PASSED [ 23%]\nr2e_tests/test_1.py::test_tcp_connector_happy_eyeballs[pyloop-0.1] PASSED [ 24%]\nr2e_tests/test_1.py::test_tcp_connector_happy_eyeballs[pyloop-0.25] PASSED [ 25%]\nr2e_tests/test_1.py::test_tcp_connector_happy_eyeballs[pyloop-None] PASSED [ 26%]\nr2e_tests/test_1.py::test_tcp_connector_interleave[pyloop] PASSED        [ 26%]\nr2e_tests/test_1.py::test_tcp_connector_family_is_respected[pyloop] PASSED [ 27%]\nr2e_tests/test_1.py::test_tcp_connector_resolve_host[pyloop] PASSED      [ 28%]\nr2e_tests/test_1.py::test_tcp_connector_dns_cache_not_expired[pyloop] PASSED [ 28%]\nr2e_tests/test_1.py::test_tcp_connector_dns_cache_forever[pyloop] PASSED [ 29%]\nr2e_tests/test_1.py::test_tcp_connector_use_dns_cache_disabled[pyloop] PASSED [ 30%]\nr2e_tests/test_1.py::test_tcp_connector_dns_throttle_requests[pyloop] PASSED [ 30%]\nr2e_tests/test_1.py::test_tcp_connector_dns_throttle_requests_exception_spread[pyloop] PASSED [ 31%]\nr2e_tests/test_1.py::test_tcp_connector_dns_throttle_requests_cancelled_when_close[pyloop] PASSED [ 32%]\nr2e_tests/test_1.py::test_tcp_connector_cancel_dns_error_captured[pyloop] PASSED [ 32%]\nr2e_tests/test_1.py::test_tcp_connector_dns_tracing[pyloop] PASSED       [ 33%]\nr2e_tests/test_1.py::test_tcp_connector_dns_tracing_cache_disabled[pyloop] PASSED [ 34%]\nr2e_tests/test_1.py::test_tcp_connector_dns_tracing_throttle_requests[pyloop] PASSED [ 34%]\nr2e_tests/test_1.py::test_dns_error[pyloop] PASSED                       [ 35%]\nr2e_tests/test_1.py::test_get_pop_empty_conns[pyloop] PASSED             [ 36%]\nr2e_tests/test_1.py::test_release_close_do_not_add_to_pool[pyloop] PASSED [ 36%]\nr2e_tests/test_1.py::test_release_close_do_not_delete_existing_connections PASSED [ 37%]\nr2e_tests/test_1.py::test_release_not_started[pyloop] PASSED             [ 38%]\nr2e_tests/test_1.py::test_release_not_opened[pyloop] PASSED              [ 39%]\nr2e_tests/test_1.py::test_connect[pyloop] PASSED                         [ 39%]\nr2e_tests/test_1.py::test_connect_tracing[pyloop] PASSED                 [ 40%]\nr2e_tests/test_1.py::test_close_during_connect[pyloop] PASSED            [ 41%]\nr2e_tests/test_1.py::test_ctor_cleanup PASSED                            [ 41%]\nr2e_tests/test_1.py::test_cleanup PASSED                                 [ 42%]\nr2e_tests/test_1.py::test_cleanup_close_ssl_transport PASSED             [ 43%]\nr2e_tests/test_1.py::test_cleanup2 PASSED                                [ 43%]\nr2e_tests/test_1.py::test_cleanup3 PASSED                                [ 44%]\nr2e_tests/test_1.py::test_cleanup_closed[pyloop] PASSED                  [ 45%]\nr2e_tests/test_1.py::test_cleanup_closed_disabled[pyloop] PASSED         [ 45%]\nr2e_tests/test_1.py::test_tcp_connector_ctor PASSED                      [ 46%]\nr2e_tests/test_1.py::test_tcp_connector_allowed_protocols[pyloop] PASSED [ 47%]\nr2e_tests/test_1.py::test_invalid_ssl_param PASSED                       [ 47%]\nr2e_tests/test_1.py::test_tcp_connector_ctor_fingerprint_valid[pyloop] PASSED [ 48%]\nr2e_tests/test_1.py::test_insecure_fingerprint_md5[pyloop] PASSED        [ 49%]\nr2e_tests/test_1.py::test_insecure_fingerprint_sha1[pyloop] PASSED       [ 50%]\nr2e_tests/test_1.py::test_tcp_connector_clear_dns_cache[pyloop] PASSED   [ 50%]\nr2e_tests/test_1.py::test_tcp_connector_clear_dns_cache_bad_args[pyloop] PASSED [ 51%]\nr2e_tests/test_1.py::test_dont_recreate_ssl_context PASSED               [ 52%]\nr2e_tests/test_1.py::test_dont_recreate_ssl_context2 PASSED              [ 52%]\nr2e_tests/test_1.py::test___get_ssl_context1 PASSED                      [ 53%]\nr2e_tests/test_1.py::test___get_ssl_context2[pyloop] PASSED              [ 54%]\nr2e_tests/test_1.py::test___get_ssl_context3[pyloop] PASSED              [ 54%]\nr2e_tests/test_1.py::test___get_ssl_context4[pyloop] PASSED              [ 55%]\nr2e_tests/test_1.py::test___get_ssl_context5[pyloop] PASSED              [ 56%]\nr2e_tests/test_1.py::test___get_ssl_context6 PASSED                      [ 56%]\nr2e_tests/test_1.py::test_ssl_context_once PASSED                        [ 57%]\nr2e_tests/test_1.py::test_ssl_context_creation_raises[OSError] PASSED    [ 58%]\nr2e_tests/test_1.py::test_ssl_context_creation_raises[SSLError] PASSED   [ 58%]\nr2e_tests/test_1.py::test_ssl_context_creation_raises[CancelledError] PASSED [ 59%]\nr2e_tests/test_1.py::test_close_twice[pyloop] PASSED                     [ 60%]\nr2e_tests/test_1.py::test_close_cancels_cleanup_handle[pyloop] PASSED    [ 60%]\nr2e_tests/test_1.py::test_close_cancels_resolve_host[pyloop] FAILED      [ 61%]\nr2e_tests/test_1.py::test_close_abort_closed_transports[pyloop] PASSED   [ 62%]\nr2e_tests/test_1.py::test_close_cancels_cleanup_closed_handle[pyloop] PASSED [ 63%]\nr2e_tests/test_1.py::test_ctor_with_default_loop[pyloop] PASSED          [ 63%]\nr2e_tests/test_1.py::test_base_connector_allows_high_level_protocols[pyloop] PASSED [ 64%]\nr2e_tests/test_1.py::test_connect_with_limit[pyloop] PASSED              [ 65%]\nr2e_tests/test_1.py::test_connect_queued_operation_tracing[pyloop] PASSED [ 65%]\nr2e_tests/test_1.py::test_connect_reuseconn_tracing[pyloop] PASSED       [ 66%]\nr2e_tests/test_1.py::test_connect_with_limit_and_limit_per_host[pyloop] PASSED [ 67%]\nr2e_tests/test_1.py::test_connect_with_no_limit_and_limit_per_host[pyloop] PASSED [ 67%]\nr2e_tests/test_1.py::test_connect_with_no_limits[pyloop] PASSED          [ 68%]\nr2e_tests/test_1.py::test_connect_with_limit_cancelled[pyloop] PASSED    [ 69%]\nr2e_tests/test_1.py::test_connect_with_capacity_release_waiters[pyloop] PASSED [ 69%]\nr2e_tests/test_1.py::test_connect_with_limit_concurrent[pyloop] PASSED   [ 70%]\nr2e_tests/test_1.py::test_connect_waiters_cleanup[pyloop] PASSED         [ 71%]\nr2e_tests/test_1.py::test_connect_waiters_cleanup_key_error[pyloop] PASSED [ 71%]\nr2e_tests/test_1.py::test_close_with_acquired_connection[pyloop] PASSED  [ 72%]\nr2e_tests/test_1.py::test_default_force_close[pyloop] PASSED             [ 73%]\nr2e_tests/test_1.py::test_limit_property[pyloop] PASSED                  [ 73%]\nr2e_tests/test_1.py::test_limit_per_host_property[pyloop] PASSED         [ 74%]\nr2e_tests/test_1.py::test_limit_property_default[pyloop] PASSED          [ 75%]\nr2e_tests/test_1.py::test_limit_per_host_property_default[pyloop] PASSED [ 76%]\nr2e_tests/test_1.py::test_force_close_and_explicit_keep_alive[pyloop] PASSED [ 76%]\nr2e_tests/test_1.py::test_error_on_connection[pyloop] PASSED             [ 77%]\nr2e_tests/test_1.py::test_cancelled_waiter[pyloop] PASSED                [ 78%]\nr2e_tests/test_1.py::test_error_on_connection_with_cancelled_waiter[pyloop] PASSED [ 78%]\nr2e_tests/test_1.py::test_tcp_connector[pyloop] PASSED                   [ 79%]\nr2e_tests/test_1.py::test_unix_connector_not_found[pyloop] PASSED        [ 80%]\nr2e_tests/test_1.py::test_unix_connector_permission[pyloop] PASSED       [ 80%]\nr2e_tests/test_1.py::test_named_pipe_connector_wrong_loop SKIPPED (P...) [ 81%]\nr2e_tests/test_1.py::test_named_pipe_connector_not_found SKIPPED (Pr...) [ 82%]\nr2e_tests/test_1.py::test_named_pipe_connector_permission SKIPPED (P...) [ 82%]\nr2e_tests/test_1.py::test_default_use_dns_cache PASSED                   [ 83%]\nr2e_tests/test_1.py::test_ssl_none PASSED                                [ 84%]\nr2e_tests/test_1.py::test_resolver_not_called_with_address_is_ip[pyloop] PASSED [ 84%]\nr2e_tests/test_1.py::test_tcp_connector_raise_connector_ssl_error[pyloop] PASSED [ 85%]\nr2e_tests/test_1.py::test_tcp_connector_do_not_raise_connector_ssl_error[pyloop-ip address] PASSED [ 86%]\nr2e_tests/test_1.py::test_tcp_connector_do_not_raise_connector_ssl_error[pyloop-domain name] PASSED [ 86%]\nr2e_tests/test_1.py::test_tcp_connector_do_not_raise_connector_ssl_error[pyloop-fully-qualified domain name] PASSED [ 87%]\nr2e_tests/test_1.py::test_tcp_connector_do_not_raise_connector_ssl_error[pyloop-fully-qualified domain name with multiple trailing dots] PASSED [ 88%]\nr2e_tests/test_1.py::test_tcp_connector_do_not_raise_connector_ssl_error[pyloop-idna fully-qualified domain name] PASSED [ 89%]\nr2e_tests/test_1.py::test_tcp_connector_uses_provided_local_addr[pyloop] PASSED [ 89%]\nr2e_tests/test_1.py::test_unix_connector[pyloop] PASSED                  [ 90%]\nr2e_tests/test_1.py::test_named_pipe_connector SKIPPED (Proactor Eve...) [ 91%]\nr2e_tests/test_1.py::TestDNSCacheTable::test_next_addrs_basic PASSED     [ 91%]\nr2e_tests/test_1.py::TestDNSCacheTable::test_remove PASSED               [ 92%]\nr2e_tests/test_1.py::TestDNSCacheTable::test_clear PASSED                [ 93%]\nr2e_tests/test_1.py::TestDNSCacheTable::test_not_expired_ttl_None PASSED [ 93%]\nr2e_tests/test_1.py::TestDNSCacheTable::test_not_expired_ttl PASSED      [ 94%]\nr2e_tests/test_1.py::TestDNSCacheTable::test_expired_ttl PASSED          [ 95%]\nr2e_tests/test_1.py::TestDNSCacheTable::test_never_expire PASSED         [ 95%]\nr2e_tests/test_1.py::TestDNSCacheTable::test_always_expire PASSED        [ 96%]\nr2e_tests/test_1.py::TestDNSCacheTable::test_next_addrs PASSED           [ 97%]\nr2e_tests/test_1.py::TestDNSCacheTable::test_next_addrs_single PASSED    [ 97%]\nr2e_tests/test_1.py::test_connector_cache_trace_race PASSED              [ 98%]\nr2e_tests/test_1.py::test_connector_throttle_trace_race[pyloop] PASSED   [ 99%]\nr2e_tests/test_1.py::test_connector_does_not_remove_needed_waiters[pyloop] PASSED [100%]\n\n=================================== FAILURES ===================================\n___________________ test_close_cancels_resolve_host[pyloop] ____________________\n\nloop = <_UnixSelectorEventLoop running=False closed=False debug=False>\n\n    async def test_close_cancels_resolve_host(loop: asyncio.AbstractEventLoop) -> None:\n        cancelled = False\n    \n        async def delay_resolve_host(*args: object) -> None:\n            \"\"\"Delay _resolve_host() task in order to test cancellation.\"\"\"\n            nonlocal cancelled\n            try:\n                await asyncio.sleep(10)\n            except asyncio.CancelledError:\n                cancelled = True\n                raise\n    \n        conn = aiohttp.TCPConnector()\n        req = ClientRequest(\n            \"GET\", URL(\"http://localhost:80\"), loop=loop, response_class=mock.Mock()\n        )\n        with mock.patch.object(conn, \"_resolve_host_with_throttle\", delay_resolve_host):\n            t = asyncio.create_task(conn.connect(req, [], ClientTimeout()))\n            # Let it create the internal task\n            await asyncio.sleep(0)\n            # Let that task start running\n            await asyncio.sleep(0)\n    \n            # We now have a task being tracked and can ensure that .close() cancels it.\n>           assert len(conn._resolve_host_tasks) == 1\nE           AttributeError: 'TCPConnector' object has no attribute '_resolve_host_tasks'\n\ncancelled  = False\nconn       = <aiohttp.connector.TCPConnector object at 0x716963a0edc0>\ndelay_resolve_host = <function test_close_cancels_resolve_host.<locals>.delay_resolve_host at 0x716963d0ddc0>\nloop       = <_UnixSelectorEventLoop running=False closed=False debug=False>\nreq        = <aiohttp.client_reqrep.ClientRequest object at 0x716963a0e520>\nt          = <Task pending name='Task-121' coro=<BaseConnector.connect() running at /home/gcpuser/buckets/local_repoeval_bucket/rep...ython-3.9.21-linux-x86_64-gnu/lib/python3.9/asyncio/tasks.py:907, <TaskWakeupMethWrapper object at 0x716963a0e2e0>()]>>\n\nr2e_tests/test_1.py:1694: AttributeError\n==================================== PASSES ====================================\n---------------------------- Captured log teardown -----------------------------\nERROR    asyncio:base_events.py:1753 Task was destroyed but it is pending!\ntask: <Task pending name='Task-54' coro=<TCPConnector._resolve_host() running at /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_ea316336f0b247bb85fd7ee0e4e41f5eac682228/aiohttp/connector.py:911> wait_for=<Future finished result=['127.0.0.1']>>\nERROR    asyncio:base_events.py:1753 Task was destroyed but it is pending!\ntask: <Task pending name='Task-55' coro=<TCPConnector._resolve_host() done, defined at /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_ea316336f0b247bb85fd7ee0e4e41f5eac682228/aiohttp/connector.py:856> wait_for=<Future pending cb=[shield.<locals>._outer_done_callback() at /home/gcpuser/.local/share/uv/python/cpython-3.9.21-linux-x86_64-gnu/lib/python3.9/asyncio/tasks.py:907, <TaskWakeupMethWrapper object at 0x7169636c5280>()]>>\n---------------------------- Captured log teardown -----------------------------\nERROR    asyncio:base_events.py:1753 Task was destroyed but it is pending!\ntask: <Task pending name='Task-76' coro=<TCPConnector._resolve_host() running at /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_ea316336f0b247bb85fd7ee0e4e41f5eac682228/aiohttp/connector.py:911> wait_for=<Future finished result=['127.0.0.1']>>\nERROR    asyncio:base_events.py:1753 Task was destroyed but it is pending!\ntask: <Task pending name='Task-77' coro=<TCPConnector._resolve_host() done, defined at /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_ea316336f0b247bb85fd7ee0e4e41f5eac682228/aiohttp/connector.py:856> wait_for=<Future pending cb=[shield.<locals>._outer_done_callback() at /home/gcpuser/.local/share/uv/python/cpython-3.9.21-linux-x86_64-gnu/lib/python3.9/asyncio/tasks.py:907, <TaskWakeupMethWrapper object at 0x7169636c5100>()]>>\n__________________ test_ssl_context_creation_raises[OSError] ___________________\n------------------------------ Captured log call -------------------------------\nERROR    asyncio:base_events.py:1753 Future exception was never retrieved\nfuture: <Future finished exception=OSError()>\nTraceback (most recent call last):\n  File \"/home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_ea316336f0b247bb85fd7ee0e4e41f5eac682228/aiohttp/connector.py\", line 1033, in _make_or_get_ssl_context\n    return await self._made_ssl_context[verified]\nKeyError: True\n\nDuring handling of the above exception, another exception occurred:\n\nTraceback (most recent call last):\n  File \"/home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_ea316336f0b247bb85fd7ee0e4e41f5eac682228/r2e_tests/test_1.py\", line 1641, in test_ssl_context_creation_raises\n    await conn._make_or_get_ssl_context(True)\n  File \"/home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_ea316336f0b247bb85fd7ee0e4e41f5eac682228/aiohttp/connector.py\", line 1039, in _make_or_get_ssl_context\n    result = await loop.run_in_executor(\n  File \"/home/gcpuser/.local/share/uv/python/cpython-3.9.21-linux-x86_64-gnu/lib/python3.9/concurrent/futures/thread.py\", line 58, in run\n    result = self.fn(*self.args, **self.kwargs)\n  File \"/home/gcpuser/.local/share/uv/python/cpython-3.9.21-linux-x86_64-gnu/lib/python3.9/unittest/mock.py\", line 1092, in __call__\n    return self._mock_call(*args, **kwargs)\n  File \"/home/gcpuser/.local/share/uv/python/cpython-3.9.21-linux-x86_64-gnu/lib/python3.9/unittest/mock.py\", line 1096, in _mock_call\n    return self._execute_mock_call(*args, **kwargs)\n  File \"/home/gcpuser/.local/share/uv/python/cpython-3.9.21-linux-x86_64-gnu/lib/python3.9/unittest/mock.py\", line 1151, in _execute_mock_call\n    raise effect\nOSError\n__________________ test_ssl_context_creation_raises[SSLError] __________________\n------------------------------ Captured log call -------------------------------\nERROR    asyncio:base_events.py:1753 Future exception was never retrieved\nfuture: <Future finished exception=SSLError()>\nTraceback (most recent call last):\n  File \"/home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_ea316336f0b247bb85fd7ee0e4e41f5eac682228/aiohttp/connector.py\", line 1033, in _make_or_get_ssl_context\n    return await self._made_ssl_context[verified]\nKeyError: True\n\nDuring handling of the above exception, another exception occurred:\n\nTraceback (most recent call last):\n  File \"/home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_ea316336f0b247bb85fd7ee0e4e41f5eac682228/r2e_tests/test_1.py\", line 1641, in test_ssl_context_creation_raises\n    await conn._make_or_get_ssl_context(True)\n  File \"/home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_ea316336f0b247bb85fd7ee0e4e41f5eac682228/aiohttp/connector.py\", line 1039, in _make_or_get_ssl_context\n    result = await loop.run_in_executor(\n  File \"/home/gcpuser/.local/share/uv/python/cpython-3.9.21-linux-x86_64-gnu/lib/python3.9/concurrent/futures/thread.py\", line 58, in run\n    result = self.fn(*self.args, **self.kwargs)\n  File \"/home/gcpuser/.local/share/uv/python/cpython-3.9.21-linux-x86_64-gnu/lib/python3.9/unittest/mock.py\", line 1092, in __call__\n    return self._mock_call(*args, **kwargs)\n  File \"/home/gcpuser/.local/share/uv/python/cpython-3.9.21-linux-x86_64-gnu/lib/python3.9/unittest/mock.py\", line 1096, in _mock_call\n    return self._execute_mock_call(*args, **kwargs)\n  File \"/home/gcpuser/.local/share/uv/python/cpython-3.9.21-linux-x86_64-gnu/lib/python3.9/unittest/mock.py\", line 1151, in _execute_mock_call\n    raise effect\nssl.SSLError: ()\n_______________ test_ssl_context_creation_raises[CancelledError] _______________\n------------------------------ Captured log call -------------------------------\nERROR    asyncio:base_events.py:1753 Future exception was never retrieved\nfuture: <Future finished exception=CancelledError()>\nTraceback (most recent call last):\n  File \"/home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_ea316336f0b247bb85fd7ee0e4e41f5eac682228/aiohttp/connector.py\", line 1033, in _make_or_get_ssl_context\n    return await self._made_ssl_context[verified]\nKeyError: True\n\nDuring handling of the above exception, another exception occurred:\n\nTraceback (most recent call last):\n  File \"/home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_ea316336f0b247bb85fd7ee0e4e41f5eac682228/r2e_tests/test_1.py\", line 1641, in test_ssl_context_creation_raises\n    await conn._make_or_get_ssl_context(True)\n  File \"/home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_ea316336f0b247bb85fd7ee0e4e41f5eac682228/aiohttp/connector.py\", line 1039, in _make_or_get_ssl_context\n    result = await loop.run_in_executor(\n  File \"/home/gcpuser/.local/share/uv/python/cpython-3.9.21-linux-x86_64-gnu/lib/python3.9/concurrent/futures/thread.py\", line 58, in run\n    result = self.fn(*self.args, **self.kwargs)\n  File \"/home/gcpuser/.local/share/uv/python/cpython-3.9.21-linux-x86_64-gnu/lib/python3.9/unittest/mock.py\", line 1092, in __call__\n    return self._mock_call(*args, **kwargs)\n  File \"/home/gcpuser/.local/share/uv/python/cpython-3.9.21-linux-x86_64-gnu/lib/python3.9/unittest/mock.py\", line 1096, in _mock_call\n    return self._execute_mock_call(*args, **kwargs)\n  File \"/home/gcpuser/.local/share/uv/python/cpython-3.9.21-linux-x86_64-gnu/lib/python3.9/unittest/mock.py\", line 1151, in _execute_mock_call\n    raise effect\nasyncio.exceptions.CancelledError\n---------------------------- Captured log teardown -----------------------------\nERROR    asyncio:base_events.py:1753 Task was destroyed but it is pending!\ntask: <Task pending name='Task-121' coro=<BaseConnector.connect() running at /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_ea316336f0b247bb85fd7ee0e4e41f5eac682228/aiohttp/connector.py:564> wait_for=<Future pending cb=[shield.<locals>._outer_done_callback() at /home/gcpuser/.local/share/uv/python/cpython-3.9.21-linux-x86_64-gnu/lib/python3.9/asyncio/tasks.py:907, <TaskWakeupMethWrapper object at 0x716963a0e2e0>()]>>\nERROR    asyncio:base_events.py:1753 Task was destroyed but it is pending!\ntask: <Task pending name='Task-122' coro=<test_close_cancels_resolve_host.<locals>.delay_resolve_host() running at /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_ea316336f0b247bb85fd7ee0e4e41f5eac682228/r2e_tests/test_1.py:1677> wait_for=<Future pending cb=[<TaskWakeupMethWrapper object at 0x716963a0ec10>()]> cb=[shield.<locals>._inner_done_callback() at /home/gcpuser/.local/share/uv/python/cpython-3.9.21-linux-x86_64-gnu/lib/python3.9/asyncio/tasks.py:890]>\n\n---------- coverage: platform linux, python 3.9.21-final-0 -----------\nName                                     Stmts   Miss Branch BrPart  Cover\n--------------------------------------------------------------------------\naiohttp/__init__.py                         27      8      2      1    69%\naiohttp/abc.py                              97      2      0      0    98%\naiohttp/base_protocol.py                    67     36     22      3    38%\naiohttp/client.py                          554    260    202     51    47%\naiohttp/client_exceptions.py               154     50     20      1    60%\naiohttp/client_proto.py                    163     53     56     19    60%\naiohttp/client_reqrep.py                   695    286    300     69    51%\naiohttp/client_ws.py                       264    211     82      1    16%\naiohttp/compression_utils.py                70     36     14      0    40%\naiohttp/connector.py                       769    147    319     19    79%\naiohttp/cookiejar.py                       255    173    118      8    25%\naiohttp/formdata.py                         97     79     46      0    13%\naiohttp/hdrs.py                             90      0      0      0   100%\naiohttp/helpers.py                         501    251    172     20    43%\naiohttp/http.py                             11      0      2      0   100%\naiohttp/http_exceptions.py                  50     20      4      0    56%\naiohttp/http_parser.py                     504    404    208      1    14%\naiohttp/http_websocket.py                  393    287    152      0    20%\naiohttp/http_writer.py                     118     44     50     13    53%\naiohttp/locks.py                            24      1      4      1    93%\naiohttp/log.py                               7      0      0      0   100%\naiohttp/multipart.py                       623    508    266      1    13%\naiohttp/payload.py                         237    113     58      1    44%\naiohttp/payload_streamer.py                 31     11      4      0    69%\naiohttp/pytest_plugin.py                   162     49     42      6    67%\naiohttp/resolver.py                         78     42     26      4    40%\naiohttp/streams.py                         398    250    146     11    29%\naiohttp/tcp_helpers.py                      19      1      6      2    88%\naiohttp/test_utils.py                      315    111     50     13    61%\naiohttp/tracing.py                         191     14     32      0    94%\naiohttp/typedefs.py                         23      0      0      0   100%\naiohttp/web.py                             122     84     52      0    23%\naiohttp/web_app.py                         282    101     74     19    57%\naiohttp/web_exceptions.py                  157     25      8      0    80%\naiohttp/web_fileresponse.py                160    126     52      0    18%\naiohttp/web_log.py                         102     37     20      1    59%\naiohttp/web_middlewares.py                  55     37     20      0    24%\naiohttp/web_protocol.py                    354    130    155     43    55%\naiohttp/web_request.py                     441    251    134      8    35%\naiohttp/web_response.py                    479    258    220     33    36%\naiohttp/web_routedef.py                    100     44     10      0    55%\naiohttp/web_runner.py                      213     65     36     11    65%\naiohttp/web_server.py                       42      5     12      1    85%\naiohttp/web_urldispatcher.py               742    386    161     21    42%\naiohttp/web_ws.py                          382    310    132      1    15%\naiohttp/worker.py                          126    126     30      0     0%\ntests/conftest.py                          130    130     16      0     0%\ntests/test_base_protocol.py                198    198      2      0     0%\ntests/test_circular_imports.py              29     29     13      0     0%\ntests/test_classbasedview.py                39     39      0      0     0%\ntests/test_client_connection.py             94     94      2      0     0%\ntests/test_client_exceptions.py            199    199     14      0     0%\ntests/test_client_fingerprint.py            59     59      0      0     0%\ntests/test_client_functional.py           2507   2507     86      0     0%\ntests/test_client_proto.py                  99     99      0      0     0%\ntests/test_client_request.py               808    808     18      0     0%\ntests/test_client_response.py              466    466      4      0     0%\ntests/test_client_session.py               556    556     29      0     0%\ntests/test_client_ws.py                    487    487      2      0     0%\ntests/test_client_ws_functional.py         788    788     32      0     0%\ntests/test_connector.py                   1676   1676     82      0     0%\ntests/test_cookiejar.py                    350    350     24      0     0%\ntests/test_flowcontrol_streams.py          100    100      0      0     0%\ntests/test_formdata.py                      81     81      6      0     0%\ntests/test_helpers.py                      470    470     24      0     0%\ntests/test_http_exceptions.py              109    109     10      0     0%\ntests/test_http_parser.py                 1088   1088     66      0     0%\ntests/test_http_writer.py                  182    182     10      0     0%\ntests/test_imports.py                       34     34      6      0     0%\ntests/test_locks.py                         39     39      0      0     0%\ntests/test_loop.py                          36     36      0      0     0%\ntests/test_multipart.py                    826    826     32      0     0%\ntests/test_multipart_helpers.py            446    446      0      0     0%\ntests/test_payload.py                       95     95      0      0     0%\ntests/test_proxy.py                        301    301      0      0     0%\ntests/test_proxy_functional.py             459    459     18      0     0%\ntests/test_pytest_plugin.py                 27     27      0      0     0%\ntests/test_resolver.py                     191    191     20      0     0%\ntests/test_route_def.py                    210    210      0      0     0%\ntests/test_run_app.py                      563    563     30      0     0%\ntests/test_streams.py                     1076   1076     38      0     0%\ntests/test_tcp_helpers.py                   52     52      2      0     0%\ntests/test_test_utils.py                   244    244      6      0     0%\ntests/test_tracing.py                       48     48      0      0     0%\ntests/test_urldispatch.py                  851    851     24      0     0%\ntests/test_web_app.py                      454    454      6      0     0%\ntests/test_web_cli.py                       75     75      0      0     0%\ntests/test_web_exceptions.py               176    176     22      0     0%\ntests/test_web_functional.py              1552   1552     34      0     0%\ntests/test_web_log.py                      116    116      2      0     0%\ntests/test_web_middleware.py               266    266     12      0     0%\ntests/test_web_request.py                  490    490      8      0     0%\ntests/test_web_request_handler.py           42     42      0      0     0%\ntests/test_web_response.py                 885    885      6      0     0%\ntests/test_web_runner.py                   151    151      4      0     0%\ntests/test_web_sendfile.py                  84     84      0      0     0%\ntests/test_web_sendfile_functional.py      655    655     18      0     0%\ntests/test_web_server.py                   162    162      0      0     0%\ntests/test_web_urldispatcher.py            517    517     24      0     0%\ntests/test_web_websocket.py                401    401      8      0     0%\ntests/test_web_websocket_functional.py     769    769     28      0     0%\ntests/test_websocket_handshake.py          152    152     12      0     0%\ntests/test_websocket_parser.py             300    300     12      0     0%\ntests/test_websocket_writer.py              95     95      6      0     0%\ntests/test_worker.py                       191    191      2      0     0%\n--------------------------------------------------------------------------\nTOTAL                                    34290  28978   4339    383    16%\n\n============================= slowest 10 durations =============================\n0.06s call     r2e_tests/test_1.py::test_tcp_connector_multiple_hosts_errors[pyloop]\n0.04s call     r2e_tests/test_1.py::test_ssl_context_creation_raises[OSError]\n0.04s call     r2e_tests/test_1.py::test_ssl_context_creation_raises[CancelledError]\n0.04s call     r2e_tests/test_1.py::test_ssl_context_creation_raises[SSLError]\n0.03s call     r2e_tests/test_1.py::test_del_with_scheduled_cleanup[pyloop]\n0.03s setup    r2e_tests/test_1.py::test_close_with_acquired_connection[pyloop]\n0.02s setup    r2e_tests/test_1.py::test_tcp_connector_do_not_raise_connector_ssl_error[pyloop-domain name]\n0.02s setup    r2e_tests/test_1.py::test_tcp_connector_do_not_raise_connector_ssl_error[pyloop-idna fully-qualified domain name]\n0.02s setup    r2e_tests/test_1.py::test_tcp_connector_do_not_raise_connector_ssl_error[pyloop-fully-qualified domain name with multiple trailing dots]\n0.02s setup    r2e_tests/test_1.py::test_tcp_connector_do_not_raise_connector_ssl_error[pyloop-fully-qualified domain name]\n=========================== short test summary info ============================\nPASSED r2e_tests/test_1.py::test_connection_del[pyloop]\nPASSED r2e_tests/test_1.py::test_connection_del_loop_debug[pyloop]\nPASSED r2e_tests/test_1.py::test_connection_del_loop_closed[pyloop]\nPASSED r2e_tests/test_1.py::test_del[pyloop]\nPASSED r2e_tests/test_1.py::test_del_with_closed_loop[pyloop]\nPASSED r2e_tests/test_1.py::test_del_empty_connector[pyloop]\nPASSED r2e_tests/test_1.py::test_create_conn[pyloop]\nPASSED r2e_tests/test_1.py::test_connector_context_manager[pyloop]\nPASSED r2e_tests/test_1.py::test_async_context_manager[pyloop]\nPASSED r2e_tests/test_1.py::test_close[pyloop]\nPASSED r2e_tests/test_1.py::test_get[pyloop]\nPASSED r2e_tests/test_1.py::test_get_unconnected_proto[pyloop]\nPASSED r2e_tests/test_1.py::test_get_unconnected_proto_ssl[pyloop]\nPASSED r2e_tests/test_1.py::test_get_expired[pyloop]\nPASSED r2e_tests/test_1.py::test_get_expired_ssl[pyloop]\nPASSED r2e_tests/test_1.py::test_release_acquired[pyloop]\nPASSED r2e_tests/test_1.py::test_release_acquired_closed[pyloop]\nPASSED r2e_tests/test_1.py::test_release[pyloop]\nPASSED r2e_tests/test_1.py::test_release_ssl_transport[pyloop]\nPASSED r2e_tests/test_1.py::test_release_already_closed[pyloop]\nPASSED r2e_tests/test_1.py::test_release_waiter_no_limit[pyloop]\nPASSED r2e_tests/test_1.py::test_release_waiter_first_available[pyloop]\nPASSED r2e_tests/test_1.py::test_release_waiter_release_first[pyloop]\nPASSED r2e_tests/test_1.py::test_release_waiter_skip_done_waiter[pyloop]\nPASSED r2e_tests/test_1.py::test_release_waiter_per_host[pyloop]\nPASSED r2e_tests/test_1.py::test_release_waiter_no_available[pyloop]\nPASSED r2e_tests/test_1.py::test_release_close[pyloop]\nPASSED r2e_tests/test_1.py::test__drop_acquire_per_host1[pyloop]\nPASSED r2e_tests/test_1.py::test__drop_acquire_per_host2[pyloop]\nPASSED r2e_tests/test_1.py::test__drop_acquire_per_host3[pyloop]\nPASSED r2e_tests/test_1.py::test_tcp_connector_certificate_error[pyloop]\nPASSED r2e_tests/test_1.py::test_tcp_connector_server_hostname_default[pyloop]\nPASSED r2e_tests/test_1.py::test_tcp_connector_server_hostname_override[pyloop]\nPASSED r2e_tests/test_1.py::test_tcp_connector_multiple_hosts_errors[pyloop]\nPASSED r2e_tests/test_1.py::test_tcp_connector_happy_eyeballs[pyloop-0.1]\nPASSED r2e_tests/test_1.py::test_tcp_connector_happy_eyeballs[pyloop-0.25]\nPASSED r2e_tests/test_1.py::test_tcp_connector_happy_eyeballs[pyloop-None]\nPASSED r2e_tests/test_1.py::test_tcp_connector_interleave[pyloop]\nPASSED r2e_tests/test_1.py::test_tcp_connector_family_is_respected[pyloop]\nPASSED r2e_tests/test_1.py::test_tcp_connector_resolve_host[pyloop]\nPASSED r2e_tests/test_1.py::test_tcp_connector_dns_cache_not_expired[pyloop]\nPASSED r2e_tests/test_1.py::test_tcp_connector_dns_cache_forever[pyloop]\nPASSED r2e_tests/test_1.py::test_tcp_connector_use_dns_cache_disabled[pyloop]\nPASSED r2e_tests/test_1.py::test_tcp_connector_dns_throttle_requests[pyloop]\nPASSED r2e_tests/test_1.py::test_tcp_connector_dns_throttle_requests_exception_spread[pyloop]\nPASSED r2e_tests/test_1.py::test_tcp_connector_dns_throttle_requests_cancelled_when_close[pyloop]\nPASSED r2e_tests/test_1.py::test_tcp_connector_cancel_dns_error_captured[pyloop]\nPASSED r2e_tests/test_1.py::test_tcp_connector_dns_tracing[pyloop]\nPASSED r2e_tests/test_1.py::test_tcp_connector_dns_tracing_cache_disabled[pyloop]\nPASSED r2e_tests/test_1.py::test_tcp_connector_dns_tracing_throttle_requests[pyloop]\nPASSED r2e_tests/test_1.py::test_dns_error[pyloop]\nPASSED r2e_tests/test_1.py::test_get_pop_empty_conns[pyloop]\nPASSED r2e_tests/test_1.py::test_release_close_do_not_add_to_pool[pyloop]\nPASSED r2e_tests/test_1.py::test_release_close_do_not_delete_existing_connections\nPASSED r2e_tests/test_1.py::test_release_not_started[pyloop]\nPASSED r2e_tests/test_1.py::test_release_not_opened[pyloop]\nPASSED r2e_tests/test_1.py::test_connect[pyloop]\nPASSED r2e_tests/test_1.py::test_connect_tracing[pyloop]\nPASSED r2e_tests/test_1.py::test_close_during_connect[pyloop]\nPASSED r2e_tests/test_1.py::test_ctor_cleanup\nPASSED r2e_tests/test_1.py::test_cleanup\nPASSED r2e_tests/test_1.py::test_cleanup_close_ssl_transport\nPASSED r2e_tests/test_1.py::test_cleanup2\nPASSED r2e_tests/test_1.py::test_cleanup3\nPASSED r2e_tests/test_1.py::test_cleanup_closed[pyloop]\nPASSED r2e_tests/test_1.py::test_cleanup_closed_disabled[pyloop]\nPASSED r2e_tests/test_1.py::test_tcp_connector_ctor\nPASSED r2e_tests/test_1.py::test_tcp_connector_allowed_protocols[pyloop]\nPASSED r2e_tests/test_1.py::test_invalid_ssl_param\nPASSED r2e_tests/test_1.py::test_tcp_connector_ctor_fingerprint_valid[pyloop]\nPASSED r2e_tests/test_1.py::test_insecure_fingerprint_md5[pyloop]\nPASSED r2e_tests/test_1.py::test_insecure_fingerprint_sha1[pyloop]\nPASSED r2e_tests/test_1.py::test_tcp_connector_clear_dns_cache[pyloop]\nPASSED r2e_tests/test_1.py::test_tcp_connector_clear_dns_cache_bad_args[pyloop]\nPASSED r2e_tests/test_1.py::test_dont_recreate_ssl_context\nPASSED r2e_tests/test_1.py::test_dont_recreate_ssl_context2\nPASSED r2e_tests/test_1.py::test___get_ssl_context1\nPASSED r2e_tests/test_1.py::test___get_ssl_context2[pyloop]\nPASSED r2e_tests/test_1.py::test___get_ssl_context3[pyloop]\nPASSED r2e_tests/test_1.py::test___get_ssl_context4[pyloop]\nPASSED r2e_tests/test_1.py::test___get_ssl_context5[pyloop]\nPASSED r2e_tests/test_1.py::test___get_ssl_context6\nPASSED r2e_tests/test_1.py::test_ssl_context_once\nPASSED r2e_tests/test_1.py::test_ssl_context_creation_raises[OSError]\nPASSED r2e_tests/test_1.py::test_ssl_context_creation_raises[SSLError]\nPASSED r2e_tests/test_1.py::test_ssl_context_creation_raises[CancelledError]\nPASSED r2e_tests/test_1.py::test_close_twice[pyloop]\nPASSED r2e_tests/test_1.py::test_close_cancels_cleanup_handle[pyloop]\nPASSED r2e_tests/test_1.py::test_close_abort_closed_transports[pyloop]\nPASSED r2e_tests/test_1.py::test_close_cancels_cleanup_closed_handle[pyloop]\nPASSED r2e_tests/test_1.py::test_ctor_with_default_loop[pyloop]\nPASSED r2e_tests/test_1.py::test_base_connector_allows_high_level_protocols[pyloop]\nPASSED r2e_tests/test_1.py::test_connect_with_limit[pyloop]\nPASSED r2e_tests/test_1.py::test_connect_queued_operation_tracing[pyloop]\nPASSED r2e_tests/test_1.py::test_connect_reuseconn_tracing[pyloop]\nPASSED r2e_tests/test_1.py::test_connect_with_limit_and_limit_per_host[pyloop]\nPASSED r2e_tests/test_1.py::test_connect_with_no_limit_and_limit_per_host[pyloop]\nPASSED r2e_tests/test_1.py::test_connect_with_no_limits[pyloop]\nPASSED r2e_tests/test_1.py::test_connect_with_limit_cancelled[pyloop]\nPASSED r2e_tests/test_1.py::test_connect_with_capacity_release_waiters[pyloop]\nPASSED r2e_tests/test_1.py::test_connect_with_limit_concurrent[pyloop]\nPASSED r2e_tests/test_1.py::test_connect_waiters_cleanup[pyloop]\nPASSED r2e_tests/test_1.py::test_connect_waiters_cleanup_key_error[pyloop]\nPASSED r2e_tests/test_1.py::test_close_with_acquired_connection[pyloop]\nPASSED r2e_tests/test_1.py::test_default_force_close[pyloop]\nPASSED r2e_tests/test_1.py::test_limit_property[pyloop]\nPASSED r2e_tests/test_1.py::test_limit_per_host_property[pyloop]\nPASSED r2e_tests/test_1.py::test_limit_property_default[pyloop]\nPASSED r2e_tests/test_1.py::test_limit_per_host_property_default[pyloop]\nPASSED r2e_tests/test_1.py::test_force_close_and_explicit_keep_alive[pyloop]\nPASSED r2e_tests/test_1.py::test_error_on_connection[pyloop]\nPASSED r2e_tests/test_1.py::test_cancelled_waiter[pyloop]\nPASSED r2e_tests/test_1.py::test_error_on_connection_with_cancelled_waiter[pyloop]\nPASSED r2e_tests/test_1.py::test_tcp_connector[pyloop]\nPASSED r2e_tests/test_1.py::test_unix_connector_not_found[pyloop]\nPASSED r2e_tests/test_1.py::test_unix_connector_permission[pyloop]\nPASSED r2e_tests/test_1.py::test_default_use_dns_cache\nPASSED r2e_tests/test_1.py::test_ssl_none\nPASSED r2e_tests/test_1.py::test_resolver_not_called_with_address_is_ip[pyloop]\nPASSED r2e_tests/test_1.py::test_tcp_connector_raise_connector_ssl_error[pyloop]\nPASSED r2e_tests/test_1.py::test_tcp_connector_do_not_raise_connector_ssl_error[pyloop-ip address]\nPASSED r2e_tests/test_1.py::test_tcp_connector_do_not_raise_connector_ssl_error[pyloop-domain name]\nPASSED r2e_tests/test_1.py::test_tcp_connector_do_not_raise_connector_ssl_error[pyloop-fully-qualified domain name]\nPASSED r2e_tests/test_1.py::test_tcp_connector_do_not_raise_connector_ssl_error[pyloop-fully-qualified domain name with multiple trailing dots]\nPASSED r2e_tests/test_1.py::test_tcp_connector_do_not_raise_connector_ssl_error[pyloop-idna fully-qualified domain name]\nPASSED r2e_tests/test_1.py::test_tcp_connector_uses_provided_local_addr[pyloop]\nPASSED r2e_tests/test_1.py::test_unix_connector[pyloop]\nPASSED r2e_tests/test_1.py::TestDNSCacheTable::test_next_addrs_basic\nPASSED r2e_tests/test_1.py::TestDNSCacheTable::test_remove\nPASSED r2e_tests/test_1.py::TestDNSCacheTable::test_clear\nPASSED r2e_tests/test_1.py::TestDNSCacheTable::test_not_expired_ttl_None\nPASSED r2e_tests/test_1.py::TestDNSCacheTable::test_not_expired_ttl\nPASSED r2e_tests/test_1.py::TestDNSCacheTable::test_expired_ttl\nPASSED r2e_tests/test_1.py::TestDNSCacheTable::test_never_expire\nPASSED r2e_tests/test_1.py::TestDNSCacheTable::test_always_expire\nPASSED r2e_tests/test_1.py::TestDNSCacheTable::test_next_addrs\nPASSED r2e_tests/test_1.py::TestDNSCacheTable::test_next_addrs_single\nPASSED r2e_tests/test_1.py::test_connector_cache_trace_race\nPASSED r2e_tests/test_1.py::test_connector_throttle_trace_race[pyloop]\nPASSED r2e_tests/test_1.py::test_connector_does_not_remove_needed_waiters[pyloop]\nSKIPPED [1] r2e_tests/test_1.py:2321: Proactor Event loop present only in Windows\nSKIPPED [1] r2e_tests/test_1.py:2329: Proactor Event loop present only in Windows\nSKIPPED [1] r2e_tests/test_1.py:2340: Proactor Event loop present only in Windows\nSKIPPED [1] r2e_tests/test_1.py:2532: Proactor Event loop present only in Windows\nXFAIL r2e_tests/test_1.py::test_del_with_scheduled_cleanup[pyloop]\nFAILED r2e_tests/test_1.py::test_close_cancels_resolve_host[pyloop] - Attribu...\n============= 1 failed, 140 passed, 4 skipped, 1 xfailed in 7.72s ==============\n",
    "old_commit_res_stderr": "/home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_ea316336f0b247bb85fd7ee0e4e41f5eac682228/.venv/lib/python3.9/site-packages/pytest_asyncio/plugin.py:207: PytestDeprecationWarning: The configuration option \"asyncio_default_fixture_loop_scope\" is unset.\nThe event loop scope for asynchronous fixtures will default to the fixture caching scope. Future versions of pytest-asyncio will default the loop scope for asynchronous fixtures to function scope. Set the default fixture loop scope explicitly in order to avoid unexpected behavior in the future. Valid fixture loop scopes are: \"function\", \"class\", \"module\", \"package\", \"session\"\n\n  warnings.warn(PytestDeprecationWarning(_DEFAULT_FIXTURE_LOOP_SCOPE_UNSET))\n"
}
CHANGES/8967.bugfix.rst aiohttp/connector.py tests/test_connector.py
We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
[ISSUE]
**Title:** Closing TCPConnector does not cancel pending resolve_host tasks, causing pending Task errors

**Description:**
When closing an `aiohttp.TCPConnector`, any ongoing DNS resolution tasks are not properly canceled. This leads to warnings such as "Task was destroyed but it is pending" because the connector does not track and cancel these tasks as expected.

**Example Code:**

```python
async def simulate_connector_close():
    cancelled = False

    async def delay_resolve_host(*args):
        try:
            await asyncio.sleep(10)
        except asyncio.CancelledError:
            cancelled = True
            raise

    conn = aiohttp.TCPConnector()
    req = ClientRequest('GET', URL('http://localhost:80'), loop=asyncio.get_event_loop(), response_class=mock.Mock())
    
    with mock.patch.object(conn, '_resolve_host_with_throttle', delay_resolve_host):
        asyncio.create_task(conn.connect(req, [], ClientTimeout()))
        await asyncio.sleep(0)  # Allow task to start
        await conn.close()
        # At this point, the resolve_host task should be cancelled
```

**Expected Behavior:**
Closing the `TCPConnector` should cancel all ongoing `resolve_host` tasks, ensuring that no tasks remain pending and no related warnings are emitted.

**Actual Behavior:**
Closing the connector does not cancel the pending `resolve_host` tasks, resulting in warnings about pending tasks being destroyed.

[/ISSUE]
--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.

--- BEGIN FILE ---
```
### aiohttp/connector.py
import asyncio
import functools
import random
import socket
import sys
import traceback
import warnings
from collections import defaultdict, deque
from contextlib import suppress
from http import HTTPStatus
from http.cookies import SimpleCookie
from itertools import cycle, islice
from time import monotonic
from types import TracebackType
from typing import (
    TYPE_CHECKING,
    Any,
    Awaitable,
    Callable,
    DefaultDict,
    Dict,
    Iterator,
    List,
    Literal,
    Optional,
    Sequence,
    Set,
    Tuple,
    Type,
    Union,
    cast,
)

import aiohappyeyeballs
import attr

from . import hdrs, helpers
from .abc import AbstractResolver, ResolveResult
from .client_exceptions import (
    ClientConnectionError,
    ClientConnectorCertificateError,
    ClientConnectorError,
    ClientConnectorSSLError,
    ClientHttpProxyError,
    ClientProxyConnectionError,
    ServerFingerprintMismatch,
    UnixClientConnectorError,
    cert_errors,
    ssl_errors,
)
from .client_proto import ResponseHandler
from .client_reqrep import ClientRequest, Fingerprint, _merge_ssl_params
from .helpers import (
    ceil_timeout,
    is_ip_address,
    noop,
    sentinel,
    set_exception,
    set_result,
)
from .locks import EventResultOrError
from .resolver import DefaultResolver

try:
    import ssl

    SSLContext = ssl.SSLContext
except ImportError:  # pragma: no cover
    ssl = None  # type: ignore[assignment]
    SSLContext = object  # type: ignore[misc,assignment]


EMPTY_SCHEMA_SET = frozenset({""})
HTTP_SCHEMA_SET = frozenset({"http", "https"})
WS_SCHEMA_SET = frozenset({"ws", "wss"})

HTTP_AND_EMPTY_SCHEMA_SET = HTTP_SCHEMA_SET | EMPTY_SCHEMA_SET
HIGH_LEVEL_SCHEMA_SET = HTTP_AND_EMPTY_SCHEMA_SET | WS_SCHEMA_SET


__all__ = ("BaseConnector", "TCPConnector", "UnixConnector", "NamedPipeConnector")


if TYPE_CHECKING:
    from .client import ClientTimeout
    from .client_reqrep import ConnectionKey
    from .tracing import Trace


class _DeprecationWaiter:
    __slots__ = ("_awaitable", "_awaited")

    def __init__(self, awaitable: Awaitable[Any]) -> None:
        self._awaitable = awaitable
        self._awaited = False

    def __await__(self) -> Any:
        self._awaited = True
        return self._awaitable.__await__()

    def __del__(self) -> None:
        if not self._awaited:
            warnings.warn(
                "Connector.close() is a coroutine, "
                "please use await connector.close()",
                DeprecationWarning,
            )


class Connection:

    _source_traceback = None
    _transport = None

    def __init__(
        self,
        connector: "BaseConnector",
        key: "ConnectionKey",
        protocol: ResponseHandler,
        loop: asyncio.AbstractEventLoop,
    ) -> None:
        self._key = key
        self._connector = connector
        self._loop = loop
        self._protocol: Optional[ResponseHandler] = protocol
        self._callbacks: List[Callable[[], None]] = []

        if loop.get_debug():
            self._source_traceback = traceback.extract_stack(sys._getframe(1))

    def __repr__(self) -> str:
        return f"Connection<{self._key}>"

    def __del__(self, _warnings: Any = warnings) -> None:
        if self._protocol is not None:
            kwargs = {"source": self}
            _warnings.warn(f"Unclosed connection {self!r}", ResourceWarning, **kwargs)
            if self._loop.is_closed():
                return

            self._connector._release(self._key, self._protocol, should_close=True)

            context = {"client_connection": self, "message": "Unclosed connection"}
            if self._source_traceback is not None:
                context["source_traceback"] = self._source_traceback
            self._loop.call_exception_handler(context)

    def __bool__(self) -> Literal[True]:
        """Force subclasses to not be falsy, to make checks simpler."""
        return True

    @property
    def loop(self) -> asyncio.AbstractEventLoop:
        warnings.warn(
            "connector.loop property is deprecated", DeprecationWarning, stacklevel=2
        )
        return self._loop

    @property
    def transport(self) -> Optional[asyncio.Transport]:
        if self._protocol is None:
            return None
        return self._protocol.transport

    @property
    def protocol(self) -> Optional[ResponseHandler]:
        return self._protocol

    def add_callback(self, callback: Callable[[], None]) -> None:
        if callback is not None:
            self._callbacks.append(callback)

    def _notify_release(self) -> None:
        callbacks, self._callbacks = self._callbacks[:], []

        for cb in callbacks:
            with suppress(Exception):
                cb()

    def close(self) -> None:
        self._notify_release()

        if self._protocol is not None:
            self._connector._release(self._key, self._protocol, should_close=True)
            self._protocol = None

    def release(self) -> None:
        self._notify_release()

        if self._protocol is not None:
            self._connector._release(
                self._key, self._protocol, should_close=self._protocol.should_close
            )
            self._protocol = None

    @property
    def closed(self) -> bool:
        return self._protocol is None or not self._protocol.is_connected()


class _TransportPlaceholder:
    """placeholder for BaseConnector.connect function"""

    def close(self) -> None:
        pass


class BaseConnector:
    """Base connector class.

    keepalive_timeout - (optional) Keep-alive timeout.
    force_close - Set to True to force close and do reconnect
        after each request (and between redirects).
    limit - The total number of simultaneous connections.
    limit_per_host - Number of simultaneous connections to one host.
    enable_cleanup_closed - Enables clean-up closed ssl transports.
                            Disabled by default.
    timeout_ceil_threshold - Trigger ceiling of timeout values when
                             it's above timeout_ceil_threshold.
    loop - Optional event loop.
    """

    _closed = True  # prevent AttributeError in __del__ if ctor was failed
    _source_traceback = None

    # abort transport after 2 seconds (cleanup broken connections)
    _cleanup_closed_period = 2.0

    allowed_protocol_schema_set = HIGH_LEVEL_SCHEMA_SET

    def __init__(
        self,
        *,
        keepalive_timeout: Union[object, None, float] = sentinel,
        force_close: bool = False,
        limit: int = 100,
        limit_per_host: int = 0,
        enable_cleanup_closed: bool = False,
        loop: Optional[asyncio.AbstractEventLoop] = None,
        timeout_ceil_threshold: float = 5,
    ) -> None:

        if force_close:
            if keepalive_timeout is not None and keepalive_timeout is not sentinel:
                raise ValueError(
                    "keepalive_timeout cannot " "be set if force_close is True"
                )
        else:
            if keepalive_timeout is sentinel:
                keepalive_timeout = 15.0

        loop = loop or asyncio.get_running_loop()
        self._timeout_ceil_threshold = timeout_ceil_threshold

        self._closed = False
        if loop.get_debug():
            self._source_traceback = traceback.extract_stack(sys._getframe(1))

        self._conns: Dict[ConnectionKey, List[Tuple[ResponseHandler, float]]] = {}
        self._limit = limit
        self._limit_per_host = limit_per_host
        self._acquired: Set[ResponseHandler] = set()
        self._acquired_per_host: DefaultDict[ConnectionKey, Set[ResponseHandler]] = (
            defaultdict(set)
        )
        self._keepalive_timeout = cast(float, keepalive_timeout)
        self._force_close = force_close

        # {host_key: FIFO list of waiters}
        self._waiters = defaultdict(deque)  # type: ignore[var-annotated]

        self._loop = loop
        self._factory = functools.partial(ResponseHandler, loop=loop)

        self.cookies = SimpleCookie()

        # start keep-alive connection cleanup task
        self._cleanup_handle: Optional[asyncio.TimerHandle] = None

        # start cleanup closed transports task
        self._cleanup_closed_handle: Optional[asyncio.TimerHandle] = None
        self._cleanup_closed_disabled = not enable_cleanup_closed
        self._cleanup_closed_transports: List[Optional[asyncio.Transport]] = []
        self._cleanup_closed()

    def __del__(self, _warnings: Any = warnings) -> None:
        if self._closed:
            return
        if not self._conns:
            return

        conns = [repr(c) for c in self._conns.values()]

        self._close()

        kwargs = {"source": self}
        _warnings.warn(f"Unclosed connector {self!r}", ResourceWarning, **kwargs)
        context = {
            "connector": self,
            "connections": conns,
            "message": "Unclosed connector",
        }
        if self._source_traceback is not None:
            context["source_traceback"] = self._source_traceback
        self._loop.call_exception_handler(context)

    def __enter__(self) -> "BaseConnector":
        warnings.warn(
            '"with Connector():" is deprecated, '
            'use "async with Connector():" instead',
            DeprecationWarning,
        )
        return self

    def __exit__(self, *exc: Any) -> None:
        self._close()

    async def __aenter__(self) -> "BaseConnector":
        return self

    async def __aexit__(
        self,
        exc_type: Optional[Type[BaseException]] = None,
        exc_value: Optional[BaseException] = None,
        exc_traceback: Optional[TracebackType] = None,
    ) -> None:
        await self.close()

    @property
    def force_close(self) -> bool:
        """Ultimately close connection on releasing if True."""
        return self._force_close

    @property
    def limit(self) -> int:
        """The total number for simultaneous connections.

        If limit is 0 the connector has no limit.
        The default limit size is 100.
        """
        return self._limit

    @property
    def limit_per_host(self) -> int:
        """The limit for simultaneous connections to the same endpoint.

        Endpoints are the same if they are have equal
        (host, port, is_ssl) triple.
        """
        return self._limit_per_host

    def _cleanup(self) -> None:
        """Cleanup unused transports."""
        if self._cleanup_handle:
            self._cleanup_handle.cancel()
            # _cleanup_handle should be unset, otherwise _release() will not
            # recreate it ever!
            self._cleanup_handle = None

        now = self._loop.time()
        timeout = self._keepalive_timeout

        if self._conns:
            connections = {}
            deadline = now - timeout
            for key, conns in self._conns.items():
                alive = []
                for proto, use_time in conns:
                    if proto.is_connected():
                        if use_time - deadline < 0:
                            transport = proto.transport
                            proto.close()
                            if key.is_ssl and not self._cleanup_closed_disabled:
                                self._cleanup_closed_transports.append(transport)
                        else:
                            alive.append((proto, use_time))
                    else:
                        transport = proto.transport
                        proto.close()
                        if key.is_ssl and not self._cleanup_closed_disabled:
                            self._cleanup_closed_transports.append(transport)

                if alive:
                    connections[key] = alive

            self._conns = connections

        if self._conns:
            self._cleanup_handle = helpers.weakref_handle(
                self,
                "_cleanup",
                timeout,
                self._loop,
                timeout_ceil_threshold=self._timeout_ceil_threshold,
            )

    def _drop_acquired_per_host(
        self, key: "ConnectionKey", val: ResponseHandler
    ) -> None:
        acquired_per_host = self._acquired_per_host
        if key not in acquired_per_host:
            return
        conns = acquired_per_host[key]
        conns.remove(val)
        if not conns:
            del self._acquired_per_host[key]

    def _cleanup_closed(self) -> None:
        """Double confirmation for transport close.

        Some broken ssl servers may leave socket open without proper close.
        """
        if self._cleanup_closed_handle:
            self._cleanup_closed_handle.cancel()

        for transport in self._cleanup_closed_transports:
            if transport is not None:
                transport.abort()

        self._cleanup_closed_transports = []

        if not self._cleanup_closed_disabled:
            self._cleanup_closed_handle = helpers.weakref_handle(
                self,
                "_cleanup_closed",
                self._cleanup_closed_period,
                self._loop,
                timeout_ceil_threshold=self._timeout_ceil_threshold,
            )

    def close(self) -> Awaitable[None]:
        """Close all opened transports."""
        self._close()
        return _DeprecationWaiter(noop())

    def _close(self) -> None:
        if self._closed:
            return

        self._closed = True

        try:
            if self._loop.is_closed():
                return

            # cancel cleanup task
            if self._cleanup_handle:
                self._cleanup_handle.cancel()

            # cancel cleanup close task
            if self._cleanup_closed_handle:
                self._cleanup_closed_handle.cancel()

            for data in self._conns.values():
                for proto, t0 in data:
                    proto.close()

            for proto in self._acquired:
                proto.close()

            for transport in self._cleanup_closed_transports:
                if transport is not None:
                    transport.abort()

        finally:
            self._conns.clear()
            self._acquired.clear()
            self._waiters.clear()
            self._cleanup_handle = None
            self._cleanup_closed_transports.clear()
            self._cleanup_closed_handle = None

    @property
    def closed(self) -> bool:
        """Is connector closed.

        A readonly property.
        """
        return self._closed

    def _available_connections(self, key: "ConnectionKey") -> int:
        """
        Return number of available connections.

        The limit, limit_per_host and the connection key are taken into account.

        If it returns less than 1 means that there are no connections
        available.
        """
        if self._limit:
            # total calc available connections
            available = self._limit - len(self._acquired)

            # check limit per host
            if (
                self._limit_per_host
                and available > 0
                and key in self._acquired_per_host
            ):
                acquired = self._acquired_per_host.get(key)
                assert acquired is not None
                available = self._limit_per_host - len(acquired)

        elif self._limit_per_host and key in self._acquired_per_host:
            # check limit per host
            acquired = self._acquired_per_host.get(key)
            assert acquired is not None
            available = self._limit_per_host - len(acquired)
        else:
            available = 1

        return available

    async def connect(
        self, req: ClientRequest, traces: List["Trace"], timeout: "ClientTimeout"
    ) -> Connection:
        """Get from pool or create new connection."""
        key = req.connection_key
        available = self._available_connections(key)

        # Wait if there are no available connections or if there are/were
        # waiters (i.e. don't steal connection from a waiter about to wake up)
        if available <= 0 or key in self._waiters:
            fut = self._loop.create_future()

            # This connection will now count towards the limit.
            self._waiters[key].append(fut)

            if traces:
                for trace in traces:
                    await trace.send_connection_queued_start()

            try:
                await fut
            except BaseException as e:
                if key in self._waiters:
                    # remove a waiter even if it was cancelled, normally it's
                    #  removed when it's notified
                    try:
                        self._waiters[key].remove(fut)
                    except ValueError:  # fut may no longer be in list
                        pass

                raise e
            finally:
                if key in self._waiters and not self._waiters[key]:
                    del self._waiters[key]

            if traces:
                for trace in traces:
                    await trace.send_connection_queued_end()

        proto = self._get(key)
        if proto is None:
            placeholder = cast(ResponseHandler, _TransportPlaceholder())
            self._acquired.add(placeholder)
            self._acquired_per_host[key].add(placeholder)

            if traces:
                for trace in traces:
                    await trace.send_connection_create_start()

            try:
                proto = await self._create_connection(req, traces, timeout)
                if self._closed:
                    proto.close()
                    raise ClientConnectionError("Connector is closed.")
            except BaseException:
                if not self._closed:
                    self._acquired.remove(placeholder)
                    self._drop_acquired_per_host(key, placeholder)
                    self._release_waiter()
                raise
            else:
                if not self._closed:
                    self._acquired.remove(placeholder)
                    self._drop_acquired_per_host(key, placeholder)

            if traces:
                for trace in traces:
                    await trace.send_connection_create_end()
        else:
            if traces:
                # Acquire the connection to prevent race conditions with limits
                placeholder = cast(ResponseHandler, _TransportPlaceholder())
                self._acquired.add(placeholder)
                self._acquired_per_host[key].add(placeholder)
                for trace in traces:
                    await trace.send_connection_reuseconn()
                self._acquired.remove(placeholder)
                self._drop_acquired_per_host(key, placeholder)

        self._acquired.add(proto)
        self._acquired_per_host[key].add(proto)
        return Connection(self, key, proto, self._loop)

    def _get(self, key: "ConnectionKey") -> Optional[ResponseHandler]:
        try:
            conns = self._conns[key]
        except KeyError:
            return None

        t1 = self._loop.time()
        while conns:
            proto, t0 = conns.pop()
            if proto.is_connected():
                if t1 - t0 > self._keepalive_timeout:
                    transport = proto.transport
                    proto.close()
                    # only for SSL transports
                    if key.is_ssl and not self._cleanup_closed_disabled:
                        self._cleanup_closed_transports.append(transport)
                else:
                    if not conns:
                        # The very last connection was reclaimed: drop the key
                        del self._conns[key]
                    return proto
            else:
                transport = proto.transport
                proto.close()
                if key.is_ssl and not self._cleanup_closed_disabled:
                    self._cleanup_closed_transports.append(transport)

        # No more connections: drop the key
        del self._conns[key]
        return None

    def _release_waiter(self) -> None:
        """
        Iterates over all waiters until one to be released is found.

        The one to be released is not finished and
        belongs to a host that has available connections.
        """
        if not self._waiters:
            return

        # Having the dict keys ordered this avoids to iterate
        # at the same order at each call.
        queues = list(self._waiters.keys())
        random.shuffle(queues)

        for key in queues:
            if self._available_connections(key) < 1:
                continue

            waiters = self._waiters[key]
            while waiters:
                waiter = waiters.popleft()
                if not waiter.done():
                    waiter.set_result(None)
                    return

    def _release_acquired(self, key: "ConnectionKey", proto: ResponseHandler) -> None:
        if self._closed:
            # acquired connection is already released on connector closing
            return

        try:
            self._acquired.remove(proto)
            self._drop_acquired_per_host(key, proto)
        except KeyError:  # pragma: no cover
            # this may be result of undetermenistic order of objects
            # finalization due garbage collection.
            pass
        else:
            self._release_waiter()

    def _release(
        self,
        key: "ConnectionKey",
        protocol: ResponseHandler,
        *,
        should_close: bool = False,
    ) -> None:
        if self._closed:
            # acquired connection is already released on connector closing
            return

        self._release_acquired(key, protocol)

        if self._force_close:
            should_close = True

        if should_close or protocol.should_close:
            transport = protocol.transport
            protocol.close()

            if key.is_ssl and not self._cleanup_closed_disabled:
                self._cleanup_closed_transports.append(transport)
        else:
            conns = self._conns.get(key)
            if conns is None:
                conns = self._conns[key] = []
            conns.append((protocol, self._loop.time()))

            if self._cleanup_handle is None:
                self._cleanup_handle = helpers.weakref_handle(
                    self,
                    "_cleanup",
                    self._keepalive_timeout,
                    self._loop,
                    timeout_ceil_threshold=self._timeout_ceil_threshold,
                )

    async def _create_connection(
        self, req: ClientRequest, traces: List["Trace"], timeout: "ClientTimeout"
    ) -> ResponseHandler:
        raise NotImplementedError()


class _DNSCacheTable:
    def __init__(self, ttl: Optional[float] = None) -> None:
        self._addrs_rr: Dict[Tuple[str, int], Tuple[Iterator[ResolveResult], int]] = {}
        self._timestamps: Dict[Tuple[str, int], float] = {}
        self._ttl = ttl

    def __contains__(self, host: object) -> bool:
        return host in self._addrs_rr

    def add(self, key: Tuple[str, int], addrs: List[ResolveResult]) -> None:
        self._addrs_rr[key] = (cycle(addrs), len(addrs))

        if self._ttl is not None:
            self._timestamps[key] = monotonic()

    def remove(self, key: Tuple[str, int]) -> None:
        self._addrs_rr.pop(key, None)

        if self._ttl is not None:
            self._timestamps.pop(key, None)

    def clear(self) -> None:
        self._addrs_rr.clear()
        self._timestamps.clear()

    def next_addrs(self, key: Tuple[str, int]) -> List[ResolveResult]:
        loop, length = self._addrs_rr[key]
        addrs = list(islice(loop, length))
        # Consume one more element to shift internal state of `cycle`
        next(loop)
        return addrs

    def expired(self, key: Tuple[str, int]) -> bool:
        if self._ttl is None:
            return False

        return self._timestamps[key] + self._ttl < monotonic()


class TCPConnector(BaseConnector):
    """TCP connector.

    verify_ssl - Set to True to check ssl certifications.
    fingerprint - Pass the binary sha256
        digest of the expected certificate in DER format to verify
        that the certificate the server presents matches. See also
        https://en.wikipedia.org/wiki/HTTP_Public_Key_Pinning
    resolver - Enable DNS lookups and use this
        resolver
    use_dns_cache - Use memory cache for DNS lookups.
    ttl_dns_cache - Max seconds having cached a DNS entry, None forever.
    family - socket address family
    local_addr - local tuple of (host, port) to bind socket to

    keepalive_timeout - (optional) Keep-alive timeout.
    force_close - Set to True to force close and do reconnect
        after each request (and between redirects).
    limit - The total number of simultaneous connections.
    limit_per_host - Number of simultaneous connections to one host.
    enable_cleanup_closed - Enables clean-up closed ssl transports.
                            Disabled by default.
    happy_eyeballs_delay - This is the “Connection Attempt Delay”
                           as defined in RFC 8305. To disable
                           the happy eyeballs algorithm, set to None.
    interleave - “First Address Family Count” as defined in RFC 8305
    loop - Optional event loop.
    """

    allowed_protocol_schema_set = HIGH_LEVEL_SCHEMA_SET | frozenset({"tcp"})
    _made_ssl_context: Dict[bool, "asyncio.Future[SSLContext]"] = {}

    def __init__(
        self,
        *,
        verify_ssl: bool = True,
        fingerprint: Optional[bytes] = None,
        use_dns_cache: bool = True,
        ttl_dns_cache: Optional[int] = 10,
        family: socket.AddressFamily = socket.AddressFamily.AF_UNSPEC,
        ssl_context: Optional[SSLContext] = None,
        ssl: Union[bool, Fingerprint, SSLContext] = True,
        local_addr: Optional[Tuple[str, int]] = None,
        resolver: Optional[AbstractResolver] = None,
        keepalive_timeout: Union[None, float, object] = sentinel,
        force_close: bool = False,
        limit: int = 100,
        limit_per_host: int = 0,
        enable_cleanup_closed: bool = False,
        loop: Optional[asyncio.AbstractEventLoop] = None,
        timeout_ceil_threshold: float = 5,
        happy_eyeballs_delay: Optional[float] = 0.25,
        interleave: Optional[int] = None,
    ):
        super().__init__(
            keepalive_timeout=keepalive_timeout,
            force_close=force_close,
            limit=limit,
            limit_per_host=limit_per_host,
            enable_cleanup_closed=enable_cleanup_closed,
            loop=loop,
            timeout_ceil_threshold=timeout_ceil_threshold,
        )

        self._ssl = _merge_ssl_params(ssl, verify_ssl, ssl_context, fingerprint)
        if resolver is None:
            resolver = DefaultResolver(loop=self._loop)
        self._resolver = resolver

        self._use_dns_cache = use_dns_cache
        self._cached_hosts = _DNSCacheTable(ttl=ttl_dns_cache)
        self._throttle_dns_events: Dict[Tuple[str, int], EventResultOrError] = {}
        self._family = family
        self._local_addr_infos = aiohappyeyeballs.addr_to_addr_infos(local_addr)
        self._happy_eyeballs_delay = happy_eyeballs_delay
        self._interleave = interleave

    def close(self) -> Awaitable[None]:
        """Close all ongoing DNS calls."""
        for ev in self._throttle_dns_events.values():
            ev.cancel()

        return super().close()

    @property
    def family(self) -> int:
        """Socket family like AF_INET."""
        return self._family

    @property
    def use_dns_cache(self) -> bool:
        """True if local DNS caching is enabled."""
        return self._use_dns_cache

    def clear_dns_cache(
        self, host: Optional[str] = None, port: Optional[int] = None
    ) -> None:
        """Remove specified host/port or clear all dns local cache."""
        if host is not None and port is not None:
            self._cached_hosts.remove((host, port))
        elif host is not None or port is not None:
            raise ValueError("either both host and port " "or none of them are allowed")
        else:
            self._cached_hosts.clear()

    async def _resolve_host(
        self, host: str, port: int, traces: Optional[Sequence["Trace"]] = None
    ) -> List[ResolveResult]:
        """Resolve host and return list of addresses."""
        if is_ip_address(host):
            return [
                {
                    "hostname": host,
                    "host": host,
                    "port": port,
                    "family": self._family,
                    "proto": 0,
                    "flags": 0,
                }
            ]

        if not self._use_dns_cache:

            if traces:
                for trace in traces:
                    await trace.send_dns_resolvehost_start(host)

            res = await self._resolver.resolve(host, port, family=self._family)

            if traces:
                for trace in traces:
                    await trace.send_dns_resolvehost_end(host)

            return res

        key = (host, port)
        if key in self._cached_hosts and not self._cached_hosts.expired(key):
            # get result early, before any await (#4014)
            result = self._cached_hosts.next_addrs(key)

            if traces:
                for trace in traces:
                    await trace.send_dns_cache_hit(host)
            return result

        #
        # If multiple connectors are resolving the same host, we wait
        # for the first one to resolve and then use the result for all of them.
        # We use a throttle event to ensure that we only resolve the host once
        # and then use the result for all the waiters.
        #
        # In this case we need to create a task to ensure that we can shield
        # the task from cancellation as cancelling this lookup should not cancel
        # the underlying lookup or else the cancel event will get broadcast to
        # all the waiters across all connections.
        #
        resolved_host_task = asyncio.create_task(
            self._resolve_host_with_throttle(key, host, port, traces)
        )
        try:
            return await asyncio.shield(resolved_host_task)
        except asyncio.CancelledError:

            def drop_exception(fut: "asyncio.Future[List[ResolveResult]]") -> None:
                with suppress(Exception, asyncio.CancelledError):
                    fut.result()

            resolved_host_task.add_done_callback(drop_exception)
            raise

    async def _resolve_host_with_throttle(
        self,
        key: Tuple[str, int],
        host: str,
        port: int,
        traces: Optional[Sequence["Trace"]],
    ) -> List[ResolveResult]:
        """Resolve host with a dns events throttle."""
        if key in self._throttle_dns_events:
            # get event early, before any await (#4014)
            event = self._throttle_dns_events[key]
            if traces:
                for trace in traces:
                    await trace.send_dns_cache_hit(host)
            await event.wait()
        else:
            # update dict early, before any await (#4014)
            self._throttle_dns_events[key] = EventResultOrError(self._loop)
            if traces:
                for trace in traces:
                    await trace.send_dns_cache_miss(host)
            try:

                if traces:
                    for trace in traces:
                        await trace.send_dns_resolvehost_start(host)

                addrs = await self._resolver.resolve(host, port, family=self._family)
                if traces:
                    for trace in traces:
                        await trace.send_dns_resolvehost_end(host)

                self._cached_hosts.add(key, addrs)
                self._throttle_dns_events[key].set()
            except BaseException as e:
                # any DNS exception, independently of the implementation
                # is set for the waiters to raise the same exception.
                self._throttle_dns_events[key].set(exc=e)
                raise
            finally:
                self._throttle_dns_events.pop(key)

        return self._cached_hosts.next_addrs(key)

    async def _create_connection(
        self, req: ClientRequest, traces: List["Trace"], timeout: "ClientTimeout"
    ) -> ResponseHandler:
        """Create connection.

        Has same keyword arguments as BaseEventLoop.create_connection.
        """
        if req.proxy:
            _, proto = await self._create_proxy_connection(req, traces, timeout)
        else:
            _, proto = await self._create_direct_connection(req, traces, timeout)

        return proto

    @staticmethod
    def _make_ssl_context(verified: bool) -> SSLContext:
        """Create SSL context.

        This method is not async-friendly and should be called from a thread
        because it will load certificates from disk and do other blocking I/O.
        """
        if verified:
            return ssl.create_default_context()
        sslcontext = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
        sslcontext.options |= ssl.OP_NO_SSLv2
        sslcontext.options |= ssl.OP_NO_SSLv3
        sslcontext.check_hostname = False
        sslcontext.verify_mode = ssl.CERT_NONE
        sslcontext.options |= ssl.OP_NO_COMPRESSION
        sslcontext.set_default_verify_paths()
        return sslcontext

    async def _get_ssl_context(self, req: ClientRequest) -> Optional[SSLContext]:
        """Logic to get the correct SSL context

        0. if req.ssl is false, return None

        1. if ssl_context is specified in req, use it
        2. if _ssl_context is specified in self, use it
        3. otherwise:
            1. if verify_ssl is not specified in req, use self.ssl_context
               (will generate a default context according to self.verify_ssl)
            2. if verify_ssl is True in req, generate a default SSL context
            3. if verify_ssl is False in req, generate a SSL context that
               won't verify
        """
        if not req.is_ssl():
            return None

        if ssl is None:  # pragma: no cover
            raise RuntimeError("SSL is not supported.")
        sslcontext = req.ssl
        if isinstance(sslcontext, ssl.SSLContext):
            return sslcontext
        if sslcontext is not True:
            # not verified or fingerprinted
            return await self._make_or_get_ssl_context(False)
        sslcontext = self._ssl
        if isinstance(sslcontext, ssl.SSLContext):
            return sslcontext
        if sslcontext is not True:
            # not verified or fingerprinted
            return await self._make_or_get_ssl_context(False)
        return await self._make_or_get_ssl_context(True)

    async def _make_or_get_ssl_context(self, verified: bool) -> SSLContext:
        """Create or get cached SSL context."""
        try:
            return await self._made_ssl_context[verified]
        except KeyError:
            loop = self._loop
            future = loop.create_future()
            self._made_ssl_context[verified] = future
            try:
                result = await loop.run_in_executor(
                    None, self._make_ssl_context, verified
                )
            # BaseException is used since we might get CancelledError
            except BaseException as ex:
                del self._made_ssl_context[verified]
                set_exception(future, ex)
                raise
            else:
                set_result(future, result)
            return result

    def _get_fingerprint(self, req: ClientRequest) -> Optional["Fingerprint"]:
        ret = req.ssl
        if isinstance(ret, Fingerprint):
            return ret
        ret = self._ssl
        if isinstance(ret, Fingerprint):
            return ret
        return None

    async def _wrap_create_connection(
        self,
        *args: Any,
        addr_infos: List[aiohappyeyeballs.AddrInfoType],
        req: ClientRequest,
        timeout: "ClientTimeout",
        client_error: Type[Exception] = ClientConnectorError,
        **kwargs: Any,
    ) -> Tuple[asyncio.Transport, ResponseHandler]:
        try:
            async with ceil_timeout(
                timeout.sock_connect, ceil_threshold=timeout.ceil_threshold
            ):
                sock = await aiohappyeyeballs.start_connection(
                    addr_infos=addr_infos,
                    local_addr_infos=self._local_addr_infos,
                    happy_eyeballs_delay=self._happy_eyeballs_delay,
                    interleave=self._interleave,
                    loop=self._loop,
                )
                return await self._loop.create_connection(*args, **kwargs, sock=sock)
        except cert_errors as exc:
            raise ClientConnectorCertificateError(req.connection_key, exc) from exc
        except ssl_errors as exc:
            raise ClientConnectorSSLError(req.connection_key, exc) from exc
        except OSError as exc:
            if exc.errno is None and isinstance(exc, asyncio.TimeoutError):
                raise
            raise client_error(req.connection_key, exc) from exc

    async def _wrap_existing_connection(
        self,
        *args: Any,
        req: ClientRequest,
        timeout: "ClientTimeout",
        client_error: Type[Exception] = ClientConnectorError,
        **kwargs: Any,
    ) -> Tuple[asyncio.Transport, ResponseHandler]:
        try:
            async with ceil_timeout(
                timeout.sock_connect, ceil_threshold=timeout.ceil_threshold
            ):
                return await self._loop.create_connection(*args, **kwargs)
        except cert_errors as exc:
            raise ClientConnectorCertificateError(req.connection_key, exc) from exc
        except ssl_errors as exc:
            raise ClientConnectorSSLError(req.connection_key, exc) from exc
        except OSError as exc:
            if exc.errno is None and isinstance(exc, asyncio.TimeoutError):
                raise
            raise client_error(req.connection_key, exc) from exc

    def _fail_on_no_start_tls(self, req: "ClientRequest") -> None:
        """Raise a :py:exc:`RuntimeError` on missing ``start_tls()``.

        It is necessary for TLS-in-TLS so that it is possible to
        send HTTPS queries through HTTPS proxies.

        This doesn't affect regular HTTP requests, though.
        """
        if not req.is_ssl():
            return

        proxy_url = req.proxy
        assert proxy_url is not None
        if proxy_url.scheme != "https":
            return

        self._check_loop_for_start_tls()

    def _check_loop_for_start_tls(self) -> None:
        try:
            self._loop.start_tls
        except AttributeError as attr_exc:
            raise RuntimeError(
                "An HTTPS request is being sent through an HTTPS proxy. "
                "This needs support for TLS in TLS but it is not implemented "
                "in your runtime for the stdlib asyncio.\n\n"
                "Please upgrade to Python 3.11 or higher. For more details, "
                "please see:\n"
                "* https://bugs.python.org/issue37179\n"
                "* https://github.com/python/cpython/pull/28073\n"
                "* https://docs.aiohttp.org/en/stable/"
                "client_advanced.html#proxy-support\n"
                "* https://github.com/aio-libs/aiohttp/discussions/6044\n",
            ) from attr_exc

    def _loop_supports_start_tls(self) -> bool:
        try:
            self._check_loop_for_start_tls()
        except RuntimeError:
            return False
        else:
            return True

    def _warn_about_tls_in_tls(
        self,
        underlying_transport: asyncio.Transport,
        req: ClientRequest,
    ) -> None:
        """Issue a warning if the requested URL has HTTPS scheme."""
        if req.request_info.url.scheme != "https":
            return

        asyncio_supports_tls_in_tls = getattr(
            underlying_transport,
            "_start_tls_compatible",
            False,
        )

        if asyncio_supports_tls_in_tls:
            return

        warnings.warn(
            "An HTTPS request is being sent through an HTTPS proxy. "
            "This support for TLS in TLS is known to be disabled "
            "in the stdlib asyncio (Python <3.11). This is why you'll probably see "
            "an error in the log below.\n\n"
            "It is possible to enable it via monkeypatching. "
            "For more details, see:\n"
            "* https://bugs.python.org/issue37179\n"
            "* https://github.com/python/cpython/pull/28073\n\n"
            "You can temporarily patch this as follows:\n"
            "* https://docs.aiohttp.org/en/stable/client_advanced.html#proxy-support\n"
            "* https://github.com/aio-libs/aiohttp/discussions/6044\n",
            RuntimeWarning,
            source=self,
            # Why `4`? At least 3 of the calls in the stack originate
            # from the methods in this class.
            stacklevel=3,
        )

    async def _start_tls_connection(
        self,
        underlying_transport: asyncio.Transport,
        req: ClientRequest,
        timeout: "ClientTimeout",
        client_error: Type[Exception] = ClientConnectorError,
    ) -> Tuple[asyncio.BaseTransport, ResponseHandler]:
        """Wrap the raw TCP transport with TLS."""
        tls_proto = self._factory()  # Create a brand new proto for TLS

        # Safety of the `cast()` call here is based on the fact that
        # internally `_get_ssl_context()` only returns `None` when
        # `req.is_ssl()` evaluates to `False` which is never gonna happen
        # in this code path. Of course, it's rather fragile
        # maintainability-wise but this is to be solved separately.
        sslcontext = cast(ssl.SSLContext, await self._get_ssl_context(req))

        try:
            async with ceil_timeout(
                timeout.sock_connect, ceil_threshold=timeout.ceil_threshold
            ):
                try:
                    tls_transport = await self._loop.start_tls(
                        underlying_transport,
                        tls_proto,
                        sslcontext,
                        server_hostname=req.server_hostname or req.host,
                        ssl_handshake_timeout=timeout.total,
                    )
                except BaseException:
                    # We need to close the underlying transport since
                    # `start_tls()` probably failed before it had a
                    # chance to do this:
                    underlying_transport.close()
                    raise
        except cert_errors as exc:
            raise ClientConnectorCertificateError(req.connection_key, exc) from exc
        except ssl_errors as exc:
            raise ClientConnectorSSLError(req.connection_key, exc) from exc
        except OSError as exc:
            if exc.errno is None and isinstance(exc, asyncio.TimeoutError):
                raise
            raise client_error(req.connection_key, exc) from exc
        except TypeError as type_err:
            # Example cause looks like this:
            # TypeError: transport <asyncio.sslproto._SSLProtocolTransport
            # object at 0x7f760615e460> is not supported by start_tls()

            raise ClientConnectionError(
                "Cannot initialize a TLS-in-TLS connection to host "
                f"{req.host!s}:{req.port:d} through an underlying connection "
                f"to an HTTPS proxy {req.proxy!s} ssl:{req.ssl or 'default'} "
                f"[{type_err!s}]"
            ) from type_err
        else:
            if tls_transport is None:
                msg = "Failed to start TLS (possibly caused by closing transport)"
                raise client_error(req.connection_key, OSError(msg))
            tls_proto.connection_made(
                tls_transport
            )  # Kick the state machine of the new TLS protocol

        return tls_transport, tls_proto

    def _convert_hosts_to_addr_infos(
        self, hosts: List[ResolveResult]
    ) -> List[aiohappyeyeballs.AddrInfoType]:
        """Converts the list of hosts to a list of addr_infos.

        The list of hosts is the result of a DNS lookup. The list of
        addr_infos is the result of a call to `socket.getaddrinfo()`.
        """
        addr_infos: List[aiohappyeyeballs.AddrInfoType] = []
        for hinfo in hosts:
            host = hinfo["host"]
            is_ipv6 = ":" in host
            family = socket.AF_INET6 if is_ipv6 else socket.AF_INET
            if self._family and self._family != family:
                continue
            addr = (host, hinfo["port"], 0, 0) if is_ipv6 else (host, hinfo["port"])
            addr_infos.append(
                (family, socket.SOCK_STREAM, socket.IPPROTO_TCP, "", addr)
            )
        return addr_infos

    async def _create_direct_connection(
        self,
        req: ClientRequest,
        traces: List["Trace"],
        timeout: "ClientTimeout",
        *,
        client_error: Type[Exception] = ClientConnectorError,
    ) -> Tuple[asyncio.Transport, ResponseHandler]:
        sslcontext = await self._get_ssl_context(req)
        fingerprint = self._get_fingerprint(req)

        host = req.url.raw_host
        assert host is not None
        # Replace multiple trailing dots with a single one.
        # A trailing dot is only present for fully-qualified domain names.
        # See https://github.com/aio-libs/aiohttp/pull/7364.
        if host.endswith(".."):
            host = host.rstrip(".") + "."
        port = req.port
        assert port is not None
        try:
            # Cancelling this lookup should not cancel the underlying lookup
            #  or else the cancel event will get broadcast to all the waiters
            #  across all connections.
            hosts = await self._resolve_host(host, port, traces=traces)
        except OSError as exc:
            if exc.errno is None and isinstance(exc, asyncio.TimeoutError):
                raise
            # in case of proxy it is not ClientProxyConnectionError
            # it is problem of resolving proxy ip itself
            raise ClientConnectorError(req.connection_key, exc) from exc

        last_exc: Optional[Exception] = None
        addr_infos = self._convert_hosts_to_addr_infos(hosts)
        while addr_infos:
            # Strip trailing dots, certificates contain FQDN without dots.
            # See https://github.com/aio-libs/aiohttp/issues/3636
            server_hostname = (
                (req.server_hostname or host).rstrip(".") if sslcontext else None
            )

            try:
                transp, proto = await self._wrap_create_connection(
                    self._factory,
                    timeout=timeout,
                    ssl=sslcontext,
                    addr_infos=addr_infos,
                    server_hostname=server_hostname,
                    req=req,
                    client_error=client_error,
                )
            except ClientConnectorError as exc:
                last_exc = exc
                aiohappyeyeballs.pop_addr_infos_interleave(addr_infos, self._interleave)
                continue

            if req.is_ssl() and fingerprint:
                try:
                    fingerprint.check(transp)
                except ServerFingerprintMismatch as exc:
                    transp.close()
                    if not self._cleanup_closed_disabled:
                        self._cleanup_closed_transports.append(transp)
                    last_exc = exc
                    # Remove the bad peer from the list of addr_infos
                    sock: socket.socket = transp.get_extra_info("socket")
                    bad_peer = sock.getpeername()
                    aiohappyeyeballs.remove_addr_infos(addr_infos, bad_peer)
                    continue

            return transp, proto
        else:
            assert last_exc is not None
            raise last_exc

    async def _create_proxy_connection(
        self, req: ClientRequest, traces: List["Trace"], timeout: "ClientTimeout"
    ) -> Tuple[asyncio.BaseTransport, ResponseHandler]:
        self._fail_on_no_start_tls(req)
        runtime_has_start_tls = self._loop_supports_start_tls()

        headers: Dict[str, str] = {}
        if req.proxy_headers is not None:
            headers = req.proxy_headers  # type: ignore[assignment]
        headers[hdrs.HOST] = req.headers[hdrs.HOST]

        url = req.proxy
        assert url is not None
        proxy_req = ClientRequest(
            hdrs.METH_GET,
            url,
            headers=headers,
            auth=req.proxy_auth,
            loop=self._loop,
            ssl=req.ssl,
        )

        # create connection to proxy server
        transport, proto = await self._create_direct_connection(
            proxy_req, [], timeout, client_error=ClientProxyConnectionError
        )

        auth = proxy_req.headers.pop(hdrs.AUTHORIZATION, None)
        if auth is not None:
            if not req.is_ssl():
                req.headers[hdrs.PROXY_AUTHORIZATION] = auth
            else:
                proxy_req.headers[hdrs.PROXY_AUTHORIZATION] = auth

        if req.is_ssl():
            if runtime_has_start_tls:
                self._warn_about_tls_in_tls(transport, req)

            # For HTTPS requests over HTTP proxy
            # we must notify proxy to tunnel connection
            # so we send CONNECT command:
            #   CONNECT www.python.org:443 HTTP/1.1
            #   Host: www.python.org
            #
            # next we must do TLS handshake and so on
            # to do this we must wrap raw socket into secure one
            # asyncio handles this perfectly
            proxy_req.method = hdrs.METH_CONNECT
            proxy_req.url = req.url
            key = attr.evolve(
                req.connection_key, proxy=None, proxy_auth=None, proxy_headers_hash=None
            )
            conn = Connection(self, key, proto, self._loop)
            proxy_resp = await proxy_req.send(conn)
            try:
                protocol = conn._protocol
                assert protocol is not None

                # read_until_eof=True will ensure the connection isn't closed
                # once the response is received and processed allowing
                # START_TLS to work on the connection below.
                protocol.set_response_params(
                    read_until_eof=runtime_has_start_tls,
                    timeout_ceil_threshold=self._timeout_ceil_threshold,
                )
                resp = await proxy_resp.start(conn)
            except BaseException:
                proxy_resp.close()
                conn.close()
                raise
            else:
                conn._protocol = None
                conn._transport = None
                try:
                    if resp.status != 200:
                        message = resp.reason
                        if message is None:
                            message = HTTPStatus(resp.status).phrase
                        raise ClientHttpProxyError(
                            proxy_resp.request_info,
                            resp.history,
                            status=resp.status,
                            message=message,
                            headers=resp.headers,
                        )
                    if not runtime_has_start_tls:
                        rawsock = transport.get_extra_info("socket", default=None)
                        if rawsock is None:
                            raise RuntimeError(
                                "Transport does not expose socket instance"
                            )
                        # Duplicate the socket, so now we can close proxy transport
                        rawsock = rawsock.dup()
                except BaseException:
                    # It shouldn't be closed in `finally` because it's fed to
                    # `loop.start_tls()` and the docs say not to touch it after
                    # passing there.
                    transport.close()
                    raise
                finally:
                    if not runtime_has_start_tls:
                        transport.close()

                if not runtime_has_start_tls:
                    # HTTP proxy with support for upgrade to HTTPS
                    sslcontext = self._get_ssl_context(req)
                    return await self._wrap_existing_connection(
                        self._factory,
                        timeout=timeout,
                        ssl=sslcontext,
                        sock=rawsock,
                        server_hostname=req.host,
                        req=req,
                    )

                return await self._start_tls_connection(
                    # Access the old transport for the last time before it's
                    # closed and forgotten forever:
                    transport,
                    req=req,
                    timeout=timeout,
                )
            finally:
                proxy_resp.close()

        return transport, proto


class UnixConnector(BaseConnector):
    """Unix socket connector.

    path - Unix socket path.
    keepalive_timeout - (optional) Keep-alive timeout.
    force_close - Set to True to force close and do reconnect
        after each request (and between redirects).
    limit - The total number of simultaneous connections.
    limit_per_host - Number of simultaneous connections to one host.
    loop - Optional event loop.
    """

    allowed_protocol_schema_set = HIGH_LEVEL_SCHEMA_SET | frozenset({"unix"})

    def __init__(
        self,
        path: str,
        force_close: bool = False,
        keepalive_timeout: Union[object, float, None] = sentinel,
        limit: int = 100,
        limit_per_host: int = 0,
        loop: Optional[asyncio.AbstractEventLoop] = None,
    ) -> None:
        super().__init__(
            force_close=force_close,
            keepalive_timeout=keepalive_timeout,
            limit=limit,
            limit_per_host=limit_per_host,
            loop=loop,
        )
        self._path = path

    @property
    def path(self) -> str:
        """Path to unix socket."""
        return self._path

    async def _create_connection(
        self, req: ClientRequest, traces: List["Trace"], timeout: "ClientTimeout"
    ) -> ResponseHandler:
        try:
            async with ceil_timeout(
                timeout.sock_connect, ceil_threshold=timeout.ceil_threshold
            ):
                _, proto = await self._loop.create_unix_connection(
                    self._factory, self._path
                )
        except OSError as exc:
            if exc.errno is None and isinstance(exc, asyncio.TimeoutError):
                raise
            raise UnixClientConnectorError(self.path, req.connection_key, exc) from exc

        return proto


class NamedPipeConnector(BaseConnector):
    """Named pipe connector.

    Only supported by the proactor event loop.
    See also: https://docs.python.org/3/library/asyncio-eventloop.html

    path - Windows named pipe path.
    keepalive_timeout - (optional) Keep-alive timeout.
    force_close - Set to True to force close and do reconnect
        after each request (and between redirects).
    limit - The total number of simultaneous connections.
    limit_per_host - Number of simultaneous connections to one host.
    loop - Optional event loop.
    """

    allowed_protocol_schema_set = HIGH_LEVEL_SCHEMA_SET | frozenset({"npipe"})

    def __init__(
        self,
        path: str,
        force_close: bool = False,
        keepalive_timeout: Union[object, float, None] = sentinel,
        limit: int = 100,
        limit_per_host: int = 0,
        loop: Optional[asyncio.AbstractEventLoop] = None,
    ) -> None:
        super().__init__(
            force_close=force_close,
            keepalive_timeout=keepalive_timeout,
            limit=limit,
            limit_per_host=limit_per_host,
            loop=loop,
        )
        if not isinstance(
            self._loop, asyncio.ProactorEventLoop  # type: ignore[attr-defined]
        ):
            raise RuntimeError(
                "Named Pipes only available in proactor " "loop under windows"
            )
        self._path = path

    @property
    def path(self) -> str:
        """Path to the named pipe."""
        return self._path

    async def _create_connection(
        self, req: ClientRequest, traces: List["Trace"], timeout: "ClientTimeout"
    ) -> ResponseHandler:
        try:
            async with ceil_timeout(
                timeout.sock_connect, ceil_threshold=timeout.ceil_threshold
            ):
                _, proto = await self._loop.create_pipe_connection(  # type: ignore[attr-defined]
                    self._factory, self._path
                )
                # the drain is required so that the connection_made is called
                # and transport is set otherwise it is not set before the
                # `assert conn.transport is not None`
                # in client.py's _request method
                await asyncio.sleep(0)
                # other option is to manually set transport like
                # `proto.transport = trans`
        except OSError as exc:
            if exc.errno is None and isinstance(exc, asyncio.TimeoutError):
                raise
            raise ClientConnectorError(req.connection_key, exc) from exc

        return cast(ResponseHandler, proto)

```
--- END FILE ---

Please first localize the bug based on the issue statement, and then generate *SEARCH/REPLACE* edits to fix the issue.

Every *SEARCH/REPLACE* edit must use this format:
1. The file path
2. The start of search block: <<<<<<< SEARCH
3. A contiguous chunk of lines to search for in the existing source code
4. The dividing line: =======
5. The lines to replace into the source code
6. The end of the replace block: >>>>>>> REPLACE

Here is an example:

```python
### mathweb/flask/app.py
<<<<<<< SEARCH
from flask import Flask
=======
import math
from flask import Flask
>>>>>>> REPLACE
```
</solution>

Please note that the *SEARCH/REPLACE* edit REQUIRES PROPER INDENTATION. If you would like to add the line '        print(x)', you must fully write that out, with all those spaces before the code!
Wrap each *SEARCH/REPLACE* edit in a code block as shown in the example above. If you have multiple *SEARCH/REPLACE* edits, use a separate code block for each one.
[ISSUE]
**Title:** Closing TCPConnector does not cancel pending resolve_host tasks, causing pending Task errors

**Description:**
When closing an `aiohttp.TCPConnector`, any ongoing DNS resolution tasks are not properly canceled. This leads to warnings such as "Task was destroyed but it is pending" because the connector does not track and cancel these tasks as expected.

**Example Code:**

```python
async def simulate_connector_close():
    cancelled = False

    async def delay_resolve_host(*args):
        try:
            await asyncio.sleep(10)
        except asyncio.CancelledError:
            cancelled = True
            raise

    conn = aiohttp.TCPConnector()
    req = ClientRequest('GET', URL('http://localhost:80'), loop=asyncio.get_event_loop(), response_class=mock.Mock())
    
    with mock.patch.object(conn, '_resolve_host_with_throttle', delay_resolve_host):
        asyncio.create_task(conn.connect(req, [], ClientTimeout()))
        await asyncio.sleep(0)  # Allow task to start
        await conn.close()
        # At this point, the resolve_host task should be cancelled
```

**Expected Behavior:**
Closing the `TCPConnector` should cancel all ongoing `resolve_host` tasks, ensuring that no tasks remain pending and no related warnings are emitted.

**Actual Behavior:**
Closing the connector does not cancel the pending `resolve_host` tasks, resulting in warnings about pending tasks being destroyed.

[/ISSUE]
{
    "test_connection_del[pyloop]": "PASSED",
    "test_connection_del_loop_debug[pyloop]": "PASSED",
    "test_connection_del_loop_closed[pyloop]": "PASSED",
    "test_del[pyloop]": "PASSED",
    "test_del_with_closed_loop[pyloop]": "PASSED",
    "test_del_empty_connector[pyloop]": "PASSED",
    "test_create_conn[pyloop]": "PASSED",
    "test_connector_context_manager[pyloop]": "PASSED",
    "test_async_context_manager[pyloop]": "PASSED",
    "test_close[pyloop]": "PASSED",
    "test_get[pyloop]": "PASSED",
    "test_get_unconnected_proto[pyloop]": "PASSED",
    "test_get_unconnected_proto_ssl[pyloop]": "PASSED",
    "test_get_expired[pyloop]": "PASSED",
    "test_get_expired_ssl[pyloop]": "PASSED",
    "test_release_acquired[pyloop]": "PASSED",
    "test_release_acquired_closed[pyloop]": "PASSED",
    "test_release[pyloop]": "PASSED",
    "test_release_ssl_transport[pyloop]": "PASSED",
    "test_release_already_closed[pyloop]": "PASSED",
    "test_release_waiter_no_limit[pyloop]": "PASSED",
    "test_release_waiter_first_available[pyloop]": "PASSED",
    "test_release_waiter_release_first[pyloop]": "PASSED",
    "test_release_waiter_skip_done_waiter[pyloop]": "PASSED",
    "test_release_waiter_per_host[pyloop]": "PASSED",
    "test_release_waiter_no_available[pyloop]": "PASSED",
    "test_release_close[pyloop]": "PASSED",
    "test__drop_acquire_per_host1[pyloop]": "PASSED",
    "test__drop_acquire_per_host2[pyloop]": "PASSED",
    "test__drop_acquire_per_host3[pyloop]": "PASSED",
    "test_tcp_connector_certificate_error[pyloop]": "PASSED",
    "test_tcp_connector_server_hostname_default[pyloop]": "PASSED",
    "test_tcp_connector_server_hostname_override[pyloop]": "PASSED",
    "test_tcp_connector_multiple_hosts_errors[pyloop]": "PASSED",
    "test_tcp_connector_happy_eyeballs[pyloop-0.1]": "PASSED",
    "test_tcp_connector_happy_eyeballs[pyloop-0.25]": "PASSED",
    "test_tcp_connector_happy_eyeballs[pyloop-None]": "PASSED",
    "test_tcp_connector_interleave[pyloop]": "PASSED",
    "test_tcp_connector_family_is_respected[pyloop]": "PASSED",
    "test_tcp_connector_resolve_host[pyloop]": "PASSED",
    "test_tcp_connector_dns_cache_not_expired[pyloop]": "PASSED",
    "test_tcp_connector_dns_cache_forever[pyloop]": "PASSED",
    "test_tcp_connector_use_dns_cache_disabled[pyloop]": "PASSED",
    "test_tcp_connector_dns_throttle_requests[pyloop]": "PASSED",
    "test_tcp_connector_dns_throttle_requests_exception_spread[pyloop]": "PASSED",
    "test_tcp_connector_dns_throttle_requests_cancelled_when_close[pyloop]": "PASSED",
    "test_tcp_connector_cancel_dns_error_captured[pyloop]": "PASSED",
    "test_tcp_connector_dns_tracing[pyloop]": "PASSED",
    "test_tcp_connector_dns_tracing_cache_disabled[pyloop]": "PASSED",
    "test_tcp_connector_dns_tracing_throttle_requests[pyloop]": "PASSED",
    "test_dns_error[pyloop]": "PASSED",
    "test_get_pop_empty_conns[pyloop]": "PASSED",
    "test_release_close_do_not_add_to_pool[pyloop]": "PASSED",
    "test_release_close_do_not_delete_existing_connections": "PASSED",
    "test_release_not_started[pyloop]": "PASSED",
    "test_release_not_opened[pyloop]": "PASSED",
    "test_connect[pyloop]": "PASSED",
    "test_connect_tracing[pyloop]": "PASSED",
    "test_close_during_connect[pyloop]": "PASSED",
    "test_ctor_cleanup": "PASSED",
    "test_cleanup": "PASSED",
    "test_cleanup_close_ssl_transport": "PASSED",
    "test_cleanup2": "PASSED",
    "test_cleanup3": "PASSED",
    "test_cleanup_closed[pyloop]": "PASSED",
    "test_cleanup_closed_disabled[pyloop]": "PASSED",
    "test_tcp_connector_ctor": "PASSED",
    "test_tcp_connector_allowed_protocols[pyloop]": "PASSED",
    "test_invalid_ssl_param": "PASSED",
    "test_tcp_connector_ctor_fingerprint_valid[pyloop]": "PASSED",
    "test_insecure_fingerprint_md5[pyloop]": "PASSED",
    "test_insecure_fingerprint_sha1[pyloop]": "PASSED",
    "test_tcp_connector_clear_dns_cache[pyloop]": "PASSED",
    "test_tcp_connector_clear_dns_cache_bad_args[pyloop]": "PASSED",
    "test_dont_recreate_ssl_context": "PASSED",
    "test_dont_recreate_ssl_context2": "PASSED",
    "test___get_ssl_context1": "PASSED",
    "test___get_ssl_context2[pyloop]": "PASSED",
    "test___get_ssl_context3[pyloop]": "PASSED",
    "test___get_ssl_context4[pyloop]": "PASSED",
    "test___get_ssl_context5[pyloop]": "PASSED",
    "test___get_ssl_context6": "PASSED",
    "test_ssl_context_once": "PASSED",
    "test_ssl_context_creation_raises[OSError]": "PASSED",
    "test_ssl_context_creation_raises[SSLError]": "PASSED",
    "test_ssl_context_creation_raises[CancelledError]": "PASSED",
    "test_close_twice[pyloop]": "PASSED",
    "test_close_cancels_cleanup_handle[pyloop]": "PASSED",
    "test_close_cancels_resolve_host[pyloop]": "PASSED",
    "test_close_abort_closed_transports[pyloop]": "PASSED",
    "test_close_cancels_cleanup_closed_handle[pyloop]": "PASSED",
    "test_ctor_with_default_loop[pyloop]": "PASSED",
    "test_base_connector_allows_high_level_protocols[pyloop]": "PASSED",
    "test_connect_with_limit[pyloop]": "PASSED",
    "test_connect_queued_operation_tracing[pyloop]": "PASSED",
    "test_connect_reuseconn_tracing[pyloop]": "PASSED",
    "test_connect_with_limit_and_limit_per_host[pyloop]": "PASSED",
    "test_connect_with_no_limit_and_limit_per_host[pyloop]": "PASSED",
    "test_connect_with_no_limits[pyloop]": "PASSED",
    "test_connect_with_limit_cancelled[pyloop]": "PASSED",
    "test_connect_with_capacity_release_waiters[pyloop]": "PASSED",
    "test_connect_with_limit_concurrent[pyloop]": "PASSED",
    "test_connect_waiters_cleanup[pyloop]": "PASSED",
    "test_connect_waiters_cleanup_key_error[pyloop]": "PASSED",
    "test_close_with_acquired_connection[pyloop]": "PASSED",
    "test_default_force_close[pyloop]": "PASSED",
    "test_limit_property[pyloop]": "PASSED",
    "test_limit_per_host_property[pyloop]": "PASSED",
    "test_limit_property_default[pyloop]": "PASSED",
    "test_limit_per_host_property_default[pyloop]": "PASSED",
    "test_force_close_and_explicit_keep_alive[pyloop]": "PASSED",
    "test_error_on_connection[pyloop]": "PASSED",
    "test_cancelled_waiter[pyloop]": "PASSED",
    "test_error_on_connection_with_cancelled_waiter[pyloop]": "PASSED",
    "test_tcp_connector[pyloop]": "PASSED",
    "test_unix_connector_not_found[pyloop]": "PASSED",
    "test_unix_connector_permission[pyloop]": "PASSED",
    "test_default_use_dns_cache": "PASSED",
    "test_ssl_none": "PASSED",
    "test_resolver_not_called_with_address_is_ip[pyloop]": "PASSED",
    "test_tcp_connector_raise_connector_ssl_error[pyloop]": "PASSED",
    "test_tcp_connector_do_not_raise_connector_ssl_error[pyloop-ip address]": "PASSED",
    "test_tcp_connector_do_not_raise_connector_ssl_error[pyloop-domain name]": "PASSED",
    "test_tcp_connector_do_not_raise_connector_ssl_error[pyloop-fully-qualified domain name]": "PASSED",
    "test_tcp_connector_do_not_raise_connector_ssl_error[pyloop-fully-qualified domain name with multiple trailing dots]": "PASSED",
    "test_tcp_connector_do_not_raise_connector_ssl_error[pyloop-idna fully-qualified domain name]": "PASSED",
    "test_tcp_connector_uses_provided_local_addr[pyloop]": "PASSED",
    "test_unix_connector[pyloop]": "PASSED",
    "TestDNSCacheTable.test_next_addrs_basic": "PASSED",
    "TestDNSCacheTable.test_remove": "PASSED",
    "TestDNSCacheTable.test_clear": "PASSED",
    "TestDNSCacheTable.test_not_expired_ttl_None": "PASSED",
    "TestDNSCacheTable.test_not_expired_ttl": "PASSED",
    "TestDNSCacheTable.test_expired_ttl": "PASSED",
    "TestDNSCacheTable.test_never_expire": "PASSED",
    "TestDNSCacheTable.test_always_expire": "PASSED",
    "TestDNSCacheTable.test_next_addrs": "PASSED",
    "TestDNSCacheTable.test_next_addrs_single": "PASSED",
    "test_connector_cache_trace_race": "PASSED",
    "test_connector_throttle_trace_race[pyloop]": "PASSED",
    "test_connector_does_not_remove_needed_waiters[pyloop]": "PASSED"
}
diff --git a/aiohttp/connector.py b/aiohttp/connector.py
index 91174e31..93c78c62 100644
--- a/aiohttp/connector.py
+++ b/aiohttp/connector.py
@@ -824,12 +824,16 @@ class TCPConnector(BaseConnector):
         self._local_addr_infos = aiohappyeyeballs.addr_to_addr_infos(local_addr)
         self._happy_eyeballs_delay = happy_eyeballs_delay
         self._interleave = interleave
+        self._resolve_host_tasks: Set["asyncio.Task[List[ResolveResult]]"] = set()
 
     def close(self) -> Awaitable[None]:
         """Close all ongoing DNS calls."""
         for ev in self._throttle_dns_events.values():
             ev.cancel()
 
+        for t in self._resolve_host_tasks:
+            t.cancel()
+
         return super().close()
 
     @property
@@ -907,6 +911,8 @@ class TCPConnector(BaseConnector):
         resolved_host_task = asyncio.create_task(
             self._resolve_host_with_throttle(key, host, port, traces)
         )
+        self._resolve_host_tasks.add(resolved_host_task)
+        resolved_host_task.add_done_callback(self._resolve_host_tasks.discard)
         try:
             return await asyncio.shield(resolved_host_task)
         except asyncio.CancelledError:

{"aiohttp/connector.py": "import asyncio\nimport functools\nimport random\nimport socket\nimport sys\nimport traceback\nimport warnings\nfrom collections import defaultdict, deque\nfrom contextlib import suppress\nfrom http import HTTPStatus\nfrom http.cookies import SimpleCookie\nfrom itertools import cycle, islice\nfrom time import monotonic\nfrom types import TracebackType\nfrom typing import (\n    TYPE_CHECKING,\n    Any,\n    Awaitable,\n    Callable,\n    DefaultDict,\n    Dict,\n    Iterator,\n    List,\n    Literal,\n    Optional,\n    Sequence,\n    Set,\n    Tuple,\n    Type,\n    Union,\n    cast,\n)\n\nimport aiohappyeyeballs\nimport attr\n\nfrom . import hdrs, helpers\nfrom .abc import AbstractResolver, ResolveResult\nfrom .client_exceptions import (\n    ClientConnectionError,\n    ClientConnectorCertificateError,\n    ClientConnectorError,\n    ClientConnectorSSLError,\n    ClientHttpProxyError,\n    ClientProxyConnectionError,\n    ServerFingerprintMismatch,\n    UnixClientConnectorError,\n    cert_errors,\n    ssl_errors,\n)\nfrom .client_proto import ResponseHandler\nfrom .client_reqrep import ClientRequest, Fingerprint, _merge_ssl_params\nfrom .helpers import (\n    ceil_timeout,\n    is_ip_address,\n    noop,\n    sentinel,\n    set_exception,\n    set_result,\n)\nfrom .locks import EventResultOrError\nfrom .resolver import DefaultResolver\n\ntry:\n    import ssl\n\n    SSLContext = ssl.SSLContext\nexcept ImportError:  # pragma: no cover\n    ssl = None  # type: ignore[assignment]\n    SSLContext = object  # type: ignore[misc,assignment]\n\n\nEMPTY_SCHEMA_SET = frozenset({\"\"})\nHTTP_SCHEMA_SET = frozenset({\"http\", \"https\"})\nWS_SCHEMA_SET = frozenset({\"ws\", \"wss\"})\n\nHTTP_AND_EMPTY_SCHEMA_SET = HTTP_SCHEMA_SET | EMPTY_SCHEMA_SET\nHIGH_LEVEL_SCHEMA_SET = HTTP_AND_EMPTY_SCHEMA_SET | WS_SCHEMA_SET\n\n\n__all__ = (\"BaseConnector\", \"TCPConnector\", \"UnixConnector\", \"NamedPipeConnector\")\n\n\nif TYPE_CHECKING:\n    from .client import ClientTimeout\n    from .client_reqrep import ConnectionKey\n    from .tracing import Trace\n\n\nclass _DeprecationWaiter:\n    __slots__ = (\"_awaitable\", \"_awaited\")\n\n    def __init__(self, awaitable: Awaitable[Any]) -> None:\n        self._awaitable = awaitable\n        self._awaited = False\n\n    def __await__(self) -> Any:\n        self._awaited = True\n        return self._awaitable.__await__()\n\n    def __del__(self) -> None:\n        if not self._awaited:\n            warnings.warn(\n                \"Connector.close() is a coroutine, \"\n                \"please use await connector.close()\",\n                DeprecationWarning,\n            )\n\n\nclass Connection:\n\n    _source_traceback = None\n    _transport = None\n\n    def __init__(\n        self,\n        connector: \"BaseConnector\",\n        key: \"ConnectionKey\",\n        protocol: ResponseHandler,\n        loop: asyncio.AbstractEventLoop,\n    ) -> None:\n        self._key = key\n        self._connector = connector\n        self._loop = loop\n        self._protocol: Optional[ResponseHandler] = protocol\n        self._callbacks: List[Callable[[], None]] = []\n\n        if loop.get_debug():\n            self._source_traceback = traceback.extract_stack(sys._getframe(1))\n\n    def __repr__(self) -> str:\n        return f\"Connection<{self._key}>\"\n\n    def __del__(self, _warnings: Any = warnings) -> None:\n        if self._protocol is not None:\n            kwargs = {\"source\": self}\n            _warnings.warn(f\"Unclosed connection {self!r}\", ResourceWarning, **kwargs)\n            if self._loop.is_closed():\n                return\n\n            self._connector._release(self._key, self._protocol, should_close=True)\n\n            context = {\"client_connection\": self, \"message\": \"Unclosed connection\"}\n            if self._source_traceback is not None:\n                context[\"source_traceback\"] = self._source_traceback\n            self._loop.call_exception_handler(context)\n\n    def __bool__(self) -> Literal[True]:\n        \"\"\"Force subclasses to not be falsy, to make checks simpler.\"\"\"\n        return True\n\n    @property\n    def loop(self) -> asyncio.AbstractEventLoop:\n        warnings.warn(\n            \"connector.loop property is deprecated\", DeprecationWarning, stacklevel=2\n        )\n        return self._loop\n\n    @property\n    def transport(self) -> Optional[asyncio.Transport]:\n        if self._protocol is None:\n            return None\n        return self._protocol.transport\n\n    @property\n    def protocol(self) -> Optional[ResponseHandler]:\n        return self._protocol\n\n    def add_callback(self, callback: Callable[[], None]) -> None:\n        if callback is not None:\n            self._callbacks.append(callback)\n\n    def _notify_release(self) -> None:\n        callbacks, self._callbacks = self._callbacks[:], []\n\n        for cb in callbacks:\n            with suppress(Exception):\n                cb()\n\n    def close(self) -> None:\n        self._notify_release()\n\n        if self._protocol is not None:\n            self._connector._release(self._key, self._protocol, should_close=True)\n            self._protocol = None\n\n    def release(self) -> None:\n        self._notify_release()\n\n        if self._protocol is not None:\n            self._connector._release(\n                self._key, self._protocol, should_close=self._protocol.should_close\n            )\n            self._protocol = None\n\n    @property\n    def closed(self) -> bool:\n        return self._protocol is None or not self._protocol.is_connected()\n\n\nclass _TransportPlaceholder:\n    \"\"\"placeholder for BaseConnector.connect function\"\"\"\n\n    def close(self) -> None:\n        pass\n\n\nclass BaseConnector:\n    \"\"\"Base connector class.\n\n    keepalive_timeout - (optional) Keep-alive timeout.\n    force_close - Set to True to force close and do reconnect\n        after each request (and between redirects).\n    limit - The total number of simultaneous connections.\n    limit_per_host - Number of simultaneous connections to one host.\n    enable_cleanup_closed - Enables clean-up closed ssl transports.\n                            Disabled by default.\n    timeout_ceil_threshold - Trigger ceiling of timeout values when\n                             it's above timeout_ceil_threshold.\n    loop - Optional event loop.\n    \"\"\"\n\n    _closed = True  # prevent AttributeError in __del__ if ctor was failed\n    _source_traceback = None\n\n    # abort transport after 2 seconds (cleanup broken connections)\n    _cleanup_closed_period = 2.0\n\n    allowed_protocol_schema_set = HIGH_LEVEL_SCHEMA_SET\n\n    def __init__(\n        self,\n        *,\n        keepalive_timeout: Union[object, None, float] = sentinel,\n        force_close: bool = False,\n        limit: int = 100,\n        limit_per_host: int = 0,\n        enable_cleanup_closed: bool = False,\n        loop: Optional[asyncio.AbstractEventLoop] = None,\n        timeout_ceil_threshold: float = 5,\n    ) -> None:\n\n        if force_close:\n            if keepalive_timeout is not None and keepalive_timeout is not sentinel:\n                raise ValueError(\n                    \"keepalive_timeout cannot \" \"be set if force_close is True\"\n                )\n        else:\n            if keepalive_timeout is sentinel:\n                keepalive_timeout = 15.0\n\n        loop = loop or asyncio.get_running_loop()\n        self._timeout_ceil_threshold = timeout_ceil_threshold\n\n        self._closed = False\n        if loop.get_debug():\n            self._source_traceback = traceback.extract_stack(sys._getframe(1))\n\n        self._conns: Dict[ConnectionKey, List[Tuple[ResponseHandler, float]]] = {}\n        self._limit = limit\n        self._limit_per_host = limit_per_host\n        self._acquired: Set[ResponseHandler] = set()\n        self._acquired_per_host: DefaultDict[ConnectionKey, Set[ResponseHandler]] = (\n            defaultdict(set)\n        )\n        self._keepalive_timeout = cast(float, keepalive_timeout)\n        self._force_close = force_close\n\n        # {host_key: FIFO list of waiters}\n        self._waiters = defaultdict(deque)  # type: ignore[var-annotated]\n\n        self._loop = loop\n        self._factory = functools.partial(ResponseHandler, loop=loop)\n\n        self.cookies = SimpleCookie()\n\n        # start keep-alive connection cleanup task\n        self._cleanup_handle: Optional[asyncio.TimerHandle] = None\n\n        # start cleanup closed transports task\n        self._cleanup_closed_handle: Optional[asyncio.TimerHandle] = None\n        self._cleanup_closed_disabled = not enable_cleanup_closed\n        self._cleanup_closed_transports: List[Optional[asyncio.Transport]] = []\n        self._cleanup_closed()\n\n    def __del__(self, _warnings: Any = warnings) -> None:\n        if self._closed:\n            return\n        if not self._conns:\n            return\n\n        conns = [repr(c) for c in self._conns.values()]\n\n        self._close()\n\n        kwargs = {\"source\": self}\n        _warnings.warn(f\"Unclosed connector {self!r}\", ResourceWarning, **kwargs)\n        context = {\n            \"connector\": self,\n            \"connections\": conns,\n            \"message\": \"Unclosed connector\",\n        }\n        if self._source_traceback is not None:\n            context[\"source_traceback\"] = self._source_traceback\n        self._loop.call_exception_handler(context)\n\n    def __enter__(self) -> \"BaseConnector\":\n        warnings.warn(\n            '\"with Connector():\" is deprecated, '\n            'use \"async with Connector():\" instead',\n            DeprecationWarning,\n        )\n        return self\n\n    def __exit__(self, *exc: Any) -> None:\n        self._close()\n\n    async def __aenter__(self) -> \"BaseConnector\":\n        return self\n\n    async def __aexit__(\n        self,\n        exc_type: Optional[Type[BaseException]] = None,\n        exc_value: Optional[BaseException] = None,\n        exc_traceback: Optional[TracebackType] = None,\n    ) -> None:\n        await self.close()\n\n    @property\n    def force_close(self) -> bool:\n        \"\"\"Ultimately close connection on releasing if True.\"\"\"\n        return self._force_close\n\n    @property\n    def limit(self) -> int:\n        \"\"\"The total number for simultaneous connections.\n\n        If limit is 0 the connector has no limit.\n        The default limit size is 100.\n        \"\"\"\n        return self._limit\n\n    @property\n    def limit_per_host(self) -> int:\n        \"\"\"The limit for simultaneous connections to the same endpoint.\n\n        Endpoints are the same if they are have equal\n        (host, port, is_ssl) triple.\n        \"\"\"\n        return self._limit_per_host\n\n    def _cleanup(self) -> None:\n        \"\"\"Cleanup unused transports.\"\"\"\n        if self._cleanup_handle:\n            self._cleanup_handle.cancel()\n            # _cleanup_handle should be unset, otherwise _release() will not\n            # recreate it ever!\n            self._cleanup_handle = None\n\n        now = self._loop.time()\n        timeout = self._keepalive_timeout\n\n        if self._conns:\n            connections = {}\n            deadline = now - timeout\n            for key, conns in self._conns.items():\n                alive = []\n                for proto, use_time in conns:\n                    if proto.is_connected():\n                        if use_time - deadline < 0:\n                            transport = proto.transport\n                            proto.close()\n                            if key.is_ssl and not self._cleanup_closed_disabled:\n                                self._cleanup_closed_transports.append(transport)\n                        else:\n                            alive.append((proto, use_time))\n                    else:\n                        transport = proto.transport\n                        proto.close()\n                        if key.is_ssl and not self._cleanup_closed_disabled:\n                            self._cleanup_closed_transports.append(transport)\n\n                if alive:\n                    connections[key] = alive\n\n            self._conns = connections\n\n        if self._conns:\n            self._cleanup_handle = helpers.weakref_handle(\n                self,\n                \"_cleanup\",\n                timeout,\n                self._loop,\n                timeout_ceil_threshold=self._timeout_ceil_threshold,\n            )\n\n    def _drop_acquired_per_host(\n        self, key: \"ConnectionKey\", val: ResponseHandler\n    ) -> None:\n        acquired_per_host = self._acquired_per_host\n        if key not in acquired_per_host:\n            return\n        conns = acquired_per_host[key]\n        conns.remove(val)\n        if not conns:\n            del self._acquired_per_host[key]\n\n    def _cleanup_closed(self) -> None:\n        \"\"\"Double confirmation for transport close.\n\n        Some broken ssl servers may leave socket open without proper close.\n        \"\"\"\n        if self._cleanup_closed_handle:\n            self._cleanup_closed_handle.cancel()\n\n        for transport in self._cleanup_closed_transports:\n            if transport is not None:\n                transport.abort()\n\n        self._cleanup_closed_transports = []\n\n        if not self._cleanup_closed_disabled:\n            self._cleanup_closed_handle = helpers.weakref_handle(\n                self,\n                \"_cleanup_closed\",\n                self._cleanup_closed_period,\n                self._loop,\n                timeout_ceil_threshold=self._timeout_ceil_threshold,\n            )\n\n    def close(self) -> Awaitable[None]:\n        \"\"\"Close all opened transports.\"\"\"\n        self._close()\n        return _DeprecationWaiter(noop())\n\n    def _close(self) -> None:\n        if self._closed:\n            return\n\n        self._closed = True\n\n        try:\n            if self._loop.is_closed():\n                return\n\n            # cancel cleanup task\n            if self._cleanup_handle:\n                self._cleanup_handle.cancel()\n\n            # cancel cleanup close task\n            if self._cleanup_closed_handle:\n                self._cleanup_closed_handle.cancel()\n\n            for data in self._conns.values():\n                for proto, t0 in data:\n                    proto.close()\n\n            for proto in self._acquired:\n                proto.close()\n\n            for transport in self._cleanup_closed_transports:\n                if transport is not None:\n                    transport.abort()\n\n        finally:\n            self._conns.clear()\n            self._acquired.clear()\n            self._waiters.clear()\n            self._cleanup_handle = None\n            self._cleanup_closed_transports.clear()\n            self._cleanup_closed_handle = None\n\n    @property\n    def closed(self) -> bool:\n        \"\"\"Is connector closed.\n\n        A readonly property.\n        \"\"\"\n        return self._closed\n\n    def _available_connections(self, key: \"ConnectionKey\") -> int:\n        \"\"\"\n        Return number of available connections.\n\n        The limit, limit_per_host and the connection key are taken into account.\n\n        If it returns less than 1 means that there are no connections\n        available.\n        \"\"\"\n        if self._limit:\n            # total calc available connections\n            available = self._limit - len(self._acquired)\n\n            # check limit per host\n            if (\n                self._limit_per_host\n                and available > 0\n                and key in self._acquired_per_host\n            ):\n                acquired = self._acquired_per_host.get(key)\n                assert acquired is not None\n                available = self._limit_per_host - len(acquired)\n\n        elif self._limit_per_host and key in self._acquired_per_host:\n            # check limit per host\n            acquired = self._acquired_per_host.get(key)\n            assert acquired is not None\n            available = self._limit_per_host - len(acquired)\n        else:\n            available = 1\n\n        return available\n\n    async def connect(\n        self, req: ClientRequest, traces: List[\"Trace\"], timeout: \"ClientTimeout\"\n    ) -> Connection:\n        \"\"\"Get from pool or create new connection.\"\"\"\n        key = req.connection_key\n        available = self._available_connections(key)\n\n        # Wait if there are no available connections or if there are/were\n        # waiters (i.e. don't steal connection from a waiter about to wake up)\n        if available <= 0 or key in self._waiters:\n            fut = self._loop.create_future()\n\n            # This connection will now count towards the limit.\n            self._waiters[key].append(fut)\n\n            if traces:\n                for trace in traces:\n                    await trace.send_connection_queued_start()\n\n            try:\n                await fut\n            except BaseException as e:\n                if key in self._waiters:\n                    # remove a waiter even if it was cancelled, normally it's\n                    #  removed when it's notified\n                    try:\n                        self._waiters[key].remove(fut)\n                    except ValueError:  # fut may no longer be in list\n                        pass\n\n                raise e\n            finally:\n                if key in self._waiters and not self._waiters[key]:\n                    del self._waiters[key]\n\n            if traces:\n                for trace in traces:\n                    await trace.send_connection_queued_end()\n\n        proto = self._get(key)\n        if proto is None:\n            placeholder = cast(ResponseHandler, _TransportPlaceholder())\n            self._acquired.add(placeholder)\n            self._acquired_per_host[key].add(placeholder)\n\n            if traces:\n                for trace in traces:\n                    await trace.send_connection_create_start()\n\n            try:\n                proto = await self._create_connection(req, traces, timeout)\n                if self._closed:\n                    proto.close()\n                    raise ClientConnectionError(\"Connector is closed.\")\n            except BaseException:\n                if not self._closed:\n                    self._acquired.remove(placeholder)\n                    self._drop_acquired_per_host(key, placeholder)\n                    self._release_waiter()\n                raise\n            else:\n                if not self._closed:\n                    self._acquired.remove(placeholder)\n                    self._drop_acquired_per_host(key, placeholder)\n\n            if traces:\n                for trace in traces:\n                    await trace.send_connection_create_end()\n        else:\n            if traces:\n                # Acquire the connection to prevent race conditions with limits\n                placeholder = cast(ResponseHandler, _TransportPlaceholder())\n                self._acquired.add(placeholder)\n                self._acquired_per_host[key].add(placeholder)\n                for trace in traces:\n                    await trace.send_connection_reuseconn()\n                self._acquired.remove(placeholder)\n                self._drop_acquired_per_host(key, placeholder)\n\n        self._acquired.add(proto)\n        self._acquired_per_host[key].add(proto)\n        return Connection(self, key, proto, self._loop)\n\n    def _get(self, key: \"ConnectionKey\") -> Optional[ResponseHandler]:\n        try:\n            conns = self._conns[key]\n        except KeyError:\n            return None\n\n        t1 = self._loop.time()\n        while conns:\n            proto, t0 = conns.pop()\n            if proto.is_connected():\n                if t1 - t0 > self._keepalive_timeout:\n                    transport = proto.transport\n                    proto.close()\n                    # only for SSL transports\n                    if key.is_ssl and not self._cleanup_closed_disabled:\n                        self._cleanup_closed_transports.append(transport)\n                else:\n                    if not conns:\n                        # The very last connection was reclaimed: drop the key\n                        del self._conns[key]\n                    return proto\n            else:\n                transport = proto.transport\n                proto.close()\n                if key.is_ssl and not self._cleanup_closed_disabled:\n                    self._cleanup_closed_transports.append(transport)\n\n        # No more connections: drop the key\n        del self._conns[key]\n        return None\n\n    def _release_waiter(self) -> None:\n        \"\"\"\n        Iterates over all waiters until one to be released is found.\n\n        The one to be released is not finished and\n        belongs to a host that has available connections.\n        \"\"\"\n        if not self._waiters:\n            return\n\n        # Having the dict keys ordered this avoids to iterate\n        # at the same order at each call.\n        queues = list(self._waiters.keys())\n        random.shuffle(queues)\n\n        for key in queues:\n            if self._available_connections(key) < 1:\n                continue\n\n            waiters = self._waiters[key]\n            while waiters:\n                waiter = waiters.popleft()\n                if not waiter.done():\n                    waiter.set_result(None)\n                    return\n\n    def _release_acquired(self, key: \"ConnectionKey\", proto: ResponseHandler) -> None:\n        if self._closed:\n            # acquired connection is already released on connector closing\n            return\n\n        try:\n            self._acquired.remove(proto)\n            self._drop_acquired_per_host(key, proto)\n        except KeyError:  # pragma: no cover\n            # this may be result of undetermenistic order of objects\n            # finalization due garbage collection.\n            pass\n        else:\n            self._release_waiter()\n\n    def _release(\n        self,\n        key: \"ConnectionKey\",\n        protocol: ResponseHandler,\n        *,\n        should_close: bool = False,\n    ) -> None:\n        if self._closed:\n            # acquired connection is already released on connector closing\n            return\n\n        self._release_acquired(key, protocol)\n\n        if self._force_close:\n            should_close = True\n\n        if should_close or protocol.should_close:\n            transport = protocol.transport\n            protocol.close()\n\n            if key.is_ssl and not self._cleanup_closed_disabled:\n                self._cleanup_closed_transports.append(transport)\n        else:\n            conns = self._conns.get(key)\n            if conns is None:\n                conns = self._conns[key] = []\n            conns.append((protocol, self._loop.time()))\n\n            if self._cleanup_handle is None:\n                self._cleanup_handle = helpers.weakref_handle(\n                    self,\n                    \"_cleanup\",\n                    self._keepalive_timeout,\n                    self._loop,\n                    timeout_ceil_threshold=self._timeout_ceil_threshold,\n                )\n\n    async def _create_connection(\n        self, req: ClientRequest, traces: List[\"Trace\"], timeout: \"ClientTimeout\"\n    ) -> ResponseHandler:\n        raise NotImplementedError()\n\n\nclass _DNSCacheTable:\n    def __init__(self, ttl: Optional[float] = None) -> None:\n        self._addrs_rr: Dict[Tuple[str, int], Tuple[Iterator[ResolveResult], int]] = {}\n        self._timestamps: Dict[Tuple[str, int], float] = {}\n        self._ttl = ttl\n\n    def __contains__(self, host: object) -> bool:\n        return host in self._addrs_rr\n\n    def add(self, key: Tuple[str, int], addrs: List[ResolveResult]) -> None:\n        self._addrs_rr[key] = (cycle(addrs), len(addrs))\n\n        if self._ttl is not None:\n            self._timestamps[key] = monotonic()\n\n    def remove(self, key: Tuple[str, int]) -> None:\n        self._addrs_rr.pop(key, None)\n\n        if self._ttl is not None:\n            self._timestamps.pop(key, None)\n\n    def clear(self) -> None:\n        self._addrs_rr.clear()\n        self._timestamps.clear()\n\n    def next_addrs(self, key: Tuple[str, int]) -> List[ResolveResult]:\n        loop, length = self._addrs_rr[key]\n        addrs = list(islice(loop, length))\n        # Consume one more element to shift internal state of `cycle`\n        next(loop)\n        return addrs\n\n    def expired(self, key: Tuple[str, int]) -> bool:\n        if self._ttl is None:\n            return False\n\n        return self._timestamps[key] + self._ttl < monotonic()\n\n\nclass TCPConnector(BaseConnector):\n    \"\"\"TCP connector.\n\n    verify_ssl - Set to True to check ssl certifications.\n    fingerprint - Pass the binary sha256\n        digest of the expected certificate in DER format to verify\n        that the certificate the server presents matches. See also\n        https://en.wikipedia.org/wiki/HTTP_Public_Key_Pinning\n    resolver - Enable DNS lookups and use this\n        resolver\n    use_dns_cache - Use memory cache for DNS lookups.\n    ttl_dns_cache - Max seconds having cached a DNS entry, None forever.\n    family - socket address family\n    local_addr - local tuple of (host, port) to bind socket to\n\n    keepalive_timeout - (optional) Keep-alive timeout.\n    force_close - Set to True to force close and do reconnect\n        after each request (and between redirects).\n    limit - The total number of simultaneous connections.\n    limit_per_host - Number of simultaneous connections to one host.\n    enable_cleanup_closed - Enables clean-up closed ssl transports.\n                            Disabled by default.\n    happy_eyeballs_delay - This is the \u201cConnection Attempt Delay\u201d\n                           as defined in RFC 8305. To disable\n                           the happy eyeballs algorithm, set to None.\n    interleave - \u201cFirst Address Family Count\u201d as defined in RFC 8305\n    loop - Optional event loop.\n    \"\"\"\n\n    allowed_protocol_schema_set = HIGH_LEVEL_SCHEMA_SET | frozenset({\"tcp\"})\n    _made_ssl_context: Dict[bool, \"asyncio.Future[SSLContext]\"] = {}\n\n    def __init__(\n        self,\n        *,\n        verify_ssl: bool = True,\n        fingerprint: Optional[bytes] = None,\n        use_dns_cache: bool = True,\n        ttl_dns_cache: Optional[int] = 10,\n        family: socket.AddressFamily = socket.AddressFamily.AF_UNSPEC,\n        ssl_context: Optional[SSLContext] = None,\n        ssl: Union[bool, Fingerprint, SSLContext] = True,\n        local_addr: Optional[Tuple[str, int]] = None,\n        resolver: Optional[AbstractResolver] = None,\n        keepalive_timeout: Union[None, float, object] = sentinel,\n        force_close: bool = False,\n        limit: int = 100,\n        limit_per_host: int = 0,\n        enable_cleanup_closed: bool = False,\n        loop: Optional[asyncio.AbstractEventLoop] = None,\n        timeout_ceil_threshold: float = 5,\n        happy_eyeballs_delay: Optional[float] = 0.25,\n        interleave: Optional[int] = None,\n    ):\n        super().__init__(\n            keepalive_timeout=keepalive_timeout,\n            force_close=force_close,\n            limit=limit,\n            limit_per_host=limit_per_host,\n            enable_cleanup_closed=enable_cleanup_closed,\n            loop=loop,\n            timeout_ceil_threshold=timeout_ceil_threshold,\n        )\n\n        self._ssl = _merge_ssl_params(ssl, verify_ssl, ssl_context, fingerprint)\n        if resolver is None:\n            resolver = DefaultResolver(loop=self._loop)\n        self._resolver = resolver\n\n        self._use_dns_cache = use_dns_cache\n        self._cached_hosts = _DNSCacheTable(ttl=ttl_dns_cache)\n        self._throttle_dns_events: Dict[Tuple[str, int], EventResultOrError] = {}\n        self._family = family\n        self._local_addr_infos = aiohappyeyeballs.addr_to_addr_infos(local_addr)\n        self._happy_eyeballs_delay = happy_eyeballs_delay\n        self._interleave = interleave\n\n    def close(self) -> Awaitable[None]:\n        \"\"\"Close all ongoing DNS calls.\"\"\"\n        for ev in self._throttle_dns_events.values():\n            ev.cancel()\n\n        return super().close()\n\n    @property\n    def family(self) -> int:\n        \"\"\"Socket family like AF_INET.\"\"\"\n        return self._family\n\n    @property\n    def use_dns_cache(self) -> bool:\n        \"\"\"True if local DNS caching is enabled.\"\"\"\n        return self._use_dns_cache\n\n    def clear_dns_cache(\n        self, host: Optional[str] = None, port: Optional[int] = None\n    ) -> None:\n        \"\"\"Remove specified host/port or clear all dns local cache.\"\"\"\n        if host is not None and port is not None:\n            self._cached_hosts.remove((host, port))\n        elif host is not None or port is not None:\n            raise ValueError(\"either both host and port \" \"or none of them are allowed\")\n        else:\n            self._cached_hosts.clear()\n\n    async def _resolve_host(\n        self, host: str, port: int, traces: Optional[Sequence[\"Trace\"]] = None\n    ) -> List[ResolveResult]:\n        \"\"\"Resolve host and return list of addresses.\"\"\"\n        if is_ip_address(host):\n            return [\n                {\n                    \"hostname\": host,\n                    \"host\": host,\n                    \"port\": port,\n                    \"family\": self._family,\n                    \"proto\": 0,\n                    \"flags\": 0,\n                }\n            ]\n\n        if not self._use_dns_cache:\n\n            if traces:\n                for trace in traces:\n                    await trace.send_dns_resolvehost_start(host)\n\n            res = await self._resolver.resolve(host, port, family=self._family)\n\n            if traces:\n                for trace in traces:\n                    await trace.send_dns_resolvehost_end(host)\n\n            return res\n\n        key = (host, port)\n        if key in self._cached_hosts and not self._cached_hosts.expired(key):\n            # get result early, before any await (#4014)\n            result = self._cached_hosts.next_addrs(key)\n\n            if traces:\n                for trace in traces:\n                    await trace.send_dns_cache_hit(host)\n            return result\n\n        #\n        # If multiple connectors are resolving the same host, we wait\n        # for the first one to resolve and then use the result for all of them.\n        # We use a throttle event to ensure that we only resolve the host once\n        # and then use the result for all the waiters.\n        #\n        # In this case we need to create a task to ensure that we can shield\n        # the task from cancellation as cancelling this lookup should not cancel\n        # the underlying lookup or else the cancel event will get broadcast to\n        # all the waiters across all connections.\n        #\n        resolved_host_task = asyncio.create_task(\n            self._resolve_host_with_throttle(key, host, port, traces)\n        )\n        try:\n            return await asyncio.shield(resolved_host_task)\n        except asyncio.CancelledError:\n\n            def drop_exception(fut: \"asyncio.Future[List[ResolveResult]]\") -> None:\n                with suppress(Exception, asyncio.CancelledError):\n                    fut.result()\n\n            resolved_host_task.add_done_callback(drop_exception)\n            raise\n\n    async def _resolve_host_with_throttle(\n        self,\n        key: Tuple[str, int],\n        host: str,\n        port: int,\n        traces: Optional[Sequence[\"Trace\"]],\n    ) -> List[ResolveResult]:\n        \"\"\"Resolve host with a dns events throttle.\"\"\"\n        if key in self._throttle_dns_events:\n            # get event early, before any await (#4014)\n            event = self._throttle_dns_events[key]\n            if traces:\n                for trace in traces:\n                    await trace.send_dns_cache_hit(host)\n            await event.wait()\n        else:\n            # update dict early, before any await (#4014)\n            self._throttle_dns_events[key] = EventResultOrError(self._loop)\n            if traces:\n                for trace in traces:\n                    await trace.send_dns_cache_miss(host)\n            try:\n\n                if traces:\n                    for trace in traces:\n                        await trace.send_dns_resolvehost_start(host)\n\n                addrs = await self._resolver.resolve(host, port, family=self._family)\n                if traces:\n                    for trace in traces:\n                        await trace.send_dns_resolvehost_end(host)\n\n                self._cached_hosts.add(key, addrs)\n                self._throttle_dns_events[key].set()\n            except BaseException as e:\n                # any DNS exception, independently of the implementation\n                # is set for the waiters to raise the same exception.\n                self._throttle_dns_events[key].set(exc=e)\n                raise\n            finally:\n                self._throttle_dns_events.pop(key)\n\n        return self._cached_hosts.next_addrs(key)\n\n    async def _create_connection(\n        self, req: ClientRequest, traces: List[\"Trace\"], timeout: \"ClientTimeout\"\n    ) -> ResponseHandler:\n        \"\"\"Create connection.\n\n        Has same keyword arguments as BaseEventLoop.create_connection.\n        \"\"\"\n        if req.proxy:\n            _, proto = await self._create_proxy_connection(req, traces, timeout)\n        else:\n            _, proto = await self._create_direct_connection(req, traces, timeout)\n\n        return proto\n\n    @staticmethod\n    def _make_ssl_context(verified: bool) -> SSLContext:\n        \"\"\"Create SSL context.\n\n        This method is not async-friendly and should be called from a thread\n        because it will load certificates from disk and do other blocking I/O.\n        \"\"\"\n        if verified:\n            return ssl.create_default_context()\n        sslcontext = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)\n        sslcontext.options |= ssl.OP_NO_SSLv2\n        sslcontext.options |= ssl.OP_NO_SSLv3\n        sslcontext.check_hostname = False\n        sslcontext.verify_mode = ssl.CERT_NONE\n        sslcontext.options |= ssl.OP_NO_COMPRESSION\n        sslcontext.set_default_verify_paths()\n        return sslcontext\n\n    async def _get_ssl_context(self, req: ClientRequest) -> Optional[SSLContext]:\n        \"\"\"Logic to get the correct SSL context\n\n        0. if req.ssl is false, return None\n\n        1. if ssl_context is specified in req, use it\n        2. if _ssl_context is specified in self, use it\n        3. otherwise:\n            1. if verify_ssl is not specified in req, use self.ssl_context\n               (will generate a default context according to self.verify_ssl)\n            2. if verify_ssl is True in req, generate a default SSL context\n            3. if verify_ssl is False in req, generate a SSL context that\n               won't verify\n        \"\"\"\n        if not req.is_ssl():\n            return None\n\n        if ssl is None:  # pragma: no cover\n            raise RuntimeError(\"SSL is not supported.\")\n        sslcontext = req.ssl\n        if isinstance(sslcontext, ssl.SSLContext):\n            return sslcontext\n        if sslcontext is not True:\n            # not verified or fingerprinted\n            return await self._make_or_get_ssl_context(False)\n        sslcontext = self._ssl\n        if isinstance(sslcontext, ssl.SSLContext):\n            return sslcontext\n        if sslcontext is not True:\n            # not verified or fingerprinted\n            return await self._make_or_get_ssl_context(False)\n        return await self._make_or_get_ssl_context(True)\n\n    async def _make_or_get_ssl_context(self, verified: bool) -> SSLContext:\n        \"\"\"Create or get cached SSL context.\"\"\"\n        try:\n            return await self._made_ssl_context[verified]\n        except KeyError:\n            loop = self._loop\n            future = loop.create_future()\n            self._made_ssl_context[verified] = future\n            try:\n                result = await loop.run_in_executor(\n                    None, self._make_ssl_context, verified\n                )\n            # BaseException is used since we might get CancelledError\n            except BaseException as ex:\n                del self._made_ssl_context[verified]\n                set_exception(future, ex)\n                raise\n            else:\n                set_result(future, result)\n            return result\n\n    def _get_fingerprint(self, req: ClientRequest) -> Optional[\"Fingerprint\"]:\n        ret = req.ssl\n        if isinstance(ret, Fingerprint):\n            return ret\n        ret = self._ssl\n        if isinstance(ret, Fingerprint):\n            return ret\n        return None\n\n    async def _wrap_create_connection(\n        self,\n        *args: Any,\n        addr_infos: List[aiohappyeyeballs.AddrInfoType],\n        req: ClientRequest,\n        timeout: \"ClientTimeout\",\n        client_error: Type[Exception] = ClientConnectorError,\n        **kwargs: Any,\n    ) -> Tuple[asyncio.Transport, ResponseHandler]:\n        try:\n            async with ceil_timeout(\n                timeout.sock_connect, ceil_threshold=timeout.ceil_threshold\n            ):\n                sock = await aiohappyeyeballs.start_connection(\n                    addr_infos=addr_infos,\n                    local_addr_infos=self._local_addr_infos,\n                    happy_eyeballs_delay=self._happy_eyeballs_delay,\n                    interleave=self._interleave,\n                    loop=self._loop,\n                )\n                return await self._loop.create_connection(*args, **kwargs, sock=sock)\n        except cert_errors as exc:\n            raise ClientConnectorCertificateError(req.connection_key, exc) from exc\n        except ssl_errors as exc:\n            raise ClientConnectorSSLError(req.connection_key, exc) from exc\n        except OSError as exc:\n            if exc.errno is None and isinstance(exc, asyncio.TimeoutError):\n                raise\n            raise client_error(req.connection_key, exc) from exc\n\n    async def _wrap_existing_connection(\n        self,\n        *args: Any,\n        req: ClientRequest,\n        timeout: \"ClientTimeout\",\n        client_error: Type[Exception] = ClientConnectorError,\n        **kwargs: Any,\n    ) -> Tuple[asyncio.Transport, ResponseHandler]:\n        try:\n            async with ceil_timeout(\n                timeout.sock_connect, ceil_threshold=timeout.ceil_threshold\n            ):\n                return await self._loop.create_connection(*args, **kwargs)\n        except cert_errors as exc:\n            raise ClientConnectorCertificateError(req.connection_key, exc) from exc\n        except ssl_errors as exc:\n            raise ClientConnectorSSLError(req.connection_key, exc) from exc\n        except OSError as exc:\n            if exc.errno is None and isinstance(exc, asyncio.TimeoutError):\n                raise\n            raise client_error(req.connection_key, exc) from exc\n\n    def _fail_on_no_start_tls(self, req: \"ClientRequest\") -> None:\n        \"\"\"Raise a :py:exc:`RuntimeError` on missing ``start_tls()``.\n\n        It is necessary for TLS-in-TLS so that it is possible to\n        send HTTPS queries through HTTPS proxies.\n\n        This doesn't affect regular HTTP requests, though.\n        \"\"\"\n        if not req.is_ssl():\n            return\n\n        proxy_url = req.proxy\n        assert proxy_url is not None\n        if proxy_url.scheme != \"https\":\n            return\n\n        self._check_loop_for_start_tls()\n\n    def _check_loop_for_start_tls(self) -> None:\n        try:\n            self._loop.start_tls\n        except AttributeError as attr_exc:\n            raise RuntimeError(\n                \"An HTTPS request is being sent through an HTTPS proxy. \"\n                \"This needs support for TLS in TLS but it is not implemented \"\n                \"in your runtime for the stdlib asyncio.\\n\\n\"\n                \"Please upgrade to Python 3.11 or higher. For more details, \"\n                \"please see:\\n\"\n                \"* https://bugs.python.org/issue37179\\n\"\n                \"* https://github.com/python/cpython/pull/28073\\n\"\n                \"* https://docs.aiohttp.org/en/stable/\"\n                \"client_advanced.html#proxy-support\\n\"\n                \"* https://github.com/aio-libs/aiohttp/discussions/6044\\n\",\n            ) from attr_exc\n\n    def _loop_supports_start_tls(self) -> bool:\n        try:\n            self._check_loop_for_start_tls()\n        except RuntimeError:\n            return False\n        else:\n            return True\n\n    def _warn_about_tls_in_tls(\n        self,\n        underlying_transport: asyncio.Transport,\n        req: ClientRequest,\n    ) -> None:\n        \"\"\"Issue a warning if the requested URL has HTTPS scheme.\"\"\"\n        if req.request_info.url.scheme != \"https\":\n            return\n\n        asyncio_supports_tls_in_tls = getattr(\n            underlying_transport,\n            \"_start_tls_compatible\",\n            False,\n        )\n\n        if asyncio_supports_tls_in_tls:\n            return\n\n        warnings.warn(\n            \"An HTTPS request is being sent through an HTTPS proxy. \"\n            \"This support for TLS in TLS is known to be disabled \"\n            \"in the stdlib asyncio (Python <3.11). This is why you'll probably see \"\n            \"an error in the log below.\\n\\n\"\n            \"It is possible to enable it via monkeypatching. \"\n            \"For more details, see:\\n\"\n            \"* https://bugs.python.org/issue37179\\n\"\n            \"* https://github.com/python/cpython/pull/28073\\n\\n\"\n            \"You can temporarily patch this as follows:\\n\"\n            \"* https://docs.aiohttp.org/en/stable/client_advanced.html#proxy-support\\n\"\n            \"* https://github.com/aio-libs/aiohttp/discussions/6044\\n\",\n            RuntimeWarning,\n            source=self,\n            # Why `4`? At least 3 of the calls in the stack originate\n            # from the methods in this class.\n            stacklevel=3,\n        )\n\n    async def _start_tls_connection(\n        self,\n        underlying_transport: asyncio.Transport,\n        req: ClientRequest,\n        timeout: \"ClientTimeout\",\n        client_error: Type[Exception] = ClientConnectorError,\n    ) -> Tuple[asyncio.BaseTransport, ResponseHandler]:\n        \"\"\"Wrap the raw TCP transport with TLS.\"\"\"\n        tls_proto = self._factory()  # Create a brand new proto for TLS\n\n        # Safety of the `cast()` call here is based on the fact that\n        # internally `_get_ssl_context()` only returns `None` when\n        # `req.is_ssl()` evaluates to `False` which is never gonna happen\n        # in this code path. Of course, it's rather fragile\n        # maintainability-wise but this is to be solved separately.\n        sslcontext = cast(ssl.SSLContext, await self._get_ssl_context(req))\n\n        try:\n            async with ceil_timeout(\n                timeout.sock_connect, ceil_threshold=timeout.ceil_threshold\n            ):\n                try:\n                    tls_transport = await self._loop.start_tls(\n                        underlying_transport,\n                        tls_proto,\n                        sslcontext,\n                        server_hostname=req.server_hostname or req.host,\n                        ssl_handshake_timeout=timeout.total,\n                    )\n                except BaseException:\n                    # We need to close the underlying transport since\n                    # `start_tls()` probably failed before it had a\n                    # chance to do this:\n                    underlying_transport.close()\n                    raise\n        except cert_errors as exc:\n            raise ClientConnectorCertificateError(req.connection_key, exc) from exc\n        except ssl_errors as exc:\n            raise ClientConnectorSSLError(req.connection_key, exc) from exc\n        except OSError as exc:\n            if exc.errno is None and isinstance(exc, asyncio.TimeoutError):\n                raise\n            raise client_error(req.connection_key, exc) from exc\n        except TypeError as type_err:\n            # Example cause looks like this:\n            # TypeError: transport <asyncio.sslproto._SSLProtocolTransport\n            # object at 0x7f760615e460> is not supported by start_tls()\n\n            raise ClientConnectionError(\n                \"Cannot initialize a TLS-in-TLS connection to host \"\n                f\"{req.host!s}:{req.port:d} through an underlying connection \"\n                f\"to an HTTPS proxy {req.proxy!s} ssl:{req.ssl or 'default'} \"\n                f\"[{type_err!s}]\"\n            ) from type_err\n        else:\n            if tls_transport is None:\n                msg = \"Failed to start TLS (possibly caused by closing transport)\"\n                raise client_error(req.connection_key, OSError(msg))\n            tls_proto.connection_made(\n                tls_transport\n            )  # Kick the state machine of the new TLS protocol\n\n        return tls_transport, tls_proto\n\n    def _convert_hosts_to_addr_infos(\n        self, hosts: List[ResolveResult]\n    ) -> List[aiohappyeyeballs.AddrInfoType]:\n        \"\"\"Converts the list of hosts to a list of addr_infos.\n\n        The list of hosts is the result of a DNS lookup. The list of\n        addr_infos is the result of a call to `socket.getaddrinfo()`.\n        \"\"\"\n        addr_infos: List[aiohappyeyeballs.AddrInfoType] = []\n        for hinfo in hosts:\n            host = hinfo[\"host\"]\n            is_ipv6 = \":\" in host\n            family = socket.AF_INET6 if is_ipv6 else socket.AF_INET\n            if self._family and self._family != family:\n                continue\n            addr = (host, hinfo[\"port\"], 0, 0) if is_ipv6 else (host, hinfo[\"port\"])\n            addr_infos.append(\n                (family, socket.SOCK_STREAM, socket.IPPROTO_TCP, \"\", addr)\n            )\n        return addr_infos\n\n    async def _create_direct_connection(\n        self,\n        req: ClientRequest,\n        traces: List[\"Trace\"],\n        timeout: \"ClientTimeout\",\n        *,\n        client_error: Type[Exception] = ClientConnectorError,\n    ) -> Tuple[asyncio.Transport, ResponseHandler]:\n        sslcontext = await self._get_ssl_context(req)\n        fingerprint = self._get_fingerprint(req)\n\n        host = req.url.raw_host\n        assert host is not None\n        # Replace multiple trailing dots with a single one.\n        # A trailing dot is only present for fully-qualified domain names.\n        # See https://github.com/aio-libs/aiohttp/pull/7364.\n        if host.endswith(\"..\"):\n            host = host.rstrip(\".\") + \".\"\n        port = req.port\n        assert port is not None\n        try:\n            # Cancelling this lookup should not cancel the underlying lookup\n            #  or else the cancel event will get broadcast to all the waiters\n            #  across all connections.\n            hosts = await self._resolve_host(host, port, traces=traces)\n        except OSError as exc:\n            if exc.errno is None and isinstance(exc, asyncio.TimeoutError):\n                raise\n            # in case of proxy it is not ClientProxyConnectionError\n            # it is problem of resolving proxy ip itself\n            raise ClientConnectorError(req.connection_key, exc) from exc\n\n        last_exc: Optional[Exception] = None\n        addr_infos = self._convert_hosts_to_addr_infos(hosts)\n        while addr_infos:\n            # Strip trailing dots, certificates contain FQDN without dots.\n            # See https://github.com/aio-libs/aiohttp/issues/3636\n            server_hostname = (\n                (req.server_hostname or host).rstrip(\".\") if sslcontext else None\n            )\n\n            try:\n                transp, proto = await self._wrap_create_connection(\n                    self._factory,\n                    timeout=timeout,\n                    ssl=sslcontext,\n                    addr_infos=addr_infos,\n                    server_hostname=server_hostname,\n                    req=req,\n                    client_error=client_error,\n                )\n            except ClientConnectorError as exc:\n                last_exc = exc\n                aiohappyeyeballs.pop_addr_infos_interleave(addr_infos, self._interleave)\n                continue\n\n            if req.is_ssl() and fingerprint:\n                try:\n                    fingerprint.check(transp)\n                except ServerFingerprintMismatch as exc:\n                    transp.close()\n                    if not self._cleanup_closed_disabled:\n                        self._cleanup_closed_transports.append(transp)\n                    last_exc = exc\n                    # Remove the bad peer from the list of addr_infos\n                    sock: socket.socket = transp.get_extra_info(\"socket\")\n                    bad_peer = sock.getpeername()\n                    aiohappyeyeballs.remove_addr_infos(addr_infos, bad_peer)\n                    continue\n\n            return transp, proto\n        else:\n            assert last_exc is not None\n            raise last_exc\n\n    async def _create_proxy_connection(\n        self, req: ClientRequest, traces: List[\"Trace\"], timeout: \"ClientTimeout\"\n    ) -> Tuple[asyncio.BaseTransport, ResponseHandler]:\n        self._fail_on_no_start_tls(req)\n        runtime_has_start_tls = self._loop_supports_start_tls()\n\n        headers: Dict[str, str] = {}\n        if req.proxy_headers is not None:\n            headers = req.proxy_headers  # type: ignore[assignment]\n        headers[hdrs.HOST] = req.headers[hdrs.HOST]\n\n        url = req.proxy\n        assert url is not None\n        proxy_req = ClientRequest(\n            hdrs.METH_GET,\n            url,\n            headers=headers,\n            auth=req.proxy_auth,\n            loop=self._loop,\n            ssl=req.ssl,\n        )\n\n        # create connection to proxy server\n        transport, proto = await self._create_direct_connection(\n            proxy_req, [], timeout, client_error=ClientProxyConnectionError\n        )\n\n        auth = proxy_req.headers.pop(hdrs.AUTHORIZATION, None)\n        if auth is not None:\n            if not req.is_ssl():\n                req.headers[hdrs.PROXY_AUTHORIZATION] = auth\n            else:\n                proxy_req.headers[hdrs.PROXY_AUTHORIZATION] = auth\n\n        if req.is_ssl():\n            if runtime_has_start_tls:\n                self._warn_about_tls_in_tls(transport, req)\n\n            # For HTTPS requests over HTTP proxy\n            # we must notify proxy to tunnel connection\n            # so we send CONNECT command:\n            #   CONNECT www.python.org:443 HTTP/1.1\n            #   Host: www.python.org\n            #\n            # next we must do TLS handshake and so on\n            # to do this we must wrap raw socket into secure one\n            # asyncio handles this perfectly\n            proxy_req.method = hdrs.METH_CONNECT\n            proxy_req.url = req.url\n            key = attr.evolve(\n                req.connection_key, proxy=None, proxy_auth=None, proxy_headers_hash=None\n            )\n            conn = Connection(self, key, proto, self._loop)\n            proxy_resp = await proxy_req.send(conn)\n            try:\n                protocol = conn._protocol\n                assert protocol is not None\n\n                # read_until_eof=True will ensure the connection isn't closed\n                # once the response is received and processed allowing\n                # START_TLS to work on the connection below.\n                protocol.set_response_params(\n                    read_until_eof=runtime_has_start_tls,\n                    timeout_ceil_threshold=self._timeout_ceil_threshold,\n                )\n                resp = await proxy_resp.start(conn)\n            except BaseException:\n                proxy_resp.close()\n                conn.close()\n                raise\n            else:\n                conn._protocol = None\n                conn._transport = None\n                try:\n                    if resp.status != 200:\n                        message = resp.reason\n                        if message is None:\n                            message = HTTPStatus(resp.status).phrase\n                        raise ClientHttpProxyError(\n                            proxy_resp.request_info,\n                            resp.history,\n                            status=resp.status,\n                            message=message,\n                            headers=resp.headers,\n                        )\n                    if not runtime_has_start_tls:\n                        rawsock = transport.get_extra_info(\"socket\", default=None)\n                        if rawsock is None:\n                            raise RuntimeError(\n                                \"Transport does not expose socket instance\"\n                            )\n                        # Duplicate the socket, so now we can close proxy transport\n                        rawsock = rawsock.dup()\n                except BaseException:\n                    # It shouldn't be closed in `finally` because it's fed to\n                    # `loop.start_tls()` and the docs say not to touch it after\n                    # passing there.\n                    transport.close()\n                    raise\n                finally:\n                    if not runtime_has_start_tls:\n                        transport.close()\n\n                if not runtime_has_start_tls:\n                    # HTTP proxy with support for upgrade to HTTPS\n                    sslcontext = self._get_ssl_context(req)\n                    return await self._wrap_existing_connection(\n                        self._factory,\n                        timeout=timeout,\n                        ssl=sslcontext,\n                        sock=rawsock,\n                        server_hostname=req.host,\n                        req=req,\n                    )\n\n                return await self._start_tls_connection(\n                    # Access the old transport for the last time before it's\n                    # closed and forgotten forever:\n                    transport,\n                    req=req,\n                    timeout=timeout,\n                )\n            finally:\n                proxy_resp.close()\n\n        return transport, proto\n\n\nclass UnixConnector(BaseConnector):\n    \"\"\"Unix socket connector.\n\n    path - Unix socket path.\n    keepalive_timeout - (optional) Keep-alive timeout.\n    force_close - Set to True to force close and do reconnect\n        after each request (and between redirects).\n    limit - The total number of simultaneous connections.\n    limit_per_host - Number of simultaneous connections to one host.\n    loop - Optional event loop.\n    \"\"\"\n\n    allowed_protocol_schema_set = HIGH_LEVEL_SCHEMA_SET | frozenset({\"unix\"})\n\n    def __init__(\n        self,\n        path: str,\n        force_close: bool = False,\n        keepalive_timeout: Union[object, float, None] = sentinel,\n        limit: int = 100,\n        limit_per_host: int = 0,\n        loop: Optional[asyncio.AbstractEventLoop] = None,\n    ) -> None:\n        super().__init__(\n            force_close=force_close,\n            keepalive_timeout=keepalive_timeout,\n            limit=limit,\n            limit_per_host=limit_per_host,\n            loop=loop,\n        )\n        self._path = path\n\n    @property\n    def path(self) -> str:\n        \"\"\"Path to unix socket.\"\"\"\n        return self._path\n\n    async def _create_connection(\n        self, req: ClientRequest, traces: List[\"Trace\"], timeout: \"ClientTimeout\"\n    ) -> ResponseHandler:\n        try:\n            async with ceil_timeout(\n                timeout.sock_connect, ceil_threshold=timeout.ceil_threshold\n            ):\n                _, proto = await self._loop.create_unix_connection(\n                    self._factory, self._path\n                )\n        except OSError as exc:\n            if exc.errno is None and isinstance(exc, asyncio.TimeoutError):\n                raise\n            raise UnixClientConnectorError(self.path, req.connection_key, exc) from exc\n\n        return proto\n\n\nclass NamedPipeConnector(BaseConnector):\n    \"\"\"Named pipe connector.\n\n    Only supported by the proactor event loop.\n    See also: https://docs.python.org/3/library/asyncio-eventloop.html\n\n    path - Windows named pipe path.\n    keepalive_timeout - (optional) Keep-alive timeout.\n    force_close - Set to True to force close and do reconnect\n        after each request (and between redirects).\n    limit - The total number of simultaneous connections.\n    limit_per_host - Number of simultaneous connections to one host.\n    loop - Optional event loop.\n    \"\"\"\n\n    allowed_protocol_schema_set = HIGH_LEVEL_SCHEMA_SET | frozenset({\"npipe\"})\n\n    def __init__(\n        self,\n        path: str,\n        force_close: bool = False,\n        keepalive_timeout: Union[object, float, None] = sentinel,\n        limit: int = 100,\n        limit_per_host: int = 0,\n        loop: Optional[asyncio.AbstractEventLoop] = None,\n    ) -> None:\n        super().__init__(\n            force_close=force_close,\n            keepalive_timeout=keepalive_timeout,\n            limit=limit,\n            limit_per_host=limit_per_host,\n            loop=loop,\n        )\n        if not isinstance(\n            self._loop, asyncio.ProactorEventLoop  # type: ignore[attr-defined]\n        ):\n            raise RuntimeError(\n                \"Named Pipes only available in proactor \" \"loop under windows\"\n            )\n        self._path = path\n\n    @property\n    def path(self) -> str:\n        \"\"\"Path to the named pipe.\"\"\"\n        return self._path\n\n    async def _create_connection(\n        self, req: ClientRequest, traces: List[\"Trace\"], timeout: \"ClientTimeout\"\n    ) -> ResponseHandler:\n        try:\n            async with ceil_timeout(\n                timeout.sock_connect, ceil_threshold=timeout.ceil_threshold\n            ):\n                _, proto = await self._loop.create_pipe_connection(  # type: ignore[attr-defined]\n                    self._factory, self._path\n                )\n                # the drain is required so that the connection_made is called\n                # and transport is set otherwise it is not set before the\n                # `assert conn.transport is not None`\n                # in client.py's _request method\n                await asyncio.sleep(0)\n                # other option is to manually set transport like\n                # `proto.transport = trans`\n        except OSError as exc:\n            if exc.errno is None and isinstance(exc, asyncio.TimeoutError):\n                raise\n            raise ClientConnectorError(req.connection_key, exc) from exc\n\n        return cast(ResponseHandler, proto)\n"}
A user will ask you to solve a task. You should first draft your thinking process (inner monologue). Then, generate the solution.

Your response format must follow the template below:
<think>
Your thoughts or/and draft, like working through an exercise on scratch paper. Be as casual and as long as you want until you are confident to generate a correct solution.
</think>
<solution>
Final solution presented to the user.
</solution>
system
We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
[ISSUE]
**Title:** Closing TCPConnector does not cancel pending resolve_host tasks, causing pending Task errors

**Description:**
When closing an `aiohttp.TCPConnector`, any ongoing DNS resolution tasks are not properly canceled. This leads to warnings such as "Task was destroyed but it is pending" because the connector does not track and cancel these tasks as expected.

**Example Code:**

```python
async def simulate_connector_close():
    cancelled = False

    async def delay_resolve_host(*args):
        try:
            await asyncio.sleep(10)
        except asyncio.CancelledError:
            cancelled = True
            raise

    conn = aiohttp.TCPConnector()
    req = ClientRequest('GET', URL('http://localhost:80'), loop=asyncio.get_event_loop(), response_class=mock.Mock())
    
    with mock.patch.object(conn, '_resolve_host_with_throttle', delay_resolve_host):
        asyncio.create_task(conn.connect(req, [], ClientTimeout()))
        await asyncio.sleep(0)  # Allow task to start
        await conn.close()
        # At this point, the resolve_host task should be cancelled
```

**Expected Behavior:**
Closing the `TCPConnector` should cancel all ongoing `resolve_host` tasks, ensuring that no tasks remain pending and no related warnings are emitted.

**Actual Behavior:**
Closing the connector does not cancel the pending `resolve_host` tasks, resulting in warnings about pending tasks being destroyed.

[/ISSUE]
--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.

--- BEGIN FILE ---
```
### aiohttp/connector.py
import asyncio
import functools
import random
import socket
import sys
import traceback
import warnings
from collections import defaultdict, deque
from contextlib import suppress
from http import HTTPStatus
from http.cookies import SimpleCookie
from itertools import cycle, islice
from time import monotonic
from types import TracebackType
from typing import (
    TYPE_CHECKING,
    Any,
    Awaitable,
    Callable,
    DefaultDict,
    Dict,
    Iterator,
    List,
    Literal,
    Optional,
    Sequence,
    Set,
    Tuple,
    Type,
    Union,
    cast,
)

import aiohappyeyeballs
import attr

from . import hdrs, helpers
from .abc import AbstractResolver, ResolveResult
from .client_exceptions import (
    ClientConnectionError,
    ClientConnectorCertificateError,
    ClientConnectorError,
    ClientConnectorSSLError,
    ClientHttpProxyError,
    ClientProxyConnectionError,
    ServerFingerprintMismatch,
    UnixClientConnectorError,
    cert_errors,
    ssl_errors,
)
from .client_proto import ResponseHandler
from .client_reqrep import ClientRequest, Fingerprint, _merge_ssl_params
from .helpers import (
    ceil_timeout,
    is_ip_address,
    noop,
    sentinel,
    set_exception,
    set_result,
)
from .locks import EventResultOrError
from .resolver import DefaultResolver

try:
    import ssl

    SSLContext = ssl.SSLContext
except ImportError:  # pragma: no cover
    ssl = None  # type: ignore[assignment]
    SSLContext = object  # type: ignore[misc,assignment]


EMPTY_SCHEMA_SET = frozenset({""})
HTTP_SCHEMA_SET = frozenset({"http", "https"})
WS_SCHEMA_SET = frozenset({"ws", "wss"})

HTTP_AND_EMPTY_SCHEMA_SET = HTTP_SCHEMA_SET | EMPTY_SCHEMA_SET
HIGH_LEVEL_SCHEMA_SET = HTTP_AND_EMPTY_SCHEMA_SET | WS_SCHEMA_SET


__all__ = ("BaseConnector", "TCPConnector", "UnixConnector", "NamedPipeConnector")


if TYPE_CHECKING:
    from .client import ClientTimeout
    from .client_reqrep import ConnectionKey
    from .tracing import Trace


class _DeprecationWaiter:
    __slots__ = ("_awaitable", "_awaited")

    def __init__(self, awaitable: Awaitable[Any]) -> None:
        self._awaitable = awaitable
        self._awaited = False

    def __await__(self) -> Any:
        self._awaited = True
        return self._awaitable.__await__()

    def __del__(self) -> None:
        if not self._awaited:
            warnings.warn(
                "Connector.close() is a coroutine, "
                "please use await connector.close()",
                DeprecationWarning,
            )


class Connection:

    _source_traceback = None
    _transport = None

    def __init__(
        self,
        connector: "BaseConnector",
        key: "ConnectionKey",
        protocol: ResponseHandler,
        loop: asyncio.AbstractEventLoop,
    ) -> None:
        self._key = key
        self._connector = connector
        self._loop = loop
        self._protocol: Optional[ResponseHandler] = protocol
        self._callbacks: List[Callable[[], None]] = []

        if loop.get_debug():
            self._source_traceback = traceback.extract_stack(sys._getframe(1))

    def __repr__(self) -> str:
        return f"Connection<{self._key}>"

    def __del__(self, _warnings: Any = warnings) -> None:
        if self._protocol is not None:
            kwargs = {"source": self}
            _warnings.warn(f"Unclosed connection {self!r}", ResourceWarning, **kwargs)
            if self._loop.is_closed():
                return

            self._connector._release(self._key, self._protocol, should_close=True)

            context = {"client_connection": self, "message": "Unclosed connection"}
            if self._source_traceback is not None:
                context["source_traceback"] = self._source_traceback
            self._loop.call_exception_handler(context)

    def __bool__(self) -> Literal[True]:
        """Force subclasses to not be falsy, to make checks simpler."""
        return True

    @property
    def loop(self) -> asyncio.AbstractEventLoop:
        warnings.warn(
            "connector.loop property is deprecated", DeprecationWarning, stacklevel=2
        )
        return self._loop

    @property
    def transport(self) -> Optional[asyncio.Transport]:
        if self._protocol is None:
            return None
        return self._protocol.transport

    @property
    def protocol(self) -> Optional[ResponseHandler]:
        return self._protocol

    def add_callback(self, callback: Callable[[], None]) -> None:
        if callback is not None:
            self._callbacks.append(callback)

    def _notify_release(self) -> None:
        callbacks, self._callbacks = self._callbacks[:], []

        for cb in callbacks:
            with suppress(Exception):
                cb()

    def close(self) -> None:
        self._notify_release()

        if self._protocol is not None:
            self._connector._release(self._key, self._protocol, should_close=True)
            self._protocol = None

    def release(self) -> None:
        self._notify_release()

        if self._protocol is not None:
            self._connector._release(
                self._key, self._protocol, should_close=self._protocol.should_close
            )
            self._protocol = None

    @property
    def closed(self) -> bool:
        return self._protocol is None or not self._protocol.is_connected()


class _TransportPlaceholder:
    """placeholder for BaseConnector.connect function"""

    def close(self) -> None:
        pass


class BaseConnector:
    """Base connector class.

    keepalive_timeout - (optional) Keep-alive timeout.
    force_close - Set to True to force close and do reconnect
        after each request (and between redirects).
    limit - The total number of simultaneous connections.
    limit_per_host - Number of simultaneous connections to one host.
    enable_cleanup_closed - Enables clean-up closed ssl transports.
                            Disabled by default.
    timeout_ceil_threshold - Trigger ceiling of timeout values when
                             it's above timeout_ceil_threshold.
    loop - Optional event loop.
    """

    _closed = True  # prevent AttributeError in __del__ if ctor was failed
    _source_traceback = None

    # abort transport after 2 seconds (cleanup broken connections)
    _cleanup_closed_period = 2.0

    allowed_protocol_schema_set = HIGH_LEVEL_SCHEMA_SET

    def __init__(
        self,
        *,
        keepalive_timeout: Union[object, None, float] = sentinel,
        force_close: bool = False,
        limit: int = 100,
        limit_per_host: int = 0,
        enable_cleanup_closed: bool = False,
        loop: Optional[asyncio.AbstractEventLoop] = None,
        timeout_ceil_threshold: float = 5,
    ) -> None:

        if force_close:
            if keepalive_timeout is not None and keepalive_timeout is not sentinel:
                raise ValueError(
                    "keepalive_timeout cannot " "be set if force_close is True"
                )
        else:
            if keepalive_timeout is sentinel:
                keepalive_timeout = 15.0

        loop = loop or asyncio.get_running_loop()
        self._timeout_ceil_threshold = timeout_ceil_threshold

        self._closed = False
        if loop.get_debug():
            self._source_traceback = traceback.extract_stack(sys._getframe(1))

        self._conns: Dict[ConnectionKey, List[Tuple[ResponseHandler, float]]] = {}
        self._limit = limit
        self._limit_per_host = limit_per_host
        self._acquired: Set[ResponseHandler] = set()
        self._acquired_per_host: DefaultDict[ConnectionKey, Set[ResponseHandler]] = (
            defaultdict(set)
        )
        self._keepalive_timeout = cast(float, keepalive_timeout)
        self._force_close = force_close

        # {host_key: FIFO list of waiters}
        self._waiters = defaultdict(deque)  # type: ignore[var-annotated]

        self._loop = loop
        self._factory = functools.partial(ResponseHandler, loop=loop)

        self.cookies = SimpleCookie()

        # start keep-alive connection cleanup task
        self._cleanup_handle: Optional[asyncio.TimerHandle] = None

        # start cleanup closed transports task
        self._cleanup_closed_handle: Optional[asyncio.TimerHandle] = None
        self._cleanup_closed_disabled = not enable_cleanup_closed
        self._cleanup_closed_transports: List[Optional[asyncio.Transport]] = []
        self._cleanup_closed()

    def __del__(self, _warnings: Any = warnings) -> None:
        if self._closed:
            return
        if not self._conns:
            return

        conns = [repr(c) for c in self._conns.values()]

        self._close()

        kwargs = {"source": self}
        _warnings.warn(f"Unclosed connector {self!r}", ResourceWarning, **kwargs)
        context = {
            "connector": self,
            "connections": conns,
            "message": "Unclosed connector",
        }
        if self._source_traceback is not None:
            context["source_traceback"] = self._source_traceback
        self._loop.call_exception_handler(context)

    def __enter__(self) -> "BaseConnector":
        warnings.warn(
            '"with Connector():" is deprecated, '
            'use "async with Connector():" instead',
            DeprecationWarning,
        )
        return self

    def __exit__(self, *exc: Any) -> None:
        self._close()

    async def __aenter__(self) -> "BaseConnector":
        return self

    async def __aexit__(
        self,
        exc_type: Optional[Type[BaseException]] = None,
        exc_value: Optional[BaseException] = None,
        exc_traceback: Optional[TracebackType] = None,
    ) -> None:
        await self.close()

    @property
    def force_close(self) -> bool:
        """Ultimately close connection on releasing if True."""
        return self._force_close

    @property
    def limit(self) -> int:
        """The total number for simultaneous connections.

        If limit is 0 the connector has no limit.
        The default limit size is 100.
        """
        return self._limit

    @property
    def limit_per_host(self) -> int:
        """The limit for simultaneous connections to the same endpoint.

        Endpoints are the same if they are have equal
        (host, port, is_ssl) triple.
        """
        return self._limit_per_host

    def _cleanup(self) -> None:
        """Cleanup unused transports."""
        if self._cleanup_handle:
            self._cleanup_handle.cancel()
            # _cleanup_handle should be unset, otherwise _release() will not
            # recreate it ever!
            self._cleanup_handle = None

        now = self._loop.time()
        timeout = self._keepalive_timeout

        if self._conns:
            connections = {}
            deadline = now - timeout
            for key, conns in self._conns.items():
                alive = []
                for proto, use_time in conns:
                    if proto.is_connected():
                        if use_time - deadline < 0:
                            transport = proto.transport
                            proto.close()
                            if key.is_ssl and not self._cleanup_closed_disabled:
                                self._cleanup_closed_transports.append(transport)
                        else:
                            alive.append((proto, use_time))
                    else:
                        transport = proto.transport
                        proto.close()
                        if key.is_ssl and not self._cleanup_closed_disabled:
                            self._cleanup_closed_transports.append(transport)

                if alive:
                    connections[key] = alive

            self._conns = connections

        if self._conns:
            self._cleanup_handle = helpers.weakref_handle(
                self,
                "_cleanup",
                timeout,
                self._loop,
                timeout_ceil_threshold=self._timeout_ceil_threshold,
            )

    def _drop_acquired_per_host(
        self, key: "ConnectionKey", val: ResponseHandler
    ) -> None:
        acquired_per_host = self._acquired_per_host
        if key not in acquired_per_host:
            return
        conns = acquired_per_host[key]
        conns.remove(val)
        if not conns:
            del self._acquired_per_host[key]

    def _cleanup_closed(self) -> None:
        """Double confirmation for transport close.

        Some broken ssl servers may leave socket open without proper close.
        """
        if self._cleanup_closed_handle:
            self._cleanup_closed_handle.cancel()

        for transport in self._cleanup_closed_transports:
            if transport is not None:
                transport.abort()

        self._cleanup_closed_transports = []

        if not self._cleanup_closed_disabled:
            self._cleanup_closed_handle = helpers.weakref_handle(
                self,
                "_cleanup_closed",
                self._cleanup_closed_period,
                self._loop,
                timeout_ceil_threshold=self._timeout_ceil_threshold,
            )

    def close(self) -> Awaitable[None]:
        """Close all opened transports."""
        self._close()
        return _DeprecationWaiter(noop())

    def _close(self) -> None:
        if self._closed:
            return

        self._closed = True

        try:
            if self._loop.is_closed():
                return

            # cancel cleanup task
            if self._cleanup_handle:
                self._cleanup_handle.cancel()

            # cancel cleanup close task
            if self._cleanup_closed_handle:
                self._cleanup_closed_handle.cancel()

            for data in self._conns.values():
                for proto, t0 in data:
                    proto.close()

            for proto in self._acquired:
                proto.close()

            for transport in self._cleanup_closed_transports:
                if transport is not None:
                    transport.abort()

        finally:
            self._conns.clear()
            self._acquired.clear()
            self._waiters.clear()
            self._cleanup_handle = None
            self._cleanup_closed_transports.clear()
            self._cleanup_closed_handle = None

    @property
    def closed(self) -> bool:
        """Is connector closed.

        A readonly property.
        """
        return self._closed

    def _available_connections(self, key: "ConnectionKey") -> int:
        """
        Return number of available connections.

        The limit, limit_per_host and the connection key are taken into account.

        If it returns less than 1 means that there are no connections
        available.
        """
        if self._limit:
            # total calc available connections
            available = self._limit - len(self._acquired)

            # check limit per host
            if (
                self._limit_per_host
                and available > 0
                and key in self._acquired_per_host
            ):
                acquired = self._acquired_per_host.get(key)
                assert acquired is not None
                available = self._limit_per_host - len(acquired)

        elif self._limit_per_host and key in self._acquired_per_host:
            # check limit per host
            acquired = self._acquired_per_host.get(key)
            assert acquired is not None
            available = self._limit_per_host - len(acquired)
        else:
            available = 1

        return available

    async def connect(
        self, req: ClientRequest, traces: List["Trace"], timeout: "ClientTimeout"
    ) -> Connection:
        """Get from pool or create new connection."""
        key = req.connection_key
        available = self._available_connections(key)

        # Wait if there are no available connections or if there are/were
        # waiters (i.e. don't steal connection from a waiter about to wake up)
        if available <= 0 or key in self._waiters:
            fut = self._loop.create_future()

            # This connection will now count towards the limit.
            self._waiters[key].append(fut)

            if traces:
                for trace in traces:
                    await trace.send_connection_queued_start()

            try:
                await fut
            except BaseException as e:
                if key in self._waiters:
                    # remove a waiter even if it was cancelled, normally it's
                    #  removed when it's notified
                    try:
                        self._waiters[key].remove(fut)
                    except ValueError:  # fut may no longer be in list
                        pass

                raise e
            finally:
                if key in self._waiters and not self._waiters[key]:
                    del self._waiters[key]

            if traces:
                for trace in traces:
                    await trace.send_connection_queued_end()

        proto = self._get(key)
        if proto is None:
            placeholder = cast(ResponseHandler, _TransportPlaceholder())
            self._acquired.add(placeholder)
            self._acquired_per_host[key].add(placeholder)

            if traces:
                for trace in traces:
                    await trace.send_connection_create_start()

            try:
                proto = await self._create_connection(req, traces, timeout)
                if self._closed:
                    proto.close()
                    raise ClientConnectionError("Connector is closed.")
            except BaseException:
                if not self._closed:
                    self._acquired.remove(placeholder)
                    self._drop_acquired_per_host(key, placeholder)
                    self._release_waiter()
                raise
            else:
                if not self._closed:
                    self._acquired.remove(placeholder)
                    self._drop_acquired_per_host(key, placeholder)

            if traces:
                for trace in traces:
                    await trace.send_connection_create_end()
        else:
            if traces:
                # Acquire the connection to prevent race conditions with limits
                placeholder = cast(ResponseHandler, _TransportPlaceholder())
                self._acquired.add(placeholder)
                self._acquired_per_host[key].add(placeholder)
                for trace in traces:
                    await trace.send_connection_reuseconn()
                self._acquired.remove(placeholder)
                self._drop_acquired_per_host(key, placeholder)

        self._acquired.add(proto)
        self._acquired_per_host[key].add(proto)
        return Connection(self, key, proto, self._loop)

    def _get(self, key: "ConnectionKey") -> Optional[ResponseHandler]:
        try:
            conns = self._conns[key]
        except KeyError:
            return None

        t1 = self._loop.time()
        while conns:
            proto, t0 = conns.pop()
            if proto.is_connected():
                if t1 - t0 > self._keepalive_timeout:
                    transport = proto.transport
                    proto.close()
                    # only for SSL transports
                    if key.is_ssl and not self._cleanup_closed_disabled:
                        self._cleanup_closed_transports.append(transport)
                else:
                    if not conns:
                        # The very last connection was reclaimed: drop the key
                        del self._conns[key]
                    return proto
            else:
                transport = proto.transport
                proto.close()
                if key.is_ssl and not self._cleanup_closed_disabled:
                    self._cleanup_closed_transports.append(transport)

        # No more connections: drop the key
        del self._conns[key]
        return None

    def _release_waiter(self) -> None:
        """
        Iterates over all waiters until one to be released is found.

        The one to be released is not finished and
        belongs to a host that has available connections.
        """
        if not self._waiters:
            return

        # Having the dict keys ordered this avoids to iterate
        # at the same order at each call.
        queues = list(self._waiters.keys())
        random.shuffle(queues)

        for key in queues:
            if self._available_connections(key) < 1:
                continue

            waiters = self._waiters[key]
            while waiters:
                waiter = waiters.popleft()
                if not waiter.done():
                    waiter.set_result(None)
                    return

    def _release_acquired(self, key: "ConnectionKey", proto: ResponseHandler) -> None:
        if self._closed:
            # acquired connection is already released on connector closing
            return

        try:
            self._acquired.remove(proto)
            self._drop_acquired_per_host(key, proto)
        except KeyError:  # pragma: no cover
            # this may be result of undetermenistic order of objects
            # finalization due garbage collection.
            pass
        else:
            self._release_waiter()

    def _release(
        self,
        key: "ConnectionKey",
        protocol: ResponseHandler,
        *,
        should_close: bool = False,
    ) -> None:
        if self._closed:
            # acquired connection is already released on connector closing
            return

        self._release_acquired(key, protocol)

        if self._force_close:
            should_close = True

        if should_close or protocol.should_close:
            transport = protocol.transport
            protocol.close()

            if key.is_ssl and not self._cleanup_closed_disabled:
                self._cleanup_closed_transports.append(transport)
        else:
            conns = self._conns.get(key)
            if conns is None:
                conns = self._conns[key] = []
            conns.append((protocol, self._loop.time()))

            if self._cleanup_handle is None:
                self._cleanup_handle = helpers.weakref_handle(
                    self,
                    "_cleanup",
                    self._keepalive_timeout,
                    self._loop,
                    timeout_ceil_threshold=self._timeout_ceil_threshold,
                )

    async def _create_connection(
        self, req: ClientRequest, traces: List["Trace"], timeout: "ClientTimeout"
    ) -> ResponseHandler:
        raise NotImplementedError()


class _DNSCacheTable:
    def __init__(self, ttl: Optional[float] = None) -> None:
        self._addrs_rr: Dict[Tuple[str, int], Tuple[Iterator[ResolveResult], int]] = {}
        self._timestamps: Dict[Tuple[str, int], float] = {}
        self._ttl = ttl

    def __contains__(self, host: object) -> bool:
        return host in self._addrs_rr

    def add(self, key: Tuple[str, int], addrs: List[ResolveResult]) -> None:
        self._addrs_rr[key] = (cycle(addrs), len(addrs))

        if self._ttl is not None:
            self._timestamps[key] = monotonic()

    def remove(self, key: Tuple[str, int]) -> None:
        self._addrs_rr.pop(key, None)

        if self._ttl is not None:
            self._timestamps.pop(key, None)

    def clear(self) -> None:
        self._addrs_rr.clear()
        self._timestamps.clear()

    def next_addrs(self, key: Tuple[str, int]) -> List[ResolveResult]:
        loop, length = self._addrs_rr[key]
        addrs = list(islice(loop, length))
        # Consume one more element to shift internal state of `cycle`
        next(loop)
        return addrs

    def expired(self, key: Tuple[str, int]) -> bool:
        if self._ttl is None:
            return False

        return self._timestamps[key] + self._ttl < monotonic()


class TCPConnector(BaseConnector):
    """TCP connector.

    verify_ssl - Set to True to check ssl certifications.
    fingerprint - Pass the binary sha256
        digest of the expected certificate in DER format to verify
        that the certificate the server presents matches. See also
        https://en.wikipedia.org/wiki/HTTP_Public_Key_Pinning
    resolver - Enable DNS lookups and use this
        resolver
    use_dns_cache - Use memory cache for DNS lookups.
    ttl_dns_cache - Max seconds having cached a DNS entry, None forever.
    family - socket address family
    local_addr - local tuple of (host, port) to bind socket to

    keepalive_timeout - (optional) Keep-alive timeout.
    force_close - Set to True to force close and do reconnect
        after each request (and between redirects).
    limit - The total number of simultaneous connections.
    limit_per_host - Number of simultaneous connections to one host.
    enable_cleanup_closed - Enables clean-up closed ssl transports.
                            Disabled by default.
    happy_eyeballs_delay - This is the “Connection Attempt Delay”
                           as defined in RFC 8305. To disable
                           the happy eyeballs algorithm, set to None.
    interleave - “First Address Family Count” as defined in RFC 8305
    loop - Optional event loop.
    """

    allowed_protocol_schema_set = HIGH_LEVEL_SCHEMA_SET | frozenset({"tcp"})
    _made_ssl_context: Dict[bool, "asyncio.Future[SSLContext]"] = {}

    def __init__(
        self,
        *,
        verify_ssl: bool = True,
        fingerprint: Optional[bytes] = None,
        use_dns_cache: bool = True,
        ttl_dns_cache: Optional[int] = 10,
        family: socket.AddressFamily = socket.AddressFamily.AF_UNSPEC,
        ssl_context: Optional[SSLContext] = None,
        ssl: Union[bool, Fingerprint, SSLContext] = True,
        local_addr: Optional[Tuple[str, int]] = None,
        resolver: Optional[AbstractResolver] = None,
        keepalive_timeout: Union[None, float, object] = sentinel,
        force_close: bool = False,
        limit: int = 100,
        limit_per_host: int = 0,
        enable_cleanup_closed: bool = False,
        loop: Optional[asyncio.AbstractEventLoop] = None,
        timeout_ceil_threshold: float = 5,
        happy_eyeballs_delay: Optional[float] = 0.25,
        interleave: Optional[int] = None,
    ):
        super().__init__(
            keepalive_timeout=keepalive_timeout,
            force_close=force_close,
            limit=limit,
            limit_per_host=limit_per_host,
            enable_cleanup_closed=enable_cleanup_closed,
            loop=loop,
            timeout_ceil_threshold=timeout_ceil_threshold,
        )

        self._ssl = _merge_ssl_params(ssl, verify_ssl, ssl_context, fingerprint)
        if resolver is None:
            resolver = DefaultResolver(loop=self._loop)
        self._resolver = resolver

        self._use_dns_cache = use_dns_cache
        self._cached_hosts = _DNSCacheTable(ttl=ttl_dns_cache)
        self._throttle_dns_events: Dict[Tuple[str, int], EventResultOrError] = {}
        self._family = family
        self._local_addr_infos = aiohappyeyeballs.addr_to_addr_infos(local_addr)
        self._happy_eyeballs_delay = happy_eyeballs_delay
        self._interleave = interleave

    def close(self) -> Awaitable[None]:
        """Close all ongoing DNS calls."""
        for ev in self._throttle_dns_events.values():
            ev.cancel()

        return super().close()

    @property
    def family(self) -> int:
        """Socket family like AF_INET."""
        return self._family

    @property
    def use_dns_cache(self) -> bool:
        """True if local DNS caching is enabled."""
        return self._use_dns_cache

    def clear_dns_cache(
        self, host: Optional[str] = None, port: Optional[int] = None
    ) -> None:
        """Remove specified host/port or clear all dns local cache."""
        if host is not None and port is not None:
            self._cached_hosts.remove((host, port))
        elif host is not None or port is not None:
            raise ValueError("either both host and port " "or none of them are allowed")
        else:
            self._cached_hosts.clear()

    async def _resolve_host(
        self, host: str, port: int, traces: Optional[Sequence["Trace"]] = None
    ) -> List[ResolveResult]:
        """Resolve host and return list of addresses."""
        if is_ip_address(host):
            return [
                {
                    "hostname": host,
                    "host": host,
                    "port": port,
                    "family": self._family,
                    "proto": 0,
                    "flags": 0,
                }
            ]

        if not self._use_dns_cache:

            if traces:
                for trace in traces:
                    await trace.send_dns_resolvehost_start(host)

            res = await self._resolver.resolve(host, port, family=self._family)

            if traces:
                for trace in traces:
                    await trace.send_dns_resolvehost_end(host)

            return res

        key = (host, port)
        if key in self._cached_hosts and not self._cached_hosts.expired(key):
            # get result early, before any await (#4014)
            result = self._cached_hosts.next_addrs(key)

            if traces:
                for trace in traces:
                    await trace.send_dns_cache_hit(host)
            return result

        #
        # If multiple connectors are resolving the same host, we wait
        # for the first one to resolve and then use the result for all of them.
        # We use a throttle event to ensure that we only resolve the host once
        # and then use the result for all the waiters.
        #
        # In this case we need to create a task to ensure that we can shield
        # the task from cancellation as cancelling this lookup should not cancel
        # the underlying lookup or else the cancel event will get broadcast to
        # all the waiters across all connections.
        #
        resolved_host_task = asyncio.create_task(
            self._resolve_host_with_throttle(key, host, port, traces)
        )
        try:
            return await asyncio.shield(resolved_host_task)
        except asyncio.CancelledError:

            def drop_exception(fut: "asyncio.Future[List[ResolveResult]]") -> None:
                with suppress(Exception, asyncio.CancelledError):
                    fut.result()

            resolved_host_task.add_done_callback(drop_exception)
            raise

    async def _resolve_host_with_throttle(
        self,
        key: Tuple[str, int],
        host: str,
        port: int,
        traces: Optional[Sequence["Trace"]],
    ) -> List[ResolveResult]:
        """Resolve host with a dns events throttle."""
        if key in self._throttle_dns_events:
            # get event early, before any await (#4014)
            event = self._throttle_dns_events[key]
            if traces:
                for trace in traces:
                    await trace.send_dns_cache_hit(host)
            await event.wait()
        else:
            # update dict early, before any await (#4014)
            self._throttle_dns_events[key] = EventResultOrError(self._loop)
            if traces:
                for trace in traces:
                    await trace.send_dns_cache_miss(host)
            try:

                if traces:
                    for trace in traces:
                        await trace.send_dns_resolvehost_start(host)

                addrs = await self._resolver.resolve(host, port, family=self._family)
                if traces:
                    for trace in traces:
                        await trace.send_dns_resolvehost_end(host)

                self._cached_hosts.add(key, addrs)
                self._throttle_dns_events[key].set()
            except BaseException as e:
                # any DNS exception, independently of the implementation
                # is set for the waiters to raise the same exception.
                self._throttle_dns_events[key].set(exc=e)
                raise
            finally:
                self._throttle_dns_events.pop(key)

        return self._cached_hosts.next_addrs(key)

    async def _create_connection(
        self, req: ClientRequest, traces: List["Trace"], timeout: "ClientTimeout"
    ) -> ResponseHandler:
        """Create connection.

        Has same keyword arguments as BaseEventLoop.create_connection.
        """
        if req.proxy:
            _, proto = await self._create_proxy_connection(req, traces, timeout)
        else:
            _, proto = await self._create_direct_connection(req, traces, timeout)

        return proto

    @staticmethod
    def _make_ssl_context(verified: bool) -> SSLContext:
        """Create SSL context.

        This method is not async-friendly and should be called from a thread
        because it will load certificates from disk and do other blocking I/O.
        """
        if verified:
            return ssl.create_default_context()
        sslcontext = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
        sslcontext.options |= ssl.OP_NO_SSLv2
        sslcontext.options |= ssl.OP_NO_SSLv3
        sslcontext.check_hostname = False
        sslcontext.verify_mode = ssl.CERT_NONE
        sslcontext.options |= ssl.OP_NO_COMPRESSION
        sslcontext.set_default_verify_paths()
        return sslcontext

    async def _get_ssl_context(self, req: ClientRequest) -> Optional[SSLContext]:
        """Logic to get the correct SSL context

        0. if req.ssl is false, return None

        1. if ssl_context is specified in req, use it
        2. if _ssl_context is specified in self, use it
        3. otherwise:
            1. if verify_ssl is not specified in req, use self.ssl_context
               (will generate a default context according to self.verify_ssl)
            2. if verify_ssl is True in req, generate a default SSL context
            3. if verify_ssl is False in req, generate a SSL context that
               won't verify
        """
        if not req.is_ssl():
            return None

        if ssl is None:  # pragma: no cover
            raise RuntimeError("SSL is not supported.")
        sslcontext = req.ssl
        if isinstance(sslcontext, ssl.SSLContext):
            return sslcontext
        if sslcontext is not True:
            # not verified or fingerprinted
            return await self._make_or_get_ssl_context(False)
        sslcontext = self._ssl
        if isinstance(sslcontext, ssl.SSLContext):
            return sslcontext
        if sslcontext is not True:
            # not verified or fingerprinted
            return await self._make_or_get_ssl_context(False)
        return await self._make_or_get_ssl_context(True)

    async def _make_or_get_ssl_context(self, verified: bool) -> SSLContext:
        """Create or get cached SSL context."""
        try:
            return await self._made_ssl_context[verified]
        except KeyError:
            loop = self._loop
            future = loop.create_future()
            self._made_ssl_context[verified] = future
            try:
                result = await loop.run_in_executor(
                    None, self._make_ssl_context, verified
                )
            # BaseException is used since we might get CancelledError
            except BaseException as ex:
                del self._made_ssl_context[verified]
                set_exception(future, ex)
                raise
            else:
                set_result(future, result)
            return result

    def _get_fingerprint(self, req: ClientRequest) -> Optional["Fingerprint"]:
        ret = req.ssl
        if isinstance(ret, Fingerprint):
            return ret
        ret = self._ssl
        if isinstance(ret, Fingerprint):
            return ret
        return None

    async def _wrap_create_connection(
        self,
        *args: Any,
        addr_infos: List[aiohappyeyeballs.AddrInfoType],
        req: ClientRequest,
        timeout: "ClientTimeout",
        client_error: Type[Exception] = ClientConnectorError,
        **kwargs: Any,
    ) -> Tuple[asyncio.Transport, ResponseHandler]:
        try:
            async with ceil_timeout(
                timeout.sock_connect, ceil_threshold=timeout.ceil_threshold
            ):
                sock = await aiohappyeyeballs.start_connection(
                    addr_infos=addr_infos,
                    local_addr_infos=self._local_addr_infos,
                    happy_eyeballs_delay=self._happy_eyeballs_delay,
                    interleave=self._interleave,
                    loop=self._loop,
                )
                return await self._loop.create_connection(*args, **kwargs, sock=sock)
        except cert_errors as exc:
            raise ClientConnectorCertificateError(req.connection_key, exc) from exc
        except ssl_errors as exc:
            raise ClientConnectorSSLError(req.connection_key, exc) from exc
        except OSError as exc:
            if exc.errno is None and isinstance(exc, asyncio.TimeoutError):
                raise
            raise client_error(req.connection_key, exc) from exc

    async def _wrap_existing_connection(
        self,
        *args: Any,
        req: ClientRequest,
        timeout: "ClientTimeout",
        client_error: Type[Exception] = ClientConnectorError,
        **kwargs: Any,
    ) -> Tuple[asyncio.Transport, ResponseHandler]:
        try:
            async with ceil_timeout(
                timeout.sock_connect, ceil_threshold=timeout.ceil_threshold
            ):
                return await self._loop.create_connection(*args, **kwargs)
        except cert_errors as exc:
            raise ClientConnectorCertificateError(req.connection_key, exc) from exc
        except ssl_errors as exc:
            raise ClientConnectorSSLError(req.connection_key, exc) from exc
        except OSError as exc:
            if exc.errno is None and isinstance(exc, asyncio.TimeoutError):
                raise
            raise client_error(req.connection_key, exc) from exc

    def _fail_on_no_start_tls(self, req: "ClientRequest") -> None:
        """Raise a :py:exc:`RuntimeError` on missing ``start_tls()``.

        It is necessary for TLS-in-TLS so that it is possible to
        send HTTPS queries through HTTPS proxies.

        This doesn't affect regular HTTP requests, though.
        """
        if not req.is_ssl():
            return

        proxy_url = req.proxy
        assert proxy_url is not None
        if proxy_url.scheme != "https":
            return

        self._check_loop_for_start_tls()

    def _check_loop_for_start_tls(self) -> None:
        try:
            self._loop.start_tls
        except AttributeError as attr_exc:
            raise RuntimeError(
                "An HTTPS request is being sent through an HTTPS proxy. "
                "This needs support for TLS in TLS but it is not implemented "
                "in your runtime for the stdlib asyncio.\n\n"
                "Please upgrade to Python 3.11 or higher. For more details, "
                "please see:\n"
                "* https://bugs.python.org/issue37179\n"
                "* https://github.com/python/cpython/pull/28073\n"
                "* https://docs.aiohttp.org/en/stable/"
                "client_advanced.html#proxy-support\n"
                "* https://github.com/aio-libs/aiohttp/discussions/6044\n",
            ) from attr_exc

    def _loop_supports_start_tls(self) -> bool:
        try:
            self._check_loop_for_start_tls()
        except RuntimeError:
            return False
        else:
            return True

    def _warn_about_tls_in_tls(
        self,
        underlying_transport: asyncio.Transport,
        req: ClientRequest,
    ) -> None:
        """Issue a warning if the requested URL has HTTPS scheme."""
        if req.request_info.url.scheme != "https":
            return

        asyncio_supports_tls_in_tls = getattr(
            underlying_transport,
            "_start_tls_compatible",
            False,
        )

        if asyncio_supports_tls_in_tls:
            return

        warnings.warn(
            "An HTTPS request is being sent through an HTTPS proxy. "
            "This support for TLS in TLS is known to be disabled "
            "in the stdlib asyncio (Python <3.11). This is why you'll probably see "
            "an error in the log below.\n\n"
            "It is possible to enable it via monkeypatching. "
            "For more details, see:\n"
            "* https://bugs.python.org/issue37179\n"
            "* https://github.com/python/cpython/pull/28073\n\n"
            "You can temporarily patch this as follows:\n"
            "* https://docs.aiohttp.org/en/stable/client_advanced.html#proxy-support\n"
            "* https://github.com/aio-libs/aiohttp/discussions/6044\n",
            RuntimeWarning,
            source=self,
            # Why `4`? At least 3 of the calls in the stack originate
            # from the methods in this class.
            stacklevel=3,
        )

    async def _start_tls_connection(
        self,
        underlying_transport: asyncio.Transport,
        req: ClientRequest,
        timeout: "ClientTimeout",
        client_error: Type[Exception] = ClientConnectorError,
    ) -> Tuple[asyncio.BaseTransport, ResponseHandler]:
        """Wrap the raw TCP transport with TLS."""
        tls_proto = self._factory()  # Create a brand new proto for TLS

        # Safety of the `cast()` call here is based on the fact that
        # internally `_get_ssl_context()` only returns `None` when
        # `req.is_ssl()` evaluates to `False` which is never gonna happen
        # in this code path. Of course, it's rather fragile
        # maintainability-wise but this is to be solved separately.
        sslcontext = cast(ssl.SSLContext, await self._get_ssl_context(req))

        try:
            async with ceil_timeout(
                timeout.sock_connect, ceil_threshold=timeout.ceil_threshold
            ):
                try:
                    tls_transport = await self._loop.start_tls(
                        underlying_transport,
                        tls_proto,
                        sslcontext,
                        server_hostname=req.server_hostname or req.host,
                        ssl_handshake_timeout=timeout.total,
                    )
                except BaseException:
                    # We need to close the underlying transport since
                    # `start_tls()` probably failed before it had a
                    # chance to do this:
                    underlying_transport.close()
                    raise
        except cert_errors as exc:
            raise ClientConnectorCertificateError(req.connection_key, exc) from exc
        except ssl_errors as exc:
            raise ClientConnectorSSLError(req.connection_key, exc) from exc
        except OSError as exc:
            if exc.errno is None and isinstance(exc, asyncio.TimeoutError):
                raise
            raise client_error(req.connection_key, exc) from exc
        except TypeError as type_err:
            # Example cause looks like this:
            # TypeError: transport <asyncio.sslproto._SSLProtocolTransport
            # object at 0x7f760615e460> is not supported by start_tls()

            raise ClientConnectionError(
                "Cannot initialize a TLS-in-TLS connection to host "
                f"{req.host!s}:{req.port:d} through an underlying connection "
                f"to an HTTPS proxy {req.proxy!s} ssl:{req.ssl or 'default'} "
                f"[{type_err!s}]"
            ) from type_err
        else:
            if tls_transport is None:
                msg = "Failed to start TLS (possibly caused by closing transport)"
                raise client_error(req.connection_key, OSError(msg))
            tls_proto.connection_made(
                tls_transport
            )  # Kick the state machine of the new TLS protocol

        return tls_transport, tls_proto

    def _convert_hosts_to_addr_infos(
        self, hosts: List[ResolveResult]
    ) -> List[aiohappyeyeballs.AddrInfoType]:
        """Converts the list of hosts to a list of addr_infos.

        The list of hosts is the result of a DNS lookup. The list of
        addr_infos is the result of a call to `socket.getaddrinfo()`.
        """
        addr_infos: List[aiohappyeyeballs.AddrInfoType] = []
        for hinfo in hosts:
            host = hinfo["host"]
            is_ipv6 = ":" in host
            family = socket.AF_INET6 if is_ipv6 else socket.AF_INET
            if self._family and self._family != family:
                continue
            addr = (host, hinfo["port"], 0, 0) if is_ipv6 else (host, hinfo["port"])
            addr_infos.append(
                (family, socket.SOCK_STREAM, socket.IPPROTO_TCP, "", addr)
            )
        return addr_infos

    async def _create_direct_connection(
        self,
        req: ClientRequest,
        traces: List["Trace"],
        timeout: "ClientTimeout",
        *,
        client_error: Type[Exception] = ClientConnectorError,
    ) -> Tuple[asyncio.Transport, ResponseHandler]:
        sslcontext = await self._get_ssl_context(req)
        fingerprint = self._get_fingerprint(req)

        host = req.url.raw_host
        assert host is not None
        # Replace multiple trailing dots with a single one.
        # A trailing dot is only present for fully-qualified domain names.
        # See https://github.com/aio-libs/aiohttp/pull/7364.
        if host.endswith(".."):
            host = host.rstrip(".") + "."
        port = req.port
        assert port is not None
        try:
            # Cancelling this lookup should not cancel the underlying lookup
            #  or else the cancel event will get broadcast to all the waiters
            #  across all connections.
            hosts = await self._resolve_host(host, port, traces=traces)
        except OSError as exc:
            if exc.errno is None and isinstance(exc, asyncio.TimeoutError):
                raise
            # in case of proxy it is not ClientProxyConnectionError
            # it is problem of resolving proxy ip itself
            raise ClientConnectorError(req.connection_key, exc) from exc

        last_exc: Optional[Exception] = None
        addr_infos = self._convert_hosts_to_addr_infos(hosts)
        while addr_infos:
            # Strip trailing dots, certificates contain FQDN without dots.
            # See https://github.com/aio-libs/aiohttp/issues/3636
            server_hostname = (
                (req.server_hostname or host).rstrip(".") if sslcontext else None
            )

            try:
                transp, proto = await self._wrap_create_connection(
                    self._factory,
                    timeout=timeout,
                    ssl=sslcontext,
                    addr_infos=addr_infos,
                    server_hostname=server_hostname,
                    req=req,
                    client_error=client_error,
                )
            except ClientConnectorError as exc:
                last_exc = exc
                aiohappyeyeballs.pop_addr_infos_interleave(addr_infos, self._interleave)
                continue

            if req.is_ssl() and fingerprint:
                try:
                    fingerprint.check(transp)
                except ServerFingerprintMismatch as exc:
                    transp.close()
                    if not self._cleanup_closed_disabled:
                        self._cleanup_closed_transports.append(transp)
                    last_exc = exc
                    # Remove the bad peer from the list of addr_infos
                    sock: socket.socket = transp.get_extra_info("socket")
                    bad_peer = sock.getpeername()
                    aiohappyeyeballs.remove_addr_infos(addr_infos, bad_peer)
                    continue

            return transp, proto
        else:
            assert last_exc is not None
            raise last_exc

    async def _create_proxy_connection(
        self, req: ClientRequest, traces: List["Trace"], timeout: "ClientTimeout"
    ) -> Tuple[asyncio.BaseTransport, ResponseHandler]:
        self._fail_on_no_start_tls(req)
        runtime_has_start_tls = self._loop_supports_start_tls()

        headers: Dict[str, str] = {}
        if req.proxy_headers is not None:
            headers = req.proxy_headers  # type: ignore[assignment]
        headers[hdrs.HOST] = req.headers[hdrs.HOST]

        url = req.proxy
        assert url is not None
        proxy_req = ClientRequest(
            hdrs.METH_GET,
            url,
            headers=headers,
            auth=req.proxy_auth,
            loop=self._loop,
            ssl=req.ssl,
        )

        # create connection to proxy server
        transport, proto = await self._create_direct_connection(
            proxy_req, [], timeout, client_error=ClientProxyConnectionError
        )

        auth = proxy_req.headers.pop(hdrs.AUTHORIZATION, None)
        if auth is not None:
            if not req.is_ssl():
                req.headers[hdrs.PROXY_AUTHORIZATION] = auth
            else:
                proxy_req.headers[hdrs.PROXY_AUTHORIZATION] = auth

        if req.is_ssl():
            if runtime_has_start_tls:
                self._warn_about_tls_in_tls(transport, req)

            # For HTTPS requests over HTTP proxy
            # we must notify proxy to tunnel connection
            # so we send CONNECT command:
            #   CONNECT www.python.org:443 HTTP/1.1
            #   Host: www.python.org
            #
            # next we must do TLS handshake and so on
            # to do this we must wrap raw socket into secure one
            # asyncio handles this perfectly
            proxy_req.method = hdrs.METH_CONNECT
            proxy_req.url = req.url
            key = attr.evolve(
                req.connection_key, proxy=None, proxy_auth=None, proxy_headers_hash=None
            )
            conn = Connection(self, key, proto, self._loop)
            proxy_resp = await proxy_req.send(conn)
            try:
                protocol = conn._protocol
                assert protocol is not None

                # read_until_eof=True will ensure the connection isn't closed
                # once the response is received and processed allowing
                # START_TLS to work on the connection below.
                protocol.set_response_params(
                    read_until_eof=runtime_has_start_tls,
                    timeout_ceil_threshold=self._timeout_ceil_threshold,
                )
                resp = await proxy_resp.start(conn)
            except BaseException:
                proxy_resp.close()
                conn.close()
                raise
            else:
                conn._protocol = None
                conn._transport = None
                try:
                    if resp.status != 200:
                        message = resp.reason
                        if message is None:
                            message = HTTPStatus(resp.status).phrase
                        raise ClientHttpProxyError(
                            proxy_resp.request_info,
                            resp.history,
                            status=resp.status,
                            message=message,
                            headers=resp.headers,
                        )
                    if not runtime_has_start_tls:
                        rawsock = transport.get_extra_info("socket", default=None)
                        if rawsock is None:
                            raise RuntimeError(
                                "Transport does not expose socket instance"
                            )
                        # Duplicate the socket, so now we can close proxy transport
                        rawsock = rawsock.dup()
                except BaseException:
                    # It shouldn't be closed in `finally` because it's fed to
                    # `loop.start_tls()` and the docs say not to touch it after
                    # passing there.
                    transport.close()
                    raise
                finally:
                    if not runtime_has_start_tls:
                        transport.close()

                if not runtime_has_start_tls:
                    # HTTP proxy with support for upgrade to HTTPS
                    sslcontext = self._get_ssl_context(req)
                    return await self._wrap_existing_connection(
                        self._factory,
                        timeout=timeout,
                        ssl=sslcontext,
                        sock=rawsock,
                        server_hostname=req.host,
                        req=req,
                    )

                return await self._start_tls_connection(
                    # Access the old transport for the last time before it's
                    # closed and forgotten forever:
                    transport,
                    req=req,
                    timeout=timeout,
                )
            finally:
                proxy_resp.close()

        return transport, proto


class UnixConnector(BaseConnector):
    """Unix socket connector.

    path - Unix socket path.
    keepalive_timeout - (optional) Keep-alive timeout.
    force_close - Set to True to force close and do reconnect
        after each request (and between redirects).
    limit - The total number of simultaneous connections.
    limit_per_host - Number of simultaneous connections to one host.
    loop - Optional event loop.
    """

    allowed_protocol_schema_set = HIGH_LEVEL_SCHEMA_SET | frozenset({"unix"})

    def __init__(
        self,
        path: str,
        force_close: bool = False,
        keepalive_timeout: Union[object, float, None] = sentinel,
        limit: int = 100,
        limit_per_host: int = 0,
        loop: Optional[asyncio.AbstractEventLoop] = None,
    ) -> None:
        super().__init__(
            force_close=force_close,
            keepalive_timeout=keepalive_timeout,
            limit=limit,
            limit_per_host=limit_per_host,
            loop=loop,
        )
        self._path = path

    @property
    def path(self) -> str:
        """Path to unix socket."""
        return self._path

    async def _create_connection(
        self, req: ClientRequest, traces: List["Trace"], timeout: "ClientTimeout"
    ) -> ResponseHandler:
        try:
            async with ceil_timeout(
                timeout.sock_connect, ceil_threshold=timeout.ceil_threshold
            ):
                _, proto = await self._loop.create_unix_connection(
                    self._factory, self._path
                )
        except OSError as exc:
            if exc.errno is None and isinstance(exc, asyncio.TimeoutError):
                raise
            raise UnixClientConnectorError(self.path, req.connection_key, exc) from exc

        return proto


class NamedPipeConnector(BaseConnector):
    """Named pipe connector.

    Only supported by the proactor event loop.
    See also: https://docs.python.org/3/library/asyncio-eventloop.html

    path - Windows named pipe path.
    keepalive_timeout - (optional) Keep-alive timeout.
    force_close - Set to True to force close and do reconnect
        after each request (and between redirects).
    limit - The total number of simultaneous connections.
    limit_per_host - Number of simultaneous connections to one host.
    loop - Optional event loop.
    """

    allowed_protocol_schema_set = HIGH_LEVEL_SCHEMA_SET | frozenset({"npipe"})

    def __init__(
        self,
        path: str,
        force_close: bool = False,
        keepalive_timeout: Union[object, float, None] = sentinel,
        limit: int = 100,
        limit_per_host: int = 0,
        loop: Optional[asyncio.AbstractEventLoop] = None,
    ) -> None:
        super().__init__(
            force_close=force_close,
            keepalive_timeout=keepalive_timeout,
            limit=limit,
            limit_per_host=limit_per_host,
            loop=loop,
        )
        if not isinstance(
            self._loop, asyncio.ProactorEventLoop  # type: ignore[attr-defined]
        ):
            raise RuntimeError(
                "Named Pipes only available in proactor " "loop under windows"
            )
        self._path = path

    @property
    def path(self) -> str:
        """Path to the named pipe."""
        return self._path

    async def _create_connection(
        self, req: ClientRequest, traces: List["Trace"], timeout: "ClientTimeout"
    ) -> ResponseHandler:
        try:
            async with ceil_timeout(
                timeout.sock_connect, ceil_threshold=timeout.ceil_threshold
            ):
                _, proto = await self._loop.create_pipe_connection(  # type: ignore[attr-defined]
                    self._factory, self._path
                )
                # the drain is required so that the connection_made is called
                # and transport is set otherwise it is not set before the
                # `assert conn.transport is not None`
                # in client.py's _request method
                await asyncio.sleep(0)
                # other option is to manually set transport like
                # `proto.transport = trans`
        except OSError as exc:
            if exc.errno is None and isinstance(exc, asyncio.TimeoutError):
                raise
            raise ClientConnectorError(req.connection_key, exc) from exc

        return cast(ResponseHandler, proto)

```
--- END FILE ---

Please first localize the bug based on the issue statement, and then generate *SEARCH/REPLACE* edits to fix the issue.

Every *SEARCH/REPLACE* edit must use this format:
1. The file path
2. The start of search block: <<<<<<< SEARCH
3. A contiguous chunk of lines to search for in the existing source code
4. The dividing line: =======
5. The lines to replace into the source code
6. The end of the replace block: >>>>>>> REPLACE

Here is an example:

```python
### mathweb/flask/app.py
<<<<<<< SEARCH
from flask import Flask
=======
import math
from flask import Flask
>>>>>>> REPLACE
```
</solution>

Please note that the *SEARCH/REPLACE* edit REQUIRES PROPER INDENTATION. If you would like to add the line '        print(x)', you must fully write that out, with all those spaces before the code!
Wrap each *SEARCH/REPLACE* edit in a code block as shown in the example above. If you have multiple *SEARCH/REPLACE* edits, use a separate code block for each one.
user