{
    "file_diffs": [
        {
            "old_file_content": "",
            "new_file_content": "Fixed arbitrary sequence types being allowed to inject headers via version parameter -- by :user:`Dreamsorcerer`\n",
            "header": {
                "file": {
                    "path": "CHANGES/7835.bugfix"
                },
                "misc_line": "new file mode 100644"
            },
            "index_line": {
                "old_commit_hash": "00000000",
                "new_commit_hash": "4ce3af4f",
                "mode": ""
            },
            "is_binary_file": false,
            "binary_line": null,
            "minus_file": {
                "path": "/dev/null"
            },
            "plus_file": {
                "path": "b/CHANGES/7835.bugfix"
            },
            "hunks": [
                {
                    "descriptor": {
                        "old_range": {
                            "start": 0,
                            "length": 0
                        },
                        "new_range": {
                            "start": 1,
                            "length": null
                        },
                        "section": ""
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "Fixed arbitrary sequence types being allowed to inject headers via version parameter -- by :user:`Dreamsorcerer`",
                                "type": "added"
                            }
                        ]
                    },
                    "modified_entities": [],
                    "added_entities": [],
                    "deleted_entities": []
                }
            ]
        },
        {
            "old_file_content": "import asyncio\nimport codecs\nimport contextlib\nimport functools\nimport io\nimport re\nimport sys\nimport traceback\nimport warnings\nfrom hashlib import md5, sha1, sha256\nfrom http.cookies import CookieError, Morsel, SimpleCookie\nfrom types import MappingProxyType, TracebackType\nfrom typing import (\n    TYPE_CHECKING,\n    Any,\n    Callable,\n    Dict,\n    Iterable,\n    List,\n    Literal,\n    Mapping,\n    Optional,\n    Tuple,\n    Type,\n    Union,\n    cast,\n)\n\nimport attr\nfrom multidict import CIMultiDict, CIMultiDictProxy, MultiDict, MultiDictProxy\nfrom yarl import URL\n\nfrom . import hdrs, helpers, http, multipart, payload\nfrom .abc import AbstractStreamWriter\nfrom .client_exceptions import (\n    ClientConnectionError,\n    ClientOSError,\n    ClientResponseError,\n    ContentTypeError,\n    InvalidURL,\n    ServerFingerprintMismatch,\n)\nfrom .compression_utils import HAS_BROTLI\nfrom .formdata import FormData\nfrom .helpers import (\n    BaseTimerContext,\n    BasicAuth,\n    HeadersMixin,\n    TimerNoop,\n    basicauth_from_netrc,\n    netrc_from_env,\n    noop,\n    reify,\n    set_result,\n)\nfrom .http import (\n    SERVER_SOFTWARE,\n    HttpVersion,\n    HttpVersion10,\n    HttpVersion11,\n    StreamWriter,\n)\nfrom .log import client_logger\nfrom .streams import StreamReader\nfrom .typedefs import (\n    DEFAULT_JSON_DECODER,\n    JSONDecoder,\n    LooseCookies,\n    LooseHeaders,\n    RawHeaders,\n)\n\ntry:\n    import ssl\n    from ssl import SSLContext\nexcept ImportError:  # pragma: no cover\n    ssl = None  # type: ignore[assignment]\n    SSLContext = object  # type: ignore[misc,assignment]\n\n\n__all__ = (\"ClientRequest\", \"ClientResponse\", \"RequestInfo\", \"Fingerprint\")\n\n\nif TYPE_CHECKING:  # pragma: no cover\n    from .client import ClientSession\n    from .connector import Connection\n    from .tracing import Trace\n\n\n_CONTAINS_CONTROL_CHAR_RE = re.compile(r\"[^-!#$%&'*+.^_`|~0-9a-zA-Z]\")\njson_re = re.compile(r\"^application/(?:[\\w.+-]+?\\+)?json\")\n\n\ndef _gen_default_accept_encoding() -> str:\n    return \"gzip, deflate, br\" if HAS_BROTLI else \"gzip, deflate\"\n\n\n@attr.s(auto_attribs=True, frozen=True, slots=True)\nclass ContentDisposition:\n    type: Optional[str]\n    parameters: \"MappingProxyType[str, str]\"\n    filename: Optional[str]\n\n\n@attr.s(auto_attribs=True, frozen=True, slots=True)\nclass RequestInfo:\n    url: URL\n    method: str\n    headers: \"CIMultiDictProxy[str]\"\n    real_url: URL = attr.ib()\n\n    @real_url.default\n    def real_url_default(self) -> URL:\n        return self.url\n\n\nclass Fingerprint:\n    HASHFUNC_BY_DIGESTLEN = {\n        16: md5,\n        20: sha1,\n        32: sha256,\n    }\n\n    def __init__(self, fingerprint: bytes) -> None:\n        digestlen = len(fingerprint)\n        hashfunc = self.HASHFUNC_BY_DIGESTLEN.get(digestlen)\n        if not hashfunc:\n            raise ValueError(\"fingerprint has invalid length\")\n        elif hashfunc is md5 or hashfunc is sha1:\n            raise ValueError(\n                \"md5 and sha1 are insecure and \" \"not supported. Use sha256.\"\n            )\n        self._hashfunc = hashfunc\n        self._fingerprint = fingerprint\n\n    @property\n    def fingerprint(self) -> bytes:\n        return self._fingerprint\n\n    def check(self, transport: asyncio.Transport) -> None:\n        if not transport.get_extra_info(\"sslcontext\"):\n            return\n        sslobj = transport.get_extra_info(\"ssl_object\")\n        cert = sslobj.getpeercert(binary_form=True)\n        got = self._hashfunc(cert).digest()\n        if got != self._fingerprint:\n            host, port, *_ = transport.get_extra_info(\"peername\")\n            raise ServerFingerprintMismatch(self._fingerprint, got, host, port)\n\n\nif ssl is not None:\n    SSL_ALLOWED_TYPES = (ssl.SSLContext, bool, Fingerprint, type(None))\nelse:  # pragma: no cover\n    SSL_ALLOWED_TYPES = type(None)\n\n\ndef _merge_ssl_params(\n    ssl: Union[\"SSLContext\", Literal[False], Fingerprint, None],\n    verify_ssl: Optional[bool],\n    ssl_context: Optional[\"SSLContext\"],\n    fingerprint: Optional[bytes],\n) -> Union[\"SSLContext\", Literal[False], Fingerprint, None]:\n    if verify_ssl is not None and not verify_ssl:\n        warnings.warn(\n            \"verify_ssl is deprecated, use ssl=False instead\",\n            DeprecationWarning,\n            stacklevel=3,\n        )\n        if ssl is not None:\n            raise ValueError(\n                \"verify_ssl, ssl_context, fingerprint and ssl \"\n                \"parameters are mutually exclusive\"\n            )\n        else:\n            ssl = False\n    if ssl_context is not None:\n        warnings.warn(\n            \"ssl_context is deprecated, use ssl=context instead\",\n            DeprecationWarning,\n            stacklevel=3,\n        )\n        if ssl is not None:\n            raise ValueError(\n                \"verify_ssl, ssl_context, fingerprint and ssl \"\n                \"parameters are mutually exclusive\"\n            )\n        else:\n            ssl = ssl_context\n    if fingerprint is not None:\n        warnings.warn(\n            \"fingerprint is deprecated, \" \"use ssl=Fingerprint(fingerprint) instead\",\n            DeprecationWarning,\n            stacklevel=3,\n        )\n        if ssl is not None:\n            raise ValueError(\n                \"verify_ssl, ssl_context, fingerprint and ssl \"\n                \"parameters are mutually exclusive\"\n            )\n        else:\n            ssl = Fingerprint(fingerprint)\n    if not isinstance(ssl, SSL_ALLOWED_TYPES):\n        raise TypeError(\n            \"ssl should be SSLContext, bool, Fingerprint or None, \"\n            \"got {!r} instead.\".format(ssl)\n        )\n    return ssl\n\n\n@attr.s(auto_attribs=True, slots=True, frozen=True)\nclass ConnectionKey:\n    # the key should contain an information about used proxy / TLS\n    # to prevent reusing wrong connections from a pool\n    host: str\n    port: Optional[int]\n    is_ssl: bool\n    ssl: Union[SSLContext, None, Literal[False], Fingerprint]\n    proxy: Optional[URL]\n    proxy_auth: Optional[BasicAuth]\n    proxy_headers_hash: Optional[int]  # hash(CIMultiDict)\n\n\ndef _is_expected_content_type(\n    response_content_type: str, expected_content_type: str\n) -> bool:\n    if expected_content_type == \"application/json\":\n        return json_re.match(response_content_type) is not None\n    return expected_content_type in response_content_type\n\n\nclass ClientRequest:\n    GET_METHODS = {\n        hdrs.METH_GET,\n        hdrs.METH_HEAD,\n        hdrs.METH_OPTIONS,\n        hdrs.METH_TRACE,\n    }\n    POST_METHODS = {hdrs.METH_PATCH, hdrs.METH_POST, hdrs.METH_PUT}\n    ALL_METHODS = GET_METHODS.union(POST_METHODS).union({hdrs.METH_DELETE})\n\n    DEFAULT_HEADERS = {\n        hdrs.ACCEPT: \"*/*\",\n        hdrs.ACCEPT_ENCODING: _gen_default_accept_encoding(),\n    }\n\n    body = b\"\"\n    auth = None\n    response = None\n\n    __writer = None  # async task for streaming data\n    _continue = None  # waiter future for '100 Continue' response\n\n    # N.B.\n    # Adding __del__ method with self._writer closing doesn't make sense\n    # because _writer is instance method, thus it keeps a reference to self.\n    # Until writer has finished finalizer will not be called.\n\n    def __init__(\n        self,\n        method: str,\n        url: URL,\n        *,\n        params: Optional[Mapping[str, str]] = None,\n        headers: Optional[LooseHeaders] = None,\n        skip_auto_headers: Iterable[str] = frozenset(),\n        data: Any = None,\n        cookies: Optional[LooseCookies] = None,\n        auth: Optional[BasicAuth] = None,\n        version: http.HttpVersion = http.HttpVersion11,\n        compress: Optional[str] = None,\n        chunked: Optional[bool] = None,\n        expect100: bool = False,\n        loop: Optional[asyncio.AbstractEventLoop] = None,\n        response_class: Optional[Type[\"ClientResponse\"]] = None,\n        proxy: Optional[URL] = None,\n        proxy_auth: Optional[BasicAuth] = None,\n        timer: Optional[BaseTimerContext] = None,\n        session: Optional[\"ClientSession\"] = None,\n        ssl: Union[SSLContext, Literal[False], Fingerprint, None] = None,\n        proxy_headers: Optional[LooseHeaders] = None,\n        traces: Optional[List[\"Trace\"]] = None,\n        trust_env: bool = False,\n        server_hostname: Optional[str] = None,\n    ):\n        if loop is None:\n            loop = asyncio.get_event_loop()\n\n        match = _CONTAINS_CONTROL_CHAR_RE.search(method)\n        if match:\n            raise ValueError(\n                f\"Method cannot contain non-token characters {method!r} \"\n                \"(found at least {match.group()!r})\"\n            )\n\n        assert isinstance(url, URL), url\n        assert isinstance(proxy, (URL, type(None))), proxy\n        # FIXME: session is None in tests only, need to fix tests\n        # assert session is not None\n        self._session = cast(\"ClientSession\", session)\n        if params:\n            q = MultiDict(url.query)\n            url2 = url.with_query(params)\n            q.extend(url2.query)\n            url = url.with_query(q)\n        self.original_url = url\n        self.url = url.with_fragment(None)\n        self.method = method.upper()\n        self.chunked = chunked\n        self.compress = compress\n        self.loop = loop\n        self.length = None\n        if response_class is None:\n            real_response_class = ClientResponse\n        else:\n            real_response_class = response_class\n        self.response_class: Type[ClientResponse] = real_response_class\n        self._timer = timer if timer is not None else TimerNoop()\n        self._ssl = ssl\n        self.server_hostname = server_hostname\n\n        if loop.get_debug():\n            self._source_traceback = traceback.extract_stack(sys._getframe(1))\n\n        self.update_version(version)\n        self.update_host(url)\n        self.update_headers(headers)\n        self.update_auto_headers(skip_auto_headers)\n        self.update_cookies(cookies)\n        self.update_content_encoding(data)\n        self.update_auth(auth, trust_env)\n        self.update_proxy(proxy, proxy_auth, proxy_headers)\n\n        self.update_body_from_data(data)\n        if data is not None or self.method not in self.GET_METHODS:\n            self.update_transfer_encoding()\n        self.update_expect_continue(expect100)\n        if traces is None:\n            traces = []\n        self._traces = traces\n\n    def __reset_writer(self, _: object = None) -> None:\n        self.__writer = None\n\n    @property\n    def _writer(self) -> Optional[\"asyncio.Task[None]\"]:\n        return self.__writer\n\n    @_writer.setter\n    def _writer(self, writer: Optional[\"asyncio.Task[None]\"]) -> None:\n        if self.__writer is not None:\n            self.__writer.remove_done_callback(self.__reset_writer)\n        self.__writer = writer\n        if writer is not None:\n            writer.add_done_callback(self.__reset_writer)\n\n    def is_ssl(self) -> bool:\n        return self.url.scheme in (\"https\", \"wss\")\n\n    @property\n    def ssl(self) -> Union[\"SSLContext\", None, Literal[False], Fingerprint]:\n        return self._ssl\n\n    @property\n    def connection_key(self) -> ConnectionKey:\n        proxy_headers = self.proxy_headers\n        if proxy_headers:\n            h: Optional[int] = hash(tuple((k, v) for k, v in proxy_headers.items()))\n        else:\n            h = None\n        return ConnectionKey(\n            self.host,\n            self.port,\n            self.is_ssl(),\n            self.ssl,\n            self.proxy,\n            self.proxy_auth,\n            h,\n        )\n\n    @property\n    def host(self) -> str:\n        ret = self.url.raw_host\n        assert ret is not None\n        return ret\n\n    @property\n    def port(self) -> Optional[int]:\n        return self.url.port\n\n    @property\n    def request_info(self) -> RequestInfo:\n        headers: CIMultiDictProxy[str] = CIMultiDictProxy(self.headers)\n        return RequestInfo(self.url, self.method, headers, self.original_url)\n\n    def update_host(self, url: URL) -> None:\n        \"\"\"Update destination host, port and connection type (ssl).\"\"\"\n        # get host/port\n        if not url.raw_host:\n            raise InvalidURL(url)\n\n        # basic auth info\n        username, password = url.user, url.password\n        if username:\n            self.auth = helpers.BasicAuth(username, password or \"\")\n\n    def update_version(self, version: Union[http.HttpVersion, str]) -> None:\n        \"\"\"Convert request version to two elements tuple.\n\n        parser HTTP version '1.1' => (1, 1)\n        \"\"\"\n        if isinstance(version, str):\n            v = [part.strip() for part in version.split(\".\", 1)]\n            try:\n                version = http.HttpVersion(int(v[0]), int(v[1]))\n            except ValueError:\n                raise ValueError(\n                    f\"Can not parse http version number: {version}\"\n                ) from None\n        self.version = version\n\n    def update_headers(self, headers: Optional[LooseHeaders]) -> None:\n        \"\"\"Update request headers.\"\"\"\n        self.headers: CIMultiDict[str] = CIMultiDict()\n\n        # add host\n        netloc = cast(str, self.url.raw_host)\n        if helpers.is_ipv6_address(netloc):\n            netloc = f\"[{netloc}]\"\n        # See https://github.com/aio-libs/aiohttp/issues/3636.\n        netloc = netloc.rstrip(\".\")\n        if self.url.port is not None and not self.url.is_default_port():\n            netloc += \":\" + str(self.url.port)\n        self.headers[hdrs.HOST] = netloc\n\n        if headers:\n            if isinstance(headers, (dict, MultiDictProxy, MultiDict)):\n                headers = headers.items()  # type: ignore[assignment]\n\n            for key, value in headers:  # type: ignore[misc]\n                # A special case for Host header\n                if key.lower() == \"host\":\n                    self.headers[key] = value\n                else:\n                    self.headers.add(key, value)\n\n    def update_auto_headers(self, skip_auto_headers: Iterable[str]) -> None:\n        self.skip_auto_headers = CIMultiDict(\n            (hdr, None) for hdr in sorted(skip_auto_headers)\n        )\n        used_headers = self.headers.copy()\n        used_headers.extend(self.skip_auto_headers)  # type: ignore[arg-type]\n\n        for hdr, val in self.DEFAULT_HEADERS.items():\n            if hdr not in used_headers:\n                self.headers.add(hdr, val)\n\n        if hdrs.USER_AGENT not in used_headers:\n            self.headers[hdrs.USER_AGENT] = SERVER_SOFTWARE\n\n    def update_cookies(self, cookies: Optional[LooseCookies]) -> None:\n        \"\"\"Update request cookies header.\"\"\"\n        if not cookies:\n            return\n\n        c = SimpleCookie()\n        if hdrs.COOKIE in self.headers:\n            c.load(self.headers.get(hdrs.COOKIE, \"\"))\n            del self.headers[hdrs.COOKIE]\n\n        if isinstance(cookies, Mapping):\n            iter_cookies = cookies.items()\n        else:\n            iter_cookies = cookies  # type: ignore[assignment]\n        for name, value in iter_cookies:\n            if isinstance(value, Morsel):\n                # Preserve coded_value\n                mrsl_val = value.get(value.key, Morsel())\n                mrsl_val.set(value.key, value.value, value.coded_value)\n                c[name] = mrsl_val\n            else:\n                c[name] = value  # type: ignore[assignment]\n\n        self.headers[hdrs.COOKIE] = c.output(header=\"\", sep=\";\").strip()\n\n    def update_content_encoding(self, data: Any) -> None:\n        \"\"\"Set request content encoding.\"\"\"\n        if data is None:\n            return\n\n        enc = self.headers.get(hdrs.CONTENT_ENCODING, \"\").lower()\n        if enc:\n            if self.compress:\n                raise ValueError(\n                    \"compress can not be set \" \"if Content-Encoding header is set\"\n                )\n        elif self.compress:\n            if not isinstance(self.compress, str):\n                self.compress = \"deflate\"\n            self.headers[hdrs.CONTENT_ENCODING] = self.compress\n            self.chunked = True  # enable chunked, no need to deal with length\n\n    def update_transfer_encoding(self) -> None:\n        \"\"\"Analyze transfer-encoding header.\"\"\"\n        te = self.headers.get(hdrs.TRANSFER_ENCODING, \"\").lower()\n\n        if \"chunked\" in te:\n            if self.chunked:\n                raise ValueError(\n                    \"chunked can not be set \"\n                    'if \"Transfer-Encoding: chunked\" header is set'\n                )\n\n        elif self.chunked:\n            if hdrs.CONTENT_LENGTH in self.headers:\n                raise ValueError(\n                    \"chunked can not be set \" \"if Content-Length header is set\"\n                )\n\n            self.headers[hdrs.TRANSFER_ENCODING] = \"chunked\"\n        else:\n            if hdrs.CONTENT_LENGTH not in self.headers:\n                self.headers[hdrs.CONTENT_LENGTH] = str(len(self.body))\n\n    def update_auth(self, auth: Optional[BasicAuth], trust_env: bool = False) -> None:\n        \"\"\"Set basic auth.\"\"\"\n        if auth is None:\n            auth = self.auth\n        if auth is None and trust_env and self.url.host is not None:\n            netrc_obj = netrc_from_env()\n            with contextlib.suppress(LookupError):\n                auth = basicauth_from_netrc(netrc_obj, self.url.host)\n        if auth is None:\n            return\n\n        if not isinstance(auth, helpers.BasicAuth):\n            raise TypeError(\"BasicAuth() tuple is required instead\")\n\n        self.headers[hdrs.AUTHORIZATION] = auth.encode()\n\n    def update_body_from_data(self, body: Any) -> None:\n        if body is None:\n            return\n\n        # FormData\n        if isinstance(body, FormData):\n            body = body()\n\n        try:\n            body = payload.PAYLOAD_REGISTRY.get(body, disposition=None)\n        except payload.LookupError:\n            body = FormData(body)()\n\n        self.body = body\n\n        # enable chunked encoding if needed\n        if not self.chunked:\n            if hdrs.CONTENT_LENGTH not in self.headers:\n                size = body.size\n                if size is None:\n                    self.chunked = True\n                else:\n                    if hdrs.CONTENT_LENGTH not in self.headers:\n                        self.headers[hdrs.CONTENT_LENGTH] = str(size)\n\n        # copy payload headers\n        assert body.headers\n        for (key, value) in body.headers.items():\n            if key in self.headers:\n                continue\n            if key in self.skip_auto_headers:\n                continue\n            self.headers[key] = value\n\n    def update_expect_continue(self, expect: bool = False) -> None:\n        if expect:\n            self.headers[hdrs.EXPECT] = \"100-continue\"\n        elif self.headers.get(hdrs.EXPECT, \"\").lower() == \"100-continue\":\n            expect = True\n\n        if expect:\n            self._continue = self.loop.create_future()\n\n    def update_proxy(\n        self,\n        proxy: Optional[URL],\n        proxy_auth: Optional[BasicAuth],\n        proxy_headers: Optional[LooseHeaders],\n    ) -> None:\n        if proxy_auth and not isinstance(proxy_auth, helpers.BasicAuth):\n            raise ValueError(\"proxy_auth must be None or BasicAuth() tuple\")\n        self.proxy = proxy\n        self.proxy_auth = proxy_auth\n        self.proxy_headers = proxy_headers\n\n    def keep_alive(self) -> bool:\n        if self.version < HttpVersion10:\n            # keep alive not supported at all\n            return False\n        if self.version == HttpVersion10:\n            if self.headers.get(hdrs.CONNECTION) == \"keep-alive\":\n                return True\n            else:  # no headers means we close for Http 1.0\n                return False\n        elif self.headers.get(hdrs.CONNECTION) == \"close\":\n            return False\n\n        return True\n\n    async def write_bytes(\n        self, writer: AbstractStreamWriter, conn: \"Connection\"\n    ) -> None:\n        \"\"\"Support coroutines that yields bytes objects.\"\"\"\n        # 100 response\n        if self._continue is not None:\n            try:\n                await writer.drain()\n                await self._continue\n            except asyncio.CancelledError:\n                return\n\n        protocol = conn.protocol\n        assert protocol is not None\n        try:\n            if isinstance(self.body, payload.Payload):\n                await self.body.write(writer)\n            else:\n                if isinstance(self.body, (bytes, bytearray)):\n                    self.body = (self.body,)  # type: ignore[assignment]\n\n                for chunk in self.body:\n                    await writer.write(chunk)  # type: ignore[arg-type]\n        except OSError as exc:\n            if exc.errno is None and isinstance(exc, asyncio.TimeoutError):\n                protocol.set_exception(exc)\n            else:\n                new_exc = ClientOSError(\n                    exc.errno, \"Can not write request body for %s\" % self.url\n                )\n                new_exc.__context__ = exc\n                new_exc.__cause__ = exc\n                protocol.set_exception(new_exc)\n        except asyncio.CancelledError:\n            await writer.write_eof()\n        except Exception as exc:\n            protocol.set_exception(exc)\n        else:\n            await writer.write_eof()\n            protocol.start_timeout()\n\n    async def send(self, conn: \"Connection\") -> \"ClientResponse\":\n        # Specify request target:\n        # - CONNECT request must send authority form URI\n        # - not CONNECT proxy must send absolute form URI\n        # - most common is origin form URI\n        if self.method == hdrs.METH_CONNECT:\n            connect_host = self.url.raw_host\n            assert connect_host is not None\n            if helpers.is_ipv6_address(connect_host):\n                connect_host = f\"[{connect_host}]\"\n            path = f\"{connect_host}:{self.url.port}\"\n        elif self.proxy and not self.is_ssl():\n            path = str(self.url)\n        else:\n            path = self.url.raw_path\n            if self.url.raw_query_string:\n                path += \"?\" + self.url.raw_query_string\n\n        protocol = conn.protocol\n        assert protocol is not None\n        writer = StreamWriter(\n            protocol,\n            self.loop,\n            on_chunk_sent=functools.partial(\n                self._on_chunk_request_sent, self.method, self.url\n            ),\n            on_headers_sent=functools.partial(\n                self._on_headers_request_sent, self.method, self.url\n            ),\n        )\n\n        if self.compress:\n            writer.enable_compression(self.compress)\n\n        if self.chunked is not None:\n            writer.enable_chunking()\n\n        # set default content-type\n        if (\n            self.method in self.POST_METHODS\n            and hdrs.CONTENT_TYPE not in self.skip_auto_headers\n            and hdrs.CONTENT_TYPE not in self.headers\n        ):\n            self.headers[hdrs.CONTENT_TYPE] = \"application/octet-stream\"\n\n        # set the connection header\n        connection = self.headers.get(hdrs.CONNECTION)\n        if not connection:\n            if self.keep_alive():\n                if self.version == HttpVersion10:\n                    connection = \"keep-alive\"\n            else:\n                if self.version == HttpVersion11:\n                    connection = \"close\"\n\n        if connection is not None:\n            self.headers[hdrs.CONNECTION] = connection\n\n        # status + headers\n        status_line = \"{0} {1} HTTP/{2[0]}.{2[1]}\".format(\n            self.method, path, self.version\n        )\n        await writer.write_headers(status_line, self.headers)\n\n        self._writer = self.loop.create_task(self.write_bytes(writer, conn))\n\n        response_class = self.response_class\n        assert response_class is not None\n        self.response = response_class(\n            self.method,\n            self.original_url,\n            writer=self._writer,\n            continue100=self._continue,\n            timer=self._timer,\n            request_info=self.request_info,\n            traces=self._traces,\n            loop=self.loop,\n            session=self._session,\n        )\n        return self.response\n\n    async def close(self) -> None:\n        if self._writer is not None:\n            with contextlib.suppress(asyncio.CancelledError):\n                await self._writer\n\n    def terminate(self) -> None:\n        if self._writer is not None:\n            if not self.loop.is_closed():\n                self._writer.cancel()\n            self._writer.remove_done_callback(self.__reset_writer)\n            self._writer = None\n\n    async def _on_chunk_request_sent(self, method: str, url: URL, chunk: bytes) -> None:\n        for trace in self._traces:\n            await trace.send_request_chunk_sent(method, url, chunk)\n\n    async def _on_headers_request_sent(\n        self, method: str, url: URL, headers: \"CIMultiDict[str]\"\n    ) -> None:\n        for trace in self._traces:\n            await trace.send_request_headers(method, url, headers)\n\n\nclass ClientResponse(HeadersMixin):\n\n    # Some of these attributes are None when created,\n    # but will be set by the start() method.\n    # As the end user will likely never see the None values, we cheat the types below.\n    # from the Status-Line of the response\n    version: Optional[HttpVersion] = None  # HTTP-Version\n    status: int = None  # type: ignore[assignment] # Status-Code\n    reason: Optional[str] = None  # Reason-Phrase\n\n    content: StreamReader = None  # type: ignore[assignment]  # Payload stream\n    _headers: CIMultiDictProxy[str] = None  # type: ignore[assignment]\n    _raw_headers: RawHeaders = None  # type: ignore[assignment]\n\n    _connection = None  # current connection\n    _source_traceback: Optional[traceback.StackSummary] = None\n    # set up by ClientRequest after ClientResponse object creation\n    # post-init stage allows to not change ctor signature\n    _closed = True  # to allow __del__ for non-initialized properly response\n    _released = False\n    __writer = None\n\n    def __init__(\n        self,\n        method: str,\n        url: URL,\n        *,\n        writer: \"asyncio.Task[None]\",\n        continue100: Optional[\"asyncio.Future[bool]\"],\n        timer: BaseTimerContext,\n        request_info: RequestInfo,\n        traces: List[\"Trace\"],\n        loop: asyncio.AbstractEventLoop,\n        session: \"ClientSession\",\n    ) -> None:\n        assert isinstance(url, URL)\n\n        self.method = method\n        self.cookies = SimpleCookie()\n\n        self._real_url = url\n        self._url = url.with_fragment(None)\n        self._body: Any = None\n        self._writer: Optional[asyncio.Task[None]] = writer\n        self._continue = continue100  # None by default\n        self._closed = True\n        self._history: Tuple[ClientResponse, ...] = ()\n        self._request_info = request_info\n        self._timer = timer if timer is not None else TimerNoop()\n        self._cache: Dict[str, Any] = {}\n        self._traces = traces\n        self._loop = loop\n        # store a reference to session #1985\n        self._session: Optional[ClientSession] = session\n        # Save reference to _resolve_charset, so that get_encoding() will still\n        # work after the response has finished reading the body.\n        if session is None:\n            # TODO: Fix session=None in tests (see ClientRequest.__init__).\n            self._resolve_charset: Callable[\n                [\"ClientResponse\", bytes], str\n            ] = lambda *_: \"utf-8\"\n        else:\n            self._resolve_charset = session._resolve_charset\n        if loop.get_debug():\n            self._source_traceback = traceback.extract_stack(sys._getframe(1))\n\n    def __reset_writer(self, _: object = None) -> None:\n        self.__writer = None\n\n    @property\n    def _writer(self) -> Optional[\"asyncio.Task[None]\"]:\n        return self.__writer\n\n    @_writer.setter\n    def _writer(self, writer: Optional[\"asyncio.Task[None]\"]) -> None:\n        if self.__writer is not None:\n            self.__writer.remove_done_callback(self.__reset_writer)\n        self.__writer = writer\n        if writer is not None:\n            writer.add_done_callback(self.__reset_writer)\n\n    @reify\n    def url(self) -> URL:\n        return self._url\n\n    @reify\n    def url_obj(self) -> URL:\n        warnings.warn(\"Deprecated, use .url #1654\", DeprecationWarning, stacklevel=2)\n        return self._url\n\n    @reify\n    def real_url(self) -> URL:\n        return self._real_url\n\n    @reify\n    def host(self) -> str:\n        assert self._url.host is not None\n        return self._url.host\n\n    @reify\n    def headers(self) -> \"CIMultiDictProxy[str]\":\n        return self._headers\n\n    @reify\n    def raw_headers(self) -> RawHeaders:\n        return self._raw_headers\n\n    @reify\n    def request_info(self) -> RequestInfo:\n        return self._request_info\n\n    @reify\n    def content_disposition(self) -> Optional[ContentDisposition]:\n        raw = self._headers.get(hdrs.CONTENT_DISPOSITION)\n        if raw is None:\n            return None\n        disposition_type, params_dct = multipart.parse_content_disposition(raw)\n        params = MappingProxyType(params_dct)\n        filename = multipart.content_disposition_filename(params)\n        return ContentDisposition(disposition_type, params, filename)\n\n    def __del__(self, _warnings: Any = warnings) -> None:\n        if self._closed:\n            return\n\n        if self._connection is not None:\n            self._connection.release()\n            self._cleanup_writer()\n\n            if self._loop.get_debug():\n                kwargs = {\"source\": self}\n                _warnings.warn(f\"Unclosed response {self!r}\", ResourceWarning, **kwargs)\n                context = {\"client_response\": self, \"message\": \"Unclosed response\"}\n                if self._source_traceback:\n                    context[\"source_traceback\"] = self._source_traceback\n                self._loop.call_exception_handler(context)\n\n    def __repr__(self) -> str:\n        out = io.StringIO()\n        ascii_encodable_url = str(self.url)\n        if self.reason:\n            ascii_encodable_reason = self.reason.encode(\n                \"ascii\", \"backslashreplace\"\n            ).decode(\"ascii\")\n        else:\n            ascii_encodable_reason = \"None\"\n        print(\n            \"<ClientResponse({}) [{} {}]>\".format(\n                ascii_encodable_url, self.status, ascii_encodable_reason\n            ),\n            file=out,\n        )\n        print(self.headers, file=out)\n        return out.getvalue()\n\n    @property\n    def connection(self) -> Optional[\"Connection\"]:\n        return self._connection\n\n    @reify\n    def history(self) -> Tuple[\"ClientResponse\", ...]:\n        \"\"\"A sequence of of responses, if redirects occurred.\"\"\"\n        return self._history\n\n    @reify\n    def links(self) -> \"MultiDictProxy[MultiDictProxy[Union[str, URL]]]\":\n        links_str = \", \".join(self.headers.getall(\"link\", []))\n\n        if not links_str:\n            return MultiDictProxy(MultiDict())\n\n        links: MultiDict[MultiDictProxy[Union[str, URL]]] = MultiDict()\n\n        for val in re.split(r\",(?=\\s*<)\", links_str):\n            match = re.match(r\"\\s*<(.*)>(.*)\", val)\n            if match is None:  # pragma: no cover\n                # the check exists to suppress mypy error\n                continue\n            url, params_str = match.groups()\n            params = params_str.split(\";\")[1:]\n\n            link: MultiDict[Union[str, URL]] = MultiDict()\n\n            for param in params:\n                match = re.match(r\"^\\s*(\\S*)\\s*=\\s*(['\\\"]?)(.*?)(\\2)\\s*$\", param, re.M)\n                if match is None:  # pragma: no cover\n                    # the check exists to suppress mypy error\n                    continue\n                key, _, value, _ = match.groups()\n\n                link.add(key, value)\n\n            key = link.get(\"rel\", url)\n\n            link.add(\"url\", self.url.join(URL(url)))\n\n            links.add(str(key), MultiDictProxy(link))\n\n        return MultiDictProxy(links)\n\n    async def start(self, connection: \"Connection\") -> \"ClientResponse\":\n        \"\"\"Start response processing.\"\"\"\n        self._closed = False\n        self._protocol = connection.protocol\n        self._connection = connection\n\n        with self._timer:\n            while True:\n                # read response\n                try:\n                    protocol = self._protocol\n                    message, payload = await protocol.read()  # type: ignore[union-attr]\n                except http.HttpProcessingError as exc:\n                    raise ClientResponseError(\n                        self.request_info,\n                        self.history,\n                        status=exc.code,\n                        message=exc.message,\n                        headers=exc.headers,\n                    ) from exc\n\n                if message.code < 100 or message.code > 199 or message.code == 101:\n                    break\n\n                if self._continue is not None:\n                    set_result(self._continue, True)\n                    self._continue = None\n\n        # payload eof handler\n        payload.on_eof(self._response_eof)\n\n        # response status\n        self.version = message.version\n        self.status = message.code\n        self.reason = message.reason\n\n        # headers\n        self._headers = message.headers  # type is CIMultiDictProxy\n        self._raw_headers = message.raw_headers  # type is Tuple[bytes, bytes]\n\n        # payload\n        self.content = payload\n\n        # cookies\n        for hdr in self.headers.getall(hdrs.SET_COOKIE, ()):\n            try:\n                self.cookies.load(hdr)\n            except CookieError as exc:\n                client_logger.warning(\"Can not load response cookies: %s\", exc)\n        return self\n\n    def _response_eof(self) -> None:\n        if self._closed:\n            return\n\n        if self._connection is not None:\n            # websocket, protocol could be None because\n            # connection could be detached\n            if (\n                self._connection.protocol is not None\n                and self._connection.protocol.upgraded\n            ):\n                return\n\n            self._release_connection()\n\n        self._closed = True\n        self._cleanup_writer()\n\n    @property\n    def closed(self) -> bool:\n        return self._closed\n\n    def close(self) -> None:\n        if not self._released:\n            self._notify_content()\n\n        self._closed = True\n        if self._loop is None or self._loop.is_closed():\n            return\n\n        self._cleanup_writer()\n        self._release_connection()\n\n    def release(self) -> Any:\n        if not self._released:\n            self._notify_content()\n\n        self._closed = True\n\n        self._cleanup_writer()\n        self._release_connection()\n        return noop()\n\n    @property\n    def ok(self) -> bool:\n        \"\"\"Returns ``True`` if ``status`` is less than ``400``, ``False`` if not.\n\n        This is **not** a check for ``200 OK`` but a check that the response\n        status is under 400.\n        \"\"\"\n        return 400 > self.status\n\n    def raise_for_status(self) -> None:\n        if not self.ok:\n            # reason should always be not None for a started response\n            assert self.reason is not None\n            self.release()\n            raise ClientResponseError(\n                self.request_info,\n                self.history,\n                status=self.status,\n                message=self.reason,\n                headers=self.headers,\n            )\n\n    def _release_connection(self) -> None:\n        if self._connection is not None:\n            if self._writer is None:\n                self._connection.release()\n                self._connection = None\n            else:\n                self._writer.add_done_callback(lambda f: self._release_connection())\n\n    async def _wait_released(self) -> None:\n        if self._writer is not None:\n            await self._writer\n        self._release_connection()\n\n    def _cleanup_writer(self) -> None:\n        if self._writer is not None:\n            self._writer.cancel()\n        self._session = None\n\n    def _notify_content(self) -> None:\n        content = self.content\n        if content and content.exception() is None:\n            content.set_exception(ClientConnectionError(\"Connection closed\"))\n        self._released = True\n\n    async def wait_for_close(self) -> None:\n        if self._writer is not None:\n            await self._writer\n        self.release()\n\n    async def read(self) -> bytes:\n        \"\"\"Read response payload.\"\"\"\n        if self._body is None:\n            try:\n                self._body = await self.content.read()\n                for trace in self._traces:\n                    await trace.send_response_chunk_received(\n                        self.method, self.url, self._body\n                    )\n            except BaseException:\n                self.close()\n                raise\n        elif self._released:  # Response explicitly released\n            raise ClientConnectionError(\"Connection closed\")\n\n        await self._wait_released()  # Underlying connection released\n        return self._body  # type: ignore[no-any-return]\n\n    def get_encoding(self) -> str:\n        ctype = self.headers.get(hdrs.CONTENT_TYPE, \"\").lower()\n        mimetype = helpers.parse_mimetype(ctype)\n\n        encoding = mimetype.parameters.get(\"charset\")\n        if encoding:\n            with contextlib.suppress(LookupError):\n                return codecs.lookup(encoding).name\n\n        if mimetype.type == \"application\" and (\n            mimetype.subtype == \"json\" or mimetype.subtype == \"rdap\"\n        ):\n            # RFC 7159 states that the default encoding is UTF-8.\n            # RFC 7483 defines application/rdap+json\n            return \"utf-8\"\n\n        if self._body is None:\n            raise RuntimeError(\n                \"Cannot compute fallback encoding of a not yet read body\"\n            )\n\n        return self._resolve_charset(self, self._body)\n\n    async def text(self, encoding: Optional[str] = None, errors: str = \"strict\") -> str:\n        \"\"\"Read response payload and decode.\"\"\"\n        if self._body is None:\n            await self.read()\n\n        if encoding is None:\n            encoding = self.get_encoding()\n\n        return self._body.decode(  # type: ignore[no-any-return,union-attr]\n            encoding, errors=errors\n        )\n\n    async def json(\n        self,\n        *,\n        encoding: Optional[str] = None,\n        loads: JSONDecoder = DEFAULT_JSON_DECODER,\n        content_type: Optional[str] = \"application/json\",\n    ) -> Any:\n        \"\"\"Read and decodes JSON response.\"\"\"\n        if self._body is None:\n            await self.read()\n\n        if content_type:\n            ctype = self.headers.get(hdrs.CONTENT_TYPE, \"\").lower()\n            if not _is_expected_content_type(ctype, content_type):\n                raise ContentTypeError(\n                    self.request_info,\n                    self.history,\n                    message=(\n                        \"Attempt to decode JSON with \" \"unexpected mimetype: %s\" % ctype\n                    ),\n                    headers=self.headers,\n                )\n\n        stripped = self._body.strip()  # type: ignore[union-attr]\n        if not stripped:\n            return None\n\n        if encoding is None:\n            encoding = self.get_encoding()\n\n        return loads(stripped.decode(encoding))\n\n    async def __aenter__(self) -> \"ClientResponse\":\n        return self\n\n    async def __aexit__(\n        self,\n        exc_type: Optional[Type[BaseException]],\n        exc_val: Optional[BaseException],\n        exc_tb: Optional[TracebackType],\n    ) -> None:\n        # similar to _RequestContextManager, we do not need to check\n        # for exceptions, response object can close connection\n        # if state is broken\n        self.release()\n        await self.wait_for_close()\n",
            "new_file_content": "import asyncio\nimport codecs\nimport contextlib\nimport functools\nimport io\nimport re\nimport sys\nimport traceback\nimport warnings\nfrom hashlib import md5, sha1, sha256\nfrom http.cookies import CookieError, Morsel, SimpleCookie\nfrom types import MappingProxyType, TracebackType\nfrom typing import (\n    TYPE_CHECKING,\n    Any,\n    Callable,\n    Dict,\n    Iterable,\n    List,\n    Literal,\n    Mapping,\n    Optional,\n    Tuple,\n    Type,\n    Union,\n    cast,\n)\n\nimport attr\nfrom multidict import CIMultiDict, CIMultiDictProxy, MultiDict, MultiDictProxy\nfrom yarl import URL\n\nfrom . import hdrs, helpers, http, multipart, payload\nfrom .abc import AbstractStreamWriter\nfrom .client_exceptions import (\n    ClientConnectionError,\n    ClientOSError,\n    ClientResponseError,\n    ContentTypeError,\n    InvalidURL,\n    ServerFingerprintMismatch,\n)\nfrom .compression_utils import HAS_BROTLI\nfrom .formdata import FormData\nfrom .helpers import (\n    BaseTimerContext,\n    BasicAuth,\n    HeadersMixin,\n    TimerNoop,\n    basicauth_from_netrc,\n    netrc_from_env,\n    noop,\n    reify,\n    set_result,\n)\nfrom .http import (\n    SERVER_SOFTWARE,\n    HttpVersion,\n    HttpVersion10,\n    HttpVersion11,\n    StreamWriter,\n)\nfrom .log import client_logger\nfrom .streams import StreamReader\nfrom .typedefs import (\n    DEFAULT_JSON_DECODER,\n    JSONDecoder,\n    LooseCookies,\n    LooseHeaders,\n    RawHeaders,\n)\n\ntry:\n    import ssl\n    from ssl import SSLContext\nexcept ImportError:  # pragma: no cover\n    ssl = None  # type: ignore[assignment]\n    SSLContext = object  # type: ignore[misc,assignment]\n\n\n__all__ = (\"ClientRequest\", \"ClientResponse\", \"RequestInfo\", \"Fingerprint\")\n\n\nif TYPE_CHECKING:  # pragma: no cover\n    from .client import ClientSession\n    from .connector import Connection\n    from .tracing import Trace\n\n\n_CONTAINS_CONTROL_CHAR_RE = re.compile(r\"[^-!#$%&'*+.^_`|~0-9a-zA-Z]\")\njson_re = re.compile(r\"^application/(?:[\\w.+-]+?\\+)?json\")\n\n\ndef _gen_default_accept_encoding() -> str:\n    return \"gzip, deflate, br\" if HAS_BROTLI else \"gzip, deflate\"\n\n\n@attr.s(auto_attribs=True, frozen=True, slots=True)\nclass ContentDisposition:\n    type: Optional[str]\n    parameters: \"MappingProxyType[str, str]\"\n    filename: Optional[str]\n\n\n@attr.s(auto_attribs=True, frozen=True, slots=True)\nclass RequestInfo:\n    url: URL\n    method: str\n    headers: \"CIMultiDictProxy[str]\"\n    real_url: URL = attr.ib()\n\n    @real_url.default\n    def real_url_default(self) -> URL:\n        return self.url\n\n\nclass Fingerprint:\n    HASHFUNC_BY_DIGESTLEN = {\n        16: md5,\n        20: sha1,\n        32: sha256,\n    }\n\n    def __init__(self, fingerprint: bytes) -> None:\n        digestlen = len(fingerprint)\n        hashfunc = self.HASHFUNC_BY_DIGESTLEN.get(digestlen)\n        if not hashfunc:\n            raise ValueError(\"fingerprint has invalid length\")\n        elif hashfunc is md5 or hashfunc is sha1:\n            raise ValueError(\n                \"md5 and sha1 are insecure and \" \"not supported. Use sha256.\"\n            )\n        self._hashfunc = hashfunc\n        self._fingerprint = fingerprint\n\n    @property\n    def fingerprint(self) -> bytes:\n        return self._fingerprint\n\n    def check(self, transport: asyncio.Transport) -> None:\n        if not transport.get_extra_info(\"sslcontext\"):\n            return\n        sslobj = transport.get_extra_info(\"ssl_object\")\n        cert = sslobj.getpeercert(binary_form=True)\n        got = self._hashfunc(cert).digest()\n        if got != self._fingerprint:\n            host, port, *_ = transport.get_extra_info(\"peername\")\n            raise ServerFingerprintMismatch(self._fingerprint, got, host, port)\n\n\nif ssl is not None:\n    SSL_ALLOWED_TYPES = (ssl.SSLContext, bool, Fingerprint, type(None))\nelse:  # pragma: no cover\n    SSL_ALLOWED_TYPES = type(None)\n\n\ndef _merge_ssl_params(\n    ssl: Union[\"SSLContext\", Literal[False], Fingerprint, None],\n    verify_ssl: Optional[bool],\n    ssl_context: Optional[\"SSLContext\"],\n    fingerprint: Optional[bytes],\n) -> Union[\"SSLContext\", Literal[False], Fingerprint, None]:\n    if verify_ssl is not None and not verify_ssl:\n        warnings.warn(\n            \"verify_ssl is deprecated, use ssl=False instead\",\n            DeprecationWarning,\n            stacklevel=3,\n        )\n        if ssl is not None:\n            raise ValueError(\n                \"verify_ssl, ssl_context, fingerprint and ssl \"\n                \"parameters are mutually exclusive\"\n            )\n        else:\n            ssl = False\n    if ssl_context is not None:\n        warnings.warn(\n            \"ssl_context is deprecated, use ssl=context instead\",\n            DeprecationWarning,\n            stacklevel=3,\n        )\n        if ssl is not None:\n            raise ValueError(\n                \"verify_ssl, ssl_context, fingerprint and ssl \"\n                \"parameters are mutually exclusive\"\n            )\n        else:\n            ssl = ssl_context\n    if fingerprint is not None:\n        warnings.warn(\n            \"fingerprint is deprecated, \" \"use ssl=Fingerprint(fingerprint) instead\",\n            DeprecationWarning,\n            stacklevel=3,\n        )\n        if ssl is not None:\n            raise ValueError(\n                \"verify_ssl, ssl_context, fingerprint and ssl \"\n                \"parameters are mutually exclusive\"\n            )\n        else:\n            ssl = Fingerprint(fingerprint)\n    if not isinstance(ssl, SSL_ALLOWED_TYPES):\n        raise TypeError(\n            \"ssl should be SSLContext, bool, Fingerprint or None, \"\n            \"got {!r} instead.\".format(ssl)\n        )\n    return ssl\n\n\n@attr.s(auto_attribs=True, slots=True, frozen=True)\nclass ConnectionKey:\n    # the key should contain an information about used proxy / TLS\n    # to prevent reusing wrong connections from a pool\n    host: str\n    port: Optional[int]\n    is_ssl: bool\n    ssl: Union[SSLContext, None, Literal[False], Fingerprint]\n    proxy: Optional[URL]\n    proxy_auth: Optional[BasicAuth]\n    proxy_headers_hash: Optional[int]  # hash(CIMultiDict)\n\n\ndef _is_expected_content_type(\n    response_content_type: str, expected_content_type: str\n) -> bool:\n    if expected_content_type == \"application/json\":\n        return json_re.match(response_content_type) is not None\n    return expected_content_type in response_content_type\n\n\nclass ClientRequest:\n    GET_METHODS = {\n        hdrs.METH_GET,\n        hdrs.METH_HEAD,\n        hdrs.METH_OPTIONS,\n        hdrs.METH_TRACE,\n    }\n    POST_METHODS = {hdrs.METH_PATCH, hdrs.METH_POST, hdrs.METH_PUT}\n    ALL_METHODS = GET_METHODS.union(POST_METHODS).union({hdrs.METH_DELETE})\n\n    DEFAULT_HEADERS = {\n        hdrs.ACCEPT: \"*/*\",\n        hdrs.ACCEPT_ENCODING: _gen_default_accept_encoding(),\n    }\n\n    body = b\"\"\n    auth = None\n    response = None\n\n    __writer = None  # async task for streaming data\n    _continue = None  # waiter future for '100 Continue' response\n\n    # N.B.\n    # Adding __del__ method with self._writer closing doesn't make sense\n    # because _writer is instance method, thus it keeps a reference to self.\n    # Until writer has finished finalizer will not be called.\n\n    def __init__(\n        self,\n        method: str,\n        url: URL,\n        *,\n        params: Optional[Mapping[str, str]] = None,\n        headers: Optional[LooseHeaders] = None,\n        skip_auto_headers: Iterable[str] = frozenset(),\n        data: Any = None,\n        cookies: Optional[LooseCookies] = None,\n        auth: Optional[BasicAuth] = None,\n        version: http.HttpVersion = http.HttpVersion11,\n        compress: Optional[str] = None,\n        chunked: Optional[bool] = None,\n        expect100: bool = False,\n        loop: Optional[asyncio.AbstractEventLoop] = None,\n        response_class: Optional[Type[\"ClientResponse\"]] = None,\n        proxy: Optional[URL] = None,\n        proxy_auth: Optional[BasicAuth] = None,\n        timer: Optional[BaseTimerContext] = None,\n        session: Optional[\"ClientSession\"] = None,\n        ssl: Union[SSLContext, Literal[False], Fingerprint, None] = None,\n        proxy_headers: Optional[LooseHeaders] = None,\n        traces: Optional[List[\"Trace\"]] = None,\n        trust_env: bool = False,\n        server_hostname: Optional[str] = None,\n    ):\n        if loop is None:\n            loop = asyncio.get_event_loop()\n\n        match = _CONTAINS_CONTROL_CHAR_RE.search(method)\n        if match:\n            raise ValueError(\n                f\"Method cannot contain non-token characters {method!r} \"\n                \"(found at least {match.group()!r})\"\n            )\n\n        assert isinstance(url, URL), url\n        assert isinstance(proxy, (URL, type(None))), proxy\n        # FIXME: session is None in tests only, need to fix tests\n        # assert session is not None\n        self._session = cast(\"ClientSession\", session)\n        if params:\n            q = MultiDict(url.query)\n            url2 = url.with_query(params)\n            q.extend(url2.query)\n            url = url.with_query(q)\n        self.original_url = url\n        self.url = url.with_fragment(None)\n        self.method = method.upper()\n        self.chunked = chunked\n        self.compress = compress\n        self.loop = loop\n        self.length = None\n        if response_class is None:\n            real_response_class = ClientResponse\n        else:\n            real_response_class = response_class\n        self.response_class: Type[ClientResponse] = real_response_class\n        self._timer = timer if timer is not None else TimerNoop()\n        self._ssl = ssl\n        self.server_hostname = server_hostname\n\n        if loop.get_debug():\n            self._source_traceback = traceback.extract_stack(sys._getframe(1))\n\n        self.update_version(version)\n        self.update_host(url)\n        self.update_headers(headers)\n        self.update_auto_headers(skip_auto_headers)\n        self.update_cookies(cookies)\n        self.update_content_encoding(data)\n        self.update_auth(auth, trust_env)\n        self.update_proxy(proxy, proxy_auth, proxy_headers)\n\n        self.update_body_from_data(data)\n        if data is not None or self.method not in self.GET_METHODS:\n            self.update_transfer_encoding()\n        self.update_expect_continue(expect100)\n        if traces is None:\n            traces = []\n        self._traces = traces\n\n    def __reset_writer(self, _: object = None) -> None:\n        self.__writer = None\n\n    @property\n    def _writer(self) -> Optional[\"asyncio.Task[None]\"]:\n        return self.__writer\n\n    @_writer.setter\n    def _writer(self, writer: Optional[\"asyncio.Task[None]\"]) -> None:\n        if self.__writer is not None:\n            self.__writer.remove_done_callback(self.__reset_writer)\n        self.__writer = writer\n        if writer is not None:\n            writer.add_done_callback(self.__reset_writer)\n\n    def is_ssl(self) -> bool:\n        return self.url.scheme in (\"https\", \"wss\")\n\n    @property\n    def ssl(self) -> Union[\"SSLContext\", None, Literal[False], Fingerprint]:\n        return self._ssl\n\n    @property\n    def connection_key(self) -> ConnectionKey:\n        proxy_headers = self.proxy_headers\n        if proxy_headers:\n            h: Optional[int] = hash(tuple((k, v) for k, v in proxy_headers.items()))\n        else:\n            h = None\n        return ConnectionKey(\n            self.host,\n            self.port,\n            self.is_ssl(),\n            self.ssl,\n            self.proxy,\n            self.proxy_auth,\n            h,\n        )\n\n    @property\n    def host(self) -> str:\n        ret = self.url.raw_host\n        assert ret is not None\n        return ret\n\n    @property\n    def port(self) -> Optional[int]:\n        return self.url.port\n\n    @property\n    def request_info(self) -> RequestInfo:\n        headers: CIMultiDictProxy[str] = CIMultiDictProxy(self.headers)\n        return RequestInfo(self.url, self.method, headers, self.original_url)\n\n    def update_host(self, url: URL) -> None:\n        \"\"\"Update destination host, port and connection type (ssl).\"\"\"\n        # get host/port\n        if not url.raw_host:\n            raise InvalidURL(url)\n\n        # basic auth info\n        username, password = url.user, url.password\n        if username:\n            self.auth = helpers.BasicAuth(username, password or \"\")\n\n    def update_version(self, version: Union[http.HttpVersion, str]) -> None:\n        \"\"\"Convert request version to two elements tuple.\n\n        parser HTTP version '1.1' => (1, 1)\n        \"\"\"\n        if isinstance(version, str):\n            v = [part.strip() for part in version.split(\".\", 1)]\n            try:\n                version = http.HttpVersion(int(v[0]), int(v[1]))\n            except ValueError:\n                raise ValueError(\n                    f\"Can not parse http version number: {version}\"\n                ) from None\n        self.version = version\n\n    def update_headers(self, headers: Optional[LooseHeaders]) -> None:\n        \"\"\"Update request headers.\"\"\"\n        self.headers: CIMultiDict[str] = CIMultiDict()\n\n        # add host\n        netloc = cast(str, self.url.raw_host)\n        if helpers.is_ipv6_address(netloc):\n            netloc = f\"[{netloc}]\"\n        # See https://github.com/aio-libs/aiohttp/issues/3636.\n        netloc = netloc.rstrip(\".\")\n        if self.url.port is not None and not self.url.is_default_port():\n            netloc += \":\" + str(self.url.port)\n        self.headers[hdrs.HOST] = netloc\n\n        if headers:\n            if isinstance(headers, (dict, MultiDictProxy, MultiDict)):\n                headers = headers.items()  # type: ignore[assignment]\n\n            for key, value in headers:  # type: ignore[misc]\n                # A special case for Host header\n                if key.lower() == \"host\":\n                    self.headers[key] = value\n                else:\n                    self.headers.add(key, value)\n\n    def update_auto_headers(self, skip_auto_headers: Iterable[str]) -> None:\n        self.skip_auto_headers = CIMultiDict(\n            (hdr, None) for hdr in sorted(skip_auto_headers)\n        )\n        used_headers = self.headers.copy()\n        used_headers.extend(self.skip_auto_headers)  # type: ignore[arg-type]\n\n        for hdr, val in self.DEFAULT_HEADERS.items():\n            if hdr not in used_headers:\n                self.headers.add(hdr, val)\n\n        if hdrs.USER_AGENT not in used_headers:\n            self.headers[hdrs.USER_AGENT] = SERVER_SOFTWARE\n\n    def update_cookies(self, cookies: Optional[LooseCookies]) -> None:\n        \"\"\"Update request cookies header.\"\"\"\n        if not cookies:\n            return\n\n        c = SimpleCookie()\n        if hdrs.COOKIE in self.headers:\n            c.load(self.headers.get(hdrs.COOKIE, \"\"))\n            del self.headers[hdrs.COOKIE]\n\n        if isinstance(cookies, Mapping):\n            iter_cookies = cookies.items()\n        else:\n            iter_cookies = cookies  # type: ignore[assignment]\n        for name, value in iter_cookies:\n            if isinstance(value, Morsel):\n                # Preserve coded_value\n                mrsl_val = value.get(value.key, Morsel())\n                mrsl_val.set(value.key, value.value, value.coded_value)\n                c[name] = mrsl_val\n            else:\n                c[name] = value  # type: ignore[assignment]\n\n        self.headers[hdrs.COOKIE] = c.output(header=\"\", sep=\";\").strip()\n\n    def update_content_encoding(self, data: Any) -> None:\n        \"\"\"Set request content encoding.\"\"\"\n        if data is None:\n            return\n\n        enc = self.headers.get(hdrs.CONTENT_ENCODING, \"\").lower()\n        if enc:\n            if self.compress:\n                raise ValueError(\n                    \"compress can not be set \" \"if Content-Encoding header is set\"\n                )\n        elif self.compress:\n            if not isinstance(self.compress, str):\n                self.compress = \"deflate\"\n            self.headers[hdrs.CONTENT_ENCODING] = self.compress\n            self.chunked = True  # enable chunked, no need to deal with length\n\n    def update_transfer_encoding(self) -> None:\n        \"\"\"Analyze transfer-encoding header.\"\"\"\n        te = self.headers.get(hdrs.TRANSFER_ENCODING, \"\").lower()\n\n        if \"chunked\" in te:\n            if self.chunked:\n                raise ValueError(\n                    \"chunked can not be set \"\n                    'if \"Transfer-Encoding: chunked\" header is set'\n                )\n\n        elif self.chunked:\n            if hdrs.CONTENT_LENGTH in self.headers:\n                raise ValueError(\n                    \"chunked can not be set \" \"if Content-Length header is set\"\n                )\n\n            self.headers[hdrs.TRANSFER_ENCODING] = \"chunked\"\n        else:\n            if hdrs.CONTENT_LENGTH not in self.headers:\n                self.headers[hdrs.CONTENT_LENGTH] = str(len(self.body))\n\n    def update_auth(self, auth: Optional[BasicAuth], trust_env: bool = False) -> None:\n        \"\"\"Set basic auth.\"\"\"\n        if auth is None:\n            auth = self.auth\n        if auth is None and trust_env and self.url.host is not None:\n            netrc_obj = netrc_from_env()\n            with contextlib.suppress(LookupError):\n                auth = basicauth_from_netrc(netrc_obj, self.url.host)\n        if auth is None:\n            return\n\n        if not isinstance(auth, helpers.BasicAuth):\n            raise TypeError(\"BasicAuth() tuple is required instead\")\n\n        self.headers[hdrs.AUTHORIZATION] = auth.encode()\n\n    def update_body_from_data(self, body: Any) -> None:\n        if body is None:\n            return\n\n        # FormData\n        if isinstance(body, FormData):\n            body = body()\n\n        try:\n            body = payload.PAYLOAD_REGISTRY.get(body, disposition=None)\n        except payload.LookupError:\n            body = FormData(body)()\n\n        self.body = body\n\n        # enable chunked encoding if needed\n        if not self.chunked:\n            if hdrs.CONTENT_LENGTH not in self.headers:\n                size = body.size\n                if size is None:\n                    self.chunked = True\n                else:\n                    if hdrs.CONTENT_LENGTH not in self.headers:\n                        self.headers[hdrs.CONTENT_LENGTH] = str(size)\n\n        # copy payload headers\n        assert body.headers\n        for (key, value) in body.headers.items():\n            if key in self.headers:\n                continue\n            if key in self.skip_auto_headers:\n                continue\n            self.headers[key] = value\n\n    def update_expect_continue(self, expect: bool = False) -> None:\n        if expect:\n            self.headers[hdrs.EXPECT] = \"100-continue\"\n        elif self.headers.get(hdrs.EXPECT, \"\").lower() == \"100-continue\":\n            expect = True\n\n        if expect:\n            self._continue = self.loop.create_future()\n\n    def update_proxy(\n        self,\n        proxy: Optional[URL],\n        proxy_auth: Optional[BasicAuth],\n        proxy_headers: Optional[LooseHeaders],\n    ) -> None:\n        if proxy_auth and not isinstance(proxy_auth, helpers.BasicAuth):\n            raise ValueError(\"proxy_auth must be None or BasicAuth() tuple\")\n        self.proxy = proxy\n        self.proxy_auth = proxy_auth\n        self.proxy_headers = proxy_headers\n\n    def keep_alive(self) -> bool:\n        if self.version < HttpVersion10:\n            # keep alive not supported at all\n            return False\n        if self.version == HttpVersion10:\n            if self.headers.get(hdrs.CONNECTION) == \"keep-alive\":\n                return True\n            else:  # no headers means we close for Http 1.0\n                return False\n        elif self.headers.get(hdrs.CONNECTION) == \"close\":\n            return False\n\n        return True\n\n    async def write_bytes(\n        self, writer: AbstractStreamWriter, conn: \"Connection\"\n    ) -> None:\n        \"\"\"Support coroutines that yields bytes objects.\"\"\"\n        # 100 response\n        if self._continue is not None:\n            try:\n                await writer.drain()\n                await self._continue\n            except asyncio.CancelledError:\n                return\n\n        protocol = conn.protocol\n        assert protocol is not None\n        try:\n            if isinstance(self.body, payload.Payload):\n                await self.body.write(writer)\n            else:\n                if isinstance(self.body, (bytes, bytearray)):\n                    self.body = (self.body,)  # type: ignore[assignment]\n\n                for chunk in self.body:\n                    await writer.write(chunk)  # type: ignore[arg-type]\n        except OSError as exc:\n            if exc.errno is None and isinstance(exc, asyncio.TimeoutError):\n                protocol.set_exception(exc)\n            else:\n                new_exc = ClientOSError(\n                    exc.errno, \"Can not write request body for %s\" % self.url\n                )\n                new_exc.__context__ = exc\n                new_exc.__cause__ = exc\n                protocol.set_exception(new_exc)\n        except asyncio.CancelledError:\n            await writer.write_eof()\n        except Exception as exc:\n            protocol.set_exception(exc)\n        else:\n            await writer.write_eof()\n            protocol.start_timeout()\n\n    async def send(self, conn: \"Connection\") -> \"ClientResponse\":\n        # Specify request target:\n        # - CONNECT request must send authority form URI\n        # - not CONNECT proxy must send absolute form URI\n        # - most common is origin form URI\n        if self.method == hdrs.METH_CONNECT:\n            connect_host = self.url.raw_host\n            assert connect_host is not None\n            if helpers.is_ipv6_address(connect_host):\n                connect_host = f\"[{connect_host}]\"\n            path = f\"{connect_host}:{self.url.port}\"\n        elif self.proxy and not self.is_ssl():\n            path = str(self.url)\n        else:\n            path = self.url.raw_path\n            if self.url.raw_query_string:\n                path += \"?\" + self.url.raw_query_string\n\n        protocol = conn.protocol\n        assert protocol is not None\n        writer = StreamWriter(\n            protocol,\n            self.loop,\n            on_chunk_sent=functools.partial(\n                self._on_chunk_request_sent, self.method, self.url\n            ),\n            on_headers_sent=functools.partial(\n                self._on_headers_request_sent, self.method, self.url\n            ),\n        )\n\n        if self.compress:\n            writer.enable_compression(self.compress)\n\n        if self.chunked is not None:\n            writer.enable_chunking()\n\n        # set default content-type\n        if (\n            self.method in self.POST_METHODS\n            and hdrs.CONTENT_TYPE not in self.skip_auto_headers\n            and hdrs.CONTENT_TYPE not in self.headers\n        ):\n            self.headers[hdrs.CONTENT_TYPE] = \"application/octet-stream\"\n\n        # set the connection header\n        connection = self.headers.get(hdrs.CONNECTION)\n        if not connection:\n            if self.keep_alive():\n                if self.version == HttpVersion10:\n                    connection = \"keep-alive\"\n            else:\n                if self.version == HttpVersion11:\n                    connection = \"close\"\n\n        if connection is not None:\n            self.headers[hdrs.CONNECTION] = connection\n\n        # status + headers\n        status_line = \"{0} {1} HTTP/{v.major}.{v.minor}\".format(\n            self.method, path, v=self.version\n        )\n        await writer.write_headers(status_line, self.headers)\n\n        self._writer = self.loop.create_task(self.write_bytes(writer, conn))\n\n        response_class = self.response_class\n        assert response_class is not None\n        self.response = response_class(\n            self.method,\n            self.original_url,\n            writer=self._writer,\n            continue100=self._continue,\n            timer=self._timer,\n            request_info=self.request_info,\n            traces=self._traces,\n            loop=self.loop,\n            session=self._session,\n        )\n        return self.response\n\n    async def close(self) -> None:\n        if self._writer is not None:\n            with contextlib.suppress(asyncio.CancelledError):\n                await self._writer\n\n    def terminate(self) -> None:\n        if self._writer is not None:\n            if not self.loop.is_closed():\n                self._writer.cancel()\n            self._writer.remove_done_callback(self.__reset_writer)\n            self._writer = None\n\n    async def _on_chunk_request_sent(self, method: str, url: URL, chunk: bytes) -> None:\n        for trace in self._traces:\n            await trace.send_request_chunk_sent(method, url, chunk)\n\n    async def _on_headers_request_sent(\n        self, method: str, url: URL, headers: \"CIMultiDict[str]\"\n    ) -> None:\n        for trace in self._traces:\n            await trace.send_request_headers(method, url, headers)\n\n\nclass ClientResponse(HeadersMixin):\n\n    # Some of these attributes are None when created,\n    # but will be set by the start() method.\n    # As the end user will likely never see the None values, we cheat the types below.\n    # from the Status-Line of the response\n    version: Optional[HttpVersion] = None  # HTTP-Version\n    status: int = None  # type: ignore[assignment] # Status-Code\n    reason: Optional[str] = None  # Reason-Phrase\n\n    content: StreamReader = None  # type: ignore[assignment]  # Payload stream\n    _headers: CIMultiDictProxy[str] = None  # type: ignore[assignment]\n    _raw_headers: RawHeaders = None  # type: ignore[assignment]\n\n    _connection = None  # current connection\n    _source_traceback: Optional[traceback.StackSummary] = None\n    # set up by ClientRequest after ClientResponse object creation\n    # post-init stage allows to not change ctor signature\n    _closed = True  # to allow __del__ for non-initialized properly response\n    _released = False\n    __writer = None\n\n    def __init__(\n        self,\n        method: str,\n        url: URL,\n        *,\n        writer: \"asyncio.Task[None]\",\n        continue100: Optional[\"asyncio.Future[bool]\"],\n        timer: BaseTimerContext,\n        request_info: RequestInfo,\n        traces: List[\"Trace\"],\n        loop: asyncio.AbstractEventLoop,\n        session: \"ClientSession\",\n    ) -> None:\n        assert isinstance(url, URL)\n\n        self.method = method\n        self.cookies = SimpleCookie()\n\n        self._real_url = url\n        self._url = url.with_fragment(None)\n        self._body: Any = None\n        self._writer: Optional[asyncio.Task[None]] = writer\n        self._continue = continue100  # None by default\n        self._closed = True\n        self._history: Tuple[ClientResponse, ...] = ()\n        self._request_info = request_info\n        self._timer = timer if timer is not None else TimerNoop()\n        self._cache: Dict[str, Any] = {}\n        self._traces = traces\n        self._loop = loop\n        # store a reference to session #1985\n        self._session: Optional[ClientSession] = session\n        # Save reference to _resolve_charset, so that get_encoding() will still\n        # work after the response has finished reading the body.\n        if session is None:\n            # TODO: Fix session=None in tests (see ClientRequest.__init__).\n            self._resolve_charset: Callable[\n                [\"ClientResponse\", bytes], str\n            ] = lambda *_: \"utf-8\"\n        else:\n            self._resolve_charset = session._resolve_charset\n        if loop.get_debug():\n            self._source_traceback = traceback.extract_stack(sys._getframe(1))\n\n    def __reset_writer(self, _: object = None) -> None:\n        self.__writer = None\n\n    @property\n    def _writer(self) -> Optional[\"asyncio.Task[None]\"]:\n        return self.__writer\n\n    @_writer.setter\n    def _writer(self, writer: Optional[\"asyncio.Task[None]\"]) -> None:\n        if self.__writer is not None:\n            self.__writer.remove_done_callback(self.__reset_writer)\n        self.__writer = writer\n        if writer is not None:\n            writer.add_done_callback(self.__reset_writer)\n\n    @reify\n    def url(self) -> URL:\n        return self._url\n\n    @reify\n    def url_obj(self) -> URL:\n        warnings.warn(\"Deprecated, use .url #1654\", DeprecationWarning, stacklevel=2)\n        return self._url\n\n    @reify\n    def real_url(self) -> URL:\n        return self._real_url\n\n    @reify\n    def host(self) -> str:\n        assert self._url.host is not None\n        return self._url.host\n\n    @reify\n    def headers(self) -> \"CIMultiDictProxy[str]\":\n        return self._headers\n\n    @reify\n    def raw_headers(self) -> RawHeaders:\n        return self._raw_headers\n\n    @reify\n    def request_info(self) -> RequestInfo:\n        return self._request_info\n\n    @reify\n    def content_disposition(self) -> Optional[ContentDisposition]:\n        raw = self._headers.get(hdrs.CONTENT_DISPOSITION)\n        if raw is None:\n            return None\n        disposition_type, params_dct = multipart.parse_content_disposition(raw)\n        params = MappingProxyType(params_dct)\n        filename = multipart.content_disposition_filename(params)\n        return ContentDisposition(disposition_type, params, filename)\n\n    def __del__(self, _warnings: Any = warnings) -> None:\n        if self._closed:\n            return\n\n        if self._connection is not None:\n            self._connection.release()\n            self._cleanup_writer()\n\n            if self._loop.get_debug():\n                kwargs = {\"source\": self}\n                _warnings.warn(f\"Unclosed response {self!r}\", ResourceWarning, **kwargs)\n                context = {\"client_response\": self, \"message\": \"Unclosed response\"}\n                if self._source_traceback:\n                    context[\"source_traceback\"] = self._source_traceback\n                self._loop.call_exception_handler(context)\n\n    def __repr__(self) -> str:\n        out = io.StringIO()\n        ascii_encodable_url = str(self.url)\n        if self.reason:\n            ascii_encodable_reason = self.reason.encode(\n                \"ascii\", \"backslashreplace\"\n            ).decode(\"ascii\")\n        else:\n            ascii_encodable_reason = \"None\"\n        print(\n            \"<ClientResponse({}) [{} {}]>\".format(\n                ascii_encodable_url, self.status, ascii_encodable_reason\n            ),\n            file=out,\n        )\n        print(self.headers, file=out)\n        return out.getvalue()\n\n    @property\n    def connection(self) -> Optional[\"Connection\"]:\n        return self._connection\n\n    @reify\n    def history(self) -> Tuple[\"ClientResponse\", ...]:\n        \"\"\"A sequence of of responses, if redirects occurred.\"\"\"\n        return self._history\n\n    @reify\n    def links(self) -> \"MultiDictProxy[MultiDictProxy[Union[str, URL]]]\":\n        links_str = \", \".join(self.headers.getall(\"link\", []))\n\n        if not links_str:\n            return MultiDictProxy(MultiDict())\n\n        links: MultiDict[MultiDictProxy[Union[str, URL]]] = MultiDict()\n\n        for val in re.split(r\",(?=\\s*<)\", links_str):\n            match = re.match(r\"\\s*<(.*)>(.*)\", val)\n            if match is None:  # pragma: no cover\n                # the check exists to suppress mypy error\n                continue\n            url, params_str = match.groups()\n            params = params_str.split(\";\")[1:]\n\n            link: MultiDict[Union[str, URL]] = MultiDict()\n\n            for param in params:\n                match = re.match(r\"^\\s*(\\S*)\\s*=\\s*(['\\\"]?)(.*?)(\\2)\\s*$\", param, re.M)\n                if match is None:  # pragma: no cover\n                    # the check exists to suppress mypy error\n                    continue\n                key, _, value, _ = match.groups()\n\n                link.add(key, value)\n\n            key = link.get(\"rel\", url)\n\n            link.add(\"url\", self.url.join(URL(url)))\n\n            links.add(str(key), MultiDictProxy(link))\n\n        return MultiDictProxy(links)\n\n    async def start(self, connection: \"Connection\") -> \"ClientResponse\":\n        \"\"\"Start response processing.\"\"\"\n        self._closed = False\n        self._protocol = connection.protocol\n        self._connection = connection\n\n        with self._timer:\n            while True:\n                # read response\n                try:\n                    protocol = self._protocol\n                    message, payload = await protocol.read()  # type: ignore[union-attr]\n                except http.HttpProcessingError as exc:\n                    raise ClientResponseError(\n                        self.request_info,\n                        self.history,\n                        status=exc.code,\n                        message=exc.message,\n                        headers=exc.headers,\n                    ) from exc\n\n                if message.code < 100 or message.code > 199 or message.code == 101:\n                    break\n\n                if self._continue is not None:\n                    set_result(self._continue, True)\n                    self._continue = None\n\n        # payload eof handler\n        payload.on_eof(self._response_eof)\n\n        # response status\n        self.version = message.version\n        self.status = message.code\n        self.reason = message.reason\n\n        # headers\n        self._headers = message.headers  # type is CIMultiDictProxy\n        self._raw_headers = message.raw_headers  # type is Tuple[bytes, bytes]\n\n        # payload\n        self.content = payload\n\n        # cookies\n        for hdr in self.headers.getall(hdrs.SET_COOKIE, ()):\n            try:\n                self.cookies.load(hdr)\n            except CookieError as exc:\n                client_logger.warning(\"Can not load response cookies: %s\", exc)\n        return self\n\n    def _response_eof(self) -> None:\n        if self._closed:\n            return\n\n        if self._connection is not None:\n            # websocket, protocol could be None because\n            # connection could be detached\n            if (\n                self._connection.protocol is not None\n                and self._connection.protocol.upgraded\n            ):\n                return\n\n            self._release_connection()\n\n        self._closed = True\n        self._cleanup_writer()\n\n    @property\n    def closed(self) -> bool:\n        return self._closed\n\n    def close(self) -> None:\n        if not self._released:\n            self._notify_content()\n\n        self._closed = True\n        if self._loop is None or self._loop.is_closed():\n            return\n\n        self._cleanup_writer()\n        self._release_connection()\n\n    def release(self) -> Any:\n        if not self._released:\n            self._notify_content()\n\n        self._closed = True\n\n        self._cleanup_writer()\n        self._release_connection()\n        return noop()\n\n    @property\n    def ok(self) -> bool:\n        \"\"\"Returns ``True`` if ``status`` is less than ``400``, ``False`` if not.\n\n        This is **not** a check for ``200 OK`` but a check that the response\n        status is under 400.\n        \"\"\"\n        return 400 > self.status\n\n    def raise_for_status(self) -> None:\n        if not self.ok:\n            # reason should always be not None for a started response\n            assert self.reason is not None\n            self.release()\n            raise ClientResponseError(\n                self.request_info,\n                self.history,\n                status=self.status,\n                message=self.reason,\n                headers=self.headers,\n            )\n\n    def _release_connection(self) -> None:\n        if self._connection is not None:\n            if self._writer is None:\n                self._connection.release()\n                self._connection = None\n            else:\n                self._writer.add_done_callback(lambda f: self._release_connection())\n\n    async def _wait_released(self) -> None:\n        if self._writer is not None:\n            await self._writer\n        self._release_connection()\n\n    def _cleanup_writer(self) -> None:\n        if self._writer is not None:\n            self._writer.cancel()\n        self._session = None\n\n    def _notify_content(self) -> None:\n        content = self.content\n        if content and content.exception() is None:\n            content.set_exception(ClientConnectionError(\"Connection closed\"))\n        self._released = True\n\n    async def wait_for_close(self) -> None:\n        if self._writer is not None:\n            await self._writer\n        self.release()\n\n    async def read(self) -> bytes:\n        \"\"\"Read response payload.\"\"\"\n        if self._body is None:\n            try:\n                self._body = await self.content.read()\n                for trace in self._traces:\n                    await trace.send_response_chunk_received(\n                        self.method, self.url, self._body\n                    )\n            except BaseException:\n                self.close()\n                raise\n        elif self._released:  # Response explicitly released\n            raise ClientConnectionError(\"Connection closed\")\n\n        await self._wait_released()  # Underlying connection released\n        return self._body  # type: ignore[no-any-return]\n\n    def get_encoding(self) -> str:\n        ctype = self.headers.get(hdrs.CONTENT_TYPE, \"\").lower()\n        mimetype = helpers.parse_mimetype(ctype)\n\n        encoding = mimetype.parameters.get(\"charset\")\n        if encoding:\n            with contextlib.suppress(LookupError):\n                return codecs.lookup(encoding).name\n\n        if mimetype.type == \"application\" and (\n            mimetype.subtype == \"json\" or mimetype.subtype == \"rdap\"\n        ):\n            # RFC 7159 states that the default encoding is UTF-8.\n            # RFC 7483 defines application/rdap+json\n            return \"utf-8\"\n\n        if self._body is None:\n            raise RuntimeError(\n                \"Cannot compute fallback encoding of a not yet read body\"\n            )\n\n        return self._resolve_charset(self, self._body)\n\n    async def text(self, encoding: Optional[str] = None, errors: str = \"strict\") -> str:\n        \"\"\"Read response payload and decode.\"\"\"\n        if self._body is None:\n            await self.read()\n\n        if encoding is None:\n            encoding = self.get_encoding()\n\n        return self._body.decode(  # type: ignore[no-any-return,union-attr]\n            encoding, errors=errors\n        )\n\n    async def json(\n        self,\n        *,\n        encoding: Optional[str] = None,\n        loads: JSONDecoder = DEFAULT_JSON_DECODER,\n        content_type: Optional[str] = \"application/json\",\n    ) -> Any:\n        \"\"\"Read and decodes JSON response.\"\"\"\n        if self._body is None:\n            await self.read()\n\n        if content_type:\n            ctype = self.headers.get(hdrs.CONTENT_TYPE, \"\").lower()\n            if not _is_expected_content_type(ctype, content_type):\n                raise ContentTypeError(\n                    self.request_info,\n                    self.history,\n                    message=(\n                        \"Attempt to decode JSON with \" \"unexpected mimetype: %s\" % ctype\n                    ),\n                    headers=self.headers,\n                )\n\n        stripped = self._body.strip()  # type: ignore[union-attr]\n        if not stripped:\n            return None\n\n        if encoding is None:\n            encoding = self.get_encoding()\n\n        return loads(stripped.decode(encoding))\n\n    async def __aenter__(self) -> \"ClientResponse\":\n        return self\n\n    async def __aexit__(\n        self,\n        exc_type: Optional[Type[BaseException]],\n        exc_val: Optional[BaseException],\n        exc_tb: Optional[TracebackType],\n    ) -> None:\n        # similar to _RequestContextManager, we do not need to check\n        # for exceptions, response object can close connection\n        # if state is broken\n        self.release()\n        await self.wait_for_close()\n",
            "header": {
                "file": {
                    "path": "aiohttp/client_reqrep.py"
                },
                "misc_line": null
            },
            "index_line": {
                "old_commit_hash": "851ab220",
                "new_commit_hash": "4cea7466",
                "mode": "100644"
            },
            "is_binary_file": false,
            "binary_line": null,
            "minus_file": {
                "path": "a/aiohttp/client_reqrep.py"
            },
            "plus_file": {
                "path": "b/aiohttp/client_reqrep.py"
            },
            "hunks": [
                {
                    "descriptor": {
                        "old_range": {
                            "start": 706,
                            "length": 8
                        },
                        "new_range": {
                            "start": 706,
                            "length": 8
                        },
                        "section": "class ClientRequest:"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "            self.headers[hdrs.CONNECTION] = connection",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "        # status + headers",
                                "type": "context"
                            },
                            {
                                "content": "        status_line = \"{0} {1} HTTP/{2[0]}.{2[1]}\".format(",
                                "type": "deleted"
                            },
                            {
                                "content": "            self.method, path, self.version",
                                "type": "deleted"
                            },
                            {
                                "content": "        status_line = \"{0} {1} HTTP/{v.major}.{v.minor}\".format(",
                                "type": "added"
                            },
                            {
                                "content": "            self.method, path, v=self.version",
                                "type": "added"
                            },
                            {
                                "content": "        )",
                                "type": "context"
                            },
                            {
                                "content": "        await writer.write_headers(status_line, self.headers)",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [
                        {
                            "file_name": "aiohttp/client_reqrep.py",
                            "type": "method",
                            "name": "ClientRequest.send",
                            "content": "class ClientRequest:\n    GET_METHODS = {\n        hdrs.METH_GET,\n        hdrs.METH_HEAD,\n        hdrs.METH_OPTIONS,\n        hdrs.METH_TRACE,\n    }\n    POST_METHODS = {hdrs.METH_PATCH, hdrs.METH_POST, hdrs.METH_PUT}\n    ALL_METHODS = GET_METHODS.union(POST_METHODS).union({hdrs.METH_DELETE})\n\n    DEFAULT_HEADERS = {\n        hdrs.ACCEPT: \"*/*\",\n        hdrs.ACCEPT_ENCODING: _gen_default_accept_encoding(),\n    }\n\n    body = b\"\"\n    auth = None\n    response = None\n\n    __writer = None  # async task for streaming data\n    _continue = None  # waiter future for '100 Continue' response\n\n    # N.B.\n    # Adding __del__ method with self._writer closing doesn't make sense\n    # because _writer is instance method, thus it keeps a reference to self.\n    # Until writer has finished finalizer will not be called.\n\n    def __init__(\n        self,\n        method: str,\n        url: URL,\n        *,\n        params: Optional[Mapping[str, str]] = None,\n        headers: Optional[LooseHeaders] = None,\n        skip_auto_headers: Iterable[str] = frozenset(),\n        data: Any = None,\n        cookies: Optional[LooseCookies] = None,\n        auth: Optional[BasicAuth] = None,\n        version: http.HttpVersion = http.HttpVersion11,\n        compress: Optional[str] = None,\n        chunked: Optional[bool] = None,\n        expect100: bool = False,\n        loop: Optional[asyncio.AbstractEventLoop] = None,\n        response_class: Optional[Type[\"ClientResponse\"]] = None,\n        proxy: Optional[URL] = None,\n        proxy_auth: Optional[BasicAuth] = None,\n        timer: Optional[BaseTimerContext] = None,\n        session: Optional[\"ClientSession\"] = None,\n        ssl: Union[SSLContext, Literal[False], Fingerprint, None] = None,\n        proxy_headers: Optional[LooseHeaders] = None,\n        traces: Optional[List[\"Trace\"]] = None,\n        trust_env: bool = False,\n        server_hostname: Optional[str] = None,\n    ):\n        if loop is None:\n            loop = asyncio.get_event_loop()\n\n        match = _CONTAINS_CONTROL_CHAR_RE.search(method)\n        if match:\n            raise ValueError(\n                f\"Method cannot contain non-token characters {method!r} \"\n                \"(found at least {match.group()!r})\"\n            )\n\n        assert isinstance(url, URL), url\n        assert isinstance(proxy, (URL, type(None))), proxy\n        # FIXME: session is None in tests only, need to fix tests\n        # assert session is not None\n        self._session = cast(\"ClientSession\", session)\n        if params:\n            q = MultiDict(url.query)\n            url2 = url.with_query(params)\n            q.extend(url2.query)\n            url = url.with_query(q)\n        self.original_url = url\n        self.url = url.with_fragment(None)\n        self.method = method.upper()\n        self.chunked = chunked\n        self.compress = compress\n        self.loop = loop\n        self.length = None\n        if response_class is None:\n            real_response_class = ClientResponse\n        else:\n            real_response_class = response_class\n        self.response_class: Type[ClientResponse] = real_response_class\n        self._timer = timer if timer is not None else TimerNoop()\n        self._ssl = ssl\n        self.server_hostname = server_hostname\n\n        if loop.get_debug():\n            self._source_traceback = traceback.extract_stack(sys._getframe(1))\n\n        self.update_version(version)\n        self.update_host(url)\n        self.update_headers(headers)\n        self.update_auto_headers(skip_auto_headers)\n        self.update_cookies(cookies)\n        self.update_content_encoding(data)\n        self.update_auth(auth, trust_env)\n        self.update_proxy(proxy, proxy_auth, proxy_headers)\n\n        self.update_body_from_data(data)\n        if data is not None or self.method not in self.GET_METHODS:\n            self.update_transfer_encoding()\n        self.update_expect_continue(expect100)\n        if traces is None:\n            traces = []\n        self._traces = traces\n\n    def __reset_writer(self, _: object = None) -> None:\n        self.__writer = None\n\n    @property\n    def _writer(self) -> Optional[\"asyncio.Task[None]\"]:\n        return self.__writer\n\n    @_writer.setter\n    def _writer(self, writer: Optional[\"asyncio.Task[None]\"]) -> None:\n        if self.__writer is not None:\n            self.__writer.remove_done_callback(self.__reset_writer)\n        self.__writer = writer\n        if writer is not None:\n            writer.add_done_callback(self.__reset_writer)\n\n    def is_ssl(self) -> bool:\n        return self.url.scheme in (\"https\", \"wss\")\n\n    @property\n    def ssl(self) -> Union[\"SSLContext\", None, Literal[False], Fingerprint]:\n        return self._ssl\n\n    @property\n    def connection_key(self) -> ConnectionKey:\n        proxy_headers = self.proxy_headers\n        if proxy_headers:\n            h: Optional[int] = hash(tuple((k, v) for k, v in proxy_headers.items()))\n        else:\n            h = None\n        return ConnectionKey(\n            self.host,\n            self.port,\n            self.is_ssl(),\n            self.ssl,\n            self.proxy,\n            self.proxy_auth,\n            h,\n        )\n\n    @property\n    def host(self) -> str:\n        ret = self.url.raw_host\n        assert ret is not None\n        return ret\n\n    @property\n    def port(self) -> Optional[int]:\n        return self.url.port\n\n    @property\n    def request_info(self) -> RequestInfo:\n        headers: CIMultiDictProxy[str] = CIMultiDictProxy(self.headers)\n        return RequestInfo(self.url, self.method, headers, self.original_url)\n\n    def update_host(self, url: URL) -> None:\n        \"\"\"Update destination host, port and connection type (ssl).\"\"\"\n        # get host/port\n        if not url.raw_host:\n            raise InvalidURL(url)\n\n        # basic auth info\n        username, password = url.user, url.password\n        if username:\n            self.auth = helpers.BasicAuth(username, password or \"\")\n\n    def update_version(self, version: Union[http.HttpVersion, str]) -> None:\n        \"\"\"Convert request version to two elements tuple.\n\n        parser HTTP version '1.1' => (1, 1)\n        \"\"\"\n        if isinstance(version, str):\n            v = [part.strip() for part in version.split(\".\", 1)]\n            try:\n                version = http.HttpVersion(int(v[0]), int(v[1]))\n            except ValueError:\n                raise ValueError(\n                    f\"Can not parse http version number: {version}\"\n                ) from None\n        self.version = version\n\n    def update_headers(self, headers: Optional[LooseHeaders]) -> None:\n        \"\"\"Update request headers.\"\"\"\n        self.headers: CIMultiDict[str] = CIMultiDict()\n\n        # add host\n        netloc = cast(str, self.url.raw_host)\n        if helpers.is_ipv6_address(netloc):\n            netloc = f\"[{netloc}]\"\n        # See https://github.com/aio-libs/aiohttp/issues/3636.\n        netloc = netloc.rstrip(\".\")\n        if self.url.port is not None and not self.url.is_default_port():\n            netloc += \":\" + str(self.url.port)\n        self.headers[hdrs.HOST] = netloc\n\n        if headers:\n            if isinstance(headers, (dict, MultiDictProxy, MultiDict)):\n                headers = headers.items()  # type: ignore[assignment]\n\n            for key, value in headers:  # type: ignore[misc]\n                # A special case for Host header\n                if key.lower() == \"host\":\n                    self.headers[key] = value\n                else:\n                    self.headers.add(key, value)\n\n    def update_auto_headers(self, skip_auto_headers: Iterable[str]) -> None:\n        self.skip_auto_headers = CIMultiDict(\n            (hdr, None) for hdr in sorted(skip_auto_headers)\n        )\n        used_headers = self.headers.copy()\n        used_headers.extend(self.skip_auto_headers)  # type: ignore[arg-type]\n\n        for hdr, val in self.DEFAULT_HEADERS.items():\n            if hdr not in used_headers:\n                self.headers.add(hdr, val)\n\n        if hdrs.USER_AGENT not in used_headers:\n            self.headers[hdrs.USER_AGENT] = SERVER_SOFTWARE\n\n    def update_cookies(self, cookies: Optional[LooseCookies]) -> None:\n        \"\"\"Update request cookies header.\"\"\"\n        if not cookies:\n            return\n\n        c = SimpleCookie()\n        if hdrs.COOKIE in self.headers:\n            c.load(self.headers.get(hdrs.COOKIE, \"\"))\n            del self.headers[hdrs.COOKIE]\n\n        if isinstance(cookies, Mapping):\n            iter_cookies = cookies.items()\n        else:\n            iter_cookies = cookies  # type: ignore[assignment]\n        for name, value in iter_cookies:\n            if isinstance(value, Morsel):\n                # Preserve coded_value\n                mrsl_val = value.get(value.key, Morsel())\n                mrsl_val.set(value.key, value.value, value.coded_value)\n                c[name] = mrsl_val\n            else:\n                c[name] = value  # type: ignore[assignment]\n\n        self.headers[hdrs.COOKIE] = c.output(header=\"\", sep=\";\").strip()\n\n    def update_content_encoding(self, data: Any) -> None:\n        \"\"\"Set request content encoding.\"\"\"\n        if data is None:\n            return\n\n        enc = self.headers.get(hdrs.CONTENT_ENCODING, \"\").lower()\n        if enc:\n            if self.compress:\n                raise ValueError(\n                    \"compress can not be set \" \"if Content-Encoding header is set\"\n                )\n        elif self.compress:\n            if not isinstance(self.compress, str):\n                self.compress = \"deflate\"\n            self.headers[hdrs.CONTENT_ENCODING] = self.compress\n            self.chunked = True  # enable chunked, no need to deal with length\n\n    def update_transfer_encoding(self) -> None:\n        \"\"\"Analyze transfer-encoding header.\"\"\"\n        te = self.headers.get(hdrs.TRANSFER_ENCODING, \"\").lower()\n\n        if \"chunked\" in te:\n            if self.chunked:\n                raise ValueError(\n                    \"chunked can not be set \"\n                    'if \"Transfer-Encoding: chunked\" header is set'\n                )\n\n        elif self.chunked:\n            if hdrs.CONTENT_LENGTH in self.headers:\n                raise ValueError(\n                    \"chunked can not be set \" \"if Content-Length header is set\"\n                )\n\n            self.headers[hdrs.TRANSFER_ENCODING] = \"chunked\"\n        else:\n            if hdrs.CONTENT_LENGTH not in self.headers:\n                self.headers[hdrs.CONTENT_LENGTH] = str(len(self.body))\n\n    def update_auth(self, auth: Optional[BasicAuth], trust_env: bool = False) -> None:\n        \"\"\"Set basic auth.\"\"\"\n        if auth is None:\n            auth = self.auth\n        if auth is None and trust_env and self.url.host is not None:\n            netrc_obj = netrc_from_env()\n            with contextlib.suppress(LookupError):\n                auth = basicauth_from_netrc(netrc_obj, self.url.host)\n        if auth is None:\n            return\n\n        if not isinstance(auth, helpers.BasicAuth):\n            raise TypeError(\"BasicAuth() tuple is required instead\")\n\n        self.headers[hdrs.AUTHORIZATION] = auth.encode()\n\n    def update_body_from_data(self, body: Any) -> None:\n        if body is None:\n            return\n\n        # FormData\n        if isinstance(body, FormData):\n            body = body()\n\n        try:\n            body = payload.PAYLOAD_REGISTRY.get(body, disposition=None)\n        except payload.LookupError:\n            body = FormData(body)()\n\n        self.body = body\n\n        # enable chunked encoding if needed\n        if not self.chunked:\n            if hdrs.CONTENT_LENGTH not in self.headers:\n                size = body.size\n                if size is None:\n                    self.chunked = True\n                else:\n                    if hdrs.CONTENT_LENGTH not in self.headers:\n                        self.headers[hdrs.CONTENT_LENGTH] = str(size)\n\n        # copy payload headers\n        assert body.headers\n        for (key, value) in body.headers.items():\n            if key in self.headers:\n                continue\n            if key in self.skip_auto_headers:\n                continue\n            self.headers[key] = value\n\n    def update_expect_continue(self, expect: bool = False) -> None:\n        if expect:\n            self.headers[hdrs.EXPECT] = \"100-continue\"\n        elif self.headers.get(hdrs.EXPECT, \"\").lower() == \"100-continue\":\n            expect = True\n\n        if expect:\n            self._continue = self.loop.create_future()\n\n    def update_proxy(\n        self,\n        proxy: Optional[URL],\n        proxy_auth: Optional[BasicAuth],\n        proxy_headers: Optional[LooseHeaders],\n    ) -> None:\n        if proxy_auth and not isinstance(proxy_auth, helpers.BasicAuth):\n            raise ValueError(\"proxy_auth must be None or BasicAuth() tuple\")\n        self.proxy = proxy\n        self.proxy_auth = proxy_auth\n        self.proxy_headers = proxy_headers\n\n    def keep_alive(self) -> bool:\n        if self.version < HttpVersion10:\n            # keep alive not supported at all\n            return False\n        if self.version == HttpVersion10:\n            if self.headers.get(hdrs.CONNECTION) == \"keep-alive\":\n                return True\n            else:  # no headers means we close for Http 1.0\n                return False\n        elif self.headers.get(hdrs.CONNECTION) == \"close\":\n            return False\n\n        return True\n\n    async def write_bytes(\n        self, writer: AbstractStreamWriter, conn: \"Connection\"\n    ) -> None:\n        \"\"\"Support coroutines that yields bytes objects.\"\"\"\n        # 100 response\n        if self._continue is not None:\n            try:\n                await writer.drain()\n                await self._continue\n            except asyncio.CancelledError:\n                return\n\n        protocol = conn.protocol\n        assert protocol is not None\n        try:\n            if isinstance(self.body, payload.Payload):\n                await self.body.write(writer)\n            else:\n                if isinstance(self.body, (bytes, bytearray)):\n                    self.body = (self.body,)  # type: ignore[assignment]\n\n                for chunk in self.body:\n                    await writer.write(chunk)  # type: ignore[arg-type]\n        except OSError as exc:\n            if exc.errno is None and isinstance(exc, asyncio.TimeoutError):\n                protocol.set_exception(exc)\n            else:\n                new_exc = ClientOSError(\n                    exc.errno, \"Can not write request body for %s\" % self.url\n                )\n                new_exc.__context__ = exc\n                new_exc.__cause__ = exc\n                protocol.set_exception(new_exc)\n        except asyncio.CancelledError:\n            await writer.write_eof()\n        except Exception as exc:\n            protocol.set_exception(exc)\n        else:\n            await writer.write_eof()\n            protocol.start_timeout()\n\n    async def send(self, conn: \"Connection\") -> \"ClientResponse\":\n        # Specify request target:\n        # - CONNECT request must send authority form URI\n        # - not CONNECT proxy must send absolute form URI\n        # - most common is origin form URI\n        if self.method == hdrs.METH_CONNECT:\n            connect_host = self.url.raw_host\n            assert connect_host is not None\n            if helpers.is_ipv6_address(connect_host):\n                connect_host = f\"[{connect_host}]\"\n            path = f\"{connect_host}:{self.url.port}\"\n        elif self.proxy and not self.is_ssl():\n            path = str(self.url)\n        else:\n            path = self.url.raw_path\n            if self.url.raw_query_string:\n                path += \"?\" + self.url.raw_query_string\n\n        protocol = conn.protocol\n        assert protocol is not None\n        writer = StreamWriter(\n            protocol,\n            self.loop,\n            on_chunk_sent=functools.partial(\n                self._on_chunk_request_sent, self.method, self.url\n            ),\n            on_headers_sent=functools.partial(\n                self._on_headers_request_sent, self.method, self.url\n            ),\n        )\n\n        if self.compress:\n            writer.enable_compression(self.compress)\n\n        if self.chunked is not None:\n            writer.enable_chunking()\n\n        # set default content-type\n        if (\n            self.method in self.POST_METHODS\n            and hdrs.CONTENT_TYPE not in self.skip_auto_headers\n            and hdrs.CONTENT_TYPE not in self.headers\n        ):\n            self.headers[hdrs.CONTENT_TYPE] = \"application/octet-stream\"\n\n        # set the connection header\n        connection = self.headers.get(hdrs.CONNECTION)\n        if not connection:\n            if self.keep_alive():\n                if self.version == HttpVersion10:\n                    connection = \"keep-alive\"\n            else:\n                if self.version == HttpVersion11:\n                    connection = \"close\"\n\n        if connection is not None:\n            self.headers[hdrs.CONNECTION] = connection\n\n        # status + headers\n        status_line = \"{0} {1} HTTP/{2[0]}.{2[1]}\".format(\n            self.method, path, self.version\n        )\n        await writer.write_headers(status_line, self.headers)\n\n        self._writer = self.loop.create_task(self.write_bytes(writer, conn))\n\n        response_class = self.response_class\n        assert response_class is not None\n        self.response = response_class(\n            self.method,\n            self.original_url,\n            writer=self._writer,\n            continue100=self._continue,\n            timer=self._timer,\n            request_info=self.request_info,\n            traces=self._traces,\n            loop=self.loop,\n            session=self._session,\n        )\n        return self.response\n\n    async def close(self) -> None:\n        if self._writer is not None:\n            with contextlib.suppress(asyncio.CancelledError):\n                await self._writer\n\n    def terminate(self) -> None:\n        if self._writer is not None:\n            if not self.loop.is_closed():\n                self._writer.cancel()\n            self._writer.remove_done_callback(self.__reset_writer)\n            self._writer = None\n\n    async def _on_chunk_request_sent(self, method: str, url: URL, chunk: bytes) -> None:\n        for trace in self._traces:\n            await trace.send_request_chunk_sent(method, url, chunk)\n\n    async def _on_headers_request_sent(\n        self, method: str, url: URL, headers: \"CIMultiDict[str]\"\n    ) -> None:\n        for trace in self._traces:\n            await trace.send_request_headers(method, url, headers)",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 650,
                            "end_lineno": 729,
                            "parent": {
                                "file_name": "aiohttp/client_reqrep.py",
                                "type": "class",
                                "name": "ClientRequest",
                                "content": "class ClientRequest:\n    GET_METHODS = {\n        hdrs.METH_GET,\n        hdrs.METH_HEAD,\n        hdrs.METH_OPTIONS,\n        hdrs.METH_TRACE,\n    }\n    POST_METHODS = {hdrs.METH_PATCH, hdrs.METH_POST, hdrs.METH_PUT}\n    ALL_METHODS = GET_METHODS.union(POST_METHODS).union({hdrs.METH_DELETE})\n\n    DEFAULT_HEADERS = {\n        hdrs.ACCEPT: \"*/*\",\n        hdrs.ACCEPT_ENCODING: _gen_default_accept_encoding(),\n    }\n\n    body = b\"\"\n    auth = None\n    response = None\n\n    __writer = None  # async task for streaming data\n    _continue = None  # waiter future for '100 Continue' response\n\n    # N.B.\n    # Adding __del__ method with self._writer closing doesn't make sense\n    # because _writer is instance method, thus it keeps a reference to self.\n    # Until writer has finished finalizer will not be called.\n\n    def __init__(\n        self,\n        method: str,\n        url: URL,\n        *,\n        params: Optional[Mapping[str, str]] = None,\n        headers: Optional[LooseHeaders] = None,\n        skip_auto_headers: Iterable[str] = frozenset(),\n        data: Any = None,\n        cookies: Optional[LooseCookies] = None,\n        auth: Optional[BasicAuth] = None,\n        version: http.HttpVersion = http.HttpVersion11,\n        compress: Optional[str] = None,\n        chunked: Optional[bool] = None,\n        expect100: bool = False,\n        loop: Optional[asyncio.AbstractEventLoop] = None,\n        response_class: Optional[Type[\"ClientResponse\"]] = None,\n        proxy: Optional[URL] = None,\n        proxy_auth: Optional[BasicAuth] = None,\n        timer: Optional[BaseTimerContext] = None,\n        session: Optional[\"ClientSession\"] = None,\n        ssl: Union[SSLContext, Literal[False], Fingerprint, None] = None,\n        proxy_headers: Optional[LooseHeaders] = None,\n        traces: Optional[List[\"Trace\"]] = None,\n        trust_env: bool = False,\n        server_hostname: Optional[str] = None,\n    ):\n        if loop is None:\n            loop = asyncio.get_event_loop()\n\n        match = _CONTAINS_CONTROL_CHAR_RE.search(method)\n        if match:\n            raise ValueError(\n                f\"Method cannot contain non-token characters {method!r} \"\n                \"(found at least {match.group()!r})\"\n            )\n\n        assert isinstance(url, URL), url\n        assert isinstance(proxy, (URL, type(None))), proxy\n        # FIXME: session is None in tests only, need to fix tests\n        # assert session is not None\n        self._session = cast(\"ClientSession\", session)\n        if params:\n            q = MultiDict(url.query)\n            url2 = url.with_query(params)\n            q.extend(url2.query)\n            url = url.with_query(q)\n        self.original_url = url\n        self.url = url.with_fragment(None)\n        self.method = method.upper()\n        self.chunked = chunked\n        self.compress = compress\n        self.loop = loop\n        self.length = None\n        if response_class is None:\n            real_response_class = ClientResponse\n        else:\n            real_response_class = response_class\n        self.response_class: Type[ClientResponse] = real_response_class\n        self._timer = timer if timer is not None else TimerNoop()\n        self._ssl = ssl\n        self.server_hostname = server_hostname\n\n        if loop.get_debug():\n            self._source_traceback = traceback.extract_stack(sys._getframe(1))\n\n        self.update_version(version)\n        self.update_host(url)\n        self.update_headers(headers)\n        self.update_auto_headers(skip_auto_headers)\n        self.update_cookies(cookies)\n        self.update_content_encoding(data)\n        self.update_auth(auth, trust_env)\n        self.update_proxy(proxy, proxy_auth, proxy_headers)\n\n        self.update_body_from_data(data)\n        if data is not None or self.method not in self.GET_METHODS:\n            self.update_transfer_encoding()\n        self.update_expect_continue(expect100)\n        if traces is None:\n            traces = []\n        self._traces = traces\n\n    def __reset_writer(self, _: object = None) -> None:\n        self.__writer = None\n\n    @property\n    def _writer(self) -> Optional[\"asyncio.Task[None]\"]:\n        return self.__writer\n\n    @_writer.setter\n    def _writer(self, writer: Optional[\"asyncio.Task[None]\"]) -> None:\n        if self.__writer is not None:\n            self.__writer.remove_done_callback(self.__reset_writer)\n        self.__writer = writer\n        if writer is not None:\n            writer.add_done_callback(self.__reset_writer)\n\n    def is_ssl(self) -> bool:\n        return self.url.scheme in (\"https\", \"wss\")\n\n    @property\n    def ssl(self) -> Union[\"SSLContext\", None, Literal[False], Fingerprint]:\n        return self._ssl\n\n    @property\n    def connection_key(self) -> ConnectionKey:\n        proxy_headers = self.proxy_headers\n        if proxy_headers:\n            h: Optional[int] = hash(tuple((k, v) for k, v in proxy_headers.items()))\n        else:\n            h = None\n        return ConnectionKey(\n            self.host,\n            self.port,\n            self.is_ssl(),\n            self.ssl,\n            self.proxy,\n            self.proxy_auth,\n            h,\n        )\n\n    @property\n    def host(self) -> str:\n        ret = self.url.raw_host\n        assert ret is not None\n        return ret\n\n    @property\n    def port(self) -> Optional[int]:\n        return self.url.port\n\n    @property\n    def request_info(self) -> RequestInfo:\n        headers: CIMultiDictProxy[str] = CIMultiDictProxy(self.headers)\n        return RequestInfo(self.url, self.method, headers, self.original_url)\n\n    def update_host(self, url: URL) -> None:\n        \"\"\"Update destination host, port and connection type (ssl).\"\"\"\n        # get host/port\n        if not url.raw_host:\n            raise InvalidURL(url)\n\n        # basic auth info\n        username, password = url.user, url.password\n        if username:\n            self.auth = helpers.BasicAuth(username, password or \"\")\n\n    def update_version(self, version: Union[http.HttpVersion, str]) -> None:\n        \"\"\"Convert request version to two elements tuple.\n\n        parser HTTP version '1.1' => (1, 1)\n        \"\"\"\n        if isinstance(version, str):\n            v = [part.strip() for part in version.split(\".\", 1)]\n            try:\n                version = http.HttpVersion(int(v[0]), int(v[1]))\n            except ValueError:\n                raise ValueError(\n                    f\"Can not parse http version number: {version}\"\n                ) from None\n        self.version = version\n\n    def update_headers(self, headers: Optional[LooseHeaders]) -> None:\n        \"\"\"Update request headers.\"\"\"\n        self.headers: CIMultiDict[str] = CIMultiDict()\n\n        # add host\n        netloc = cast(str, self.url.raw_host)\n        if helpers.is_ipv6_address(netloc):\n            netloc = f\"[{netloc}]\"\n        # See https://github.com/aio-libs/aiohttp/issues/3636.\n        netloc = netloc.rstrip(\".\")\n        if self.url.port is not None and not self.url.is_default_port():\n            netloc += \":\" + str(self.url.port)\n        self.headers[hdrs.HOST] = netloc\n\n        if headers:\n            if isinstance(headers, (dict, MultiDictProxy, MultiDict)):\n                headers = headers.items()  # type: ignore[assignment]\n\n            for key, value in headers:  # type: ignore[misc]\n                # A special case for Host header\n                if key.lower() == \"host\":\n                    self.headers[key] = value\n                else:\n                    self.headers.add(key, value)\n\n    def update_auto_headers(self, skip_auto_headers: Iterable[str]) -> None:\n        self.skip_auto_headers = CIMultiDict(\n            (hdr, None) for hdr in sorted(skip_auto_headers)\n        )\n        used_headers = self.headers.copy()\n        used_headers.extend(self.skip_auto_headers)  # type: ignore[arg-type]\n\n        for hdr, val in self.DEFAULT_HEADERS.items():\n            if hdr not in used_headers:\n                self.headers.add(hdr, val)\n\n        if hdrs.USER_AGENT not in used_headers:\n            self.headers[hdrs.USER_AGENT] = SERVER_SOFTWARE\n\n    def update_cookies(self, cookies: Optional[LooseCookies]) -> None:\n        \"\"\"Update request cookies header.\"\"\"\n        if not cookies:\n            return\n\n        c = SimpleCookie()\n        if hdrs.COOKIE in self.headers:\n            c.load(self.headers.get(hdrs.COOKIE, \"\"))\n            del self.headers[hdrs.COOKIE]\n\n        if isinstance(cookies, Mapping):\n            iter_cookies = cookies.items()\n        else:\n            iter_cookies = cookies  # type: ignore[assignment]\n        for name, value in iter_cookies:\n            if isinstance(value, Morsel):\n                # Preserve coded_value\n                mrsl_val = value.get(value.key, Morsel())\n                mrsl_val.set(value.key, value.value, value.coded_value)\n                c[name] = mrsl_val\n            else:\n                c[name] = value  # type: ignore[assignment]\n\n        self.headers[hdrs.COOKIE] = c.output(header=\"\", sep=\";\").strip()\n\n    def update_content_encoding(self, data: Any) -> None:\n        \"\"\"Set request content encoding.\"\"\"\n        if data is None:\n            return\n\n        enc = self.headers.get(hdrs.CONTENT_ENCODING, \"\").lower()\n        if enc:\n            if self.compress:\n                raise ValueError(\n                    \"compress can not be set \" \"if Content-Encoding header is set\"\n                )\n        elif self.compress:\n            if not isinstance(self.compress, str):\n                self.compress = \"deflate\"\n            self.headers[hdrs.CONTENT_ENCODING] = self.compress\n            self.chunked = True  # enable chunked, no need to deal with length\n\n    def update_transfer_encoding(self) -> None:\n        \"\"\"Analyze transfer-encoding header.\"\"\"\n        te = self.headers.get(hdrs.TRANSFER_ENCODING, \"\").lower()\n\n        if \"chunked\" in te:\n            if self.chunked:\n                raise ValueError(\n                    \"chunked can not be set \"\n                    'if \"Transfer-Encoding: chunked\" header is set'\n                )\n\n        elif self.chunked:\n            if hdrs.CONTENT_LENGTH in self.headers:\n                raise ValueError(\n                    \"chunked can not be set \" \"if Content-Length header is set\"\n                )\n\n            self.headers[hdrs.TRANSFER_ENCODING] = \"chunked\"\n        else:\n            if hdrs.CONTENT_LENGTH not in self.headers:\n                self.headers[hdrs.CONTENT_LENGTH] = str(len(self.body))\n\n    def update_auth(self, auth: Optional[BasicAuth], trust_env: bool = False) -> None:\n        \"\"\"Set basic auth.\"\"\"\n        if auth is None:\n            auth = self.auth\n        if auth is None and trust_env and self.url.host is not None:\n            netrc_obj = netrc_from_env()\n            with contextlib.suppress(LookupError):\n                auth = basicauth_from_netrc(netrc_obj, self.url.host)\n        if auth is None:\n            return\n\n        if not isinstance(auth, helpers.BasicAuth):\n            raise TypeError(\"BasicAuth() tuple is required instead\")\n\n        self.headers[hdrs.AUTHORIZATION] = auth.encode()\n\n    def update_body_from_data(self, body: Any) -> None:\n        if body is None:\n            return\n\n        # FormData\n        if isinstance(body, FormData):\n            body = body()\n\n        try:\n            body = payload.PAYLOAD_REGISTRY.get(body, disposition=None)\n        except payload.LookupError:\n            body = FormData(body)()\n\n        self.body = body\n\n        # enable chunked encoding if needed\n        if not self.chunked:\n            if hdrs.CONTENT_LENGTH not in self.headers:\n                size = body.size\n                if size is None:\n                    self.chunked = True\n                else:\n                    if hdrs.CONTENT_LENGTH not in self.headers:\n                        self.headers[hdrs.CONTENT_LENGTH] = str(size)\n\n        # copy payload headers\n        assert body.headers\n        for (key, value) in body.headers.items():\n            if key in self.headers:\n                continue\n            if key in self.skip_auto_headers:\n                continue\n            self.headers[key] = value\n\n    def update_expect_continue(self, expect: bool = False) -> None:\n        if expect:\n            self.headers[hdrs.EXPECT] = \"100-continue\"\n        elif self.headers.get(hdrs.EXPECT, \"\").lower() == \"100-continue\":\n            expect = True\n\n        if expect:\n            self._continue = self.loop.create_future()\n\n    def update_proxy(\n        self,\n        proxy: Optional[URL],\n        proxy_auth: Optional[BasicAuth],\n        proxy_headers: Optional[LooseHeaders],\n    ) -> None:\n        if proxy_auth and not isinstance(proxy_auth, helpers.BasicAuth):\n            raise ValueError(\"proxy_auth must be None or BasicAuth() tuple\")\n        self.proxy = proxy\n        self.proxy_auth = proxy_auth\n        self.proxy_headers = proxy_headers\n\n    def keep_alive(self) -> bool:\n        if self.version < HttpVersion10:\n            # keep alive not supported at all\n            return False\n        if self.version == HttpVersion10:\n            if self.headers.get(hdrs.CONNECTION) == \"keep-alive\":\n                return True\n            else:  # no headers means we close for Http 1.0\n                return False\n        elif self.headers.get(hdrs.CONNECTION) == \"close\":\n            return False\n\n        return True\n\n    async def write_bytes(\n        self, writer: AbstractStreamWriter, conn: \"Connection\"\n    ) -> None:\n        \"\"\"Support coroutines that yields bytes objects.\"\"\"\n        # 100 response\n        if self._continue is not None:\n            try:\n                await writer.drain()\n                await self._continue\n            except asyncio.CancelledError:\n                return\n\n        protocol = conn.protocol\n        assert protocol is not None\n        try:\n            if isinstance(self.body, payload.Payload):\n                await self.body.write(writer)\n            else:\n                if isinstance(self.body, (bytes, bytearray)):\n                    self.body = (self.body,)  # type: ignore[assignment]\n\n                for chunk in self.body:\n                    await writer.write(chunk)  # type: ignore[arg-type]\n        except OSError as exc:\n            if exc.errno is None and isinstance(exc, asyncio.TimeoutError):\n                protocol.set_exception(exc)\n            else:\n                new_exc = ClientOSError(\n                    exc.errno, \"Can not write request body for %s\" % self.url\n                )\n                new_exc.__context__ = exc\n                new_exc.__cause__ = exc\n                protocol.set_exception(new_exc)\n        except asyncio.CancelledError:\n            await writer.write_eof()\n        except Exception as exc:\n            protocol.set_exception(exc)\n        else:\n            await writer.write_eof()\n            protocol.start_timeout()\n\n    async def send(self, conn: \"Connection\") -> \"ClientResponse\":\n        # Specify request target:\n        # - CONNECT request must send authority form URI\n        # - not CONNECT proxy must send absolute form URI\n        # - most common is origin form URI\n        if self.method == hdrs.METH_CONNECT:\n            connect_host = self.url.raw_host\n            assert connect_host is not None\n            if helpers.is_ipv6_address(connect_host):\n                connect_host = f\"[{connect_host}]\"\n            path = f\"{connect_host}:{self.url.port}\"\n        elif self.proxy and not self.is_ssl():\n            path = str(self.url)\n        else:\n            path = self.url.raw_path\n            if self.url.raw_query_string:\n                path += \"?\" + self.url.raw_query_string\n\n        protocol = conn.protocol\n        assert protocol is not None\n        writer = StreamWriter(\n            protocol,\n            self.loop,\n            on_chunk_sent=functools.partial(\n                self._on_chunk_request_sent, self.method, self.url\n            ),\n            on_headers_sent=functools.partial(\n                self._on_headers_request_sent, self.method, self.url\n            ),\n        )\n\n        if self.compress:\n            writer.enable_compression(self.compress)\n\n        if self.chunked is not None:\n            writer.enable_chunking()\n\n        # set default content-type\n        if (\n            self.method in self.POST_METHODS\n            and hdrs.CONTENT_TYPE not in self.skip_auto_headers\n            and hdrs.CONTENT_TYPE not in self.headers\n        ):\n            self.headers[hdrs.CONTENT_TYPE] = \"application/octet-stream\"\n\n        # set the connection header\n        connection = self.headers.get(hdrs.CONNECTION)\n        if not connection:\n            if self.keep_alive():\n                if self.version == HttpVersion10:\n                    connection = \"keep-alive\"\n            else:\n                if self.version == HttpVersion11:\n                    connection = \"close\"\n\n        if connection is not None:\n            self.headers[hdrs.CONNECTION] = connection\n\n        # status + headers\n        status_line = \"{0} {1} HTTP/{2[0]}.{2[1]}\".format(\n            self.method, path, self.version\n        )\n        await writer.write_headers(status_line, self.headers)\n\n        self._writer = self.loop.create_task(self.write_bytes(writer, conn))\n\n        response_class = self.response_class\n        assert response_class is not None\n        self.response = response_class(\n            self.method,\n            self.original_url,\n            writer=self._writer,\n            continue100=self._continue,\n            timer=self._timer,\n            request_info=self.request_info,\n            traces=self._traces,\n            loop=self.loop,\n            session=self._session,\n        )\n        return self.response\n\n    async def close(self) -> None:\n        if self._writer is not None:\n            with contextlib.suppress(asyncio.CancelledError):\n                await self._writer\n\n    def terminate(self) -> None:\n        if self._writer is not None:\n            if not self.loop.is_closed():\n                self._writer.cancel()\n            self._writer.remove_done_callback(self.__reset_writer)\n            self._writer = None\n\n    async def _on_chunk_request_sent(self, method: str, url: URL, chunk: bytes) -> None:\n        for trace in self._traces:\n            await trace.send_request_chunk_sent(method, url, chunk)\n\n    async def _on_headers_request_sent(\n        self, method: str, url: URL, headers: \"CIMultiDict[str]\"\n    ) -> None:\n        for trace in self._traces:\n            await trace.send_request_headers(method, url, headers)",
                                "ast_type_str": "ClassDef",
                                "start_lineno": 231,
                                "end_lineno": 751,
                                "parent": null
                            }
                        },
                        {
                            "file_name": "aiohttp/client_reqrep.py",
                            "type": "class",
                            "name": "ClientRequest",
                            "content": "class ClientRequest:\n    GET_METHODS = {\n        hdrs.METH_GET,\n        hdrs.METH_HEAD,\n        hdrs.METH_OPTIONS,\n        hdrs.METH_TRACE,\n    }\n    POST_METHODS = {hdrs.METH_PATCH, hdrs.METH_POST, hdrs.METH_PUT}\n    ALL_METHODS = GET_METHODS.union(POST_METHODS).union({hdrs.METH_DELETE})\n\n    DEFAULT_HEADERS = {\n        hdrs.ACCEPT: \"*/*\",\n        hdrs.ACCEPT_ENCODING: _gen_default_accept_encoding(),\n    }\n\n    body = b\"\"\n    auth = None\n    response = None\n\n    __writer = None  # async task for streaming data\n    _continue = None  # waiter future for '100 Continue' response\n\n    # N.B.\n    # Adding __del__ method with self._writer closing doesn't make sense\n    # because _writer is instance method, thus it keeps a reference to self.\n    # Until writer has finished finalizer will not be called.\n\n    def __init__(\n        self,\n        method: str,\n        url: URL,\n        *,\n        params: Optional[Mapping[str, str]] = None,\n        headers: Optional[LooseHeaders] = None,\n        skip_auto_headers: Iterable[str] = frozenset(),\n        data: Any = None,\n        cookies: Optional[LooseCookies] = None,\n        auth: Optional[BasicAuth] = None,\n        version: http.HttpVersion = http.HttpVersion11,\n        compress: Optional[str] = None,\n        chunked: Optional[bool] = None,\n        expect100: bool = False,\n        loop: Optional[asyncio.AbstractEventLoop] = None,\n        response_class: Optional[Type[\"ClientResponse\"]] = None,\n        proxy: Optional[URL] = None,\n        proxy_auth: Optional[BasicAuth] = None,\n        timer: Optional[BaseTimerContext] = None,\n        session: Optional[\"ClientSession\"] = None,\n        ssl: Union[SSLContext, Literal[False], Fingerprint, None] = None,\n        proxy_headers: Optional[LooseHeaders] = None,\n        traces: Optional[List[\"Trace\"]] = None,\n        trust_env: bool = False,\n        server_hostname: Optional[str] = None,\n    ):\n        if loop is None:\n            loop = asyncio.get_event_loop()\n\n        match = _CONTAINS_CONTROL_CHAR_RE.search(method)\n        if match:\n            raise ValueError(\n                f\"Method cannot contain non-token characters {method!r} \"\n                \"(found at least {match.group()!r})\"\n            )\n\n        assert isinstance(url, URL), url\n        assert isinstance(proxy, (URL, type(None))), proxy\n        # FIXME: session is None in tests only, need to fix tests\n        # assert session is not None\n        self._session = cast(\"ClientSession\", session)\n        if params:\n            q = MultiDict(url.query)\n            url2 = url.with_query(params)\n            q.extend(url2.query)\n            url = url.with_query(q)\n        self.original_url = url\n        self.url = url.with_fragment(None)\n        self.method = method.upper()\n        self.chunked = chunked\n        self.compress = compress\n        self.loop = loop\n        self.length = None\n        if response_class is None:\n            real_response_class = ClientResponse\n        else:\n            real_response_class = response_class\n        self.response_class: Type[ClientResponse] = real_response_class\n        self._timer = timer if timer is not None else TimerNoop()\n        self._ssl = ssl\n        self.server_hostname = server_hostname\n\n        if loop.get_debug():\n            self._source_traceback = traceback.extract_stack(sys._getframe(1))\n\n        self.update_version(version)\n        self.update_host(url)\n        self.update_headers(headers)\n        self.update_auto_headers(skip_auto_headers)\n        self.update_cookies(cookies)\n        self.update_content_encoding(data)\n        self.update_auth(auth, trust_env)\n        self.update_proxy(proxy, proxy_auth, proxy_headers)\n\n        self.update_body_from_data(data)\n        if data is not None or self.method not in self.GET_METHODS:\n            self.update_transfer_encoding()\n        self.update_expect_continue(expect100)\n        if traces is None:\n            traces = []\n        self._traces = traces\n\n    def __reset_writer(self, _: object = None) -> None:\n        self.__writer = None\n\n    @property\n    def _writer(self) -> Optional[\"asyncio.Task[None]\"]:\n        return self.__writer\n\n    @_writer.setter\n    def _writer(self, writer: Optional[\"asyncio.Task[None]\"]) -> None:\n        if self.__writer is not None:\n            self.__writer.remove_done_callback(self.__reset_writer)\n        self.__writer = writer\n        if writer is not None:\n            writer.add_done_callback(self.__reset_writer)\n\n    def is_ssl(self) -> bool:\n        return self.url.scheme in (\"https\", \"wss\")\n\n    @property\n    def ssl(self) -> Union[\"SSLContext\", None, Literal[False], Fingerprint]:\n        return self._ssl\n\n    @property\n    def connection_key(self) -> ConnectionKey:\n        proxy_headers = self.proxy_headers\n        if proxy_headers:\n            h: Optional[int] = hash(tuple((k, v) for k, v in proxy_headers.items()))\n        else:\n            h = None\n        return ConnectionKey(\n            self.host,\n            self.port,\n            self.is_ssl(),\n            self.ssl,\n            self.proxy,\n            self.proxy_auth,\n            h,\n        )\n\n    @property\n    def host(self) -> str:\n        ret = self.url.raw_host\n        assert ret is not None\n        return ret\n\n    @property\n    def port(self) -> Optional[int]:\n        return self.url.port\n\n    @property\n    def request_info(self) -> RequestInfo:\n        headers: CIMultiDictProxy[str] = CIMultiDictProxy(self.headers)\n        return RequestInfo(self.url, self.method, headers, self.original_url)\n\n    def update_host(self, url: URL) -> None:\n        \"\"\"Update destination host, port and connection type (ssl).\"\"\"\n        # get host/port\n        if not url.raw_host:\n            raise InvalidURL(url)\n\n        # basic auth info\n        username, password = url.user, url.password\n        if username:\n            self.auth = helpers.BasicAuth(username, password or \"\")\n\n    def update_version(self, version: Union[http.HttpVersion, str]) -> None:\n        \"\"\"Convert request version to two elements tuple.\n\n        parser HTTP version '1.1' => (1, 1)\n        \"\"\"\n        if isinstance(version, str):\n            v = [part.strip() for part in version.split(\".\", 1)]\n            try:\n                version = http.HttpVersion(int(v[0]), int(v[1]))\n            except ValueError:\n                raise ValueError(\n                    f\"Can not parse http version number: {version}\"\n                ) from None\n        self.version = version\n\n    def update_headers(self, headers: Optional[LooseHeaders]) -> None:\n        \"\"\"Update request headers.\"\"\"\n        self.headers: CIMultiDict[str] = CIMultiDict()\n\n        # add host\n        netloc = cast(str, self.url.raw_host)\n        if helpers.is_ipv6_address(netloc):\n            netloc = f\"[{netloc}]\"\n        # See https://github.com/aio-libs/aiohttp/issues/3636.\n        netloc = netloc.rstrip(\".\")\n        if self.url.port is not None and not self.url.is_default_port():\n            netloc += \":\" + str(self.url.port)\n        self.headers[hdrs.HOST] = netloc\n\n        if headers:\n            if isinstance(headers, (dict, MultiDictProxy, MultiDict)):\n                headers = headers.items()  # type: ignore[assignment]\n\n            for key, value in headers:  # type: ignore[misc]\n                # A special case for Host header\n                if key.lower() == \"host\":\n                    self.headers[key] = value\n                else:\n                    self.headers.add(key, value)\n\n    def update_auto_headers(self, skip_auto_headers: Iterable[str]) -> None:\n        self.skip_auto_headers = CIMultiDict(\n            (hdr, None) for hdr in sorted(skip_auto_headers)\n        )\n        used_headers = self.headers.copy()\n        used_headers.extend(self.skip_auto_headers)  # type: ignore[arg-type]\n\n        for hdr, val in self.DEFAULT_HEADERS.items():\n            if hdr not in used_headers:\n                self.headers.add(hdr, val)\n\n        if hdrs.USER_AGENT not in used_headers:\n            self.headers[hdrs.USER_AGENT] = SERVER_SOFTWARE\n\n    def update_cookies(self, cookies: Optional[LooseCookies]) -> None:\n        \"\"\"Update request cookies header.\"\"\"\n        if not cookies:\n            return\n\n        c = SimpleCookie()\n        if hdrs.COOKIE in self.headers:\n            c.load(self.headers.get(hdrs.COOKIE, \"\"))\n            del self.headers[hdrs.COOKIE]\n\n        if isinstance(cookies, Mapping):\n            iter_cookies = cookies.items()\n        else:\n            iter_cookies = cookies  # type: ignore[assignment]\n        for name, value in iter_cookies:\n            if isinstance(value, Morsel):\n                # Preserve coded_value\n                mrsl_val = value.get(value.key, Morsel())\n                mrsl_val.set(value.key, value.value, value.coded_value)\n                c[name] = mrsl_val\n            else:\n                c[name] = value  # type: ignore[assignment]\n\n        self.headers[hdrs.COOKIE] = c.output(header=\"\", sep=\";\").strip()\n\n    def update_content_encoding(self, data: Any) -> None:\n        \"\"\"Set request content encoding.\"\"\"\n        if data is None:\n            return\n\n        enc = self.headers.get(hdrs.CONTENT_ENCODING, \"\").lower()\n        if enc:\n            if self.compress:\n                raise ValueError(\n                    \"compress can not be set \" \"if Content-Encoding header is set\"\n                )\n        elif self.compress:\n            if not isinstance(self.compress, str):\n                self.compress = \"deflate\"\n            self.headers[hdrs.CONTENT_ENCODING] = self.compress\n            self.chunked = True  # enable chunked, no need to deal with length\n\n    def update_transfer_encoding(self) -> None:\n        \"\"\"Analyze transfer-encoding header.\"\"\"\n        te = self.headers.get(hdrs.TRANSFER_ENCODING, \"\").lower()\n\n        if \"chunked\" in te:\n            if self.chunked:\n                raise ValueError(\n                    \"chunked can not be set \"\n                    'if \"Transfer-Encoding: chunked\" header is set'\n                )\n\n        elif self.chunked:\n            if hdrs.CONTENT_LENGTH in self.headers:\n                raise ValueError(\n                    \"chunked can not be set \" \"if Content-Length header is set\"\n                )\n\n            self.headers[hdrs.TRANSFER_ENCODING] = \"chunked\"\n        else:\n            if hdrs.CONTENT_LENGTH not in self.headers:\n                self.headers[hdrs.CONTENT_LENGTH] = str(len(self.body))\n\n    def update_auth(self, auth: Optional[BasicAuth], trust_env: bool = False) -> None:\n        \"\"\"Set basic auth.\"\"\"\n        if auth is None:\n            auth = self.auth\n        if auth is None and trust_env and self.url.host is not None:\n            netrc_obj = netrc_from_env()\n            with contextlib.suppress(LookupError):\n                auth = basicauth_from_netrc(netrc_obj, self.url.host)\n        if auth is None:\n            return\n\n        if not isinstance(auth, helpers.BasicAuth):\n            raise TypeError(\"BasicAuth() tuple is required instead\")\n\n        self.headers[hdrs.AUTHORIZATION] = auth.encode()\n\n    def update_body_from_data(self, body: Any) -> None:\n        if body is None:\n            return\n\n        # FormData\n        if isinstance(body, FormData):\n            body = body()\n\n        try:\n            body = payload.PAYLOAD_REGISTRY.get(body, disposition=None)\n        except payload.LookupError:\n            body = FormData(body)()\n\n        self.body = body\n\n        # enable chunked encoding if needed\n        if not self.chunked:\n            if hdrs.CONTENT_LENGTH not in self.headers:\n                size = body.size\n                if size is None:\n                    self.chunked = True\n                else:\n                    if hdrs.CONTENT_LENGTH not in self.headers:\n                        self.headers[hdrs.CONTENT_LENGTH] = str(size)\n\n        # copy payload headers\n        assert body.headers\n        for (key, value) in body.headers.items():\n            if key in self.headers:\n                continue\n            if key in self.skip_auto_headers:\n                continue\n            self.headers[key] = value\n\n    def update_expect_continue(self, expect: bool = False) -> None:\n        if expect:\n            self.headers[hdrs.EXPECT] = \"100-continue\"\n        elif self.headers.get(hdrs.EXPECT, \"\").lower() == \"100-continue\":\n            expect = True\n\n        if expect:\n            self._continue = self.loop.create_future()\n\n    def update_proxy(\n        self,\n        proxy: Optional[URL],\n        proxy_auth: Optional[BasicAuth],\n        proxy_headers: Optional[LooseHeaders],\n    ) -> None:\n        if proxy_auth and not isinstance(proxy_auth, helpers.BasicAuth):\n            raise ValueError(\"proxy_auth must be None or BasicAuth() tuple\")\n        self.proxy = proxy\n        self.proxy_auth = proxy_auth\n        self.proxy_headers = proxy_headers\n\n    def keep_alive(self) -> bool:\n        if self.version < HttpVersion10:\n            # keep alive not supported at all\n            return False\n        if self.version == HttpVersion10:\n            if self.headers.get(hdrs.CONNECTION) == \"keep-alive\":\n                return True\n            else:  # no headers means we close for Http 1.0\n                return False\n        elif self.headers.get(hdrs.CONNECTION) == \"close\":\n            return False\n\n        return True\n\n    async def write_bytes(\n        self, writer: AbstractStreamWriter, conn: \"Connection\"\n    ) -> None:\n        \"\"\"Support coroutines that yields bytes objects.\"\"\"\n        # 100 response\n        if self._continue is not None:\n            try:\n                await writer.drain()\n                await self._continue\n            except asyncio.CancelledError:\n                return\n\n        protocol = conn.protocol\n        assert protocol is not None\n        try:\n            if isinstance(self.body, payload.Payload):\n                await self.body.write(writer)\n            else:\n                if isinstance(self.body, (bytes, bytearray)):\n                    self.body = (self.body,)  # type: ignore[assignment]\n\n                for chunk in self.body:\n                    await writer.write(chunk)  # type: ignore[arg-type]\n        except OSError as exc:\n            if exc.errno is None and isinstance(exc, asyncio.TimeoutError):\n                protocol.set_exception(exc)\n            else:\n                new_exc = ClientOSError(\n                    exc.errno, \"Can not write request body for %s\" % self.url\n                )\n                new_exc.__context__ = exc\n                new_exc.__cause__ = exc\n                protocol.set_exception(new_exc)\n        except asyncio.CancelledError:\n            await writer.write_eof()\n        except Exception as exc:\n            protocol.set_exception(exc)\n        else:\n            await writer.write_eof()\n            protocol.start_timeout()\n\n    async def send(self, conn: \"Connection\") -> \"ClientResponse\":\n        # Specify request target:\n        # - CONNECT request must send authority form URI\n        # - not CONNECT proxy must send absolute form URI\n        # - most common is origin form URI\n        if self.method == hdrs.METH_CONNECT:\n            connect_host = self.url.raw_host\n            assert connect_host is not None\n            if helpers.is_ipv6_address(connect_host):\n                connect_host = f\"[{connect_host}]\"\n            path = f\"{connect_host}:{self.url.port}\"\n        elif self.proxy and not self.is_ssl():\n            path = str(self.url)\n        else:\n            path = self.url.raw_path\n            if self.url.raw_query_string:\n                path += \"?\" + self.url.raw_query_string\n\n        protocol = conn.protocol\n        assert protocol is not None\n        writer = StreamWriter(\n            protocol,\n            self.loop,\n            on_chunk_sent=functools.partial(\n                self._on_chunk_request_sent, self.method, self.url\n            ),\n            on_headers_sent=functools.partial(\n                self._on_headers_request_sent, self.method, self.url\n            ),\n        )\n\n        if self.compress:\n            writer.enable_compression(self.compress)\n\n        if self.chunked is not None:\n            writer.enable_chunking()\n\n        # set default content-type\n        if (\n            self.method in self.POST_METHODS\n            and hdrs.CONTENT_TYPE not in self.skip_auto_headers\n            and hdrs.CONTENT_TYPE not in self.headers\n        ):\n            self.headers[hdrs.CONTENT_TYPE] = \"application/octet-stream\"\n\n        # set the connection header\n        connection = self.headers.get(hdrs.CONNECTION)\n        if not connection:\n            if self.keep_alive():\n                if self.version == HttpVersion10:\n                    connection = \"keep-alive\"\n            else:\n                if self.version == HttpVersion11:\n                    connection = \"close\"\n\n        if connection is not None:\n            self.headers[hdrs.CONNECTION] = connection\n\n        # status + headers\n        status_line = \"{0} {1} HTTP/{2[0]}.{2[1]}\".format(\n            self.method, path, self.version\n        )\n        await writer.write_headers(status_line, self.headers)\n\n        self._writer = self.loop.create_task(self.write_bytes(writer, conn))\n\n        response_class = self.response_class\n        assert response_class is not None\n        self.response = response_class(\n            self.method,\n            self.original_url,\n            writer=self._writer,\n            continue100=self._continue,\n            timer=self._timer,\n            request_info=self.request_info,\n            traces=self._traces,\n            loop=self.loop,\n            session=self._session,\n        )\n        return self.response\n\n    async def close(self) -> None:\n        if self._writer is not None:\n            with contextlib.suppress(asyncio.CancelledError):\n                await self._writer\n\n    def terminate(self) -> None:\n        if self._writer is not None:\n            if not self.loop.is_closed():\n                self._writer.cancel()\n            self._writer.remove_done_callback(self.__reset_writer)\n            self._writer = None\n\n    async def _on_chunk_request_sent(self, method: str, url: URL, chunk: bytes) -> None:\n        for trace in self._traces:\n            await trace.send_request_chunk_sent(method, url, chunk)\n\n    async def _on_headers_request_sent(\n        self, method: str, url: URL, headers: \"CIMultiDict[str]\"\n    ) -> None:\n        for trace in self._traces:\n            await trace.send_request_headers(method, url, headers)",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 231,
                            "end_lineno": 751,
                            "parent": null
                        }
                    ],
                    "added_entities": [],
                    "deleted_entities": []
                }
            ]
        },
        {
            "old_file_content": "import asyncio\nimport hashlib\nimport io\nimport os.path\nimport urllib.parse\nimport zlib\nfrom http.cookies import BaseCookie, Morsel, SimpleCookie\nfrom typing import Any, Callable, Dict, Optional\nfrom unittest import mock\n\nimport pytest\nfrom multidict import CIMultiDict, CIMultiDictProxy, istr\nfrom yarl import URL\n\nimport aiohttp\nfrom aiohttp import BaseConnector, hdrs, helpers, payload\nfrom aiohttp.client_reqrep import (\n    ClientRequest,\n    ClientResponse,\n    Fingerprint,\n    _gen_default_accept_encoding,\n    _merge_ssl_params,\n)\nfrom aiohttp.test_utils import make_mocked_coro\n\n\nclass WriterMock(mock.AsyncMock):\n    def __await__(self) -> None:\n        return self().__await__()\n\n    def add_done_callback(self, cb: Callable[[], None]) -> None:\n        \"\"\"Dummy method.\"\"\"\n\n    def remove_done_callback(self, cb: Callable[[], None]) -> None:\n        \"\"\"Dummy method.\"\"\"\n\n\n@pytest.fixture\ndef make_request(loop):\n    request = None\n\n    def maker(method, url, *args, **kwargs):\n        nonlocal request\n        request = ClientRequest(method, URL(url), *args, loop=loop, **kwargs)\n        return request\n\n    yield maker\n    if request is not None:\n        loop.run_until_complete(request.close())\n\n\n@pytest.fixture\ndef buf():\n    return bytearray()\n\n\n@pytest.fixture\ndef protocol(loop, transport):\n    protocol = mock.Mock()\n    protocol.transport = transport\n    protocol._drain_helper.return_value = loop.create_future()\n    protocol._drain_helper.return_value.set_result(None)\n    return protocol\n\n\n@pytest.fixture\ndef transport(buf):\n    transport = mock.Mock()\n\n    def write(chunk):\n        buf.extend(chunk)\n\n    async def write_eof():\n        pass\n\n    transport.write.side_effect = write\n    transport.write_eof.side_effect = write_eof\n    transport.is_closing.return_value = False\n\n    return transport\n\n\n@pytest.fixture\ndef conn(transport, protocol):\n    return mock.Mock(transport=transport, protocol=protocol)\n\n\ndef test_method1(make_request) -> None:\n    req = make_request(\"get\", \"http://python.org/\")\n    assert req.method == \"GET\"\n\n\ndef test_method2(make_request) -> None:\n    req = make_request(\"head\", \"http://python.org/\")\n    assert req.method == \"HEAD\"\n\n\ndef test_method3(make_request) -> None:\n    req = make_request(\"HEAD\", \"http://python.org/\")\n    assert req.method == \"HEAD\"\n\n\ndef test_method_invalid(make_request) -> None:\n    with pytest.raises(ValueError, match=\"Method cannot contain non-token characters\"):\n        make_request(\"METHOD WITH\\nWHITESPACES\", \"http://python.org/\")\n\n\ndef test_version_1_0(make_request) -> None:\n    req = make_request(\"get\", \"http://python.org/\", version=\"1.0\")\n    assert req.version == (1, 0)\n\n\ndef test_version_default(make_request) -> None:\n    req = make_request(\"get\", \"http://python.org/\")\n    assert req.version == (1, 1)\n\n\ndef test_request_info(make_request) -> None:\n    req = make_request(\"get\", \"http://python.org/\")\n    assert req.request_info == aiohttp.RequestInfo(\n        URL(\"http://python.org/\"), \"GET\", req.headers\n    )\n\n\ndef test_request_info_with_fragment(make_request) -> None:\n    req = make_request(\"get\", \"http://python.org/#urlfragment\")\n    assert req.request_info == aiohttp.RequestInfo(\n        URL(\"http://python.org/\"),\n        \"GET\",\n        req.headers,\n        URL(\"http://python.org/#urlfragment\"),\n    )\n\n\ndef test_version_err(make_request) -> None:\n    with pytest.raises(ValueError):\n        make_request(\"get\", \"http://python.org/\", version=\"1.c\")\n\n\ndef test_keep_alive(make_request) -> None:\n    req = make_request(\"get\", \"http://python.org/\", version=(0, 9))\n    assert not req.keep_alive()\n\n    req = make_request(\"get\", \"http://python.org/\", version=(1, 0))\n    assert not req.keep_alive()\n\n    req = make_request(\n        \"get\",\n        \"http://python.org/\",\n        version=(1, 0),\n        headers={\"connection\": \"keep-alive\"},\n    )\n    assert req.keep_alive()\n\n    req = make_request(\"get\", \"http://python.org/\", version=(1, 1))\n    assert req.keep_alive()\n\n    req = make_request(\n        \"get\", \"http://python.org/\", version=(1, 1), headers={\"connection\": \"close\"}\n    )\n    assert not req.keep_alive()\n\n\ndef test_host_port_default_http(make_request) -> None:\n    req = make_request(\"get\", \"http://python.org/\")\n    assert req.host == \"python.org\"\n    assert req.port == 80\n    assert not req.ssl\n\n\ndef test_host_port_default_https(make_request) -> None:\n    req = make_request(\"get\", \"https://python.org/\")\n    assert req.host == \"python.org\"\n    assert req.port == 443\n    assert req.is_ssl()\n\n\ndef test_host_port_nondefault_http(make_request) -> None:\n    req = make_request(\"get\", \"http://python.org:960/\")\n    assert req.host == \"python.org\"\n    assert req.port == 960\n    assert not req.is_ssl()\n\n\ndef test_host_port_nondefault_https(make_request) -> None:\n    req = make_request(\"get\", \"https://python.org:960/\")\n    assert req.host == \"python.org\"\n    assert req.port == 960\n    assert req.is_ssl()\n\n\ndef test_host_port_default_ws(make_request) -> None:\n    req = make_request(\"get\", \"ws://python.org/\")\n    assert req.host == \"python.org\"\n    assert req.port == 80\n    assert not req.is_ssl()\n\n\ndef test_host_port_default_wss(make_request) -> None:\n    req = make_request(\"get\", \"wss://python.org/\")\n    assert req.host == \"python.org\"\n    assert req.port == 443\n    assert req.is_ssl()\n\n\ndef test_host_port_nondefault_ws(make_request) -> None:\n    req = make_request(\"get\", \"ws://python.org:960/\")\n    assert req.host == \"python.org\"\n    assert req.port == 960\n    assert not req.is_ssl()\n\n\ndef test_host_port_nondefault_wss(make_request) -> None:\n    req = make_request(\"get\", \"wss://python.org:960/\")\n    assert req.host == \"python.org\"\n    assert req.port == 960\n    assert req.is_ssl()\n\n\ndef test_host_port_none_port(make_request) -> None:\n    req = make_request(\"get\", \"unix://localhost/path\")\n    assert req.headers[\"Host\"] == \"localhost\"\n\n\ndef test_host_port_err(make_request) -> None:\n    with pytest.raises(ValueError):\n        make_request(\"get\", \"http://python.org:123e/\")\n\n\ndef test_hostname_err(make_request) -> None:\n    with pytest.raises(ValueError):\n        make_request(\"get\", \"http://:8080/\")\n\n\ndef test_host_header_host_first(make_request) -> None:\n    req = make_request(\"get\", \"http://python.org/\")\n    assert list(req.headers)[0] == \"Host\"\n\n\ndef test_host_header_host_without_port(make_request) -> None:\n    req = make_request(\"get\", \"http://python.org/\")\n    assert req.headers[\"HOST\"] == \"python.org\"\n\n\ndef test_host_header_host_with_default_port(make_request) -> None:\n    req = make_request(\"get\", \"http://python.org:80/\")\n    assert req.headers[\"HOST\"] == \"python.org\"\n\n\ndef test_host_header_host_with_nondefault_port(make_request) -> None:\n    req = make_request(\"get\", \"http://python.org:99/\")\n    assert req.headers[\"HOST\"] == \"python.org:99\"\n\n\ndef test_host_header_host_idna_encode(make_request) -> None:\n    req = make_request(\"get\", \"http://xn--9caa.com\")\n    assert req.headers[\"HOST\"] == \"xn--9caa.com\"\n\n\ndef test_host_header_host_unicode(make_request) -> None:\n    req = make_request(\"get\", \"http://éé.com\")\n    assert req.headers[\"HOST\"] == \"xn--9caa.com\"\n\n\ndef test_host_header_explicit_host(make_request) -> None:\n    req = make_request(\"get\", \"http://python.org/\", headers={\"host\": \"example.com\"})\n    assert req.headers[\"HOST\"] == \"example.com\"\n\n\ndef test_host_header_explicit_host_with_port(make_request) -> None:\n    req = make_request(\"get\", \"http://python.org/\", headers={\"host\": \"example.com:99\"})\n    assert req.headers[\"HOST\"] == \"example.com:99\"\n\n\ndef test_host_header_ipv4(make_request) -> None:\n    req = make_request(\"get\", \"http://127.0.0.2\")\n    assert req.headers[\"HOST\"] == \"127.0.0.2\"\n\n\ndef test_host_header_ipv6(make_request) -> None:\n    req = make_request(\"get\", \"http://[::2]\")\n    assert req.headers[\"HOST\"] == \"[::2]\"\n\n\ndef test_host_header_ipv4_with_port(make_request) -> None:\n    req = make_request(\"get\", \"http://127.0.0.2:99\")\n    assert req.headers[\"HOST\"] == \"127.0.0.2:99\"\n\n\ndef test_host_header_ipv6_with_port(make_request) -> None:\n    req = make_request(\"get\", \"http://[::2]:99\")\n    assert req.headers[\"HOST\"] == \"[::2]:99\"\n\n\ndef test_default_loop(loop) -> None:\n    asyncio.set_event_loop(loop)\n    req = ClientRequest(\"get\", URL(\"http://python.org/\"))\n    assert req.loop is loop\n    loop.run_until_complete(req.close())\n\n\n@pytest.mark.parametrize(\n    (\"url\", \"headers\", \"expected\"),\n    (\n        pytest.param(\"http://localhost.\", None, \"localhost\", id=\"dot only at the end\"),\n        pytest.param(\"http://python.org.\", None, \"python.org\", id=\"single dot\"),\n        pytest.param(\n            \"http://python.org.:99\", None, \"python.org:99\", id=\"single dot with port\"\n        ),\n        pytest.param(\n            \"http://python.org...:99\",\n            None,\n            \"python.org:99\",\n            id=\"multiple dots with port\",\n        ),\n        pytest.param(\n            \"http://python.org.:99\",\n            {\"host\": \"example.com.:99\"},\n            \"example.com.:99\",\n            id=\"explicit host header\",\n        ),\n        pytest.param(\"https://python.org.\", None, \"python.org\", id=\"https\"),\n        pytest.param(\"https://...\", None, \"\", id=\"only dots\"),\n        pytest.param(\n            \"http://príklad.example.org.:99\",\n            None,\n            \"xn--prklad-4va.example.org:99\",\n            id=\"single dot with port idna\",\n        ),\n    ),\n)\ndef test_host_header_fqdn(\n    make_request: Any, url: str, headers: Dict[str, str], expected: str\n) -> None:\n    req = make_request(\"get\", url, headers=headers)\n    assert req.headers[\"HOST\"] == expected\n\n\ndef test_default_headers_useragent(make_request) -> None:\n    req = make_request(\"get\", \"http://python.org/\")\n\n    assert \"SERVER\" not in req.headers\n    assert \"USER-AGENT\" in req.headers\n\n\ndef test_default_headers_useragent_custom(make_request) -> None:\n    req = make_request(\n        \"get\", \"http://python.org/\", headers={\"user-agent\": \"my custom agent\"}\n    )\n\n    assert \"USER-Agent\" in req.headers\n    assert \"my custom agent\" == req.headers[\"User-Agent\"]\n\n\ndef test_skip_default_useragent_header(make_request) -> None:\n    req = make_request(\n        \"get\", \"http://python.org/\", skip_auto_headers={istr(\"user-agent\")}\n    )\n\n    assert \"User-Agent\" not in req.headers\n\n\ndef test_headers(make_request) -> None:\n    req = make_request(\n        \"post\", \"http://python.org/\", headers={\"Content-Type\": \"text/plain\"}\n    )\n\n    assert \"CONTENT-TYPE\" in req.headers\n    assert req.headers[\"CONTENT-TYPE\"] == \"text/plain\"\n    assert req.headers[\"ACCEPT-ENCODING\"] == \"gzip, deflate, br\"\n\n\ndef test_headers_list(make_request) -> None:\n    req = make_request(\n        \"post\", \"http://python.org/\", headers=[(\"Content-Type\", \"text/plain\")]\n    )\n    assert \"CONTENT-TYPE\" in req.headers\n    assert req.headers[\"CONTENT-TYPE\"] == \"text/plain\"\n\n\ndef test_headers_default(make_request) -> None:\n    req = make_request(\n        \"get\", \"http://python.org/\", headers={\"ACCEPT-ENCODING\": \"deflate\"}\n    )\n    assert req.headers[\"ACCEPT-ENCODING\"] == \"deflate\"\n\n\ndef test_invalid_url(make_request) -> None:\n    with pytest.raises(aiohttp.InvalidURL):\n        make_request(\"get\", \"hiwpefhipowhefopw\")\n\n\ndef test_no_path(make_request) -> None:\n    req = make_request(\"get\", \"http://python.org\")\n    assert \"/\" == req.url.path\n\n\ndef test_ipv6_default_http_port(make_request) -> None:\n    req = make_request(\"get\", \"http://[2001:db8::1]/\")\n    assert req.host == \"2001:db8::1\"\n    assert req.port == 80\n    assert not req.ssl\n\n\ndef test_ipv6_default_https_port(make_request) -> None:\n    req = make_request(\"get\", \"https://[2001:db8::1]/\")\n    assert req.host == \"2001:db8::1\"\n    assert req.port == 443\n    assert req.is_ssl()\n\n\ndef test_ipv6_nondefault_http_port(make_request) -> None:\n    req = make_request(\"get\", \"http://[2001:db8::1]:960/\")\n    assert req.host == \"2001:db8::1\"\n    assert req.port == 960\n    assert not req.is_ssl()\n\n\ndef test_ipv6_nondefault_https_port(make_request) -> None:\n    req = make_request(\"get\", \"https://[2001:db8::1]:960/\")\n    assert req.host == \"2001:db8::1\"\n    assert req.port == 960\n    assert req.is_ssl()\n\n\ndef test_basic_auth(make_request) -> None:\n    req = make_request(\n        \"get\", \"http://python.org\", auth=aiohttp.BasicAuth(\"nkim\", \"1234\")\n    )\n    assert \"AUTHORIZATION\" in req.headers\n    assert \"Basic bmtpbToxMjM0\" == req.headers[\"AUTHORIZATION\"]\n\n\ndef test_basic_auth_utf8(make_request) -> None:\n    req = make_request(\n        \"get\", \"http://python.org\", auth=aiohttp.BasicAuth(\"nkim\", \"секрет\", \"utf-8\")\n    )\n    assert \"AUTHORIZATION\" in req.headers\n    assert \"Basic bmtpbTrRgdC10LrRgNC10YI=\" == req.headers[\"AUTHORIZATION\"]\n\n\ndef test_basic_auth_tuple_forbidden(make_request) -> None:\n    with pytest.raises(TypeError):\n        make_request(\"get\", \"http://python.org\", auth=(\"nkim\", \"1234\"))\n\n\ndef test_basic_auth_from_url(make_request) -> None:\n    req = make_request(\"get\", \"http://nkim:1234@python.org\")\n    assert \"AUTHORIZATION\" in req.headers\n    assert \"Basic bmtpbToxMjM0\" == req.headers[\"AUTHORIZATION\"]\n    assert \"python.org\" == req.host\n\n\ndef test_basic_auth_from_url_overridden(make_request) -> None:\n    req = make_request(\n        \"get\", \"http://garbage@python.org\", auth=aiohttp.BasicAuth(\"nkim\", \"1234\")\n    )\n    assert \"AUTHORIZATION\" in req.headers\n    assert \"Basic bmtpbToxMjM0\" == req.headers[\"AUTHORIZATION\"]\n    assert \"python.org\" == req.host\n\n\ndef test_path_is_not_double_encoded1(make_request) -> None:\n    req = make_request(\"get\", \"http://0.0.0.0/get/test case\")\n    assert req.url.raw_path == \"/get/test%20case\"\n\n\ndef test_path_is_not_double_encoded2(make_request) -> None:\n    req = make_request(\"get\", \"http://0.0.0.0/get/test%2fcase\")\n    assert req.url.raw_path == \"/get/test%2Fcase\"\n\n\ndef test_path_is_not_double_encoded3(make_request) -> None:\n    req = make_request(\"get\", \"http://0.0.0.0/get/test%20case\")\n    assert req.url.raw_path == \"/get/test%20case\"\n\n\ndef test_path_safe_chars_preserved(make_request) -> None:\n    req = make_request(\"get\", \"http://0.0.0.0/get/:=+/%2B/\")\n    assert req.url.path == \"/get/:=+/+/\"\n\n\ndef test_params_are_added_before_fragment1(make_request) -> None:\n    req = make_request(\"GET\", \"http://example.com/path#fragment\", params={\"a\": \"b\"})\n    assert str(req.url) == \"http://example.com/path?a=b\"\n\n\ndef test_params_are_added_before_fragment2(make_request) -> None:\n    req = make_request(\n        \"GET\", \"http://example.com/path?key=value#fragment\", params={\"a\": \"b\"}\n    )\n    assert str(req.url) == \"http://example.com/path?key=value&a=b\"\n\n\ndef test_path_not_contain_fragment1(make_request) -> None:\n    req = make_request(\"GET\", \"http://example.com/path#fragment\")\n    assert req.url.path == \"/path\"\n\n\ndef test_path_not_contain_fragment2(make_request) -> None:\n    req = make_request(\"GET\", \"http://example.com/path?key=value#fragment\")\n    assert str(req.url) == \"http://example.com/path?key=value\"\n\n\ndef test_cookies(make_request) -> None:\n    req = make_request(\"get\", \"http://test.com/path\", cookies={\"cookie1\": \"val1\"})\n\n    assert \"COOKIE\" in req.headers\n    assert \"cookie1=val1\" == req.headers[\"COOKIE\"]\n\n\ndef test_cookies_is_quoted_with_special_characters(make_request) -> None:\n    req = make_request(\"get\", \"http://test.com/path\", cookies={\"cookie1\": \"val/one\"})\n\n    assert \"COOKIE\" in req.headers\n    assert 'cookie1=\"val/one\"' == req.headers[\"COOKIE\"]\n\n\ndef test_cookies_merge_with_headers(make_request) -> None:\n    req = make_request(\n        \"get\",\n        \"http://test.com/path\",\n        headers={\"cookie\": \"cookie1=val1\"},\n        cookies={\"cookie2\": \"val2\"},\n    )\n\n    assert \"cookie1=val1; cookie2=val2\" == req.headers[\"COOKIE\"]\n\n\ndef test_unicode_get1(make_request) -> None:\n    req = make_request(\"get\", \"http://python.org\", params={\"foo\": \"f\\xf8\\xf8\"})\n    assert \"http://python.org/?foo=f%C3%B8%C3%B8\" == str(req.url)\n\n\ndef test_unicode_get2(make_request) -> None:\n    req = make_request(\"\", \"http://python.org\", params={\"f\\xf8\\xf8\": \"f\\xf8\\xf8\"})\n\n    assert \"http://python.org/?f%C3%B8%C3%B8=f%C3%B8%C3%B8\" == str(req.url)\n\n\ndef test_unicode_get3(make_request) -> None:\n    req = make_request(\"\", \"http://python.org\", params={\"foo\": \"foo\"})\n    assert \"http://python.org/?foo=foo\" == str(req.url)\n\n\ndef test_unicode_get4(make_request) -> None:\n    def join(*suffix):\n        return urllib.parse.urljoin(\"http://python.org/\", \"/\".join(suffix))\n\n    req = make_request(\"\", join(\"\\xf8\"), params={\"foo\": \"foo\"})\n    assert \"http://python.org/%C3%B8?foo=foo\" == str(req.url)\n\n\ndef test_query_multivalued_param(make_request) -> None:\n    for meth in ClientRequest.ALL_METHODS:\n        req = make_request(\n            meth, \"http://python.org\", params=((\"test\", \"foo\"), (\"test\", \"baz\"))\n        )\n\n        assert str(req.url) == \"http://python.org/?test=foo&test=baz\"\n\n\ndef test_query_str_param(make_request) -> None:\n    for meth in ClientRequest.ALL_METHODS:\n        req = make_request(meth, \"http://python.org\", params=\"test=foo\")\n        assert str(req.url) == \"http://python.org/?test=foo\"\n\n\ndef test_query_bytes_param_raises(make_request) -> None:\n    for meth in ClientRequest.ALL_METHODS:\n        with pytest.raises(TypeError):\n            make_request(meth, \"http://python.org\", params=b\"test=foo\")\n\n\ndef test_query_str_param_is_not_encoded(make_request) -> None:\n    for meth in ClientRequest.ALL_METHODS:\n        req = make_request(meth, \"http://python.org\", params=\"test=f+oo\")\n        assert str(req.url) == \"http://python.org/?test=f+oo\"\n\n\ndef test_params_update_path_and_url(make_request) -> None:\n    req = make_request(\n        \"get\", \"http://python.org\", params=((\"test\", \"foo\"), (\"test\", \"baz\"))\n    )\n    assert str(req.url) == \"http://python.org/?test=foo&test=baz\"\n\n\ndef test_params_empty_path_and_url(make_request) -> None:\n    req_empty = make_request(\"get\", \"http://python.org\", params={})\n    assert str(req_empty.url) == \"http://python.org\"\n    req_none = make_request(\"get\", \"http://python.org\")\n    assert str(req_none.url) == \"http://python.org\"\n\n\ndef test_gen_netloc_all(make_request) -> None:\n    req = make_request(\n        \"get\",\n        \"https://aiohttp:pwpwpw@\"\n        + \"12345678901234567890123456789\"\n        + \"012345678901234567890:8080\",\n    )\n    assert (\n        req.headers[\"HOST\"]\n        == \"12345678901234567890123456789\" + \"012345678901234567890:8080\"\n    )\n\n\ndef test_gen_netloc_no_port(make_request) -> None:\n    req = make_request(\n        \"get\",\n        \"https://aiohttp:pwpwpw@\"\n        + \"12345678901234567890123456789\"\n        + \"012345678901234567890/\",\n    )\n    assert (\n        req.headers[\"HOST\"] == \"12345678901234567890123456789\" + \"012345678901234567890\"\n    )\n\n\nasync def test_connection_header(loop, conn) -> None:\n    req = ClientRequest(\"get\", URL(\"http://python.org\"), loop=loop)\n    req.keep_alive = mock.Mock()\n    req.headers.clear()\n\n    req.keep_alive.return_value = True\n    req.version = (1, 1)\n    req.headers.clear()\n    await req.send(conn)\n    assert req.headers.get(\"CONNECTION\") is None\n\n    req.version = (1, 0)\n    req.headers.clear()\n    await req.send(conn)\n    assert req.headers.get(\"CONNECTION\") == \"keep-alive\"\n\n    req.keep_alive.return_value = False\n    req.version = (1, 1)\n    req.headers.clear()\n    await req.send(conn)\n    assert req.headers.get(\"CONNECTION\") == \"close\"\n\n    await req.close()\n\n\nasync def test_no_content_length(loop, conn) -> None:\n    req = ClientRequest(\"get\", URL(\"http://python.org\"), loop=loop)\n    resp = await req.send(conn)\n    assert req.headers.get(\"CONTENT-LENGTH\") is None\n    await req.close()\n    resp.close()\n\n\nasync def test_no_content_length_head(loop, conn) -> None:\n    req = ClientRequest(\"head\", URL(\"http://python.org\"), loop=loop)\n    resp = await req.send(conn)\n    assert req.headers.get(\"CONTENT-LENGTH\") is None\n    await req.close()\n    resp.close()\n\n\nasync def test_content_type_auto_header_get(loop, conn) -> None:\n    req = ClientRequest(\"get\", URL(\"http://python.org\"), loop=loop)\n    resp = await req.send(conn)\n    assert \"CONTENT-TYPE\" not in req.headers\n    resp.close()\n    await req.close()\n\n\nasync def test_content_type_auto_header_form(loop, conn) -> None:\n    req = ClientRequest(\n        \"post\", URL(\"http://python.org\"), data={\"hey\": \"you\"}, loop=loop\n    )\n    resp = await req.send(conn)\n    assert \"application/x-www-form-urlencoded\" == req.headers.get(\"CONTENT-TYPE\")\n    resp.close()\n    await req.close()\n\n\nasync def test_content_type_auto_header_bytes(loop, conn) -> None:\n    req = ClientRequest(\"post\", URL(\"http://python.org\"), data=b\"hey you\", loop=loop)\n    resp = await req.send(conn)\n    assert \"application/octet-stream\" == req.headers.get(\"CONTENT-TYPE\")\n    resp.close()\n    await req.close()\n\n\nasync def test_content_type_skip_auto_header_bytes(loop, conn) -> None:\n    req = ClientRequest(\n        \"post\",\n        URL(\"http://python.org\"),\n        data=b\"hey you\",\n        skip_auto_headers={\"Content-Type\"},\n        loop=loop,\n    )\n    resp = await req.send(conn)\n    assert \"CONTENT-TYPE\" not in req.headers\n    resp.close()\n    await req.close()\n\n\nasync def test_content_type_skip_auto_header_form(loop, conn) -> None:\n    req = ClientRequest(\n        \"post\",\n        URL(\"http://python.org\"),\n        data={\"hey\": \"you\"},\n        loop=loop,\n        skip_auto_headers={\"Content-Type\"},\n    )\n    resp = await req.send(conn)\n    assert \"CONTENT-TYPE\" not in req.headers\n    resp.close()\n    await req.close()\n\n\nasync def test_content_type_auto_header_content_length_no_skip(loop, conn) -> None:\n    with io.BytesIO(b\"hey\") as file_handle:\n        req = ClientRequest(\n            \"post\",\n            URL(\"http://python.org\"),\n            data=file_handle,\n            skip_auto_headers={\"Content-Length\"},\n            loop=loop,\n        )\n        resp = await req.send(conn)\n        assert req.headers.get(\"CONTENT-LENGTH\") == \"3\"\n        resp.close()\n        await req.close()\n\n\nasync def test_urlencoded_formdata_charset(loop, conn) -> None:\n    req = ClientRequest(\n        \"post\",\n        URL(\"http://python.org\"),\n        data=aiohttp.FormData({\"hey\": \"you\"}, charset=\"koi8-r\"),\n        loop=loop,\n    )\n    await req.send(conn)\n    assert \"application/x-www-form-urlencoded; charset=koi8-r\" == req.headers.get(\n        \"CONTENT-TYPE\"\n    )\n    await req.close()\n\n\nasync def test_post_data(loop, conn) -> None:\n    for meth in ClientRequest.POST_METHODS:\n        req = ClientRequest(\n            meth, URL(\"http://python.org/\"), data={\"life\": \"42\"}, loop=loop\n        )\n        resp = await req.send(conn)\n        assert \"/\" == req.url.path\n        assert b\"life=42\" == req.body._value\n        assert \"application/x-www-form-urlencoded\" == req.headers[\"CONTENT-TYPE\"]\n        await req.close()\n        resp.close()\n\n\nasync def test_pass_falsy_data(loop) -> None:\n    with mock.patch(\"aiohttp.client_reqrep.ClientRequest.update_body_from_data\"):\n        req = ClientRequest(\"post\", URL(\"http://python.org/\"), data={}, loop=loop)\n        req.update_body_from_data.assert_called_once_with({})\n    await req.close()\n\n\nasync def test_pass_falsy_data_file(loop, tmpdir) -> None:\n    testfile = tmpdir.join(\"tmpfile\").open(\"w+b\")\n    testfile.write(b\"data\")\n    testfile.seek(0)\n    skip = frozenset([hdrs.CONTENT_TYPE])\n    req = ClientRequest(\n        \"post\",\n        URL(\"http://python.org/\"),\n        data=testfile,\n        skip_auto_headers=skip,\n        loop=loop,\n    )\n    assert req.headers.get(\"CONTENT-LENGTH\", None) is not None\n    await req.close()\n    testfile.close()\n\n\n# Elasticsearch API requires to send request body with GET-requests\nasync def test_get_with_data(loop) -> None:\n    for meth in ClientRequest.GET_METHODS:\n        req = ClientRequest(\n            meth, URL(\"http://python.org/\"), data={\"life\": \"42\"}, loop=loop\n        )\n        assert \"/\" == req.url.path\n        assert b\"life=42\" == req.body._value\n        await req.close()\n\n\nasync def test_bytes_data(loop, conn) -> None:\n    for meth in ClientRequest.POST_METHODS:\n        req = ClientRequest(\n            meth, URL(\"http://python.org/\"), data=b\"binary data\", loop=loop\n        )\n        resp = await req.send(conn)\n        assert \"/\" == req.url.path\n        assert isinstance(req.body, payload.BytesPayload)\n        assert b\"binary data\" == req.body._value\n        assert \"application/octet-stream\" == req.headers[\"CONTENT-TYPE\"]\n        await req.close()\n        resp.close()\n\n\nasync def test_content_encoding(loop, conn) -> None:\n    req = ClientRequest(\n        \"post\", URL(\"http://python.org/\"), data=\"foo\", compress=\"deflate\", loop=loop\n    )\n    with mock.patch(\"aiohttp.client_reqrep.StreamWriter\") as m_writer:\n        m_writer.return_value.write_headers = make_mocked_coro()\n        resp = await req.send(conn)\n    assert req.headers[\"TRANSFER-ENCODING\"] == \"chunked\"\n    assert req.headers[\"CONTENT-ENCODING\"] == \"deflate\"\n    m_writer.return_value.enable_compression.assert_called_with(\"deflate\")\n    await req.close()\n    resp.close()\n\n\nasync def test_content_encoding_dont_set_headers_if_no_body(loop, conn) -> None:\n    req = ClientRequest(\n        \"post\", URL(\"http://python.org/\"), compress=\"deflate\", loop=loop\n    )\n    with mock.patch(\"aiohttp.client_reqrep.http\"):\n        resp = await req.send(conn)\n    assert \"TRANSFER-ENCODING\" not in req.headers\n    assert \"CONTENT-ENCODING\" not in req.headers\n    await req.close()\n    resp.close()\n\n\nasync def test_content_encoding_header(loop, conn) -> None:\n    req = ClientRequest(\n        \"post\",\n        URL(\"http://python.org/\"),\n        data=\"foo\",\n        headers={\"Content-Encoding\": \"deflate\"},\n        loop=loop,\n    )\n    with mock.patch(\"aiohttp.client_reqrep.StreamWriter\") as m_writer:\n        m_writer.return_value.write_headers = make_mocked_coro()\n        resp = await req.send(conn)\n\n    assert not m_writer.return_value.enable_compression.called\n    assert not m_writer.return_value.enable_chunking.called\n    await req.close()\n    resp.close()\n\n\nasync def test_compress_and_content_encoding(loop, conn) -> None:\n    with pytest.raises(ValueError):\n        ClientRequest(\n            \"post\",\n            URL(\"http://python.org/\"),\n            data=\"foo\",\n            headers={\"content-encoding\": \"deflate\"},\n            compress=\"deflate\",\n            loop=loop,\n        )\n\n\nasync def test_chunked(loop, conn) -> None:\n    req = ClientRequest(\n        \"post\",\n        URL(\"http://python.org/\"),\n        headers={\"TRANSFER-ENCODING\": \"gzip\"},\n        loop=loop,\n    )\n    resp = await req.send(conn)\n    assert \"gzip\" == req.headers[\"TRANSFER-ENCODING\"]\n    await req.close()\n    resp.close()\n\n\nasync def test_chunked2(loop, conn) -> None:\n    req = ClientRequest(\n        \"post\",\n        URL(\"http://python.org/\"),\n        headers={\"Transfer-encoding\": \"chunked\"},\n        loop=loop,\n    )\n    resp = await req.send(conn)\n    assert \"chunked\" == req.headers[\"TRANSFER-ENCODING\"]\n    await req.close()\n    resp.close()\n\n\nasync def test_chunked_explicit(loop, conn) -> None:\n    req = ClientRequest(\"post\", URL(\"http://python.org/\"), chunked=True, loop=loop)\n    with mock.patch(\"aiohttp.client_reqrep.StreamWriter\") as m_writer:\n        m_writer.return_value.write_headers = make_mocked_coro()\n        resp = await req.send(conn)\n\n    assert \"chunked\" == req.headers[\"TRANSFER-ENCODING\"]\n    m_writer.return_value.enable_chunking.assert_called_with()\n    await req.close()\n    resp.close()\n\n\nasync def test_chunked_length(loop, conn) -> None:\n    with pytest.raises(ValueError):\n        ClientRequest(\n            \"post\",\n            URL(\"http://python.org/\"),\n            headers={\"CONTENT-LENGTH\": \"1000\"},\n            chunked=True,\n            loop=loop,\n        )\n\n\nasync def test_chunked_transfer_encoding(loop, conn) -> None:\n    with pytest.raises(ValueError):\n        ClientRequest(\n            \"post\",\n            URL(\"http://python.org/\"),\n            headers={\"TRANSFER-ENCODING\": \"chunked\"},\n            chunked=True,\n            loop=loop,\n        )\n\n\nasync def test_file_upload_not_chunked(loop) -> None:\n    here = os.path.dirname(__file__)\n    fname = os.path.join(here, \"aiohttp.png\")\n    with open(fname, \"rb\") as f:\n        req = ClientRequest(\"post\", URL(\"http://python.org/\"), data=f, loop=loop)\n        assert not req.chunked\n        assert req.headers[\"CONTENT-LENGTH\"] == str(os.path.getsize(fname))\n        await req.close()\n\n\nasync def test_precompressed_data_stays_intact(loop) -> None:\n    data = zlib.compress(b\"foobar\")\n    req = ClientRequest(\n        \"post\",\n        URL(\"http://python.org/\"),\n        data=data,\n        headers={\"CONTENT-ENCODING\": \"deflate\"},\n        compress=False,\n        loop=loop,\n    )\n    assert not req.compress\n    assert not req.chunked\n    assert req.headers[\"CONTENT-ENCODING\"] == \"deflate\"\n    await req.close()\n\n\nasync def test_file_upload_not_chunked_seek(loop) -> None:\n    here = os.path.dirname(__file__)\n    fname = os.path.join(here, \"aiohttp.png\")\n    with open(fname, \"rb\") as f:\n        f.seek(100)\n        req = ClientRequest(\"post\", URL(\"http://python.org/\"), data=f, loop=loop)\n        assert req.headers[\"CONTENT-LENGTH\"] == str(os.path.getsize(fname) - 100)\n        await req.close()\n\n\nasync def test_file_upload_force_chunked(loop) -> None:\n    here = os.path.dirname(__file__)\n    fname = os.path.join(here, \"aiohttp.png\")\n    with open(fname, \"rb\") as f:\n        req = ClientRequest(\n            \"post\", URL(\"http://python.org/\"), data=f, chunked=True, loop=loop\n        )\n        assert req.chunked\n        assert \"CONTENT-LENGTH\" not in req.headers\n        await req.close()\n\n\nasync def test_expect100(loop, conn) -> None:\n    req = ClientRequest(\"get\", URL(\"http://python.org/\"), expect100=True, loop=loop)\n    resp = await req.send(conn)\n    assert \"100-continue\" == req.headers[\"EXPECT\"]\n    assert req._continue is not None\n    req.terminate()\n    resp.close()\n    await req.close()\n\n\nasync def test_expect_100_continue_header(loop, conn) -> None:\n    req = ClientRequest(\n        \"get\", URL(\"http://python.org/\"), headers={\"expect\": \"100-continue\"}, loop=loop\n    )\n    resp = await req.send(conn)\n    assert \"100-continue\" == req.headers[\"EXPECT\"]\n    assert req._continue is not None\n    req.terminate()\n    resp.close()\n    await req.close()\n\n\nasync def test_data_stream(loop, buf, conn) -> None:\n    async def gen():\n        yield b\"binary data\"\n        yield b\" result\"\n\n    req = ClientRequest(\"POST\", URL(\"http://python.org/\"), data=gen(), loop=loop)\n    assert req.chunked\n    assert req.headers[\"TRANSFER-ENCODING\"] == \"chunked\"\n\n    resp = await req.send(conn)\n    assert asyncio.isfuture(req._writer)\n    await resp.wait_for_close()\n    assert req._writer is None\n    assert (\n        buf.split(b\"\\r\\n\\r\\n\", 1)[1] == b\"b\\r\\nbinary data\\r\\n7\\r\\n result\\r\\n0\\r\\n\\r\\n\"\n    )\n    await req.close()\n\n\nasync def test_data_stream_deprecated(loop, buf, conn) -> None:\n    with pytest.warns(DeprecationWarning):\n\n        @aiohttp.streamer\n        async def gen(writer):\n            await writer.write(b\"binary data\")\n            await writer.write(b\" result\")\n\n    req = ClientRequest(\"POST\", URL(\"http://python.org/\"), data=gen(), loop=loop)\n    assert req.chunked\n    assert req.headers[\"TRANSFER-ENCODING\"] == \"chunked\"\n\n    resp = await req.send(conn)\n    assert asyncio.isfuture(req._writer)\n    await resp.wait_for_close()\n    assert req._writer is None\n    assert (\n        buf.split(b\"\\r\\n\\r\\n\", 1)[1] == b\"b\\r\\nbinary data\\r\\n7\\r\\n result\\r\\n0\\r\\n\\r\\n\"\n    )\n    await req.close()\n\n\nasync def test_data_file(loop, buf, conn) -> None:\n    with io.BufferedReader(io.BytesIO(b\"*\" * 2)) as file_handle:\n        req = ClientRequest(\n            \"POST\",\n            URL(\"http://python.org/\"),\n            data=file_handle,\n            loop=loop,\n        )\n        assert req.chunked\n        assert isinstance(req.body, payload.BufferedReaderPayload)\n        assert req.headers[\"TRANSFER-ENCODING\"] == \"chunked\"\n\n        resp = await req.send(conn)\n        assert asyncio.isfuture(req._writer)\n        await resp.wait_for_close()\n\n        assert req._writer is None\n        assert buf.split(b\"\\r\\n\\r\\n\", 1)[1] == b\"2\\r\\n\" + b\"*\" * 2 + b\"\\r\\n0\\r\\n\\r\\n\"\n        await req.close()\n\n\nasync def test_data_stream_exc(loop, conn) -> None:\n    fut = loop.create_future()\n\n    async def gen():\n        yield b\"binary data\"\n        await fut\n\n    req = ClientRequest(\"POST\", URL(\"http://python.org/\"), data=gen(), loop=loop)\n    assert req.chunked\n    assert req.headers[\"TRANSFER-ENCODING\"] == \"chunked\"\n\n    async def throw_exc():\n        await asyncio.sleep(0.01)\n        fut.set_exception(ValueError)\n\n    loop.create_task(throw_exc())\n\n    await req.send(conn)\n    await req._writer\n    # assert conn.close.called\n    assert conn.protocol.set_exception.called\n    await req.close()\n\n\nasync def test_data_stream_exc_chain(loop, conn) -> None:\n    fut = loop.create_future()\n\n    async def gen():\n        await fut\n        return\n        yield\n\n    req = ClientRequest(\"POST\", URL(\"http://python.org/\"), data=gen(), loop=loop)\n\n    inner_exc = ValueError()\n\n    async def throw_exc():\n        await asyncio.sleep(0.01)\n        fut.set_exception(inner_exc)\n\n    loop.create_task(throw_exc())\n\n    await req.send(conn)\n    await req._writer\n    # assert connection.close.called\n    assert conn.protocol.set_exception.called\n    outer_exc = conn.protocol.set_exception.call_args[0][0]\n    assert isinstance(outer_exc, ValueError)\n    assert inner_exc is outer_exc\n    assert inner_exc is outer_exc\n    await req.close()\n\n\nasync def test_data_stream_continue(loop, buf, conn) -> None:\n    async def gen():\n        yield b\"binary data\"\n        yield b\" result\"\n\n    req = ClientRequest(\n        \"POST\", URL(\"http://python.org/\"), data=gen(), expect100=True, loop=loop\n    )\n    assert req.chunked\n\n    async def coro():\n        await asyncio.sleep(0.0001)\n        req._continue.set_result(1)\n\n    loop.create_task(coro())\n\n    resp = await req.send(conn)\n    await req._writer\n    assert (\n        buf.split(b\"\\r\\n\\r\\n\", 1)[1] == b\"b\\r\\nbinary data\\r\\n7\\r\\n result\\r\\n0\\r\\n\\r\\n\"\n    )\n    await req.close()\n    resp.close()\n\n\nasync def test_data_continue(loop, buf, conn) -> None:\n    req = ClientRequest(\n        \"POST\", URL(\"http://python.org/\"), data=b\"data\", expect100=True, loop=loop\n    )\n\n    async def coro():\n        await asyncio.sleep(0.0001)\n        req._continue.set_result(1)\n\n    loop.create_task(coro())\n\n    resp = await req.send(conn)\n\n    await req._writer\n    assert buf.split(b\"\\r\\n\\r\\n\", 1)[1] == b\"data\"\n    await req.close()\n    resp.close()\n\n\nasync def test_close(loop, buf, conn) -> None:\n    async def gen():\n        await asyncio.sleep(0.00001)\n        yield b\"result\"\n\n    req = ClientRequest(\"POST\", URL(\"http://python.org/\"), data=gen(), loop=loop)\n    resp = await req.send(conn)\n    await req.close()\n    assert buf.split(b\"\\r\\n\\r\\n\", 1)[1] == b\"6\\r\\nresult\\r\\n0\\r\\n\\r\\n\"\n    await req.close()\n    resp.close()\n\n\nasync def test_custom_response_class(loop, conn) -> None:\n    class CustomResponse(ClientResponse):\n        def read(self, decode=False):\n            return \"customized!\"\n\n    req = ClientRequest(\n        \"GET\", URL(\"http://python.org/\"), response_class=CustomResponse, loop=loop\n    )\n    resp = await req.send(conn)\n    assert \"customized!\" == resp.read()\n    await req.close()\n    resp.close()\n\n\nasync def test_oserror_on_write_bytes(loop, conn) -> None:\n    req = ClientRequest(\"POST\", URL(\"http://python.org/\"), loop=loop)\n\n    writer = WriterMock()\n    writer.write.side_effect = OSError\n\n    await req.write_bytes(writer, conn)\n\n    assert conn.protocol.set_exception.called\n    exc = conn.protocol.set_exception.call_args[0][0]\n    assert isinstance(exc, aiohttp.ClientOSError)\n\n    await req.close()\n\n\nasync def test_terminate(loop, conn) -> None:\n    req = ClientRequest(\"get\", URL(\"http://python.org\"), loop=loop)\n    resp = await req.send(conn)\n    assert req._writer is not None\n    writer = req._writer = WriterMock()\n    writer.cancel = mock.Mock()\n\n    req.terminate()\n    assert req._writer is None\n    writer.cancel.assert_called_with()\n    resp.close()\n\n    await req.close()\n\n\ndef test_terminate_with_closed_loop(loop, conn) -> None:\n    req = resp = writer = None\n\n    async def go():\n        nonlocal req, resp, writer\n        req = ClientRequest(\"get\", URL(\"http://python.org\"))\n        resp = await req.send(conn)\n        assert req._writer is not None\n        writer = req._writer = WriterMock()\n\n        await asyncio.sleep(0.05)\n\n    loop.run_until_complete(go())\n\n    loop.run_until_complete(req.close())\n    loop.close()\n    req.terminate()\n    assert req._writer is None\n    assert not writer.cancel.called\n    resp.close()\n\n\ndef test_terminate_without_writer(loop) -> None:\n    req = ClientRequest(\"get\", URL(\"http://python.org\"), loop=loop)\n    assert req._writer is None\n\n    req.terminate()\n    assert req._writer is None\n\n    loop.run_until_complete(req.close())\n\n\nasync def test_custom_req_rep(loop) -> None:\n    conn = None\n\n    class CustomResponse(ClientResponse):\n        async def start(self, connection, read_until_eof=False):\n            nonlocal conn\n            conn = connection\n            self.status = 123\n            self.reason = \"Test OK\"\n            self._headers = CIMultiDictProxy(CIMultiDict())\n            self.cookies = SimpleCookie()\n            return\n\n    called = False\n\n    class CustomRequest(ClientRequest):\n        async def send(self, conn):\n            resp = self.response_class(\n                self.method,\n                self.url,\n                writer=self._writer,\n                continue100=self._continue,\n                timer=self._timer,\n                request_info=self.request_info,\n                traces=self._traces,\n                loop=self.loop,\n                session=self._session,\n            )\n            self.response = resp\n            nonlocal called\n            called = True\n            return resp\n\n    async def create_connection(req, traces, timeout):\n        assert isinstance(req, CustomRequest)\n        return mock.Mock()\n\n    connector = BaseConnector(loop=loop)\n    connector._create_connection = create_connection\n\n    session = aiohttp.ClientSession(\n        request_class=CustomRequest,\n        response_class=CustomResponse,\n        connector=connector,\n        loop=loop,\n    )\n\n    resp = await session.request(\"get\", URL(\"http://example.com/path/to\"))\n    assert isinstance(resp, CustomResponse)\n    assert called\n    resp.close()\n    await session.close()\n    conn.close()\n\n\ndef test_verify_ssl_false_with_ssl_context(loop, ssl_ctx) -> None:\n    with pytest.warns(DeprecationWarning):\n        with pytest.raises(ValueError):\n            _merge_ssl_params(\n                None, verify_ssl=False, ssl_context=ssl_ctx, fingerprint=None\n            )\n\n\ndef test_bad_fingerprint(loop) -> None:\n    with pytest.raises(ValueError):\n        Fingerprint(b\"invalid\")\n\n\ndef test_insecure_fingerprint_md5(loop) -> None:\n    with pytest.raises(ValueError):\n        Fingerprint(hashlib.md5(b\"foo\").digest())\n\n\ndef test_insecure_fingerprint_sha1(loop) -> None:\n    with pytest.raises(ValueError):\n        Fingerprint(hashlib.sha1(b\"foo\").digest())\n\n\ndef test_loose_cookies_types(loop) -> None:\n    req = ClientRequest(\"get\", URL(\"http://python.org\"), loop=loop)\n    morsel = Morsel()\n    morsel.set(key=\"string\", val=\"Another string\", coded_val=\"really\")\n\n    accepted_types = [\n        [(\"str\", BaseCookie())],\n        [(\"str\", morsel)],\n        [\n            (\"str\", \"str\"),\n        ],\n        {\"str\": BaseCookie()},\n        {\"str\": morsel},\n        {\"str\": \"str\"},\n        SimpleCookie(),\n    ]\n\n    for loose_cookies_type in accepted_types:\n        req.update_cookies(cookies=loose_cookies_type)\n\n    loop.run_until_complete(req.close())\n\n\n@pytest.mark.parametrize(\n    \"has_brotli,expected\",\n    [\n        (False, \"gzip, deflate\"),\n        (True, \"gzip, deflate, br\"),\n    ],\n)\ndef test_gen_default_accept_encoding(has_brotli, expected) -> None:\n    with mock.patch(\"aiohttp.client_reqrep.HAS_BROTLI\", has_brotli):\n        assert _gen_default_accept_encoding() == expected\n\n\n@pytest.mark.parametrize(\n    (\"netrc_contents\", \"expected_auth\"),\n    [\n        (\n            \"machine example.com login username password pass\\n\",\n            helpers.BasicAuth(\"username\", \"pass\"),\n        )\n    ],\n    indirect=(\"netrc_contents\",),\n)\n@pytest.mark.usefixtures(\"netrc_contents\")\ndef test_basicauth_from_netrc_present(\n    make_request: Any,\n    expected_auth: Optional[helpers.BasicAuth],\n):\n    \"\"\"Test appropriate Authorization header is sent when netrc is not empty.\"\"\"\n    req = make_request(\"get\", \"http://example.com\", trust_env=True)\n    assert req.headers[hdrs.AUTHORIZATION] == expected_auth.encode()\n\n\n@pytest.mark.parametrize(\n    \"netrc_contents\",\n    (\"machine example.com login username password pass\\n\",),\n    indirect=(\"netrc_contents\",),\n)\n@pytest.mark.usefixtures(\"netrc_contents\")\ndef test_basicauth_from_netrc_present_untrusted_env(\n    make_request: Any,\n):\n    \"\"\"Test no authorization header is sent via netrc if trust_env is False\"\"\"\n    req = make_request(\"get\", \"http://example.com\", trust_env=False)\n    assert hdrs.AUTHORIZATION not in req.headers\n\n\n@pytest.mark.parametrize(\n    \"netrc_contents\",\n    (\"\",),\n    indirect=(\"netrc_contents\",),\n)\n@pytest.mark.usefixtures(\"netrc_contents\")\ndef test_basicauth_from_empty_netrc(\n    make_request: Any,\n):\n    \"\"\"Test that no Authorization header is sent when netrc is empty\"\"\"\n    req = make_request(\"get\", \"http://example.com\", trust_env=True)\n    assert hdrs.AUTHORIZATION not in req.headers\n",
            "new_file_content": "import asyncio\nimport hashlib\nimport io\nimport os.path\nimport urllib.parse\nimport zlib\nfrom http.cookies import BaseCookie, Morsel, SimpleCookie\nfrom typing import Any, Callable, Dict, Optional\nfrom unittest import mock\n\nimport pytest\nfrom multidict import CIMultiDict, CIMultiDictProxy, istr\nfrom yarl import URL\n\nimport aiohttp\nfrom aiohttp import BaseConnector, hdrs, helpers, payload\nfrom aiohttp.client_reqrep import (\n    ClientRequest,\n    ClientResponse,\n    Fingerprint,\n    _gen_default_accept_encoding,\n    _merge_ssl_params,\n)\nfrom aiohttp.http import HttpVersion\nfrom aiohttp.test_utils import make_mocked_coro\n\n\nclass WriterMock(mock.AsyncMock):\n    def __await__(self) -> None:\n        return self().__await__()\n\n    def add_done_callback(self, cb: Callable[[], None]) -> None:\n        \"\"\"Dummy method.\"\"\"\n\n    def remove_done_callback(self, cb: Callable[[], None]) -> None:\n        \"\"\"Dummy method.\"\"\"\n\n\n@pytest.fixture\ndef make_request(loop):\n    request = None\n\n    def maker(method, url, *args, **kwargs):\n        nonlocal request\n        request = ClientRequest(method, URL(url), *args, loop=loop, **kwargs)\n        return request\n\n    yield maker\n    if request is not None:\n        loop.run_until_complete(request.close())\n\n\n@pytest.fixture\ndef buf():\n    return bytearray()\n\n\n@pytest.fixture\ndef protocol(loop, transport):\n    protocol = mock.Mock()\n    protocol.transport = transport\n    protocol._drain_helper.return_value = loop.create_future()\n    protocol._drain_helper.return_value.set_result(None)\n    return protocol\n\n\n@pytest.fixture\ndef transport(buf):\n    transport = mock.Mock()\n\n    def write(chunk):\n        buf.extend(chunk)\n\n    async def write_eof():\n        pass\n\n    transport.write.side_effect = write\n    transport.write_eof.side_effect = write_eof\n    transport.is_closing.return_value = False\n\n    return transport\n\n\n@pytest.fixture\ndef conn(transport, protocol):\n    return mock.Mock(transport=transport, protocol=protocol)\n\n\ndef test_method1(make_request) -> None:\n    req = make_request(\"get\", \"http://python.org/\")\n    assert req.method == \"GET\"\n\n\ndef test_method2(make_request) -> None:\n    req = make_request(\"head\", \"http://python.org/\")\n    assert req.method == \"HEAD\"\n\n\ndef test_method3(make_request) -> None:\n    req = make_request(\"HEAD\", \"http://python.org/\")\n    assert req.method == \"HEAD\"\n\n\ndef test_method_invalid(make_request) -> None:\n    with pytest.raises(ValueError, match=\"Method cannot contain non-token characters\"):\n        make_request(\"METHOD WITH\\nWHITESPACES\", \"http://python.org/\")\n\n\ndef test_version_1_0(make_request) -> None:\n    req = make_request(\"get\", \"http://python.org/\", version=\"1.0\")\n    assert req.version == (1, 0)\n\n\ndef test_version_default(make_request) -> None:\n    req = make_request(\"get\", \"http://python.org/\")\n    assert req.version == (1, 1)\n\n\ndef test_request_info(make_request) -> None:\n    req = make_request(\"get\", \"http://python.org/\")\n    assert req.request_info == aiohttp.RequestInfo(\n        URL(\"http://python.org/\"), \"GET\", req.headers\n    )\n\n\ndef test_request_info_with_fragment(make_request) -> None:\n    req = make_request(\"get\", \"http://python.org/#urlfragment\")\n    assert req.request_info == aiohttp.RequestInfo(\n        URL(\"http://python.org/\"),\n        \"GET\",\n        req.headers,\n        URL(\"http://python.org/#urlfragment\"),\n    )\n\n\ndef test_version_err(make_request) -> None:\n    with pytest.raises(ValueError):\n        make_request(\"get\", \"http://python.org/\", version=\"1.c\")\n\n\ndef test_keep_alive(make_request) -> None:\n    req = make_request(\"get\", \"http://python.org/\", version=(0, 9))\n    assert not req.keep_alive()\n\n    req = make_request(\"get\", \"http://python.org/\", version=(1, 0))\n    assert not req.keep_alive()\n\n    req = make_request(\n        \"get\",\n        \"http://python.org/\",\n        version=(1, 0),\n        headers={\"connection\": \"keep-alive\"},\n    )\n    assert req.keep_alive()\n\n    req = make_request(\"get\", \"http://python.org/\", version=(1, 1))\n    assert req.keep_alive()\n\n    req = make_request(\n        \"get\", \"http://python.org/\", version=(1, 1), headers={\"connection\": \"close\"}\n    )\n    assert not req.keep_alive()\n\n\ndef test_host_port_default_http(make_request) -> None:\n    req = make_request(\"get\", \"http://python.org/\")\n    assert req.host == \"python.org\"\n    assert req.port == 80\n    assert not req.ssl\n\n\ndef test_host_port_default_https(make_request) -> None:\n    req = make_request(\"get\", \"https://python.org/\")\n    assert req.host == \"python.org\"\n    assert req.port == 443\n    assert req.is_ssl()\n\n\ndef test_host_port_nondefault_http(make_request) -> None:\n    req = make_request(\"get\", \"http://python.org:960/\")\n    assert req.host == \"python.org\"\n    assert req.port == 960\n    assert not req.is_ssl()\n\n\ndef test_host_port_nondefault_https(make_request) -> None:\n    req = make_request(\"get\", \"https://python.org:960/\")\n    assert req.host == \"python.org\"\n    assert req.port == 960\n    assert req.is_ssl()\n\n\ndef test_host_port_default_ws(make_request) -> None:\n    req = make_request(\"get\", \"ws://python.org/\")\n    assert req.host == \"python.org\"\n    assert req.port == 80\n    assert not req.is_ssl()\n\n\ndef test_host_port_default_wss(make_request) -> None:\n    req = make_request(\"get\", \"wss://python.org/\")\n    assert req.host == \"python.org\"\n    assert req.port == 443\n    assert req.is_ssl()\n\n\ndef test_host_port_nondefault_ws(make_request) -> None:\n    req = make_request(\"get\", \"ws://python.org:960/\")\n    assert req.host == \"python.org\"\n    assert req.port == 960\n    assert not req.is_ssl()\n\n\ndef test_host_port_nondefault_wss(make_request) -> None:\n    req = make_request(\"get\", \"wss://python.org:960/\")\n    assert req.host == \"python.org\"\n    assert req.port == 960\n    assert req.is_ssl()\n\n\ndef test_host_port_none_port(make_request) -> None:\n    req = make_request(\"get\", \"unix://localhost/path\")\n    assert req.headers[\"Host\"] == \"localhost\"\n\n\ndef test_host_port_err(make_request) -> None:\n    with pytest.raises(ValueError):\n        make_request(\"get\", \"http://python.org:123e/\")\n\n\ndef test_hostname_err(make_request) -> None:\n    with pytest.raises(ValueError):\n        make_request(\"get\", \"http://:8080/\")\n\n\ndef test_host_header_host_first(make_request) -> None:\n    req = make_request(\"get\", \"http://python.org/\")\n    assert list(req.headers)[0] == \"Host\"\n\n\ndef test_host_header_host_without_port(make_request) -> None:\n    req = make_request(\"get\", \"http://python.org/\")\n    assert req.headers[\"HOST\"] == \"python.org\"\n\n\ndef test_host_header_host_with_default_port(make_request) -> None:\n    req = make_request(\"get\", \"http://python.org:80/\")\n    assert req.headers[\"HOST\"] == \"python.org\"\n\n\ndef test_host_header_host_with_nondefault_port(make_request) -> None:\n    req = make_request(\"get\", \"http://python.org:99/\")\n    assert req.headers[\"HOST\"] == \"python.org:99\"\n\n\ndef test_host_header_host_idna_encode(make_request) -> None:\n    req = make_request(\"get\", \"http://xn--9caa.com\")\n    assert req.headers[\"HOST\"] == \"xn--9caa.com\"\n\n\ndef test_host_header_host_unicode(make_request) -> None:\n    req = make_request(\"get\", \"http://éé.com\")\n    assert req.headers[\"HOST\"] == \"xn--9caa.com\"\n\n\ndef test_host_header_explicit_host(make_request) -> None:\n    req = make_request(\"get\", \"http://python.org/\", headers={\"host\": \"example.com\"})\n    assert req.headers[\"HOST\"] == \"example.com\"\n\n\ndef test_host_header_explicit_host_with_port(make_request) -> None:\n    req = make_request(\"get\", \"http://python.org/\", headers={\"host\": \"example.com:99\"})\n    assert req.headers[\"HOST\"] == \"example.com:99\"\n\n\ndef test_host_header_ipv4(make_request) -> None:\n    req = make_request(\"get\", \"http://127.0.0.2\")\n    assert req.headers[\"HOST\"] == \"127.0.0.2\"\n\n\ndef test_host_header_ipv6(make_request) -> None:\n    req = make_request(\"get\", \"http://[::2]\")\n    assert req.headers[\"HOST\"] == \"[::2]\"\n\n\ndef test_host_header_ipv4_with_port(make_request) -> None:\n    req = make_request(\"get\", \"http://127.0.0.2:99\")\n    assert req.headers[\"HOST\"] == \"127.0.0.2:99\"\n\n\ndef test_host_header_ipv6_with_port(make_request) -> None:\n    req = make_request(\"get\", \"http://[::2]:99\")\n    assert req.headers[\"HOST\"] == \"[::2]:99\"\n\n\ndef test_default_loop(loop) -> None:\n    asyncio.set_event_loop(loop)\n    req = ClientRequest(\"get\", URL(\"http://python.org/\"))\n    assert req.loop is loop\n    loop.run_until_complete(req.close())\n\n\n@pytest.mark.parametrize(\n    (\"url\", \"headers\", \"expected\"),\n    (\n        pytest.param(\"http://localhost.\", None, \"localhost\", id=\"dot only at the end\"),\n        pytest.param(\"http://python.org.\", None, \"python.org\", id=\"single dot\"),\n        pytest.param(\n            \"http://python.org.:99\", None, \"python.org:99\", id=\"single dot with port\"\n        ),\n        pytest.param(\n            \"http://python.org...:99\",\n            None,\n            \"python.org:99\",\n            id=\"multiple dots with port\",\n        ),\n        pytest.param(\n            \"http://python.org.:99\",\n            {\"host\": \"example.com.:99\"},\n            \"example.com.:99\",\n            id=\"explicit host header\",\n        ),\n        pytest.param(\"https://python.org.\", None, \"python.org\", id=\"https\"),\n        pytest.param(\"https://...\", None, \"\", id=\"only dots\"),\n        pytest.param(\n            \"http://príklad.example.org.:99\",\n            None,\n            \"xn--prklad-4va.example.org:99\",\n            id=\"single dot with port idna\",\n        ),\n    ),\n)\ndef test_host_header_fqdn(\n    make_request: Any, url: str, headers: Dict[str, str], expected: str\n) -> None:\n    req = make_request(\"get\", url, headers=headers)\n    assert req.headers[\"HOST\"] == expected\n\n\ndef test_default_headers_useragent(make_request) -> None:\n    req = make_request(\"get\", \"http://python.org/\")\n\n    assert \"SERVER\" not in req.headers\n    assert \"USER-AGENT\" in req.headers\n\n\ndef test_default_headers_useragent_custom(make_request) -> None:\n    req = make_request(\n        \"get\", \"http://python.org/\", headers={\"user-agent\": \"my custom agent\"}\n    )\n\n    assert \"USER-Agent\" in req.headers\n    assert \"my custom agent\" == req.headers[\"User-Agent\"]\n\n\ndef test_skip_default_useragent_header(make_request) -> None:\n    req = make_request(\n        \"get\", \"http://python.org/\", skip_auto_headers={istr(\"user-agent\")}\n    )\n\n    assert \"User-Agent\" not in req.headers\n\n\ndef test_headers(make_request) -> None:\n    req = make_request(\n        \"post\", \"http://python.org/\", headers={\"Content-Type\": \"text/plain\"}\n    )\n\n    assert \"CONTENT-TYPE\" in req.headers\n    assert req.headers[\"CONTENT-TYPE\"] == \"text/plain\"\n    assert req.headers[\"ACCEPT-ENCODING\"] == \"gzip, deflate, br\"\n\n\ndef test_headers_list(make_request) -> None:\n    req = make_request(\n        \"post\", \"http://python.org/\", headers=[(\"Content-Type\", \"text/plain\")]\n    )\n    assert \"CONTENT-TYPE\" in req.headers\n    assert req.headers[\"CONTENT-TYPE\"] == \"text/plain\"\n\n\ndef test_headers_default(make_request) -> None:\n    req = make_request(\n        \"get\", \"http://python.org/\", headers={\"ACCEPT-ENCODING\": \"deflate\"}\n    )\n    assert req.headers[\"ACCEPT-ENCODING\"] == \"deflate\"\n\n\ndef test_invalid_url(make_request) -> None:\n    with pytest.raises(aiohttp.InvalidURL):\n        make_request(\"get\", \"hiwpefhipowhefopw\")\n\n\ndef test_no_path(make_request) -> None:\n    req = make_request(\"get\", \"http://python.org\")\n    assert \"/\" == req.url.path\n\n\ndef test_ipv6_default_http_port(make_request) -> None:\n    req = make_request(\"get\", \"http://[2001:db8::1]/\")\n    assert req.host == \"2001:db8::1\"\n    assert req.port == 80\n    assert not req.ssl\n\n\ndef test_ipv6_default_https_port(make_request) -> None:\n    req = make_request(\"get\", \"https://[2001:db8::1]/\")\n    assert req.host == \"2001:db8::1\"\n    assert req.port == 443\n    assert req.is_ssl()\n\n\ndef test_ipv6_nondefault_http_port(make_request) -> None:\n    req = make_request(\"get\", \"http://[2001:db8::1]:960/\")\n    assert req.host == \"2001:db8::1\"\n    assert req.port == 960\n    assert not req.is_ssl()\n\n\ndef test_ipv6_nondefault_https_port(make_request) -> None:\n    req = make_request(\"get\", \"https://[2001:db8::1]:960/\")\n    assert req.host == \"2001:db8::1\"\n    assert req.port == 960\n    assert req.is_ssl()\n\n\ndef test_basic_auth(make_request) -> None:\n    req = make_request(\n        \"get\", \"http://python.org\", auth=aiohttp.BasicAuth(\"nkim\", \"1234\")\n    )\n    assert \"AUTHORIZATION\" in req.headers\n    assert \"Basic bmtpbToxMjM0\" == req.headers[\"AUTHORIZATION\"]\n\n\ndef test_basic_auth_utf8(make_request) -> None:\n    req = make_request(\n        \"get\", \"http://python.org\", auth=aiohttp.BasicAuth(\"nkim\", \"секрет\", \"utf-8\")\n    )\n    assert \"AUTHORIZATION\" in req.headers\n    assert \"Basic bmtpbTrRgdC10LrRgNC10YI=\" == req.headers[\"AUTHORIZATION\"]\n\n\ndef test_basic_auth_tuple_forbidden(make_request) -> None:\n    with pytest.raises(TypeError):\n        make_request(\"get\", \"http://python.org\", auth=(\"nkim\", \"1234\"))\n\n\ndef test_basic_auth_from_url(make_request) -> None:\n    req = make_request(\"get\", \"http://nkim:1234@python.org\")\n    assert \"AUTHORIZATION\" in req.headers\n    assert \"Basic bmtpbToxMjM0\" == req.headers[\"AUTHORIZATION\"]\n    assert \"python.org\" == req.host\n\n\ndef test_basic_auth_from_url_overridden(make_request) -> None:\n    req = make_request(\n        \"get\", \"http://garbage@python.org\", auth=aiohttp.BasicAuth(\"nkim\", \"1234\")\n    )\n    assert \"AUTHORIZATION\" in req.headers\n    assert \"Basic bmtpbToxMjM0\" == req.headers[\"AUTHORIZATION\"]\n    assert \"python.org\" == req.host\n\n\ndef test_path_is_not_double_encoded1(make_request) -> None:\n    req = make_request(\"get\", \"http://0.0.0.0/get/test case\")\n    assert req.url.raw_path == \"/get/test%20case\"\n\n\ndef test_path_is_not_double_encoded2(make_request) -> None:\n    req = make_request(\"get\", \"http://0.0.0.0/get/test%2fcase\")\n    assert req.url.raw_path == \"/get/test%2Fcase\"\n\n\ndef test_path_is_not_double_encoded3(make_request) -> None:\n    req = make_request(\"get\", \"http://0.0.0.0/get/test%20case\")\n    assert req.url.raw_path == \"/get/test%20case\"\n\n\ndef test_path_safe_chars_preserved(make_request) -> None:\n    req = make_request(\"get\", \"http://0.0.0.0/get/:=+/%2B/\")\n    assert req.url.path == \"/get/:=+/+/\"\n\n\ndef test_params_are_added_before_fragment1(make_request) -> None:\n    req = make_request(\"GET\", \"http://example.com/path#fragment\", params={\"a\": \"b\"})\n    assert str(req.url) == \"http://example.com/path?a=b\"\n\n\ndef test_params_are_added_before_fragment2(make_request) -> None:\n    req = make_request(\n        \"GET\", \"http://example.com/path?key=value#fragment\", params={\"a\": \"b\"}\n    )\n    assert str(req.url) == \"http://example.com/path?key=value&a=b\"\n\n\ndef test_path_not_contain_fragment1(make_request) -> None:\n    req = make_request(\"GET\", \"http://example.com/path#fragment\")\n    assert req.url.path == \"/path\"\n\n\ndef test_path_not_contain_fragment2(make_request) -> None:\n    req = make_request(\"GET\", \"http://example.com/path?key=value#fragment\")\n    assert str(req.url) == \"http://example.com/path?key=value\"\n\n\ndef test_cookies(make_request) -> None:\n    req = make_request(\"get\", \"http://test.com/path\", cookies={\"cookie1\": \"val1\"})\n\n    assert \"COOKIE\" in req.headers\n    assert \"cookie1=val1\" == req.headers[\"COOKIE\"]\n\n\ndef test_cookies_is_quoted_with_special_characters(make_request) -> None:\n    req = make_request(\"get\", \"http://test.com/path\", cookies={\"cookie1\": \"val/one\"})\n\n    assert \"COOKIE\" in req.headers\n    assert 'cookie1=\"val/one\"' == req.headers[\"COOKIE\"]\n\n\ndef test_cookies_merge_with_headers(make_request) -> None:\n    req = make_request(\n        \"get\",\n        \"http://test.com/path\",\n        headers={\"cookie\": \"cookie1=val1\"},\n        cookies={\"cookie2\": \"val2\"},\n    )\n\n    assert \"cookie1=val1; cookie2=val2\" == req.headers[\"COOKIE\"]\n\n\ndef test_unicode_get1(make_request) -> None:\n    req = make_request(\"get\", \"http://python.org\", params={\"foo\": \"f\\xf8\\xf8\"})\n    assert \"http://python.org/?foo=f%C3%B8%C3%B8\" == str(req.url)\n\n\ndef test_unicode_get2(make_request) -> None:\n    req = make_request(\"\", \"http://python.org\", params={\"f\\xf8\\xf8\": \"f\\xf8\\xf8\"})\n\n    assert \"http://python.org/?f%C3%B8%C3%B8=f%C3%B8%C3%B8\" == str(req.url)\n\n\ndef test_unicode_get3(make_request) -> None:\n    req = make_request(\"\", \"http://python.org\", params={\"foo\": \"foo\"})\n    assert \"http://python.org/?foo=foo\" == str(req.url)\n\n\ndef test_unicode_get4(make_request) -> None:\n    def join(*suffix):\n        return urllib.parse.urljoin(\"http://python.org/\", \"/\".join(suffix))\n\n    req = make_request(\"\", join(\"\\xf8\"), params={\"foo\": \"foo\"})\n    assert \"http://python.org/%C3%B8?foo=foo\" == str(req.url)\n\n\ndef test_query_multivalued_param(make_request) -> None:\n    for meth in ClientRequest.ALL_METHODS:\n        req = make_request(\n            meth, \"http://python.org\", params=((\"test\", \"foo\"), (\"test\", \"baz\"))\n        )\n\n        assert str(req.url) == \"http://python.org/?test=foo&test=baz\"\n\n\ndef test_query_str_param(make_request) -> None:\n    for meth in ClientRequest.ALL_METHODS:\n        req = make_request(meth, \"http://python.org\", params=\"test=foo\")\n        assert str(req.url) == \"http://python.org/?test=foo\"\n\n\ndef test_query_bytes_param_raises(make_request) -> None:\n    for meth in ClientRequest.ALL_METHODS:\n        with pytest.raises(TypeError):\n            make_request(meth, \"http://python.org\", params=b\"test=foo\")\n\n\ndef test_query_str_param_is_not_encoded(make_request) -> None:\n    for meth in ClientRequest.ALL_METHODS:\n        req = make_request(meth, \"http://python.org\", params=\"test=f+oo\")\n        assert str(req.url) == \"http://python.org/?test=f+oo\"\n\n\ndef test_params_update_path_and_url(make_request) -> None:\n    req = make_request(\n        \"get\", \"http://python.org\", params=((\"test\", \"foo\"), (\"test\", \"baz\"))\n    )\n    assert str(req.url) == \"http://python.org/?test=foo&test=baz\"\n\n\ndef test_params_empty_path_and_url(make_request) -> None:\n    req_empty = make_request(\"get\", \"http://python.org\", params={})\n    assert str(req_empty.url) == \"http://python.org\"\n    req_none = make_request(\"get\", \"http://python.org\")\n    assert str(req_none.url) == \"http://python.org\"\n\n\ndef test_gen_netloc_all(make_request) -> None:\n    req = make_request(\n        \"get\",\n        \"https://aiohttp:pwpwpw@\"\n        + \"12345678901234567890123456789\"\n        + \"012345678901234567890:8080\",\n    )\n    assert (\n        req.headers[\"HOST\"]\n        == \"12345678901234567890123456789\" + \"012345678901234567890:8080\"\n    )\n\n\ndef test_gen_netloc_no_port(make_request) -> None:\n    req = make_request(\n        \"get\",\n        \"https://aiohttp:pwpwpw@\"\n        + \"12345678901234567890123456789\"\n        + \"012345678901234567890/\",\n    )\n    assert (\n        req.headers[\"HOST\"] == \"12345678901234567890123456789\" + \"012345678901234567890\"\n    )\n\n\nasync def test_connection_header(loop, conn) -> None:\n    req = ClientRequest(\"get\", URL(\"http://python.org\"), loop=loop)\n    req.keep_alive = mock.Mock()\n    req.headers.clear()\n\n    req.keep_alive.return_value = True\n    req.version = HttpVersion(1, 1)\n    req.headers.clear()\n    await req.send(conn)\n    assert req.headers.get(\"CONNECTION\") is None\n\n    req.version = HttpVersion(1, 0)\n    req.headers.clear()\n    await req.send(conn)\n    assert req.headers.get(\"CONNECTION\") == \"keep-alive\"\n\n    req.keep_alive.return_value = False\n    req.version = HttpVersion(1, 1)\n    req.headers.clear()\n    await req.send(conn)\n    assert req.headers.get(\"CONNECTION\") == \"close\"\n\n    await req.close()\n\n\nasync def test_no_content_length(loop, conn) -> None:\n    req = ClientRequest(\"get\", URL(\"http://python.org\"), loop=loop)\n    resp = await req.send(conn)\n    assert req.headers.get(\"CONTENT-LENGTH\") is None\n    await req.close()\n    resp.close()\n\n\nasync def test_no_content_length_head(loop, conn) -> None:\n    req = ClientRequest(\"head\", URL(\"http://python.org\"), loop=loop)\n    resp = await req.send(conn)\n    assert req.headers.get(\"CONTENT-LENGTH\") is None\n    await req.close()\n    resp.close()\n\n\nasync def test_content_type_auto_header_get(loop, conn) -> None:\n    req = ClientRequest(\"get\", URL(\"http://python.org\"), loop=loop)\n    resp = await req.send(conn)\n    assert \"CONTENT-TYPE\" not in req.headers\n    resp.close()\n    await req.close()\n\n\nasync def test_content_type_auto_header_form(loop, conn) -> None:\n    req = ClientRequest(\n        \"post\", URL(\"http://python.org\"), data={\"hey\": \"you\"}, loop=loop\n    )\n    resp = await req.send(conn)\n    assert \"application/x-www-form-urlencoded\" == req.headers.get(\"CONTENT-TYPE\")\n    resp.close()\n    await req.close()\n\n\nasync def test_content_type_auto_header_bytes(loop, conn) -> None:\n    req = ClientRequest(\"post\", URL(\"http://python.org\"), data=b\"hey you\", loop=loop)\n    resp = await req.send(conn)\n    assert \"application/octet-stream\" == req.headers.get(\"CONTENT-TYPE\")\n    resp.close()\n    await req.close()\n\n\nasync def test_content_type_skip_auto_header_bytes(loop, conn) -> None:\n    req = ClientRequest(\n        \"post\",\n        URL(\"http://python.org\"),\n        data=b\"hey you\",\n        skip_auto_headers={\"Content-Type\"},\n        loop=loop,\n    )\n    resp = await req.send(conn)\n    assert \"CONTENT-TYPE\" not in req.headers\n    resp.close()\n    await req.close()\n\n\nasync def test_content_type_skip_auto_header_form(loop, conn) -> None:\n    req = ClientRequest(\n        \"post\",\n        URL(\"http://python.org\"),\n        data={\"hey\": \"you\"},\n        loop=loop,\n        skip_auto_headers={\"Content-Type\"},\n    )\n    resp = await req.send(conn)\n    assert \"CONTENT-TYPE\" not in req.headers\n    resp.close()\n    await req.close()\n\n\nasync def test_content_type_auto_header_content_length_no_skip(loop, conn) -> None:\n    with io.BytesIO(b\"hey\") as file_handle:\n        req = ClientRequest(\n            \"post\",\n            URL(\"http://python.org\"),\n            data=file_handle,\n            skip_auto_headers={\"Content-Length\"},\n            loop=loop,\n        )\n        resp = await req.send(conn)\n        assert req.headers.get(\"CONTENT-LENGTH\") == \"3\"\n        resp.close()\n        await req.close()\n\n\nasync def test_urlencoded_formdata_charset(loop, conn) -> None:\n    req = ClientRequest(\n        \"post\",\n        URL(\"http://python.org\"),\n        data=aiohttp.FormData({\"hey\": \"you\"}, charset=\"koi8-r\"),\n        loop=loop,\n    )\n    await req.send(conn)\n    assert \"application/x-www-form-urlencoded; charset=koi8-r\" == req.headers.get(\n        \"CONTENT-TYPE\"\n    )\n    await req.close()\n\n\nasync def test_post_data(loop, conn) -> None:\n    for meth in ClientRequest.POST_METHODS:\n        req = ClientRequest(\n            meth, URL(\"http://python.org/\"), data={\"life\": \"42\"}, loop=loop\n        )\n        resp = await req.send(conn)\n        assert \"/\" == req.url.path\n        assert b\"life=42\" == req.body._value\n        assert \"application/x-www-form-urlencoded\" == req.headers[\"CONTENT-TYPE\"]\n        await req.close()\n        resp.close()\n\n\nasync def test_pass_falsy_data(loop) -> None:\n    with mock.patch(\"aiohttp.client_reqrep.ClientRequest.update_body_from_data\"):\n        req = ClientRequest(\"post\", URL(\"http://python.org/\"), data={}, loop=loop)\n        req.update_body_from_data.assert_called_once_with({})\n    await req.close()\n\n\nasync def test_pass_falsy_data_file(loop, tmpdir) -> None:\n    testfile = tmpdir.join(\"tmpfile\").open(\"w+b\")\n    testfile.write(b\"data\")\n    testfile.seek(0)\n    skip = frozenset([hdrs.CONTENT_TYPE])\n    req = ClientRequest(\n        \"post\",\n        URL(\"http://python.org/\"),\n        data=testfile,\n        skip_auto_headers=skip,\n        loop=loop,\n    )\n    assert req.headers.get(\"CONTENT-LENGTH\", None) is not None\n    await req.close()\n    testfile.close()\n\n\n# Elasticsearch API requires to send request body with GET-requests\nasync def test_get_with_data(loop) -> None:\n    for meth in ClientRequest.GET_METHODS:\n        req = ClientRequest(\n            meth, URL(\"http://python.org/\"), data={\"life\": \"42\"}, loop=loop\n        )\n        assert \"/\" == req.url.path\n        assert b\"life=42\" == req.body._value\n        await req.close()\n\n\nasync def test_bytes_data(loop, conn) -> None:\n    for meth in ClientRequest.POST_METHODS:\n        req = ClientRequest(\n            meth, URL(\"http://python.org/\"), data=b\"binary data\", loop=loop\n        )\n        resp = await req.send(conn)\n        assert \"/\" == req.url.path\n        assert isinstance(req.body, payload.BytesPayload)\n        assert b\"binary data\" == req.body._value\n        assert \"application/octet-stream\" == req.headers[\"CONTENT-TYPE\"]\n        await req.close()\n        resp.close()\n\n\nasync def test_content_encoding(loop, conn) -> None:\n    req = ClientRequest(\n        \"post\", URL(\"http://python.org/\"), data=\"foo\", compress=\"deflate\", loop=loop\n    )\n    with mock.patch(\"aiohttp.client_reqrep.StreamWriter\") as m_writer:\n        m_writer.return_value.write_headers = make_mocked_coro()\n        resp = await req.send(conn)\n    assert req.headers[\"TRANSFER-ENCODING\"] == \"chunked\"\n    assert req.headers[\"CONTENT-ENCODING\"] == \"deflate\"\n    m_writer.return_value.enable_compression.assert_called_with(\"deflate\")\n    await req.close()\n    resp.close()\n\n\nasync def test_content_encoding_dont_set_headers_if_no_body(loop, conn) -> None:\n    req = ClientRequest(\n        \"post\", URL(\"http://python.org/\"), compress=\"deflate\", loop=loop\n    )\n    with mock.patch(\"aiohttp.client_reqrep.http\"):\n        resp = await req.send(conn)\n    assert \"TRANSFER-ENCODING\" not in req.headers\n    assert \"CONTENT-ENCODING\" not in req.headers\n    await req.close()\n    resp.close()\n\n\nasync def test_content_encoding_header(loop, conn) -> None:\n    req = ClientRequest(\n        \"post\",\n        URL(\"http://python.org/\"),\n        data=\"foo\",\n        headers={\"Content-Encoding\": \"deflate\"},\n        loop=loop,\n    )\n    with mock.patch(\"aiohttp.client_reqrep.StreamWriter\") as m_writer:\n        m_writer.return_value.write_headers = make_mocked_coro()\n        resp = await req.send(conn)\n\n    assert not m_writer.return_value.enable_compression.called\n    assert not m_writer.return_value.enable_chunking.called\n    await req.close()\n    resp.close()\n\n\nasync def test_compress_and_content_encoding(loop, conn) -> None:\n    with pytest.raises(ValueError):\n        ClientRequest(\n            \"post\",\n            URL(\"http://python.org/\"),\n            data=\"foo\",\n            headers={\"content-encoding\": \"deflate\"},\n            compress=\"deflate\",\n            loop=loop,\n        )\n\n\nasync def test_chunked(loop, conn) -> None:\n    req = ClientRequest(\n        \"post\",\n        URL(\"http://python.org/\"),\n        headers={\"TRANSFER-ENCODING\": \"gzip\"},\n        loop=loop,\n    )\n    resp = await req.send(conn)\n    assert \"gzip\" == req.headers[\"TRANSFER-ENCODING\"]\n    await req.close()\n    resp.close()\n\n\nasync def test_chunked2(loop, conn) -> None:\n    req = ClientRequest(\n        \"post\",\n        URL(\"http://python.org/\"),\n        headers={\"Transfer-encoding\": \"chunked\"},\n        loop=loop,\n    )\n    resp = await req.send(conn)\n    assert \"chunked\" == req.headers[\"TRANSFER-ENCODING\"]\n    await req.close()\n    resp.close()\n\n\nasync def test_chunked_explicit(loop, conn) -> None:\n    req = ClientRequest(\"post\", URL(\"http://python.org/\"), chunked=True, loop=loop)\n    with mock.patch(\"aiohttp.client_reqrep.StreamWriter\") as m_writer:\n        m_writer.return_value.write_headers = make_mocked_coro()\n        resp = await req.send(conn)\n\n    assert \"chunked\" == req.headers[\"TRANSFER-ENCODING\"]\n    m_writer.return_value.enable_chunking.assert_called_with()\n    await req.close()\n    resp.close()\n\n\nasync def test_chunked_length(loop, conn) -> None:\n    with pytest.raises(ValueError):\n        ClientRequest(\n            \"post\",\n            URL(\"http://python.org/\"),\n            headers={\"CONTENT-LENGTH\": \"1000\"},\n            chunked=True,\n            loop=loop,\n        )\n\n\nasync def test_chunked_transfer_encoding(loop, conn) -> None:\n    with pytest.raises(ValueError):\n        ClientRequest(\n            \"post\",\n            URL(\"http://python.org/\"),\n            headers={\"TRANSFER-ENCODING\": \"chunked\"},\n            chunked=True,\n            loop=loop,\n        )\n\n\nasync def test_file_upload_not_chunked(loop) -> None:\n    here = os.path.dirname(__file__)\n    fname = os.path.join(here, \"aiohttp.png\")\n    with open(fname, \"rb\") as f:\n        req = ClientRequest(\"post\", URL(\"http://python.org/\"), data=f, loop=loop)\n        assert not req.chunked\n        assert req.headers[\"CONTENT-LENGTH\"] == str(os.path.getsize(fname))\n        await req.close()\n\n\nasync def test_precompressed_data_stays_intact(loop) -> None:\n    data = zlib.compress(b\"foobar\")\n    req = ClientRequest(\n        \"post\",\n        URL(\"http://python.org/\"),\n        data=data,\n        headers={\"CONTENT-ENCODING\": \"deflate\"},\n        compress=False,\n        loop=loop,\n    )\n    assert not req.compress\n    assert not req.chunked\n    assert req.headers[\"CONTENT-ENCODING\"] == \"deflate\"\n    await req.close()\n\n\nasync def test_file_upload_not_chunked_seek(loop) -> None:\n    here = os.path.dirname(__file__)\n    fname = os.path.join(here, \"aiohttp.png\")\n    with open(fname, \"rb\") as f:\n        f.seek(100)\n        req = ClientRequest(\"post\", URL(\"http://python.org/\"), data=f, loop=loop)\n        assert req.headers[\"CONTENT-LENGTH\"] == str(os.path.getsize(fname) - 100)\n        await req.close()\n\n\nasync def test_file_upload_force_chunked(loop) -> None:\n    here = os.path.dirname(__file__)\n    fname = os.path.join(here, \"aiohttp.png\")\n    with open(fname, \"rb\") as f:\n        req = ClientRequest(\n            \"post\", URL(\"http://python.org/\"), data=f, chunked=True, loop=loop\n        )\n        assert req.chunked\n        assert \"CONTENT-LENGTH\" not in req.headers\n        await req.close()\n\n\nasync def test_expect100(loop, conn) -> None:\n    req = ClientRequest(\"get\", URL(\"http://python.org/\"), expect100=True, loop=loop)\n    resp = await req.send(conn)\n    assert \"100-continue\" == req.headers[\"EXPECT\"]\n    assert req._continue is not None\n    req.terminate()\n    resp.close()\n    await req.close()\n\n\nasync def test_expect_100_continue_header(loop, conn) -> None:\n    req = ClientRequest(\n        \"get\", URL(\"http://python.org/\"), headers={\"expect\": \"100-continue\"}, loop=loop\n    )\n    resp = await req.send(conn)\n    assert \"100-continue\" == req.headers[\"EXPECT\"]\n    assert req._continue is not None\n    req.terminate()\n    resp.close()\n    await req.close()\n\n\nasync def test_data_stream(loop, buf, conn) -> None:\n    async def gen():\n        yield b\"binary data\"\n        yield b\" result\"\n\n    req = ClientRequest(\"POST\", URL(\"http://python.org/\"), data=gen(), loop=loop)\n    assert req.chunked\n    assert req.headers[\"TRANSFER-ENCODING\"] == \"chunked\"\n\n    resp = await req.send(conn)\n    assert asyncio.isfuture(req._writer)\n    await resp.wait_for_close()\n    assert req._writer is None\n    assert (\n        buf.split(b\"\\r\\n\\r\\n\", 1)[1] == b\"b\\r\\nbinary data\\r\\n7\\r\\n result\\r\\n0\\r\\n\\r\\n\"\n    )\n    await req.close()\n\n\nasync def test_data_stream_deprecated(loop, buf, conn) -> None:\n    with pytest.warns(DeprecationWarning):\n\n        @aiohttp.streamer\n        async def gen(writer):\n            await writer.write(b\"binary data\")\n            await writer.write(b\" result\")\n\n    req = ClientRequest(\"POST\", URL(\"http://python.org/\"), data=gen(), loop=loop)\n    assert req.chunked\n    assert req.headers[\"TRANSFER-ENCODING\"] == \"chunked\"\n\n    resp = await req.send(conn)\n    assert asyncio.isfuture(req._writer)\n    await resp.wait_for_close()\n    assert req._writer is None\n    assert (\n        buf.split(b\"\\r\\n\\r\\n\", 1)[1] == b\"b\\r\\nbinary data\\r\\n7\\r\\n result\\r\\n0\\r\\n\\r\\n\"\n    )\n    await req.close()\n\n\nasync def test_data_file(loop, buf, conn) -> None:\n    with io.BufferedReader(io.BytesIO(b\"*\" * 2)) as file_handle:\n        req = ClientRequest(\n            \"POST\",\n            URL(\"http://python.org/\"),\n            data=file_handle,\n            loop=loop,\n        )\n        assert req.chunked\n        assert isinstance(req.body, payload.BufferedReaderPayload)\n        assert req.headers[\"TRANSFER-ENCODING\"] == \"chunked\"\n\n        resp = await req.send(conn)\n        assert asyncio.isfuture(req._writer)\n        await resp.wait_for_close()\n\n        assert req._writer is None\n        assert buf.split(b\"\\r\\n\\r\\n\", 1)[1] == b\"2\\r\\n\" + b\"*\" * 2 + b\"\\r\\n0\\r\\n\\r\\n\"\n        await req.close()\n\n\nasync def test_data_stream_exc(loop, conn) -> None:\n    fut = loop.create_future()\n\n    async def gen():\n        yield b\"binary data\"\n        await fut\n\n    req = ClientRequest(\"POST\", URL(\"http://python.org/\"), data=gen(), loop=loop)\n    assert req.chunked\n    assert req.headers[\"TRANSFER-ENCODING\"] == \"chunked\"\n\n    async def throw_exc():\n        await asyncio.sleep(0.01)\n        fut.set_exception(ValueError)\n\n    loop.create_task(throw_exc())\n\n    await req.send(conn)\n    await req._writer\n    # assert conn.close.called\n    assert conn.protocol.set_exception.called\n    await req.close()\n\n\nasync def test_data_stream_exc_chain(loop, conn) -> None:\n    fut = loop.create_future()\n\n    async def gen():\n        await fut\n        return\n        yield\n\n    req = ClientRequest(\"POST\", URL(\"http://python.org/\"), data=gen(), loop=loop)\n\n    inner_exc = ValueError()\n\n    async def throw_exc():\n        await asyncio.sleep(0.01)\n        fut.set_exception(inner_exc)\n\n    loop.create_task(throw_exc())\n\n    await req.send(conn)\n    await req._writer\n    # assert connection.close.called\n    assert conn.protocol.set_exception.called\n    outer_exc = conn.protocol.set_exception.call_args[0][0]\n    assert isinstance(outer_exc, ValueError)\n    assert inner_exc is outer_exc\n    assert inner_exc is outer_exc\n    await req.close()\n\n\nasync def test_data_stream_continue(loop, buf, conn) -> None:\n    async def gen():\n        yield b\"binary data\"\n        yield b\" result\"\n\n    req = ClientRequest(\n        \"POST\", URL(\"http://python.org/\"), data=gen(), expect100=True, loop=loop\n    )\n    assert req.chunked\n\n    async def coro():\n        await asyncio.sleep(0.0001)\n        req._continue.set_result(1)\n\n    loop.create_task(coro())\n\n    resp = await req.send(conn)\n    await req._writer\n    assert (\n        buf.split(b\"\\r\\n\\r\\n\", 1)[1] == b\"b\\r\\nbinary data\\r\\n7\\r\\n result\\r\\n0\\r\\n\\r\\n\"\n    )\n    await req.close()\n    resp.close()\n\n\nasync def test_data_continue(loop, buf, conn) -> None:\n    req = ClientRequest(\n        \"POST\", URL(\"http://python.org/\"), data=b\"data\", expect100=True, loop=loop\n    )\n\n    async def coro():\n        await asyncio.sleep(0.0001)\n        req._continue.set_result(1)\n\n    loop.create_task(coro())\n\n    resp = await req.send(conn)\n\n    await req._writer\n    assert buf.split(b\"\\r\\n\\r\\n\", 1)[1] == b\"data\"\n    await req.close()\n    resp.close()\n\n\nasync def test_close(loop, buf, conn) -> None:\n    async def gen():\n        await asyncio.sleep(0.00001)\n        yield b\"result\"\n\n    req = ClientRequest(\"POST\", URL(\"http://python.org/\"), data=gen(), loop=loop)\n    resp = await req.send(conn)\n    await req.close()\n    assert buf.split(b\"\\r\\n\\r\\n\", 1)[1] == b\"6\\r\\nresult\\r\\n0\\r\\n\\r\\n\"\n    await req.close()\n    resp.close()\n\n\nasync def test_bad_version(loop, conn) -> None:\n    req = ClientRequest(\n        \"GET\",\n        URL(\"http://python.org\"),\n        loop=loop,\n        headers={\"Connection\": \"Close\"},\n        version=(\"1\", \"1\\r\\nInjected-Header: not allowed\"),\n    )\n\n    with pytest.raises(AttributeError):\n        await req.send(conn)\n\n\nasync def test_custom_response_class(loop, conn) -> None:\n    class CustomResponse(ClientResponse):\n        def read(self, decode=False):\n            return \"customized!\"\n\n    req = ClientRequest(\n        \"GET\", URL(\"http://python.org/\"), response_class=CustomResponse, loop=loop\n    )\n    resp = await req.send(conn)\n    assert \"customized!\" == resp.read()\n    await req.close()\n    resp.close()\n\n\nasync def test_oserror_on_write_bytes(loop, conn) -> None:\n    req = ClientRequest(\"POST\", URL(\"http://python.org/\"), loop=loop)\n\n    writer = WriterMock()\n    writer.write.side_effect = OSError\n\n    await req.write_bytes(writer, conn)\n\n    assert conn.protocol.set_exception.called\n    exc = conn.protocol.set_exception.call_args[0][0]\n    assert isinstance(exc, aiohttp.ClientOSError)\n\n    await req.close()\n\n\nasync def test_terminate(loop, conn) -> None:\n    req = ClientRequest(\"get\", URL(\"http://python.org\"), loop=loop)\n    resp = await req.send(conn)\n    assert req._writer is not None\n    writer = req._writer = WriterMock()\n    writer.cancel = mock.Mock()\n\n    req.terminate()\n    assert req._writer is None\n    writer.cancel.assert_called_with()\n    resp.close()\n\n    await req.close()\n\n\ndef test_terminate_with_closed_loop(loop, conn) -> None:\n    req = resp = writer = None\n\n    async def go():\n        nonlocal req, resp, writer\n        req = ClientRequest(\"get\", URL(\"http://python.org\"))\n        resp = await req.send(conn)\n        assert req._writer is not None\n        writer = req._writer = WriterMock()\n\n        await asyncio.sleep(0.05)\n\n    loop.run_until_complete(go())\n\n    loop.run_until_complete(req.close())\n    loop.close()\n    req.terminate()\n    assert req._writer is None\n    assert not writer.cancel.called\n    resp.close()\n\n\ndef test_terminate_without_writer(loop) -> None:\n    req = ClientRequest(\"get\", URL(\"http://python.org\"), loop=loop)\n    assert req._writer is None\n\n    req.terminate()\n    assert req._writer is None\n\n    loop.run_until_complete(req.close())\n\n\nasync def test_custom_req_rep(loop) -> None:\n    conn = None\n\n    class CustomResponse(ClientResponse):\n        async def start(self, connection, read_until_eof=False):\n            nonlocal conn\n            conn = connection\n            self.status = 123\n            self.reason = \"Test OK\"\n            self._headers = CIMultiDictProxy(CIMultiDict())\n            self.cookies = SimpleCookie()\n            return\n\n    called = False\n\n    class CustomRequest(ClientRequest):\n        async def send(self, conn):\n            resp = self.response_class(\n                self.method,\n                self.url,\n                writer=self._writer,\n                continue100=self._continue,\n                timer=self._timer,\n                request_info=self.request_info,\n                traces=self._traces,\n                loop=self.loop,\n                session=self._session,\n            )\n            self.response = resp\n            nonlocal called\n            called = True\n            return resp\n\n    async def create_connection(req, traces, timeout):\n        assert isinstance(req, CustomRequest)\n        return mock.Mock()\n\n    connector = BaseConnector(loop=loop)\n    connector._create_connection = create_connection\n\n    session = aiohttp.ClientSession(\n        request_class=CustomRequest,\n        response_class=CustomResponse,\n        connector=connector,\n        loop=loop,\n    )\n\n    resp = await session.request(\"get\", URL(\"http://example.com/path/to\"))\n    assert isinstance(resp, CustomResponse)\n    assert called\n    resp.close()\n    await session.close()\n    conn.close()\n\n\ndef test_verify_ssl_false_with_ssl_context(loop, ssl_ctx) -> None:\n    with pytest.warns(DeprecationWarning):\n        with pytest.raises(ValueError):\n            _merge_ssl_params(\n                None, verify_ssl=False, ssl_context=ssl_ctx, fingerprint=None\n            )\n\n\ndef test_bad_fingerprint(loop) -> None:\n    with pytest.raises(ValueError):\n        Fingerprint(b\"invalid\")\n\n\ndef test_insecure_fingerprint_md5(loop) -> None:\n    with pytest.raises(ValueError):\n        Fingerprint(hashlib.md5(b\"foo\").digest())\n\n\ndef test_insecure_fingerprint_sha1(loop) -> None:\n    with pytest.raises(ValueError):\n        Fingerprint(hashlib.sha1(b\"foo\").digest())\n\n\ndef test_loose_cookies_types(loop) -> None:\n    req = ClientRequest(\"get\", URL(\"http://python.org\"), loop=loop)\n    morsel = Morsel()\n    morsel.set(key=\"string\", val=\"Another string\", coded_val=\"really\")\n\n    accepted_types = [\n        [(\"str\", BaseCookie())],\n        [(\"str\", morsel)],\n        [\n            (\"str\", \"str\"),\n        ],\n        {\"str\": BaseCookie()},\n        {\"str\": morsel},\n        {\"str\": \"str\"},\n        SimpleCookie(),\n    ]\n\n    for loose_cookies_type in accepted_types:\n        req.update_cookies(cookies=loose_cookies_type)\n\n    loop.run_until_complete(req.close())\n\n\n@pytest.mark.parametrize(\n    \"has_brotli,expected\",\n    [\n        (False, \"gzip, deflate\"),\n        (True, \"gzip, deflate, br\"),\n    ],\n)\ndef test_gen_default_accept_encoding(has_brotli, expected) -> None:\n    with mock.patch(\"aiohttp.client_reqrep.HAS_BROTLI\", has_brotli):\n        assert _gen_default_accept_encoding() == expected\n\n\n@pytest.mark.parametrize(\n    (\"netrc_contents\", \"expected_auth\"),\n    [\n        (\n            \"machine example.com login username password pass\\n\",\n            helpers.BasicAuth(\"username\", \"pass\"),\n        )\n    ],\n    indirect=(\"netrc_contents\",),\n)\n@pytest.mark.usefixtures(\"netrc_contents\")\ndef test_basicauth_from_netrc_present(\n    make_request: Any,\n    expected_auth: Optional[helpers.BasicAuth],\n):\n    \"\"\"Test appropriate Authorization header is sent when netrc is not empty.\"\"\"\n    req = make_request(\"get\", \"http://example.com\", trust_env=True)\n    assert req.headers[hdrs.AUTHORIZATION] == expected_auth.encode()\n\n\n@pytest.mark.parametrize(\n    \"netrc_contents\",\n    (\"machine example.com login username password pass\\n\",),\n    indirect=(\"netrc_contents\",),\n)\n@pytest.mark.usefixtures(\"netrc_contents\")\ndef test_basicauth_from_netrc_present_untrusted_env(\n    make_request: Any,\n):\n    \"\"\"Test no authorization header is sent via netrc if trust_env is False\"\"\"\n    req = make_request(\"get\", \"http://example.com\", trust_env=False)\n    assert hdrs.AUTHORIZATION not in req.headers\n\n\n@pytest.mark.parametrize(\n    \"netrc_contents\",\n    (\"\",),\n    indirect=(\"netrc_contents\",),\n)\n@pytest.mark.usefixtures(\"netrc_contents\")\ndef test_basicauth_from_empty_netrc(\n    make_request: Any,\n):\n    \"\"\"Test that no Authorization header is sent when netrc is empty\"\"\"\n    req = make_request(\"get\", \"http://example.com\", trust_env=True)\n    assert hdrs.AUTHORIZATION not in req.headers\n",
            "header": {
                "file": {
                    "path": "tests/test_client_request.py"
                },
                "misc_line": null
            },
            "index_line": {
                "old_commit_hash": "0f58d752",
                "new_commit_hash": "c8ce98d4",
                "mode": "100644"
            },
            "is_binary_file": false,
            "binary_line": null,
            "minus_file": {
                "path": "a/tests/test_client_request.py"
            },
            "plus_file": {
                "path": "b/tests/test_client_request.py"
            },
            "hunks": [
                {
                    "descriptor": {
                        "old_range": {
                            "start": 21,
                            "length": 6
                        },
                        "new_range": {
                            "start": 21,
                            "length": 7
                        },
                        "section": "from aiohttp.client_reqrep import ("
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "    _gen_default_accept_encoding,",
                                "type": "context"
                            },
                            {
                                "content": "    _merge_ssl_params,",
                                "type": "context"
                            },
                            {
                                "content": ")",
                                "type": "context"
                            },
                            {
                                "content": "from aiohttp.http import HttpVersion",
                                "type": "added"
                            },
                            {
                                "content": "from aiohttp.test_utils import make_mocked_coro",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [],
                    "added_entities": [
                        {
                            "file_name": "tests/test_client_request.py",
                            "type": "statement",
                            "name": "",
                            "content": "from aiohttp.http import HttpVersion",
                            "ast_type_str": "ImportFrom",
                            "start_lineno": 24,
                            "end_lineno": 24,
                            "parent": null
                        }
                    ],
                    "deleted_entities": []
                },
                {
                    "descriptor": {
                        "old_range": {
                            "start": 623,
                            "length": 18
                        },
                        "new_range": {
                            "start": 624,
                            "length": 18
                        },
                        "section": "async def test_connection_header(loop, conn) -> None:"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "    req.headers.clear()",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "    req.keep_alive.return_value = True",
                                "type": "context"
                            },
                            {
                                "content": "    req.version = (1, 1)",
                                "type": "deleted"
                            },
                            {
                                "content": "    req.version = HttpVersion(1, 1)",
                                "type": "added"
                            },
                            {
                                "content": "    req.headers.clear()",
                                "type": "context"
                            },
                            {
                                "content": "    await req.send(conn)",
                                "type": "context"
                            },
                            {
                                "content": "    assert req.headers.get(\"CONNECTION\") is None",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "    req.version = (1, 0)",
                                "type": "deleted"
                            },
                            {
                                "content": "    req.version = HttpVersion(1, 0)",
                                "type": "added"
                            },
                            {
                                "content": "    req.headers.clear()",
                                "type": "context"
                            },
                            {
                                "content": "    await req.send(conn)",
                                "type": "context"
                            },
                            {
                                "content": "    assert req.headers.get(\"CONNECTION\") == \"keep-alive\"",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "    req.keep_alive.return_value = False",
                                "type": "context"
                            },
                            {
                                "content": "    req.version = (1, 1)",
                                "type": "deleted"
                            },
                            {
                                "content": "    req.version = HttpVersion(1, 1)",
                                "type": "added"
                            },
                            {
                                "content": "    req.headers.clear()",
                                "type": "context"
                            },
                            {
                                "content": "    await req.send(conn)",
                                "type": "context"
                            },
                            {
                                "content": "    assert req.headers.get(\"CONNECTION\") == \"close\"",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [
                        {
                            "file_name": "tests/test_client_request.py",
                            "type": "function",
                            "name": "test_connection_header",
                            "content": "async def test_connection_header(loop, conn) -> None:\n    req = ClientRequest(\"get\", URL(\"http://python.org\"), loop=loop)\n    req.keep_alive = mock.Mock()\n    req.headers.clear()\n\n    req.keep_alive.return_value = True\n    req.version = (1, 1)\n    req.headers.clear()\n    await req.send(conn)\n    assert req.headers.get(\"CONNECTION\") is None\n\n    req.version = (1, 0)\n    req.headers.clear()\n    await req.send(conn)\n    assert req.headers.get(\"CONNECTION\") == \"keep-alive\"\n\n    req.keep_alive.return_value = False\n    req.version = (1, 1)\n    req.headers.clear()\n    await req.send(conn)\n    assert req.headers.get(\"CONNECTION\") == \"close\"\n\n    await req.close()",
                            "ast_type_str": "AsyncFunctionDef",
                            "start_lineno": 620,
                            "end_lineno": 642,
                            "parent": null
                        }
                    ],
                    "added_entities": [],
                    "deleted_entities": []
                },
                {
                    "descriptor": {
                        "old_range": {
                            "start": 1161,
                            "length": 6
                        },
                        "new_range": {
                            "start": 1162,
                            "length": 19
                        },
                        "section": "async def test_close(loop, buf, conn) -> None:"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "    resp.close()",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "async def test_bad_version(loop, conn) -> None:",
                                "type": "added"
                            },
                            {
                                "content": "    req = ClientRequest(",
                                "type": "added"
                            },
                            {
                                "content": "        \"GET\",",
                                "type": "added"
                            },
                            {
                                "content": "        URL(\"http://python.org\"),",
                                "type": "added"
                            },
                            {
                                "content": "        loop=loop,",
                                "type": "added"
                            },
                            {
                                "content": "        headers={\"Connection\": \"Close\"},",
                                "type": "added"
                            },
                            {
                                "content": "        version=(\"1\", \"1\\r\\nInjected-Header: not allowed\"),",
                                "type": "added"
                            },
                            {
                                "content": "    )",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "    with pytest.raises(AttributeError):",
                                "type": "added"
                            },
                            {
                                "content": "        await req.send(conn)",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "async def test_custom_response_class(loop, conn) -> None:",
                                "type": "context"
                            },
                            {
                                "content": "    class CustomResponse(ClientResponse):",
                                "type": "context"
                            },
                            {
                                "content": "        def read(self, decode=False):",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [],
                    "added_entities": [
                        {
                            "file_name": "tests/test_client_request.py",
                            "type": "function",
                            "name": "test_bad_version",
                            "content": "async def test_bad_version(loop, conn) -> None:\n    req = ClientRequest(\n        \"GET\",\n        URL(\"http://python.org\"),\n        loop=loop,\n        headers={\"Connection\": \"Close\"},\n        version=(\"1\", \"1\\r\\nInjected-Header: not allowed\"),\n    )\n\n    with pytest.raises(AttributeError):\n        await req.send(conn)",
                            "ast_type_str": "AsyncFunctionDef",
                            "start_lineno": 1165,
                            "end_lineno": 1175,
                            "parent": null
                        }
                    ],
                    "deleted_entities": []
                }
            ]
        }
    ],
    "old_commit_hash": "53476dfd4ef4fb1bb74a267714bbc39eda71b403^",
    "new_commit_hash": "53476dfd4ef4fb1bb74a267714bbc39eda71b403",
    "commit_message": "Disallow arbitrary sequence types in version (#7835) (#7836)\n\n(cherry picked from commit 1e86b777e61cf4eefc7d92fa57fa19dcc676013b)",
    "commit_date": "2023-11-13T22:36:04Z",
    "metadata": {}
}
{
    "repo_name": "aiohttp",
    "new_commit_hash": "53476dfd4ef4fb1bb74a267714bbc39eda71b403",
    "test_file_codes": [
        "import asyncio\nimport hashlib\nimport io\nimport os.path\nimport urllib.parse\nimport zlib\nfrom http.cookies import BaseCookie, Morsel, SimpleCookie\nfrom typing import Any, Callable, Dict, Optional\nfrom unittest import mock\n\nimport pytest\nfrom multidict import CIMultiDict, CIMultiDictProxy, istr\nfrom yarl import URL\n\nimport aiohttp\nfrom aiohttp import BaseConnector, hdrs, helpers, payload\nfrom aiohttp.client_reqrep import (\n    ClientRequest,\n    ClientResponse,\n    Fingerprint,\n    _gen_default_accept_encoding,\n    _merge_ssl_params,\n)\nfrom aiohttp.http import HttpVersion\nfrom aiohttp.test_utils import make_mocked_coro\n\n\nclass WriterMock(mock.AsyncMock):\n    def __await__(self) -> None:\n        return self().__await__()\n\n    def add_done_callback(self, cb: Callable[[], None]) -> None:\n        \"\"\"Dummy method.\"\"\"\n\n    def remove_done_callback(self, cb: Callable[[], None]) -> None:\n        \"\"\"Dummy method.\"\"\"\n\n\n@pytest.fixture\ndef make_request(loop):\n    request = None\n\n    def maker(method, url, *args, **kwargs):\n        nonlocal request\n        request = ClientRequest(method, URL(url), *args, loop=loop, **kwargs)\n        return request\n\n    yield maker\n    if request is not None:\n        loop.run_until_complete(request.close())\n\n\n@pytest.fixture\ndef buf():\n    return bytearray()\n\n\n@pytest.fixture\ndef protocol(loop, transport):\n    protocol = mock.Mock()\n    protocol.transport = transport\n    protocol._drain_helper.return_value = loop.create_future()\n    protocol._drain_helper.return_value.set_result(None)\n    return protocol\n\n\n@pytest.fixture\ndef transport(buf):\n    transport = mock.Mock()\n\n    def write(chunk):\n        buf.extend(chunk)\n\n    async def write_eof():\n        pass\n\n    transport.write.side_effect = write\n    transport.write_eof.side_effect = write_eof\n    transport.is_closing.return_value = False\n\n    return transport\n\n\n@pytest.fixture\ndef conn(transport, protocol):\n    return mock.Mock(transport=transport, protocol=protocol)\n\n\ndef test_method1(make_request) -> None:\n    req = make_request(\"get\", \"http://python.org/\")\n    assert req.method == \"GET\"\n\n\ndef test_method2(make_request) -> None:\n    req = make_request(\"head\", \"http://python.org/\")\n    assert req.method == \"HEAD\"\n\n\ndef test_method3(make_request) -> None:\n    req = make_request(\"HEAD\", \"http://python.org/\")\n    assert req.method == \"HEAD\"\n\n\ndef test_method_invalid(make_request) -> None:\n    with pytest.raises(ValueError, match=\"Method cannot contain non-token characters\"):\n        make_request(\"METHOD WITH\\nWHITESPACES\", \"http://python.org/\")\n\n\ndef test_version_1_0(make_request) -> None:\n    req = make_request(\"get\", \"http://python.org/\", version=\"1.0\")\n    assert req.version == (1, 0)\n\n\ndef test_version_default(make_request) -> None:\n    req = make_request(\"get\", \"http://python.org/\")\n    assert req.version == (1, 1)\n\n\ndef test_request_info(make_request) -> None:\n    req = make_request(\"get\", \"http://python.org/\")\n    assert req.request_info == aiohttp.RequestInfo(\n        URL(\"http://python.org/\"), \"GET\", req.headers\n    )\n\n\ndef test_request_info_with_fragment(make_request) -> None:\n    req = make_request(\"get\", \"http://python.org/#urlfragment\")\n    assert req.request_info == aiohttp.RequestInfo(\n        URL(\"http://python.org/\"),\n        \"GET\",\n        req.headers,\n        URL(\"http://python.org/#urlfragment\"),\n    )\n\n\ndef test_version_err(make_request) -> None:\n    with pytest.raises(ValueError):\n        make_request(\"get\", \"http://python.org/\", version=\"1.c\")\n\n\ndef test_keep_alive(make_request) -> None:\n    req = make_request(\"get\", \"http://python.org/\", version=(0, 9))\n    assert not req.keep_alive()\n\n    req = make_request(\"get\", \"http://python.org/\", version=(1, 0))\n    assert not req.keep_alive()\n\n    req = make_request(\n        \"get\",\n        \"http://python.org/\",\n        version=(1, 0),\n        headers={\"connection\": \"keep-alive\"},\n    )\n    assert req.keep_alive()\n\n    req = make_request(\"get\", \"http://python.org/\", version=(1, 1))\n    assert req.keep_alive()\n\n    req = make_request(\n        \"get\", \"http://python.org/\", version=(1, 1), headers={\"connection\": \"close\"}\n    )\n    assert not req.keep_alive()\n\n\ndef test_host_port_default_http(make_request) -> None:\n    req = make_request(\"get\", \"http://python.org/\")\n    assert req.host == \"python.org\"\n    assert req.port == 80\n    assert not req.ssl\n\n\ndef test_host_port_default_https(make_request) -> None:\n    req = make_request(\"get\", \"https://python.org/\")\n    assert req.host == \"python.org\"\n    assert req.port == 443\n    assert req.is_ssl()\n\n\ndef test_host_port_nondefault_http(make_request) -> None:\n    req = make_request(\"get\", \"http://python.org:960/\")\n    assert req.host == \"python.org\"\n    assert req.port == 960\n    assert not req.is_ssl()\n\n\ndef test_host_port_nondefault_https(make_request) -> None:\n    req = make_request(\"get\", \"https://python.org:960/\")\n    assert req.host == \"python.org\"\n    assert req.port == 960\n    assert req.is_ssl()\n\n\ndef test_host_port_default_ws(make_request) -> None:\n    req = make_request(\"get\", \"ws://python.org/\")\n    assert req.host == \"python.org\"\n    assert req.port == 80\n    assert not req.is_ssl()\n\n\ndef test_host_port_default_wss(make_request) -> None:\n    req = make_request(\"get\", \"wss://python.org/\")\n    assert req.host == \"python.org\"\n    assert req.port == 443\n    assert req.is_ssl()\n\n\ndef test_host_port_nondefault_ws(make_request) -> None:\n    req = make_request(\"get\", \"ws://python.org:960/\")\n    assert req.host == \"python.org\"\n    assert req.port == 960\n    assert not req.is_ssl()\n\n\ndef test_host_port_nondefault_wss(make_request) -> None:\n    req = make_request(\"get\", \"wss://python.org:960/\")\n    assert req.host == \"python.org\"\n    assert req.port == 960\n    assert req.is_ssl()\n\n\ndef test_host_port_none_port(make_request) -> None:\n    req = make_request(\"get\", \"unix://localhost/path\")\n    assert req.headers[\"Host\"] == \"localhost\"\n\n\ndef test_host_port_err(make_request) -> None:\n    with pytest.raises(ValueError):\n        make_request(\"get\", \"http://python.org:123e/\")\n\n\ndef test_hostname_err(make_request) -> None:\n    with pytest.raises(ValueError):\n        make_request(\"get\", \"http://:8080/\")\n\n\ndef test_host_header_host_first(make_request) -> None:\n    req = make_request(\"get\", \"http://python.org/\")\n    assert list(req.headers)[0] == \"Host\"\n\n\ndef test_host_header_host_without_port(make_request) -> None:\n    req = make_request(\"get\", \"http://python.org/\")\n    assert req.headers[\"HOST\"] == \"python.org\"\n\n\ndef test_host_header_host_with_default_port(make_request) -> None:\n    req = make_request(\"get\", \"http://python.org:80/\")\n    assert req.headers[\"HOST\"] == \"python.org\"\n\n\ndef test_host_header_host_with_nondefault_port(make_request) -> None:\n    req = make_request(\"get\", \"http://python.org:99/\")\n    assert req.headers[\"HOST\"] == \"python.org:99\"\n\n\ndef test_host_header_host_idna_encode(make_request) -> None:\n    req = make_request(\"get\", \"http://xn--9caa.com\")\n    assert req.headers[\"HOST\"] == \"xn--9caa.com\"\n\n\ndef test_host_header_host_unicode(make_request) -> None:\n    req = make_request(\"get\", \"http://éé.com\")\n    assert req.headers[\"HOST\"] == \"xn--9caa.com\"\n\n\ndef test_host_header_explicit_host(make_request) -> None:\n    req = make_request(\"get\", \"http://python.org/\", headers={\"host\": \"example.com\"})\n    assert req.headers[\"HOST\"] == \"example.com\"\n\n\ndef test_host_header_explicit_host_with_port(make_request) -> None:\n    req = make_request(\"get\", \"http://python.org/\", headers={\"host\": \"example.com:99\"})\n    assert req.headers[\"HOST\"] == \"example.com:99\"\n\n\ndef test_host_header_ipv4(make_request) -> None:\n    req = make_request(\"get\", \"http://127.0.0.2\")\n    assert req.headers[\"HOST\"] == \"127.0.0.2\"\n\n\ndef test_host_header_ipv6(make_request) -> None:\n    req = make_request(\"get\", \"http://[::2]\")\n    assert req.headers[\"HOST\"] == \"[::2]\"\n\n\ndef test_host_header_ipv4_with_port(make_request) -> None:\n    req = make_request(\"get\", \"http://127.0.0.2:99\")\n    assert req.headers[\"HOST\"] == \"127.0.0.2:99\"\n\n\ndef test_host_header_ipv6_with_port(make_request) -> None:\n    req = make_request(\"get\", \"http://[::2]:99\")\n    assert req.headers[\"HOST\"] == \"[::2]:99\"\n\n\ndef test_default_loop(loop) -> None:\n    asyncio.set_event_loop(loop)\n    req = ClientRequest(\"get\", URL(\"http://python.org/\"))\n    assert req.loop is loop\n    loop.run_until_complete(req.close())\n\n\n@pytest.mark.parametrize(\n    (\"url\", \"headers\", \"expected\"),\n    (\n        pytest.param(\"http://localhost.\", None, \"localhost\", id=\"dot only at the end\"),\n        pytest.param(\"http://python.org.\", None, \"python.org\", id=\"single dot\"),\n        pytest.param(\n            \"http://python.org.:99\", None, \"python.org:99\", id=\"single dot with port\"\n        ),\n        pytest.param(\n            \"http://python.org...:99\",\n            None,\n            \"python.org:99\",\n            id=\"multiple dots with port\",\n        ),\n        pytest.param(\n            \"http://python.org.:99\",\n            {\"host\": \"example.com.:99\"},\n            \"example.com.:99\",\n            id=\"explicit host header\",\n        ),\n        pytest.param(\"https://python.org.\", None, \"python.org\", id=\"https\"),\n        pytest.param(\"https://...\", None, \"\", id=\"only dots\"),\n        pytest.param(\n            \"http://príklad.example.org.:99\",\n            None,\n            \"xn--prklad-4va.example.org:99\",\n            id=\"single dot with port idna\",\n        ),\n    ),\n)\ndef test_host_header_fqdn(\n    make_request: Any, url: str, headers: Dict[str, str], expected: str\n) -> None:\n    req = make_request(\"get\", url, headers=headers)\n    assert req.headers[\"HOST\"] == expected\n\n\ndef test_default_headers_useragent(make_request) -> None:\n    req = make_request(\"get\", \"http://python.org/\")\n\n    assert \"SERVER\" not in req.headers\n    assert \"USER-AGENT\" in req.headers\n\n\ndef test_default_headers_useragent_custom(make_request) -> None:\n    req = make_request(\n        \"get\", \"http://python.org/\", headers={\"user-agent\": \"my custom agent\"}\n    )\n\n    assert \"USER-Agent\" in req.headers\n    assert \"my custom agent\" == req.headers[\"User-Agent\"]\n\n\ndef test_skip_default_useragent_header(make_request) -> None:\n    req = make_request(\n        \"get\", \"http://python.org/\", skip_auto_headers={istr(\"user-agent\")}\n    )\n\n    assert \"User-Agent\" not in req.headers\n\n\ndef test_headers(make_request) -> None:\n    req = make_request(\n        \"post\", \"http://python.org/\", headers={\"Content-Type\": \"text/plain\"}\n    )\n\n    assert \"CONTENT-TYPE\" in req.headers\n    assert req.headers[\"CONTENT-TYPE\"] == \"text/plain\"\n    assert req.headers[\"ACCEPT-ENCODING\"] == \"gzip, deflate, br\"\n\n\ndef test_headers_list(make_request) -> None:\n    req = make_request(\n        \"post\", \"http://python.org/\", headers=[(\"Content-Type\", \"text/plain\")]\n    )\n    assert \"CONTENT-TYPE\" in req.headers\n    assert req.headers[\"CONTENT-TYPE\"] == \"text/plain\"\n\n\ndef test_headers_default(make_request) -> None:\n    req = make_request(\n        \"get\", \"http://python.org/\", headers={\"ACCEPT-ENCODING\": \"deflate\"}\n    )\n    assert req.headers[\"ACCEPT-ENCODING\"] == \"deflate\"\n\n\ndef test_invalid_url(make_request) -> None:\n    with pytest.raises(aiohttp.InvalidURL):\n        make_request(\"get\", \"hiwpefhipowhefopw\")\n\n\ndef test_no_path(make_request) -> None:\n    req = make_request(\"get\", \"http://python.org\")\n    assert \"/\" == req.url.path\n\n\ndef test_ipv6_default_http_port(make_request) -> None:\n    req = make_request(\"get\", \"http://[2001:db8::1]/\")\n    assert req.host == \"2001:db8::1\"\n    assert req.port == 80\n    assert not req.ssl\n\n\ndef test_ipv6_default_https_port(make_request) -> None:\n    req = make_request(\"get\", \"https://[2001:db8::1]/\")\n    assert req.host == \"2001:db8::1\"\n    assert req.port == 443\n    assert req.is_ssl()\n\n\ndef test_ipv6_nondefault_http_port(make_request) -> None:\n    req = make_request(\"get\", \"http://[2001:db8::1]:960/\")\n    assert req.host == \"2001:db8::1\"\n    assert req.port == 960\n    assert not req.is_ssl()\n\n\ndef test_ipv6_nondefault_https_port(make_request) -> None:\n    req = make_request(\"get\", \"https://[2001:db8::1]:960/\")\n    assert req.host == \"2001:db8::1\"\n    assert req.port == 960\n    assert req.is_ssl()\n\n\ndef test_basic_auth(make_request) -> None:\n    req = make_request(\n        \"get\", \"http://python.org\", auth=aiohttp.BasicAuth(\"nkim\", \"1234\")\n    )\n    assert \"AUTHORIZATION\" in req.headers\n    assert \"Basic bmtpbToxMjM0\" == req.headers[\"AUTHORIZATION\"]\n\n\ndef test_basic_auth_utf8(make_request) -> None:\n    req = make_request(\n        \"get\", \"http://python.org\", auth=aiohttp.BasicAuth(\"nkim\", \"секрет\", \"utf-8\")\n    )\n    assert \"AUTHORIZATION\" in req.headers\n    assert \"Basic bmtpbTrRgdC10LrRgNC10YI=\" == req.headers[\"AUTHORIZATION\"]\n\n\ndef test_basic_auth_tuple_forbidden(make_request) -> None:\n    with pytest.raises(TypeError):\n        make_request(\"get\", \"http://python.org\", auth=(\"nkim\", \"1234\"))\n\n\ndef test_basic_auth_from_url(make_request) -> None:\n    req = make_request(\"get\", \"http://nkim:1234@python.org\")\n    assert \"AUTHORIZATION\" in req.headers\n    assert \"Basic bmtpbToxMjM0\" == req.headers[\"AUTHORIZATION\"]\n    assert \"python.org\" == req.host\n\n\ndef test_basic_auth_from_url_overridden(make_request) -> None:\n    req = make_request(\n        \"get\", \"http://garbage@python.org\", auth=aiohttp.BasicAuth(\"nkim\", \"1234\")\n    )\n    assert \"AUTHORIZATION\" in req.headers\n    assert \"Basic bmtpbToxMjM0\" == req.headers[\"AUTHORIZATION\"]\n    assert \"python.org\" == req.host\n\n\ndef test_path_is_not_double_encoded1(make_request) -> None:\n    req = make_request(\"get\", \"http://0.0.0.0/get/test case\")\n    assert req.url.raw_path == \"/get/test%20case\"\n\n\ndef test_path_is_not_double_encoded2(make_request) -> None:\n    req = make_request(\"get\", \"http://0.0.0.0/get/test%2fcase\")\n    assert req.url.raw_path == \"/get/test%2Fcase\"\n\n\ndef test_path_is_not_double_encoded3(make_request) -> None:\n    req = make_request(\"get\", \"http://0.0.0.0/get/test%20case\")\n    assert req.url.raw_path == \"/get/test%20case\"\n\n\ndef test_path_safe_chars_preserved(make_request) -> None:\n    req = make_request(\"get\", \"http://0.0.0.0/get/:=+/%2B/\")\n    assert req.url.path == \"/get/:=+/+/\"\n\n\ndef test_params_are_added_before_fragment1(make_request) -> None:\n    req = make_request(\"GET\", \"http://example.com/path#fragment\", params={\"a\": \"b\"})\n    assert str(req.url) == \"http://example.com/path?a=b\"\n\n\ndef test_params_are_added_before_fragment2(make_request) -> None:\n    req = make_request(\n        \"GET\", \"http://example.com/path?key=value#fragment\", params={\"a\": \"b\"}\n    )\n    assert str(req.url) == \"http://example.com/path?key=value&a=b\"\n\n\ndef test_path_not_contain_fragment1(make_request) -> None:\n    req = make_request(\"GET\", \"http://example.com/path#fragment\")\n    assert req.url.path == \"/path\"\n\n\ndef test_path_not_contain_fragment2(make_request) -> None:\n    req = make_request(\"GET\", \"http://example.com/path?key=value#fragment\")\n    assert str(req.url) == \"http://example.com/path?key=value\"\n\n\ndef test_cookies(make_request) -> None:\n    req = make_request(\"get\", \"http://test.com/path\", cookies={\"cookie1\": \"val1\"})\n\n    assert \"COOKIE\" in req.headers\n    assert \"cookie1=val1\" == req.headers[\"COOKIE\"]\n\n\ndef test_cookies_is_quoted_with_special_characters(make_request) -> None:\n    req = make_request(\"get\", \"http://test.com/path\", cookies={\"cookie1\": \"val/one\"})\n\n    assert \"COOKIE\" in req.headers\n    assert 'cookie1=\"val/one\"' == req.headers[\"COOKIE\"]\n\n\ndef test_cookies_merge_with_headers(make_request) -> None:\n    req = make_request(\n        \"get\",\n        \"http://test.com/path\",\n        headers={\"cookie\": \"cookie1=val1\"},\n        cookies={\"cookie2\": \"val2\"},\n    )\n\n    assert \"cookie1=val1; cookie2=val2\" == req.headers[\"COOKIE\"]\n\n\ndef test_unicode_get1(make_request) -> None:\n    req = make_request(\"get\", \"http://python.org\", params={\"foo\": \"f\\xf8\\xf8\"})\n    assert \"http://python.org/?foo=f%C3%B8%C3%B8\" == str(req.url)\n\n\ndef test_unicode_get2(make_request) -> None:\n    req = make_request(\"\", \"http://python.org\", params={\"f\\xf8\\xf8\": \"f\\xf8\\xf8\"})\n\n    assert \"http://python.org/?f%C3%B8%C3%B8=f%C3%B8%C3%B8\" == str(req.url)\n\n\ndef test_unicode_get3(make_request) -> None:\n    req = make_request(\"\", \"http://python.org\", params={\"foo\": \"foo\"})\n    assert \"http://python.org/?foo=foo\" == str(req.url)\n\n\ndef test_unicode_get4(make_request) -> None:\n    def join(*suffix):\n        return urllib.parse.urljoin(\"http://python.org/\", \"/\".join(suffix))\n\n    req = make_request(\"\", join(\"\\xf8\"), params={\"foo\": \"foo\"})\n    assert \"http://python.org/%C3%B8?foo=foo\" == str(req.url)\n\n\ndef test_query_multivalued_param(make_request) -> None:\n    for meth in ClientRequest.ALL_METHODS:\n        req = make_request(\n            meth, \"http://python.org\", params=((\"test\", \"foo\"), (\"test\", \"baz\"))\n        )\n\n        assert str(req.url) == \"http://python.org/?test=foo&test=baz\"\n\n\ndef test_query_str_param(make_request) -> None:\n    for meth in ClientRequest.ALL_METHODS:\n        req = make_request(meth, \"http://python.org\", params=\"test=foo\")\n        assert str(req.url) == \"http://python.org/?test=foo\"\n\n\ndef test_query_bytes_param_raises(make_request) -> None:\n    for meth in ClientRequest.ALL_METHODS:\n        with pytest.raises(TypeError):\n            make_request(meth, \"http://python.org\", params=b\"test=foo\")\n\n\ndef test_query_str_param_is_not_encoded(make_request) -> None:\n    for meth in ClientRequest.ALL_METHODS:\n        req = make_request(meth, \"http://python.org\", params=\"test=f+oo\")\n        assert str(req.url) == \"http://python.org/?test=f+oo\"\n\n\ndef test_params_update_path_and_url(make_request) -> None:\n    req = make_request(\n        \"get\", \"http://python.org\", params=((\"test\", \"foo\"), (\"test\", \"baz\"))\n    )\n    assert str(req.url) == \"http://python.org/?test=foo&test=baz\"\n\n\ndef test_params_empty_path_and_url(make_request) -> None:\n    req_empty = make_request(\"get\", \"http://python.org\", params={})\n    assert str(req_empty.url) == \"http://python.org\"\n    req_none = make_request(\"get\", \"http://python.org\")\n    assert str(req_none.url) == \"http://python.org\"\n\n\ndef test_gen_netloc_all(make_request) -> None:\n    req = make_request(\n        \"get\",\n        \"https://aiohttp:pwpwpw@\"\n        + \"12345678901234567890123456789\"\n        + \"012345678901234567890:8080\",\n    )\n    assert (\n        req.headers[\"HOST\"]\n        == \"12345678901234567890123456789\" + \"012345678901234567890:8080\"\n    )\n\n\ndef test_gen_netloc_no_port(make_request) -> None:\n    req = make_request(\n        \"get\",\n        \"https://aiohttp:pwpwpw@\"\n        + \"12345678901234567890123456789\"\n        + \"012345678901234567890/\",\n    )\n    assert (\n        req.headers[\"HOST\"] == \"12345678901234567890123456789\" + \"012345678901234567890\"\n    )\n\n\nasync def test_connection_header(loop, conn) -> None:\n    req = ClientRequest(\"get\", URL(\"http://python.org\"), loop=loop)\n    req.keep_alive = mock.Mock()\n    req.headers.clear()\n\n    req.keep_alive.return_value = True\n    req.version = HttpVersion(1, 1)\n    req.headers.clear()\n    await req.send(conn)\n    assert req.headers.get(\"CONNECTION\") is None\n\n    req.version = HttpVersion(1, 0)\n    req.headers.clear()\n    await req.send(conn)\n    assert req.headers.get(\"CONNECTION\") == \"keep-alive\"\n\n    req.keep_alive.return_value = False\n    req.version = HttpVersion(1, 1)\n    req.headers.clear()\n    await req.send(conn)\n    assert req.headers.get(\"CONNECTION\") == \"close\"\n\n    await req.close()\n\n\nasync def test_no_content_length(loop, conn) -> None:\n    req = ClientRequest(\"get\", URL(\"http://python.org\"), loop=loop)\n    resp = await req.send(conn)\n    assert req.headers.get(\"CONTENT-LENGTH\") is None\n    await req.close()\n    resp.close()\n\n\nasync def test_no_content_length_head(loop, conn) -> None:\n    req = ClientRequest(\"head\", URL(\"http://python.org\"), loop=loop)\n    resp = await req.send(conn)\n    assert req.headers.get(\"CONTENT-LENGTH\") is None\n    await req.close()\n    resp.close()\n\n\nasync def test_content_type_auto_header_get(loop, conn) -> None:\n    req = ClientRequest(\"get\", URL(\"http://python.org\"), loop=loop)\n    resp = await req.send(conn)\n    assert \"CONTENT-TYPE\" not in req.headers\n    resp.close()\n    await req.close()\n\n\nasync def test_content_type_auto_header_form(loop, conn) -> None:\n    req = ClientRequest(\n        \"post\", URL(\"http://python.org\"), data={\"hey\": \"you\"}, loop=loop\n    )\n    resp = await req.send(conn)\n    assert \"application/x-www-form-urlencoded\" == req.headers.get(\"CONTENT-TYPE\")\n    resp.close()\n    await req.close()\n\n\nasync def test_content_type_auto_header_bytes(loop, conn) -> None:\n    req = ClientRequest(\"post\", URL(\"http://python.org\"), data=b\"hey you\", loop=loop)\n    resp = await req.send(conn)\n    assert \"application/octet-stream\" == req.headers.get(\"CONTENT-TYPE\")\n    resp.close()\n    await req.close()\n\n\nasync def test_content_type_skip_auto_header_bytes(loop, conn) -> None:\n    req = ClientRequest(\n        \"post\",\n        URL(\"http://python.org\"),\n        data=b\"hey you\",\n        skip_auto_headers={\"Content-Type\"},\n        loop=loop,\n    )\n    resp = await req.send(conn)\n    assert \"CONTENT-TYPE\" not in req.headers\n    resp.close()\n    await req.close()\n\n\nasync def test_content_type_skip_auto_header_form(loop, conn) -> None:\n    req = ClientRequest(\n        \"post\",\n        URL(\"http://python.org\"),\n        data={\"hey\": \"you\"},\n        loop=loop,\n        skip_auto_headers={\"Content-Type\"},\n    )\n    resp = await req.send(conn)\n    assert \"CONTENT-TYPE\" not in req.headers\n    resp.close()\n    await req.close()\n\n\nasync def test_content_type_auto_header_content_length_no_skip(loop, conn) -> None:\n    with io.BytesIO(b\"hey\") as file_handle:\n        req = ClientRequest(\n            \"post\",\n            URL(\"http://python.org\"),\n            data=file_handle,\n            skip_auto_headers={\"Content-Length\"},\n            loop=loop,\n        )\n        resp = await req.send(conn)\n        assert req.headers.get(\"CONTENT-LENGTH\") == \"3\"\n        resp.close()\n        await req.close()\n\n\nasync def test_urlencoded_formdata_charset(loop, conn) -> None:\n    req = ClientRequest(\n        \"post\",\n        URL(\"http://python.org\"),\n        data=aiohttp.FormData({\"hey\": \"you\"}, charset=\"koi8-r\"),\n        loop=loop,\n    )\n    await req.send(conn)\n    assert \"application/x-www-form-urlencoded; charset=koi8-r\" == req.headers.get(\n        \"CONTENT-TYPE\"\n    )\n    await req.close()\n\n\nasync def test_post_data(loop, conn) -> None:\n    for meth in ClientRequest.POST_METHODS:\n        req = ClientRequest(\n            meth, URL(\"http://python.org/\"), data={\"life\": \"42\"}, loop=loop\n        )\n        resp = await req.send(conn)\n        assert \"/\" == req.url.path\n        assert b\"life=42\" == req.body._value\n        assert \"application/x-www-form-urlencoded\" == req.headers[\"CONTENT-TYPE\"]\n        await req.close()\n        resp.close()\n\n\nasync def test_pass_falsy_data(loop) -> None:\n    with mock.patch(\"aiohttp.client_reqrep.ClientRequest.update_body_from_data\"):\n        req = ClientRequest(\"post\", URL(\"http://python.org/\"), data={}, loop=loop)\n        req.update_body_from_data.assert_called_once_with({})\n    await req.close()\n\n\nasync def test_pass_falsy_data_file(loop, tmpdir) -> None:\n    testfile = tmpdir.join(\"tmpfile\").open(\"w+b\")\n    testfile.write(b\"data\")\n    testfile.seek(0)\n    skip = frozenset([hdrs.CONTENT_TYPE])\n    req = ClientRequest(\n        \"post\",\n        URL(\"http://python.org/\"),\n        data=testfile,\n        skip_auto_headers=skip,\n        loop=loop,\n    )\n    assert req.headers.get(\"CONTENT-LENGTH\", None) is not None\n    await req.close()\n    testfile.close()\n\n\n# Elasticsearch API requires to send request body with GET-requests\nasync def test_get_with_data(loop) -> None:\n    for meth in ClientRequest.GET_METHODS:\n        req = ClientRequest(\n            meth, URL(\"http://python.org/\"), data={\"life\": \"42\"}, loop=loop\n        )\n        assert \"/\" == req.url.path\n        assert b\"life=42\" == req.body._value\n        await req.close()\n\n\nasync def test_bytes_data(loop, conn) -> None:\n    for meth in ClientRequest.POST_METHODS:\n        req = ClientRequest(\n            meth, URL(\"http://python.org/\"), data=b\"binary data\", loop=loop\n        )\n        resp = await req.send(conn)\n        assert \"/\" == req.url.path\n        assert isinstance(req.body, payload.BytesPayload)\n        assert b\"binary data\" == req.body._value\n        assert \"application/octet-stream\" == req.headers[\"CONTENT-TYPE\"]\n        await req.close()\n        resp.close()\n\n\nasync def test_content_encoding(loop, conn) -> None:\n    req = ClientRequest(\n        \"post\", URL(\"http://python.org/\"), data=\"foo\", compress=\"deflate\", loop=loop\n    )\n    with mock.patch(\"aiohttp.client_reqrep.StreamWriter\") as m_writer:\n        m_writer.return_value.write_headers = make_mocked_coro()\n        resp = await req.send(conn)\n    assert req.headers[\"TRANSFER-ENCODING\"] == \"chunked\"\n    assert req.headers[\"CONTENT-ENCODING\"] == \"deflate\"\n    m_writer.return_value.enable_compression.assert_called_with(\"deflate\")\n    await req.close()\n    resp.close()\n\n\nasync def test_content_encoding_dont_set_headers_if_no_body(loop, conn) -> None:\n    req = ClientRequest(\n        \"post\", URL(\"http://python.org/\"), compress=\"deflate\", loop=loop\n    )\n    with mock.patch(\"aiohttp.client_reqrep.http\"):\n        resp = await req.send(conn)\n    assert \"TRANSFER-ENCODING\" not in req.headers\n    assert \"CONTENT-ENCODING\" not in req.headers\n    await req.close()\n    resp.close()\n\n\nasync def test_content_encoding_header(loop, conn) -> None:\n    req = ClientRequest(\n        \"post\",\n        URL(\"http://python.org/\"),\n        data=\"foo\",\n        headers={\"Content-Encoding\": \"deflate\"},\n        loop=loop,\n    )\n    with mock.patch(\"aiohttp.client_reqrep.StreamWriter\") as m_writer:\n        m_writer.return_value.write_headers = make_mocked_coro()\n        resp = await req.send(conn)\n\n    assert not m_writer.return_value.enable_compression.called\n    assert not m_writer.return_value.enable_chunking.called\n    await req.close()\n    resp.close()\n\n\nasync def test_compress_and_content_encoding(loop, conn) -> None:\n    with pytest.raises(ValueError):\n        ClientRequest(\n            \"post\",\n            URL(\"http://python.org/\"),\n            data=\"foo\",\n            headers={\"content-encoding\": \"deflate\"},\n            compress=\"deflate\",\n            loop=loop,\n        )\n\n\nasync def test_chunked(loop, conn) -> None:\n    req = ClientRequest(\n        \"post\",\n        URL(\"http://python.org/\"),\n        headers={\"TRANSFER-ENCODING\": \"gzip\"},\n        loop=loop,\n    )\n    resp = await req.send(conn)\n    assert \"gzip\" == req.headers[\"TRANSFER-ENCODING\"]\n    await req.close()\n    resp.close()\n\n\nasync def test_chunked2(loop, conn) -> None:\n    req = ClientRequest(\n        \"post\",\n        URL(\"http://python.org/\"),\n        headers={\"Transfer-encoding\": \"chunked\"},\n        loop=loop,\n    )\n    resp = await req.send(conn)\n    assert \"chunked\" == req.headers[\"TRANSFER-ENCODING\"]\n    await req.close()\n    resp.close()\n\n\nasync def test_chunked_explicit(loop, conn) -> None:\n    req = ClientRequest(\"post\", URL(\"http://python.org/\"), chunked=True, loop=loop)\n    with mock.patch(\"aiohttp.client_reqrep.StreamWriter\") as m_writer:\n        m_writer.return_value.write_headers = make_mocked_coro()\n        resp = await req.send(conn)\n\n    assert \"chunked\" == req.headers[\"TRANSFER-ENCODING\"]\n    m_writer.return_value.enable_chunking.assert_called_with()\n    await req.close()\n    resp.close()\n\n\nasync def test_chunked_length(loop, conn) -> None:\n    with pytest.raises(ValueError):\n        ClientRequest(\n            \"post\",\n            URL(\"http://python.org/\"),\n            headers={\"CONTENT-LENGTH\": \"1000\"},\n            chunked=True,\n            loop=loop,\n        )\n\n\nasync def test_chunked_transfer_encoding(loop, conn) -> None:\n    with pytest.raises(ValueError):\n        ClientRequest(\n            \"post\",\n            URL(\"http://python.org/\"),\n            headers={\"TRANSFER-ENCODING\": \"chunked\"},\n            chunked=True,\n            loop=loop,\n        )\n\n\nasync def test_file_upload_not_chunked(loop) -> None:\n    here = os.path.dirname(__file__)\n    fname = os.path.join(here, \"aiohttp.png\")\n    with open(fname, \"rb\") as f:\n        req = ClientRequest(\"post\", URL(\"http://python.org/\"), data=f, loop=loop)\n        assert not req.chunked\n        assert req.headers[\"CONTENT-LENGTH\"] == str(os.path.getsize(fname))\n        await req.close()\n\n\nasync def test_precompressed_data_stays_intact(loop) -> None:\n    data = zlib.compress(b\"foobar\")\n    req = ClientRequest(\n        \"post\",\n        URL(\"http://python.org/\"),\n        data=data,\n        headers={\"CONTENT-ENCODING\": \"deflate\"},\n        compress=False,\n        loop=loop,\n    )\n    assert not req.compress\n    assert not req.chunked\n    assert req.headers[\"CONTENT-ENCODING\"] == \"deflate\"\n    await req.close()\n\n\nasync def test_file_upload_not_chunked_seek(loop) -> None:\n    here = os.path.dirname(__file__)\n    fname = os.path.join(here, \"aiohttp.png\")\n    with open(fname, \"rb\") as f:\n        f.seek(100)\n        req = ClientRequest(\"post\", URL(\"http://python.org/\"), data=f, loop=loop)\n        assert req.headers[\"CONTENT-LENGTH\"] == str(os.path.getsize(fname) - 100)\n        await req.close()\n\n\nasync def test_file_upload_force_chunked(loop) -> None:\n    here = os.path.dirname(__file__)\n    fname = os.path.join(here, \"aiohttp.png\")\n    with open(fname, \"rb\") as f:\n        req = ClientRequest(\n            \"post\", URL(\"http://python.org/\"), data=f, chunked=True, loop=loop\n        )\n        assert req.chunked\n        assert \"CONTENT-LENGTH\" not in req.headers\n        await req.close()\n\n\nasync def test_expect100(loop, conn) -> None:\n    req = ClientRequest(\"get\", URL(\"http://python.org/\"), expect100=True, loop=loop)\n    resp = await req.send(conn)\n    assert \"100-continue\" == req.headers[\"EXPECT\"]\n    assert req._continue is not None\n    req.terminate()\n    resp.close()\n    await req.close()\n\n\nasync def test_expect_100_continue_header(loop, conn) -> None:\n    req = ClientRequest(\n        \"get\", URL(\"http://python.org/\"), headers={\"expect\": \"100-continue\"}, loop=loop\n    )\n    resp = await req.send(conn)\n    assert \"100-continue\" == req.headers[\"EXPECT\"]\n    assert req._continue is not None\n    req.terminate()\n    resp.close()\n    await req.close()\n\n\nasync def test_data_stream(loop, buf, conn) -> None:\n    async def gen():\n        yield b\"binary data\"\n        yield b\" result\"\n\n    req = ClientRequest(\"POST\", URL(\"http://python.org/\"), data=gen(), loop=loop)\n    assert req.chunked\n    assert req.headers[\"TRANSFER-ENCODING\"] == \"chunked\"\n\n    resp = await req.send(conn)\n    assert asyncio.isfuture(req._writer)\n    await resp.wait_for_close()\n    assert req._writer is None\n    assert (\n        buf.split(b\"\\r\\n\\r\\n\", 1)[1] == b\"b\\r\\nbinary data\\r\\n7\\r\\n result\\r\\n0\\r\\n\\r\\n\"\n    )\n    await req.close()\n\n\nasync def test_data_stream_deprecated(loop, buf, conn) -> None:\n    with pytest.warns(DeprecationWarning):\n\n        @aiohttp.streamer\n        async def gen(writer):\n            await writer.write(b\"binary data\")\n            await writer.write(b\" result\")\n\n    req = ClientRequest(\"POST\", URL(\"http://python.org/\"), data=gen(), loop=loop)\n    assert req.chunked\n    assert req.headers[\"TRANSFER-ENCODING\"] == \"chunked\"\n\n    resp = await req.send(conn)\n    assert asyncio.isfuture(req._writer)\n    await resp.wait_for_close()\n    assert req._writer is None\n    assert (\n        buf.split(b\"\\r\\n\\r\\n\", 1)[1] == b\"b\\r\\nbinary data\\r\\n7\\r\\n result\\r\\n0\\r\\n\\r\\n\"\n    )\n    await req.close()\n\n\nasync def test_data_file(loop, buf, conn) -> None:\n    with io.BufferedReader(io.BytesIO(b\"*\" * 2)) as file_handle:\n        req = ClientRequest(\n            \"POST\",\n            URL(\"http://python.org/\"),\n            data=file_handle,\n            loop=loop,\n        )\n        assert req.chunked\n        assert isinstance(req.body, payload.BufferedReaderPayload)\n        assert req.headers[\"TRANSFER-ENCODING\"] == \"chunked\"\n\n        resp = await req.send(conn)\n        assert asyncio.isfuture(req._writer)\n        await resp.wait_for_close()\n\n        assert req._writer is None\n        assert buf.split(b\"\\r\\n\\r\\n\", 1)[1] == b\"2\\r\\n\" + b\"*\" * 2 + b\"\\r\\n0\\r\\n\\r\\n\"\n        await req.close()\n\n\nasync def test_data_stream_exc(loop, conn) -> None:\n    fut = loop.create_future()\n\n    async def gen():\n        yield b\"binary data\"\n        await fut\n\n    req = ClientRequest(\"POST\", URL(\"http://python.org/\"), data=gen(), loop=loop)\n    assert req.chunked\n    assert req.headers[\"TRANSFER-ENCODING\"] == \"chunked\"\n\n    async def throw_exc():\n        await asyncio.sleep(0.01)\n        fut.set_exception(ValueError)\n\n    loop.create_task(throw_exc())\n\n    await req.send(conn)\n    await req._writer\n    # assert conn.close.called\n    assert conn.protocol.set_exception.called\n    await req.close()\n\n\nasync def test_data_stream_exc_chain(loop, conn) -> None:\n    fut = loop.create_future()\n\n    async def gen():\n        await fut\n        return\n        yield\n\n    req = ClientRequest(\"POST\", URL(\"http://python.org/\"), data=gen(), loop=loop)\n\n    inner_exc = ValueError()\n\n    async def throw_exc():\n        await asyncio.sleep(0.01)\n        fut.set_exception(inner_exc)\n\n    loop.create_task(throw_exc())\n\n    await req.send(conn)\n    await req._writer\n    # assert connection.close.called\n    assert conn.protocol.set_exception.called\n    outer_exc = conn.protocol.set_exception.call_args[0][0]\n    assert isinstance(outer_exc, ValueError)\n    assert inner_exc is outer_exc\n    assert inner_exc is outer_exc\n    await req.close()\n\n\nasync def test_data_stream_continue(loop, buf, conn) -> None:\n    async def gen():\n        yield b\"binary data\"\n        yield b\" result\"\n\n    req = ClientRequest(\n        \"POST\", URL(\"http://python.org/\"), data=gen(), expect100=True, loop=loop\n    )\n    assert req.chunked\n\n    async def coro():\n        await asyncio.sleep(0.0001)\n        req._continue.set_result(1)\n\n    loop.create_task(coro())\n\n    resp = await req.send(conn)\n    await req._writer\n    assert (\n        buf.split(b\"\\r\\n\\r\\n\", 1)[1] == b\"b\\r\\nbinary data\\r\\n7\\r\\n result\\r\\n0\\r\\n\\r\\n\"\n    )\n    await req.close()\n    resp.close()\n\n\nasync def test_data_continue(loop, buf, conn) -> None:\n    req = ClientRequest(\n        \"POST\", URL(\"http://python.org/\"), data=b\"data\", expect100=True, loop=loop\n    )\n\n    async def coro():\n        await asyncio.sleep(0.0001)\n        req._continue.set_result(1)\n\n    loop.create_task(coro())\n\n    resp = await req.send(conn)\n\n    await req._writer\n    assert buf.split(b\"\\r\\n\\r\\n\", 1)[1] == b\"data\"\n    await req.close()\n    resp.close()\n\n\nasync def test_close(loop, buf, conn) -> None:\n    async def gen():\n        await asyncio.sleep(0.00001)\n        yield b\"result\"\n\n    req = ClientRequest(\"POST\", URL(\"http://python.org/\"), data=gen(), loop=loop)\n    resp = await req.send(conn)\n    await req.close()\n    assert buf.split(b\"\\r\\n\\r\\n\", 1)[1] == b\"6\\r\\nresult\\r\\n0\\r\\n\\r\\n\"\n    await req.close()\n    resp.close()\n\n\nasync def test_bad_version(loop, conn) -> None:\n    req = ClientRequest(\n        \"GET\",\n        URL(\"http://python.org\"),\n        loop=loop,\n        headers={\"Connection\": \"Close\"},\n        version=(\"1\", \"1\\r\\nInjected-Header: not allowed\"),\n    )\n\n    with pytest.raises(AttributeError):\n        await req.send(conn)\n\n\nasync def test_custom_response_class(loop, conn) -> None:\n    class CustomResponse(ClientResponse):\n        def read(self, decode=False):\n            return \"customized!\"\n\n    req = ClientRequest(\n        \"GET\", URL(\"http://python.org/\"), response_class=CustomResponse, loop=loop\n    )\n    resp = await req.send(conn)\n    assert \"customized!\" == resp.read()\n    await req.close()\n    resp.close()\n\n\nasync def test_oserror_on_write_bytes(loop, conn) -> None:\n    req = ClientRequest(\"POST\", URL(\"http://python.org/\"), loop=loop)\n\n    writer = WriterMock()\n    writer.write.side_effect = OSError\n\n    await req.write_bytes(writer, conn)\n\n    assert conn.protocol.set_exception.called\n    exc = conn.protocol.set_exception.call_args[0][0]\n    assert isinstance(exc, aiohttp.ClientOSError)\n\n    await req.close()\n\n\nasync def test_terminate(loop, conn) -> None:\n    req = ClientRequest(\"get\", URL(\"http://python.org\"), loop=loop)\n    resp = await req.send(conn)\n    assert req._writer is not None\n    writer = req._writer = WriterMock()\n    writer.cancel = mock.Mock()\n\n    req.terminate()\n    assert req._writer is None\n    writer.cancel.assert_called_with()\n    resp.close()\n\n    await req.close()\n\n\ndef test_terminate_with_closed_loop(loop, conn) -> None:\n    req = resp = writer = None\n\n    async def go():\n        nonlocal req, resp, writer\n        req = ClientRequest(\"get\", URL(\"http://python.org\"))\n        resp = await req.send(conn)\n        assert req._writer is not None\n        writer = req._writer = WriterMock()\n\n        await asyncio.sleep(0.05)\n\n    loop.run_until_complete(go())\n\n    loop.run_until_complete(req.close())\n    loop.close()\n    req.terminate()\n    assert req._writer is None\n    assert not writer.cancel.called\n    resp.close()\n\n\ndef test_terminate_without_writer(loop) -> None:\n    req = ClientRequest(\"get\", URL(\"http://python.org\"), loop=loop)\n    assert req._writer is None\n\n    req.terminate()\n    assert req._writer is None\n\n    loop.run_until_complete(req.close())\n\n\nasync def test_custom_req_rep(loop) -> None:\n    conn = None\n\n    class CustomResponse(ClientResponse):\n        async def start(self, connection, read_until_eof=False):\n            nonlocal conn\n            conn = connection\n            self.status = 123\n            self.reason = \"Test OK\"\n            self._headers = CIMultiDictProxy(CIMultiDict())\n            self.cookies = SimpleCookie()\n            return\n\n    called = False\n\n    class CustomRequest(ClientRequest):\n        async def send(self, conn):\n            resp = self.response_class(\n                self.method,\n                self.url,\n                writer=self._writer,\n                continue100=self._continue,\n                timer=self._timer,\n                request_info=self.request_info,\n                traces=self._traces,\n                loop=self.loop,\n                session=self._session,\n            )\n            self.response = resp\n            nonlocal called\n            called = True\n            return resp\n\n    async def create_connection(req, traces, timeout):\n        assert isinstance(req, CustomRequest)\n        return mock.Mock()\n\n    connector = BaseConnector(loop=loop)\n    connector._create_connection = create_connection\n\n    session = aiohttp.ClientSession(\n        request_class=CustomRequest,\n        response_class=CustomResponse,\n        connector=connector,\n        loop=loop,\n    )\n\n    resp = await session.request(\"get\", URL(\"http://example.com/path/to\"))\n    assert isinstance(resp, CustomResponse)\n    assert called\n    resp.close()\n    await session.close()\n    conn.close()\n\n\ndef test_verify_ssl_false_with_ssl_context(loop, ssl_ctx) -> None:\n    with pytest.warns(DeprecationWarning):\n        with pytest.raises(ValueError):\n            _merge_ssl_params(\n                None, verify_ssl=False, ssl_context=ssl_ctx, fingerprint=None\n            )\n\n\ndef test_bad_fingerprint(loop) -> None:\n    with pytest.raises(ValueError):\n        Fingerprint(b\"invalid\")\n\n\ndef test_insecure_fingerprint_md5(loop) -> None:\n    with pytest.raises(ValueError):\n        Fingerprint(hashlib.md5(b\"foo\").digest())\n\n\ndef test_insecure_fingerprint_sha1(loop) -> None:\n    with pytest.raises(ValueError):\n        Fingerprint(hashlib.sha1(b\"foo\").digest())\n\n\ndef test_loose_cookies_types(loop) -> None:\n    req = ClientRequest(\"get\", URL(\"http://python.org\"), loop=loop)\n    morsel = Morsel()\n    morsel.set(key=\"string\", val=\"Another string\", coded_val=\"really\")\n\n    accepted_types = [\n        [(\"str\", BaseCookie())],\n        [(\"str\", morsel)],\n        [\n            (\"str\", \"str\"),\n        ],\n        {\"str\": BaseCookie()},\n        {\"str\": morsel},\n        {\"str\": \"str\"},\n        SimpleCookie(),\n    ]\n\n    for loose_cookies_type in accepted_types:\n        req.update_cookies(cookies=loose_cookies_type)\n\n    loop.run_until_complete(req.close())\n\n\n@pytest.mark.parametrize(\n    \"has_brotli,expected\",\n    [\n        (False, \"gzip, deflate\"),\n        (True, \"gzip, deflate, br\"),\n    ],\n)\ndef test_gen_default_accept_encoding(has_brotli, expected) -> None:\n    with mock.patch(\"aiohttp.client_reqrep.HAS_BROTLI\", has_brotli):\n        assert _gen_default_accept_encoding() == expected\n\n\n@pytest.mark.parametrize(\n    (\"netrc_contents\", \"expected_auth\"),\n    [\n        (\n            \"machine example.com login username password pass\\n\",\n            helpers.BasicAuth(\"username\", \"pass\"),\n        )\n    ],\n    indirect=(\"netrc_contents\",),\n)\n@pytest.mark.usefixtures(\"netrc_contents\")\ndef test_basicauth_from_netrc_present(\n    make_request: Any,\n    expected_auth: Optional[helpers.BasicAuth],\n):\n    \"\"\"Test appropriate Authorization header is sent when netrc is not empty.\"\"\"\n    req = make_request(\"get\", \"http://example.com\", trust_env=True)\n    assert req.headers[hdrs.AUTHORIZATION] == expected_auth.encode()\n\n\n@pytest.mark.parametrize(\n    \"netrc_contents\",\n    (\"machine example.com login username password pass\\n\",),\n    indirect=(\"netrc_contents\",),\n)\n@pytest.mark.usefixtures(\"netrc_contents\")\ndef test_basicauth_from_netrc_present_untrusted_env(\n    make_request: Any,\n):\n    \"\"\"Test no authorization header is sent via netrc if trust_env is False\"\"\"\n    req = make_request(\"get\", \"http://example.com\", trust_env=False)\n    assert hdrs.AUTHORIZATION not in req.headers\n\n\n@pytest.mark.parametrize(\n    \"netrc_contents\",\n    (\"\",),\n    indirect=(\"netrc_contents\",),\n)\n@pytest.mark.usefixtures(\"netrc_contents\")\ndef test_basicauth_from_empty_netrc(\n    make_request: Any,\n):\n    \"\"\"Test that no Authorization header is sent when netrc is empty\"\"\"\n    req = make_request(\"get\", \"http://example.com\", trust_env=True)\n    assert hdrs.AUTHORIZATION not in req.headers\n",
        "import asyncio\nimport os\nimport socket\nimport ssl\nimport sys\nfrom hashlib import md5, sha256\nfrom pathlib import Path\nfrom tempfile import TemporaryDirectory\nfrom uuid import uuid4\n\nimport pytest\n\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 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"
    ],
    "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_53476dfd4ef4fb1bb74a267714bbc39eda71b403/requirements/cython.txt\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_53476dfd4ef4fb1bb74a267714bbc39eda71b403/tools/gen.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_53476dfd4ef4fb1bb74a267714bbc39eda71b403/aiohttp/hdrs.py\n./tools/gen.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_53476dfd4ef4fb1bb74a267714bbc39eda71b403/aiohttp/_helpers.pyx\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_53476dfd4ef4fb1bb74a267714bbc39eda71b403/aiohttp/_http_parser.pyx\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_53476dfd4ef4fb1bb74a267714bbc39eda71b403/aiohttp/_http_writer.pyx\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_53476dfd4ef4fb1bb74a267714bbc39eda71b403/aiohttp/_websocket.pyx\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_53476dfd4ef4fb1bb74a267714bbc39eda71b403/aiohttp/_helpers.pyi\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_53476dfd4ef4fb1bb74a267714bbc39eda71b403/aiohttp/_cparser.pxd\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_53476dfd4ef4fb1bb74a267714bbc39eda71b403/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 install\n\n> llhttp@9.1.3 prepare\n> npm run clean && npm run build-ts\n\n\n> llhttp@9.1.3 clean\n> rm -rf lib && rm -rf test/tmp\n\n\n> llhttp@9.1.3 build-ts\n> tsc\n\n\nadded 157 packages, and audited 158 packages in 4s\n\n23 packages are looking for funding\n  run `npm fund` for details\n\n5 vulnerabilities (4 moderate, 1 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_53476dfd4ef4fb1bb74a267714bbc39eda71b403/vendor/llhttp'\nnpx ts-node bin/generate.ts\nmake[1]: Leaving directory '/home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_53476dfd4ef4fb1bb74a267714bbc39eda71b403/vendor/llhttp'\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_53476dfd4ef4fb1bb74a267714bbc39eda71b403/aiohttp/__init__.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_53476dfd4ef4fb1bb74a267714bbc39eda71b403/aiohttp/abc.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_53476dfd4ef4fb1bb74a267714bbc39eda71b403/aiohttp/base_protocol.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_53476dfd4ef4fb1bb74a267714bbc39eda71b403/aiohttp/client.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_53476dfd4ef4fb1bb74a267714bbc39eda71b403/aiohttp/client_exceptions.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_53476dfd4ef4fb1bb74a267714bbc39eda71b403/aiohttp/client_proto.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_53476dfd4ef4fb1bb74a267714bbc39eda71b403/aiohttp/client_reqrep.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_53476dfd4ef4fb1bb74a267714bbc39eda71b403/aiohttp/client_ws.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_53476dfd4ef4fb1bb74a267714bbc39eda71b403/aiohttp/compression_utils.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_53476dfd4ef4fb1bb74a267714bbc39eda71b403/aiohttp/connector.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_53476dfd4ef4fb1bb74a267714bbc39eda71b403/aiohttp/cookiejar.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_53476dfd4ef4fb1bb74a267714bbc39eda71b403/aiohttp/formdata.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_53476dfd4ef4fb1bb74a267714bbc39eda71b403/aiohttp/helpers.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_53476dfd4ef4fb1bb74a267714bbc39eda71b403/aiohttp/http.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_53476dfd4ef4fb1bb74a267714bbc39eda71b403/aiohttp/http_exceptions.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_53476dfd4ef4fb1bb74a267714bbc39eda71b403/aiohttp/http_parser.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_53476dfd4ef4fb1bb74a267714bbc39eda71b403/aiohttp/http_websocket.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_53476dfd4ef4fb1bb74a267714bbc39eda71b403/aiohttp/http_writer.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_53476dfd4ef4fb1bb74a267714bbc39eda71b403/aiohttp/locks.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_53476dfd4ef4fb1bb74a267714bbc39eda71b403/aiohttp/log.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_53476dfd4ef4fb1bb74a267714bbc39eda71b403/aiohttp/multipart.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_53476dfd4ef4fb1bb74a267714bbc39eda71b403/aiohttp/payload.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_53476dfd4ef4fb1bb74a267714bbc39eda71b403/aiohttp/payload_streamer.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_53476dfd4ef4fb1bb74a267714bbc39eda71b403/aiohttp/pytest_plugin.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_53476dfd4ef4fb1bb74a267714bbc39eda71b403/aiohttp/resolver.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_53476dfd4ef4fb1bb74a267714bbc39eda71b403/aiohttp/streams.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_53476dfd4ef4fb1bb74a267714bbc39eda71b403/aiohttp/tcp_helpers.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_53476dfd4ef4fb1bb74a267714bbc39eda71b403/aiohttp/test_utils.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_53476dfd4ef4fb1bb74a267714bbc39eda71b403/aiohttp/tracing.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_53476dfd4ef4fb1bb74a267714bbc39eda71b403/aiohttp/typedefs.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_53476dfd4ef4fb1bb74a267714bbc39eda71b403/aiohttp/web.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_53476dfd4ef4fb1bb74a267714bbc39eda71b403/aiohttp/web_app.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_53476dfd4ef4fb1bb74a267714bbc39eda71b403/aiohttp/web_exceptions.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_53476dfd4ef4fb1bb74a267714bbc39eda71b403/aiohttp/web_fileresponse.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_53476dfd4ef4fb1bb74a267714bbc39eda71b403/aiohttp/web_log.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_53476dfd4ef4fb1bb74a267714bbc39eda71b403/aiohttp/web_middlewares.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_53476dfd4ef4fb1bb74a267714bbc39eda71b403/aiohttp/web_protocol.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_53476dfd4ef4fb1bb74a267714bbc39eda71b403/aiohttp/web_request.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_53476dfd4ef4fb1bb74a267714bbc39eda71b403/aiohttp/web_response.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_53476dfd4ef4fb1bb74a267714bbc39eda71b403/aiohttp/web_routedef.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_53476dfd4ef4fb1bb74a267714bbc39eda71b403/aiohttp/web_runner.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_53476dfd4ef4fb1bb74a267714bbc39eda71b403/aiohttp/web_server.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_53476dfd4ef4fb1bb74a267714bbc39eda71b403/aiohttp/web_urldispatcher.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_53476dfd4ef4fb1bb74a267714bbc39eda71b403/aiohttp/web_ws.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_53476dfd4ef4fb1bb74a267714bbc39eda71b403/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 41ms\nPrepared 1 package in 0.29ms\nInstalled 1 package in 15ms\n + pip==24.3.1\nResolved 3 packages in 7ms\nInstalled 3 packages in 12ms\n + cython==3.0.5\n + multidict==6.0.4\n + typing-extensions==4.7.1\nResolved 95 packages in 116ms\nUninstalled 1 package in 7ms\nInstalled 93 packages in 175ms\n + aiodns==3.1.1\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.5.0\n + async-timeout==4.0.3\n + attrs==23.1.0\n + babel==2.12.1\n + blockdiag==3.0.0\n + brotli==1.1.0\n + build==0.10.0\n + certifi==2023.7.22\n + cffi==1.15.1\n + cfgv==3.3.1\n + charset-normalizer==3.2.0\n + cherry-picker==2.2.0\n + click==8.1.6\n + coverage==7.3.2\n + cryptography==41.0.3\n + distlib==0.3.7\n + docutils==0.20.1\n + exceptiongroup==1.1.2\n + filelock==3.12.2\n + frozenlist==1.4.0\n + funcparserlib==1.0.1\n + gidgethub==5.3.0\n + gunicorn==21.2.0\n + identify==2.5.26\n + idna==3.4\n + imagesize==1.4.1\n + importlib-metadata==6.8.0\n + importlib-resources==6.1.0\n + incremental==22.10.0\n + iniconfig==2.0.0\n + jinja2==3.1.2\n + markupsafe==2.1.3\n + mypy==1.7.0\n + mypy-extensions==1.0.0\n + nodeenv==1.8.0\n + packaging==23.1\n + pillow==9.5.0\n - pip==24.3.1\n + pip==23.2.1\n + pip-tools==7.3.0\n + platformdirs==3.10.0\n + pluggy==1.2.0\n + pre-commit==3.5.0\n + proxy-py==2.4.3\n + pycares==4.3.0\n + pycparser==2.21\n + pydantic==2.2.0\n + pydantic-core==2.6.0\n + pygments==2.15.1\n + pyjwt==2.8.0\n + pyproject-hooks==1.0.0\n + pytest==7.4.3\n + pytest-cov==4.1.0\n + pytest-mock==3.12.0\n + python-dateutil==2.8.2\n + python-on-whales==0.67.0\n + pyyaml==6.0.1\n + re-assert==1.1.0\n + regex==2023.6.3\n + requests==2.31.0\n + setuptools==68.0.0\n + setuptools-git==1.2\n + six==1.16.0\n + slotscheck==0.17.1\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 + time-machine==2.13.0\n + tomli==2.0.1\n + towncrier==23.11.0\n + tqdm==4.65.0\n + trustme==1.1.0\n + typer==0.9.0\n + uritemplate==4.1.1\n + urllib3==2.0.4\n + uvloop==0.19.0\n + virtualenv==20.24.2\n + wait-for-it==2.2.2\n + webcolors==1.13\n + wheel==0.41.0\n + yarl==1.9.2\n + zipp==3.17.0\nResolved 8 packages in 1.20s\nPrepared 1 package in 15.54s\nInstalled 1 package in 1ms\n + aiohttp==3.9.0b1 (from file:///home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_53476dfd4ef4fb1bb74a267714bbc39eda71b403)\nResolved 24 packages in 13ms\nInstalled 5 packages in 7ms\n + async-generator==1.10\n + brotlipy==0.7.0\n + chardet==5.2.0\n + multdict==0.0.5\n + pytest-asyncio==0.23.8\n",
    "new_commit_res_code": 1,
    "new_commit_res_stdout": "============================= test session starts ==============================\nplatform linux -- Python 3.9.21, pytest-7.4.3, pluggy-1.2.0 -- /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_53476dfd4ef4fb1bb74a267714bbc39eda71b403/.venv/bin/python\ncachedir: .pytest_cache\nrootdir: /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_53476dfd4ef4fb1bb74a267714bbc39eda71b403\nconfigfile: setup.cfg\nplugins: time-machine-2.13.0, mock-3.12.0, asyncio-0.23.8, cov-4.1.0\nasyncio: mode=strict\ncollecting ... collected 137 items\n\nr2e_tests/test_1.py::test_method1[pyloop] PASSED                         [  0%]\nr2e_tests/test_1.py::test_method2[pyloop] PASSED                         [  1%]\nr2e_tests/test_1.py::test_method3[pyloop] PASSED                         [  2%]\nr2e_tests/test_1.py::test_method_invalid[pyloop] PASSED                  [  2%]\nr2e_tests/test_1.py::test_version_1_0[pyloop] PASSED                     [  3%]\nr2e_tests/test_1.py::test_version_default[pyloop] PASSED                 [  4%]\nr2e_tests/test_1.py::test_request_info[pyloop] PASSED                    [  5%]\nr2e_tests/test_1.py::test_request_info_with_fragment[pyloop] PASSED      [  5%]\nr2e_tests/test_1.py::test_version_err[pyloop] PASSED                     [  6%]\nr2e_tests/test_1.py::test_keep_alive[pyloop] PASSED                      [  7%]\nr2e_tests/test_1.py::test_host_port_default_http[pyloop] PASSED          [  8%]\nr2e_tests/test_1.py::test_host_port_default_https[pyloop] PASSED         [  8%]\nr2e_tests/test_1.py::test_host_port_nondefault_http[pyloop] PASSED       [  9%]\nr2e_tests/test_1.py::test_host_port_nondefault_https[pyloop] PASSED      [ 10%]\nr2e_tests/test_1.py::test_host_port_default_ws[pyloop] PASSED            [ 10%]\nr2e_tests/test_1.py::test_host_port_default_wss[pyloop] PASSED           [ 11%]\nr2e_tests/test_1.py::test_host_port_nondefault_ws[pyloop] PASSED         [ 12%]\nr2e_tests/test_1.py::test_host_port_nondefault_wss[pyloop] PASSED        [ 13%]\nr2e_tests/test_1.py::test_host_port_none_port[pyloop] PASSED             [ 13%]\nr2e_tests/test_1.py::test_host_port_err[pyloop] PASSED                   [ 14%]\nr2e_tests/test_1.py::test_hostname_err[pyloop] PASSED                    [ 15%]\nr2e_tests/test_1.py::test_host_header_host_first[pyloop] PASSED          [ 16%]\nr2e_tests/test_1.py::test_host_header_host_without_port[pyloop] PASSED   [ 16%]\nr2e_tests/test_1.py::test_host_header_host_with_default_port[pyloop] PASSED [ 17%]\nr2e_tests/test_1.py::test_host_header_host_with_nondefault_port[pyloop] PASSED [ 18%]\nr2e_tests/test_1.py::test_host_header_host_idna_encode[pyloop] PASSED    [ 18%]\nr2e_tests/test_1.py::test_host_header_host_unicode[pyloop] PASSED        [ 19%]\nr2e_tests/test_1.py::test_host_header_explicit_host[pyloop] PASSED       [ 20%]\nr2e_tests/test_1.py::test_host_header_explicit_host_with_port[pyloop] PASSED [ 21%]\nr2e_tests/test_1.py::test_host_header_ipv4[pyloop] PASSED                [ 21%]\nr2e_tests/test_1.py::test_host_header_ipv6[pyloop] PASSED                [ 22%]\nr2e_tests/test_1.py::test_host_header_ipv4_with_port[pyloop] PASSED      [ 23%]\nr2e_tests/test_1.py::test_host_header_ipv6_with_port[pyloop] PASSED      [ 24%]\nr2e_tests/test_1.py::test_default_loop[pyloop] PASSED                    [ 24%]\nr2e_tests/test_1.py::test_host_header_fqdn[pyloop-dot only at the end] PASSED [ 25%]\nr2e_tests/test_1.py::test_host_header_fqdn[pyloop-single dot] PASSED     [ 26%]\nr2e_tests/test_1.py::test_host_header_fqdn[pyloop-single dot with port] PASSED [ 27%]\nr2e_tests/test_1.py::test_host_header_fqdn[pyloop-multiple dots with port] PASSED [ 27%]\nr2e_tests/test_1.py::test_host_header_fqdn[pyloop-explicit host header] PASSED [ 28%]\nr2e_tests/test_1.py::test_host_header_fqdn[pyloop-https] PASSED          [ 29%]\nr2e_tests/test_1.py::test_host_header_fqdn[pyloop-only dots] PASSED      [ 29%]\nr2e_tests/test_1.py::test_host_header_fqdn[pyloop-single dot with port idna] PASSED [ 30%]\nr2e_tests/test_1.py::test_default_headers_useragent[pyloop] PASSED       [ 31%]\nr2e_tests/test_1.py::test_default_headers_useragent_custom[pyloop] PASSED [ 32%]\nr2e_tests/test_1.py::test_skip_default_useragent_header[pyloop] PASSED   [ 32%]\nr2e_tests/test_1.py::test_headers[pyloop] PASSED                         [ 33%]\nr2e_tests/test_1.py::test_headers_list[pyloop] PASSED                    [ 34%]\nr2e_tests/test_1.py::test_headers_default[pyloop] PASSED                 [ 35%]\nr2e_tests/test_1.py::test_invalid_url[pyloop] PASSED                     [ 35%]\nr2e_tests/test_1.py::test_no_path[pyloop] PASSED                         [ 36%]\nr2e_tests/test_1.py::test_ipv6_default_http_port[pyloop] PASSED          [ 37%]\nr2e_tests/test_1.py::test_ipv6_default_https_port[pyloop] PASSED         [ 37%]\nr2e_tests/test_1.py::test_ipv6_nondefault_http_port[pyloop] PASSED       [ 38%]\nr2e_tests/test_1.py::test_ipv6_nondefault_https_port[pyloop] PASSED      [ 39%]\nr2e_tests/test_1.py::test_basic_auth[pyloop] PASSED                      [ 40%]\nr2e_tests/test_1.py::test_basic_auth_utf8[pyloop] PASSED                 [ 40%]\nr2e_tests/test_1.py::test_basic_auth_tuple_forbidden[pyloop] PASSED      [ 41%]\nr2e_tests/test_1.py::test_basic_auth_from_url[pyloop] PASSED             [ 42%]\nr2e_tests/test_1.py::test_basic_auth_from_url_overridden[pyloop] PASSED  [ 43%]\nr2e_tests/test_1.py::test_path_is_not_double_encoded1[pyloop] PASSED     [ 43%]\nr2e_tests/test_1.py::test_path_is_not_double_encoded2[pyloop] PASSED     [ 44%]\nr2e_tests/test_1.py::test_path_is_not_double_encoded3[pyloop] PASSED     [ 45%]\nr2e_tests/test_1.py::test_path_safe_chars_preserved[pyloop] PASSED       [ 45%]\nr2e_tests/test_1.py::test_params_are_added_before_fragment1[pyloop] PASSED [ 46%]\nr2e_tests/test_1.py::test_params_are_added_before_fragment2[pyloop] PASSED [ 47%]\nr2e_tests/test_1.py::test_path_not_contain_fragment1[pyloop] PASSED      [ 48%]\nr2e_tests/test_1.py::test_path_not_contain_fragment2[pyloop] PASSED      [ 48%]\nr2e_tests/test_1.py::test_cookies[pyloop] PASSED                         [ 49%]\nr2e_tests/test_1.py::test_cookies_is_quoted_with_special_characters[pyloop] PASSED [ 50%]\nr2e_tests/test_1.py::test_cookies_merge_with_headers[pyloop] PASSED      [ 51%]\nr2e_tests/test_1.py::test_unicode_get1[pyloop] PASSED                    [ 51%]\nr2e_tests/test_1.py::test_unicode_get2[pyloop] PASSED                    [ 52%]\nr2e_tests/test_1.py::test_unicode_get3[pyloop] PASSED                    [ 53%]\nr2e_tests/test_1.py::test_unicode_get4[pyloop] PASSED                    [ 54%]\nr2e_tests/test_1.py::test_query_multivalued_param[pyloop] PASSED         [ 54%]\nr2e_tests/test_1.py::test_query_str_param[pyloop] PASSED                 [ 55%]\nr2e_tests/test_1.py::test_query_bytes_param_raises[pyloop] PASSED        [ 56%]\nr2e_tests/test_1.py::test_query_str_param_is_not_encoded[pyloop] PASSED  [ 56%]\nr2e_tests/test_1.py::test_params_update_path_and_url[pyloop] PASSED      [ 57%]\nr2e_tests/test_1.py::test_params_empty_path_and_url[pyloop] PASSED       [ 58%]\nr2e_tests/test_1.py::test_gen_netloc_all[pyloop] PASSED                  [ 59%]\nr2e_tests/test_1.py::test_gen_netloc_no_port[pyloop] PASSED              [ 59%]\nr2e_tests/test_1.py::test_connection_header[pyloop] PASSED               [ 60%]\nr2e_tests/test_1.py::test_no_content_length[pyloop] PASSED               [ 61%]\nr2e_tests/test_1.py::test_no_content_length_head[pyloop] PASSED          [ 62%]\nr2e_tests/test_1.py::test_content_type_auto_header_get[pyloop] PASSED    [ 62%]\nr2e_tests/test_1.py::test_content_type_auto_header_form[pyloop] PASSED   [ 63%]\nr2e_tests/test_1.py::test_content_type_auto_header_bytes[pyloop] PASSED  [ 64%]\nr2e_tests/test_1.py::test_content_type_skip_auto_header_bytes[pyloop] PASSED [ 64%]\nr2e_tests/test_1.py::test_content_type_skip_auto_header_form[pyloop] PASSED [ 65%]\nr2e_tests/test_1.py::test_content_type_auto_header_content_length_no_skip[pyloop] PASSED [ 66%]\nr2e_tests/test_1.py::test_urlencoded_formdata_charset[pyloop] PASSED     [ 67%]\nr2e_tests/test_1.py::test_post_data[pyloop] PASSED                       [ 67%]\nr2e_tests/test_1.py::test_pass_falsy_data[pyloop] PASSED                 [ 68%]\nr2e_tests/test_1.py::test_pass_falsy_data_file[pyloop] PASSED            [ 69%]\nr2e_tests/test_1.py::test_get_with_data[pyloop] PASSED                   [ 70%]\nr2e_tests/test_1.py::test_bytes_data[pyloop] PASSED                      [ 70%]\nr2e_tests/test_1.py::test_content_encoding[pyloop] PASSED                [ 71%]\nr2e_tests/test_1.py::test_content_encoding_dont_set_headers_if_no_body[pyloop] PASSED [ 72%]\nr2e_tests/test_1.py::test_content_encoding_header[pyloop] PASSED         [ 72%]\nr2e_tests/test_1.py::test_compress_and_content_encoding[pyloop] PASSED   [ 73%]\nr2e_tests/test_1.py::test_chunked[pyloop] PASSED                         [ 74%]\nr2e_tests/test_1.py::test_chunked2[pyloop] PASSED                        [ 75%]\nr2e_tests/test_1.py::test_chunked_explicit[pyloop] PASSED                [ 75%]\nr2e_tests/test_1.py::test_chunked_length[pyloop] PASSED                  [ 76%]\nr2e_tests/test_1.py::test_chunked_transfer_encoding[pyloop] PASSED       [ 77%]\nr2e_tests/test_1.py::test_file_upload_not_chunked[pyloop] FAILED         [ 78%]\nr2e_tests/test_1.py::test_precompressed_data_stays_intact[pyloop] PASSED [ 78%]\nr2e_tests/test_1.py::test_file_upload_not_chunked_seek[pyloop] FAILED    [ 79%]\nr2e_tests/test_1.py::test_file_upload_force_chunked[pyloop] FAILED       [ 80%]\nr2e_tests/test_1.py::test_expect100[pyloop] PASSED                       [ 81%]\nr2e_tests/test_1.py::test_expect_100_continue_header[pyloop] PASSED      [ 81%]\nr2e_tests/test_1.py::test_data_stream[pyloop] PASSED                     [ 82%]\nr2e_tests/test_1.py::test_data_stream_deprecated[pyloop] PASSED          [ 83%]\nr2e_tests/test_1.py::test_data_file[pyloop] PASSED                       [ 83%]\nr2e_tests/test_1.py::test_data_stream_exc[pyloop] PASSED                 [ 84%]\nr2e_tests/test_1.py::test_data_stream_exc_chain[pyloop] PASSED           [ 85%]\nr2e_tests/test_1.py::test_data_stream_continue[pyloop] PASSED            [ 86%]\nr2e_tests/test_1.py::test_data_continue[pyloop] PASSED                   [ 86%]\nr2e_tests/test_1.py::test_close[pyloop] PASSED                           [ 87%]\nr2e_tests/test_1.py::test_bad_version[pyloop] PASSED                     [ 88%]\nr2e_tests/test_1.py::test_custom_response_class[pyloop] PASSED           [ 89%]\nr2e_tests/test_1.py::test_oserror_on_write_bytes[pyloop] PASSED          [ 89%]\nr2e_tests/test_1.py::test_terminate[pyloop] PASSED                       [ 90%]\nr2e_tests/test_1.py::test_terminate_with_closed_loop[pyloop] PASSED      [ 91%]\nr2e_tests/test_1.py::test_terminate_without_writer[pyloop] PASSED        [ 91%]\nr2e_tests/test_1.py::test_custom_req_rep[pyloop] PASSED                  [ 92%]\nr2e_tests/test_1.py::test_verify_ssl_false_with_ssl_context[pyloop] PASSED [ 93%]\nr2e_tests/test_1.py::test_bad_fingerprint[pyloop] PASSED                 [ 94%]\nr2e_tests/test_1.py::test_insecure_fingerprint_md5[pyloop] PASSED        [ 94%]\nr2e_tests/test_1.py::test_insecure_fingerprint_sha1[pyloop] PASSED       [ 95%]\nr2e_tests/test_1.py::test_loose_cookies_types[pyloop] PASSED             [ 96%]\nr2e_tests/test_1.py::test_gen_default_accept_encoding[False-gzip, deflate] PASSED [ 97%]\nr2e_tests/test_1.py::test_gen_default_accept_encoding[True-gzip, deflate, br] PASSED [ 97%]\nr2e_tests/test_1.py::test_basicauth_from_netrc_present[pyloop-machine example.com login username password pass\\n-expected_auth0] PASSED [ 98%]\nr2e_tests/test_1.py::test_basicauth_from_netrc_present_untrusted_env[pyloop-machine example.com login username password pass\\n] PASSED [ 99%]\nr2e_tests/test_1.py::test_basicauth_from_empty_netrc[pyloop-] PASSED     [100%]\n\n=================================== FAILURES ===================================\n_____________________ test_file_upload_not_chunked[pyloop] _____________________\n\nloop = <_UnixSelectorEventLoop running=False closed=False debug=False>\n\n    async def test_file_upload_not_chunked(loop) -> None:\n        here = os.path.dirname(__file__)\n        fname = os.path.join(here, \"aiohttp.png\")\n>       with open(fname, \"rb\") as f:\nE       FileNotFoundError: [Errno 2] No such file or directory: '/home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_53476dfd4ef4fb1bb74a267714bbc39eda71b403/r2e_tests/aiohttp.png'\n\nfname      = '/home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_53476dfd4ef4fb1bb74a267714bbc39eda71b403/r2e_tests/aiohttp.png'\nhere       = '/home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_53476dfd4ef4fb1bb74a267714bbc39eda71b403/r2e_tests'\nloop       = <_UnixSelectorEventLoop running=False closed=False debug=False>\n\nr2e_tests/test_1.py:926: FileNotFoundError\n__________________ test_file_upload_not_chunked_seek[pyloop] ___________________\n\nloop = <_UnixSelectorEventLoop running=False closed=False debug=False>\n\n    async def test_file_upload_not_chunked_seek(loop) -> None:\n        here = os.path.dirname(__file__)\n        fname = os.path.join(here, \"aiohttp.png\")\n>       with open(fname, \"rb\") as f:\nE       FileNotFoundError: [Errno 2] No such file or directory: '/home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_53476dfd4ef4fb1bb74a267714bbc39eda71b403/r2e_tests/aiohttp.png'\n\nfname      = '/home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_53476dfd4ef4fb1bb74a267714bbc39eda71b403/r2e_tests/aiohttp.png'\nhere       = '/home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_53476dfd4ef4fb1bb74a267714bbc39eda71b403/r2e_tests'\nloop       = <_UnixSelectorEventLoop running=False closed=False debug=False>\n\nr2e_tests/test_1.py:952: FileNotFoundError\n____________________ test_file_upload_force_chunked[pyloop] ____________________\n\nloop = <_UnixSelectorEventLoop running=False closed=False debug=False>\n\n    async def test_file_upload_force_chunked(loop) -> None:\n        here = os.path.dirname(__file__)\n        fname = os.path.join(here, \"aiohttp.png\")\n>       with open(fname, \"rb\") as f:\nE       FileNotFoundError: [Errno 2] No such file or directory: '/home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_53476dfd4ef4fb1bb74a267714bbc39eda71b403/r2e_tests/aiohttp.png'\n\nfname      = '/home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_53476dfd4ef4fb1bb74a267714bbc39eda71b403/r2e_tests/aiohttp.png'\nhere       = '/home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_53476dfd4ef4fb1bb74a267714bbc39eda71b403/r2e_tests'\nloop       = <_UnixSelectorEventLoop running=False closed=False debug=False>\n\nr2e_tests/test_1.py:962: FileNotFoundError\n==================================== PASSES ====================================\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                              90      7      0      0    92%\naiohttp/base_protocol.py                    66     51     22      0    17%\naiohttp/client.py                          491    243    180     49    45%\naiohttp/client_exceptions.py               135     60     16      0    50%\naiohttp/client_proto.py                    149    120     54      0    14%\naiohttp/client_reqrep.py                   676    184    288     29    70%\naiohttp/client_ws.py                       210    168     66      1    16%\naiohttp/compression_utils.py                68     22     14      3    60%\naiohttp/connector.py                       713    486    311     31    25%\naiohttp/cookiejar.py                       262    180    123      9    24%\naiohttp/formdata.py                         93     39     46     12    52%\naiohttp/hdrs.py                             90      0      0      0   100%\naiohttp/helpers.py                         521    261    178     24    43%\naiohttp/http.py                             11      0      2      0   100%\naiohttp/http_exceptions.py                  50     20      4      0    56%\naiohttp/http_parser.py                     497    398    200      1    14%\naiohttp/http_websocket.py                  386    285    152      0    19%\naiohttp/http_writer.py                     118     29     50     14    68%\naiohttp/locks.py                            24     16      4      0    29%\naiohttp/log.py                               7      0      0      0   100%\naiohttp/multipart.py                       562    446    232      1    15%\naiohttp/payload.py                         219     43     56     12    75%\naiohttp/payload_streamer.py                 29      2      4      0    94%\naiohttp/pytest_plugin.py                   167     81     42      5    49%\naiohttp/resolver.py                         68     48     22      0    22%\naiohttp/streams.py                         396    313    144      0    15%\naiohttp/tcp_helpers.py                      19     11      6      0    32%\naiohttp/test_utils.py                      313    190     52      3    35%\naiohttp/tracing.py                         191     69     32      0    69%\naiohttp/typedefs.py                         23      0      0      0   100%\naiohttp/web.py                             135     95     54      0    22%\naiohttp/web_app.py                         302    196     74      0    28%\naiohttp/web_exceptions.py                  157     25      8      0    80%\naiohttp/web_fileresponse.py                141    118     50      0    12%\naiohttp/web_log.py                         102     58     20      0    36%\naiohttp/web_middlewares.py                  55     42     20      0    17%\naiohttp/web_protocol.py                    343    283    157      0    12%\naiohttp/web_request.py                     435    285    128      1    28%\naiohttp/web_response.py                    483    370    218      0    16%\naiohttp/web_routedef.py                    106     46     10      0    55%\naiohttp/web_runner.py                      215    132     38      0    33%\naiohttp/web_server.py                       41     22      8      0    39%\naiohttp/web_urldispatcher.py               708    451    161      0    30%\naiohttp/web_ws.py                          327    262    112      1    15%\naiohttp/worker.py                          126    126     30      0     0%\ntests/__init__.py                            0      0      0      0   100%\ntests/conftest.py                          105    105     16      0     0%\ntests/test_base_protocol.py                198    198      2      0     0%\ntests/test_circular_imports.py              31     31     15      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            183    183     14      0     0%\ntests/test_client_fingerprint.py            59     59      0      0     0%\ntests/test_client_functional.py           2307   2307     74      0     0%\ntests/test_client_proto.py                  99     99      0      0     0%\ntests/test_client_request.py               787    787     18      0     0%\ntests/test_client_response.py              464    464      4      0     0%\ntests/test_client_session.py               482    482     23      0     0%\ntests/test_client_ws.py                    415    415      2      0     0%\ntests/test_client_ws_functional.py         605    605     16      0     0%\ntests/test_connector.py                   1520   1520     76      0     0%\ntests/test_cookiejar.py                    356    356     22      0     0%\ntests/test_flowcontrol_streams.py          100    100      0      0     0%\ntests/test_formdata.py                      72     72      6      0     0%\ntests/test_helpers.py                      464    464     24      0     0%\ntests/test_http_exceptions.py              109    109     10      0     0%\ntests/test_http_parser.py                  957    957     50      0     0%\ntests/test_http_writer.py                  182    182     10      0     0%\ntests/test_imports.py                       31     31      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                    747    747     22      0     0%\ntests/test_multipart_helpers.py            446    446      0      0     0%\ntests/test_payload.py                       94     94      0      0     0%\ntests/test_proxy.py                        285    285      0      0     0%\ntests/test_proxy_functional.py             473    473     22      0     0%\ntests/test_pytest_plugin.py                 27     27      0      0     0%\ntests/test_resolver.py                     176    176     12      0     0%\ntests/test_route_def.py                    210    210      0      0     0%\ntests/test_run_app.py                      522    522     30      0     0%\ntests/test_streams.py                     1077   1077     40      0     0%\ntests/test_tcp_helpers.py                   52     52      2      0     0%\ntests/test_test_utils.py                   242    242      6      0     0%\ntests/test_tracing.py                       48     48      0      0     0%\ntests/test_urldispatch.py                  844    844     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              1547   1547     36      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           40     40      0      0     0%\ntests/test_web_response.py                 863    863      4      0     0%\ntests/test_web_runner.py                   146    146      4      0     0%\ntests/test_web_sendfile.py                  76     76      0      0     0%\ntests/test_web_sendfile_functional.py      634    634     18      0     0%\ntests/test_web_server.py                   160    160      0      0     0%\ntests/test_web_urldispatcher.py            306    306     14      0     0%\ntests/test_web_websocket.py                313    313      6      0     0%\ntests/test_web_websocket_functional.py     542    542     16      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              68     68      0      0     0%\ntests/test_worker.py                       193    193      4      0     0%\n--------------------------------------------------------------------------\nTOTAL                                    32241  28185   4114    197    12%\n\n============================= slowest 10 durations =============================\n0.05s call     r2e_tests/test_1.py::test_terminate_with_closed_loop[pyloop]\n0.05s call     r2e_tests/test_1.py::test_host_header_host_unicode[pyloop]\n0.02s teardown r2e_tests/test_1.py::test_host_header_ipv6_with_port[pyloop]\n0.02s teardown r2e_tests/test_1.py::test_file_upload_not_chunked[pyloop]\n0.02s teardown r2e_tests/test_1.py::test_default_headers_useragent[pyloop]\n0.02s teardown r2e_tests/test_1.py::test_terminate_with_closed_loop[pyloop]\n0.02s teardown r2e_tests/test_1.py::test_data_stream_exc_chain[pyloop]\n0.02s teardown r2e_tests/test_1.py::test_pass_falsy_data_file[pyloop]\n0.02s teardown r2e_tests/test_1.py::test_oserror_on_write_bytes[pyloop]\n0.02s teardown r2e_tests/test_1.py::test_file_upload_not_chunked_seek[pyloop]\n=========================== short test summary info ============================\nPASSED r2e_tests/test_1.py::test_method1[pyloop]\nPASSED r2e_tests/test_1.py::test_method2[pyloop]\nPASSED r2e_tests/test_1.py::test_method3[pyloop]\nPASSED r2e_tests/test_1.py::test_method_invalid[pyloop]\nPASSED r2e_tests/test_1.py::test_version_1_0[pyloop]\nPASSED r2e_tests/test_1.py::test_version_default[pyloop]\nPASSED r2e_tests/test_1.py::test_request_info[pyloop]\nPASSED r2e_tests/test_1.py::test_request_info_with_fragment[pyloop]\nPASSED r2e_tests/test_1.py::test_version_err[pyloop]\nPASSED r2e_tests/test_1.py::test_keep_alive[pyloop]\nPASSED r2e_tests/test_1.py::test_host_port_default_http[pyloop]\nPASSED r2e_tests/test_1.py::test_host_port_default_https[pyloop]\nPASSED r2e_tests/test_1.py::test_host_port_nondefault_http[pyloop]\nPASSED r2e_tests/test_1.py::test_host_port_nondefault_https[pyloop]\nPASSED r2e_tests/test_1.py::test_host_port_default_ws[pyloop]\nPASSED r2e_tests/test_1.py::test_host_port_default_wss[pyloop]\nPASSED r2e_tests/test_1.py::test_host_port_nondefault_ws[pyloop]\nPASSED r2e_tests/test_1.py::test_host_port_nondefault_wss[pyloop]\nPASSED r2e_tests/test_1.py::test_host_port_none_port[pyloop]\nPASSED r2e_tests/test_1.py::test_host_port_err[pyloop]\nPASSED r2e_tests/test_1.py::test_hostname_err[pyloop]\nPASSED r2e_tests/test_1.py::test_host_header_host_first[pyloop]\nPASSED r2e_tests/test_1.py::test_host_header_host_without_port[pyloop]\nPASSED r2e_tests/test_1.py::test_host_header_host_with_default_port[pyloop]\nPASSED r2e_tests/test_1.py::test_host_header_host_with_nondefault_port[pyloop]\nPASSED r2e_tests/test_1.py::test_host_header_host_idna_encode[pyloop]\nPASSED r2e_tests/test_1.py::test_host_header_host_unicode[pyloop]\nPASSED r2e_tests/test_1.py::test_host_header_explicit_host[pyloop]\nPASSED r2e_tests/test_1.py::test_host_header_explicit_host_with_port[pyloop]\nPASSED r2e_tests/test_1.py::test_host_header_ipv4[pyloop]\nPASSED r2e_tests/test_1.py::test_host_header_ipv6[pyloop]\nPASSED r2e_tests/test_1.py::test_host_header_ipv4_with_port[pyloop]\nPASSED r2e_tests/test_1.py::test_host_header_ipv6_with_port[pyloop]\nPASSED r2e_tests/test_1.py::test_default_loop[pyloop]\nPASSED r2e_tests/test_1.py::test_host_header_fqdn[pyloop-dot only at the end]\nPASSED r2e_tests/test_1.py::test_host_header_fqdn[pyloop-single dot]\nPASSED r2e_tests/test_1.py::test_host_header_fqdn[pyloop-single dot with port]\nPASSED r2e_tests/test_1.py::test_host_header_fqdn[pyloop-multiple dots with port]\nPASSED r2e_tests/test_1.py::test_host_header_fqdn[pyloop-explicit host header]\nPASSED r2e_tests/test_1.py::test_host_header_fqdn[pyloop-https]\nPASSED r2e_tests/test_1.py::test_host_header_fqdn[pyloop-only dots]\nPASSED r2e_tests/test_1.py::test_host_header_fqdn[pyloop-single dot with port idna]\nPASSED r2e_tests/test_1.py::test_default_headers_useragent[pyloop]\nPASSED r2e_tests/test_1.py::test_default_headers_useragent_custom[pyloop]\nPASSED r2e_tests/test_1.py::test_skip_default_useragent_header[pyloop]\nPASSED r2e_tests/test_1.py::test_headers[pyloop]\nPASSED r2e_tests/test_1.py::test_headers_list[pyloop]\nPASSED r2e_tests/test_1.py::test_headers_default[pyloop]\nPASSED r2e_tests/test_1.py::test_invalid_url[pyloop]\nPASSED r2e_tests/test_1.py::test_no_path[pyloop]\nPASSED r2e_tests/test_1.py::test_ipv6_default_http_port[pyloop]\nPASSED r2e_tests/test_1.py::test_ipv6_default_https_port[pyloop]\nPASSED r2e_tests/test_1.py::test_ipv6_nondefault_http_port[pyloop]\nPASSED r2e_tests/test_1.py::test_ipv6_nondefault_https_port[pyloop]\nPASSED r2e_tests/test_1.py::test_basic_auth[pyloop]\nPASSED r2e_tests/test_1.py::test_basic_auth_utf8[pyloop]\nPASSED r2e_tests/test_1.py::test_basic_auth_tuple_forbidden[pyloop]\nPASSED r2e_tests/test_1.py::test_basic_auth_from_url[pyloop]\nPASSED r2e_tests/test_1.py::test_basic_auth_from_url_overridden[pyloop]\nPASSED r2e_tests/test_1.py::test_path_is_not_double_encoded1[pyloop]\nPASSED r2e_tests/test_1.py::test_path_is_not_double_encoded2[pyloop]\nPASSED r2e_tests/test_1.py::test_path_is_not_double_encoded3[pyloop]\nPASSED r2e_tests/test_1.py::test_path_safe_chars_preserved[pyloop]\nPASSED r2e_tests/test_1.py::test_params_are_added_before_fragment1[pyloop]\nPASSED r2e_tests/test_1.py::test_params_are_added_before_fragment2[pyloop]\nPASSED r2e_tests/test_1.py::test_path_not_contain_fragment1[pyloop]\nPASSED r2e_tests/test_1.py::test_path_not_contain_fragment2[pyloop]\nPASSED r2e_tests/test_1.py::test_cookies[pyloop]\nPASSED r2e_tests/test_1.py::test_cookies_is_quoted_with_special_characters[pyloop]\nPASSED r2e_tests/test_1.py::test_cookies_merge_with_headers[pyloop]\nPASSED r2e_tests/test_1.py::test_unicode_get1[pyloop]\nPASSED r2e_tests/test_1.py::test_unicode_get2[pyloop]\nPASSED r2e_tests/test_1.py::test_unicode_get3[pyloop]\nPASSED r2e_tests/test_1.py::test_unicode_get4[pyloop]\nPASSED r2e_tests/test_1.py::test_query_multivalued_param[pyloop]\nPASSED r2e_tests/test_1.py::test_query_str_param[pyloop]\nPASSED r2e_tests/test_1.py::test_query_bytes_param_raises[pyloop]\nPASSED r2e_tests/test_1.py::test_query_str_param_is_not_encoded[pyloop]\nPASSED r2e_tests/test_1.py::test_params_update_path_and_url[pyloop]\nPASSED r2e_tests/test_1.py::test_params_empty_path_and_url[pyloop]\nPASSED r2e_tests/test_1.py::test_gen_netloc_all[pyloop]\nPASSED r2e_tests/test_1.py::test_gen_netloc_no_port[pyloop]\nPASSED r2e_tests/test_1.py::test_connection_header[pyloop]\nPASSED r2e_tests/test_1.py::test_no_content_length[pyloop]\nPASSED r2e_tests/test_1.py::test_no_content_length_head[pyloop]\nPASSED r2e_tests/test_1.py::test_content_type_auto_header_get[pyloop]\nPASSED r2e_tests/test_1.py::test_content_type_auto_header_form[pyloop]\nPASSED r2e_tests/test_1.py::test_content_type_auto_header_bytes[pyloop]\nPASSED r2e_tests/test_1.py::test_content_type_skip_auto_header_bytes[pyloop]\nPASSED r2e_tests/test_1.py::test_content_type_skip_auto_header_form[pyloop]\nPASSED r2e_tests/test_1.py::test_content_type_auto_header_content_length_no_skip[pyloop]\nPASSED r2e_tests/test_1.py::test_urlencoded_formdata_charset[pyloop]\nPASSED r2e_tests/test_1.py::test_post_data[pyloop]\nPASSED r2e_tests/test_1.py::test_pass_falsy_data[pyloop]\nPASSED r2e_tests/test_1.py::test_pass_falsy_data_file[pyloop]\nPASSED r2e_tests/test_1.py::test_get_with_data[pyloop]\nPASSED r2e_tests/test_1.py::test_bytes_data[pyloop]\nPASSED r2e_tests/test_1.py::test_content_encoding[pyloop]\nPASSED r2e_tests/test_1.py::test_content_encoding_dont_set_headers_if_no_body[pyloop]\nPASSED r2e_tests/test_1.py::test_content_encoding_header[pyloop]\nPASSED r2e_tests/test_1.py::test_compress_and_content_encoding[pyloop]\nPASSED r2e_tests/test_1.py::test_chunked[pyloop]\nPASSED r2e_tests/test_1.py::test_chunked2[pyloop]\nPASSED r2e_tests/test_1.py::test_chunked_explicit[pyloop]\nPASSED r2e_tests/test_1.py::test_chunked_length[pyloop]\nPASSED r2e_tests/test_1.py::test_chunked_transfer_encoding[pyloop]\nPASSED r2e_tests/test_1.py::test_precompressed_data_stays_intact[pyloop]\nPASSED r2e_tests/test_1.py::test_expect100[pyloop]\nPASSED r2e_tests/test_1.py::test_expect_100_continue_header[pyloop]\nPASSED r2e_tests/test_1.py::test_data_stream[pyloop]\nPASSED r2e_tests/test_1.py::test_data_stream_deprecated[pyloop]\nPASSED r2e_tests/test_1.py::test_data_file[pyloop]\nPASSED r2e_tests/test_1.py::test_data_stream_exc[pyloop]\nPASSED r2e_tests/test_1.py::test_data_stream_exc_chain[pyloop]\nPASSED r2e_tests/test_1.py::test_data_stream_continue[pyloop]\nPASSED r2e_tests/test_1.py::test_data_continue[pyloop]\nPASSED r2e_tests/test_1.py::test_close[pyloop]\nPASSED r2e_tests/test_1.py::test_bad_version[pyloop]\nPASSED r2e_tests/test_1.py::test_custom_response_class[pyloop]\nPASSED r2e_tests/test_1.py::test_oserror_on_write_bytes[pyloop]\nPASSED r2e_tests/test_1.py::test_terminate[pyloop]\nPASSED r2e_tests/test_1.py::test_terminate_with_closed_loop[pyloop]\nPASSED r2e_tests/test_1.py::test_terminate_without_writer[pyloop]\nPASSED r2e_tests/test_1.py::test_custom_req_rep[pyloop]\nPASSED r2e_tests/test_1.py::test_verify_ssl_false_with_ssl_context[pyloop]\nPASSED r2e_tests/test_1.py::test_bad_fingerprint[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_loose_cookies_types[pyloop]\nPASSED r2e_tests/test_1.py::test_gen_default_accept_encoding[False-gzip, deflate]\nPASSED r2e_tests/test_1.py::test_gen_default_accept_encoding[True-gzip, deflate, br]\nPASSED r2e_tests/test_1.py::test_basicauth_from_netrc_present[pyloop-machine example.com login username password pass\\n-expected_auth0]\nPASSED r2e_tests/test_1.py::test_basicauth_from_netrc_present_untrusted_env[pyloop-machine example.com login username password pass\\n]\nPASSED r2e_tests/test_1.py::test_basicauth_from_empty_netrc[pyloop-]\nFAILED r2e_tests/test_1.py::test_file_upload_not_chunked[pyloop] - FileNotFou...\nFAILED r2e_tests/test_1.py::test_file_upload_not_chunked_seek[pyloop] - FileN...\nFAILED r2e_tests/test_1.py::test_file_upload_force_chunked[pyloop] - FileNotF...\n======================== 3 failed, 134 passed in 6.00s =========================\n",
    "new_commit_res_stderr": "",
    "old_commit_res_code": 1,
    "old_commit_res_stdout": "============================= test session starts ==============================\nplatform linux -- Python 3.9.21, pytest-7.4.3, pluggy-1.2.0 -- /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_53476dfd4ef4fb1bb74a267714bbc39eda71b403/.venv/bin/python\ncachedir: .pytest_cache\nrootdir: /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_53476dfd4ef4fb1bb74a267714bbc39eda71b403\nconfigfile: setup.cfg\nplugins: time-machine-2.13.0, mock-3.12.0, asyncio-0.23.8, cov-4.1.0\nasyncio: mode=strict\ncollecting ... collected 137 items\n\nr2e_tests/test_1.py::test_method1[pyloop] PASSED                         [  0%]\nr2e_tests/test_1.py::test_method2[pyloop] PASSED                         [  1%]\nr2e_tests/test_1.py::test_method3[pyloop] PASSED                         [  2%]\nr2e_tests/test_1.py::test_method_invalid[pyloop] PASSED                  [  2%]\nr2e_tests/test_1.py::test_version_1_0[pyloop] PASSED                     [  3%]\nr2e_tests/test_1.py::test_version_default[pyloop] PASSED                 [  4%]\nr2e_tests/test_1.py::test_request_info[pyloop] PASSED                    [  5%]\nr2e_tests/test_1.py::test_request_info_with_fragment[pyloop] PASSED      [  5%]\nr2e_tests/test_1.py::test_version_err[pyloop] PASSED                     [  6%]\nr2e_tests/test_1.py::test_keep_alive[pyloop] PASSED                      [  7%]\nr2e_tests/test_1.py::test_host_port_default_http[pyloop] PASSED          [  8%]\nr2e_tests/test_1.py::test_host_port_default_https[pyloop] PASSED         [  8%]\nr2e_tests/test_1.py::test_host_port_nondefault_http[pyloop] PASSED       [  9%]\nr2e_tests/test_1.py::test_host_port_nondefault_https[pyloop] PASSED      [ 10%]\nr2e_tests/test_1.py::test_host_port_default_ws[pyloop] PASSED            [ 10%]\nr2e_tests/test_1.py::test_host_port_default_wss[pyloop] PASSED           [ 11%]\nr2e_tests/test_1.py::test_host_port_nondefault_ws[pyloop] PASSED         [ 12%]\nr2e_tests/test_1.py::test_host_port_nondefault_wss[pyloop] PASSED        [ 13%]\nr2e_tests/test_1.py::test_host_port_none_port[pyloop] PASSED             [ 13%]\nr2e_tests/test_1.py::test_host_port_err[pyloop] PASSED                   [ 14%]\nr2e_tests/test_1.py::test_hostname_err[pyloop] PASSED                    [ 15%]\nr2e_tests/test_1.py::test_host_header_host_first[pyloop] PASSED          [ 16%]\nr2e_tests/test_1.py::test_host_header_host_without_port[pyloop] PASSED   [ 16%]\nr2e_tests/test_1.py::test_host_header_host_with_default_port[pyloop] PASSED [ 17%]\nr2e_tests/test_1.py::test_host_header_host_with_nondefault_port[pyloop] PASSED [ 18%]\nr2e_tests/test_1.py::test_host_header_host_idna_encode[pyloop] PASSED    [ 18%]\nr2e_tests/test_1.py::test_host_header_host_unicode[pyloop] PASSED        [ 19%]\nr2e_tests/test_1.py::test_host_header_explicit_host[pyloop] PASSED       [ 20%]\nr2e_tests/test_1.py::test_host_header_explicit_host_with_port[pyloop] PASSED [ 21%]\nr2e_tests/test_1.py::test_host_header_ipv4[pyloop] PASSED                [ 21%]\nr2e_tests/test_1.py::test_host_header_ipv6[pyloop] PASSED                [ 22%]\nr2e_tests/test_1.py::test_host_header_ipv4_with_port[pyloop] PASSED      [ 23%]\nr2e_tests/test_1.py::test_host_header_ipv6_with_port[pyloop] PASSED      [ 24%]\nr2e_tests/test_1.py::test_default_loop[pyloop] PASSED                    [ 24%]\nr2e_tests/test_1.py::test_host_header_fqdn[pyloop-dot only at the end] PASSED [ 25%]\nr2e_tests/test_1.py::test_host_header_fqdn[pyloop-single dot] PASSED     [ 26%]\nr2e_tests/test_1.py::test_host_header_fqdn[pyloop-single dot with port] PASSED [ 27%]\nr2e_tests/test_1.py::test_host_header_fqdn[pyloop-multiple dots with port] PASSED [ 27%]\nr2e_tests/test_1.py::test_host_header_fqdn[pyloop-explicit host header] PASSED [ 28%]\nr2e_tests/test_1.py::test_host_header_fqdn[pyloop-https] PASSED          [ 29%]\nr2e_tests/test_1.py::test_host_header_fqdn[pyloop-only dots] PASSED      [ 29%]\nr2e_tests/test_1.py::test_host_header_fqdn[pyloop-single dot with port idna] PASSED [ 30%]\nr2e_tests/test_1.py::test_default_headers_useragent[pyloop] PASSED       [ 31%]\nr2e_tests/test_1.py::test_default_headers_useragent_custom[pyloop] PASSED [ 32%]\nr2e_tests/test_1.py::test_skip_default_useragent_header[pyloop] PASSED   [ 32%]\nr2e_tests/test_1.py::test_headers[pyloop] PASSED                         [ 33%]\nr2e_tests/test_1.py::test_headers_list[pyloop] PASSED                    [ 34%]\nr2e_tests/test_1.py::test_headers_default[pyloop] PASSED                 [ 35%]\nr2e_tests/test_1.py::test_invalid_url[pyloop] PASSED                     [ 35%]\nr2e_tests/test_1.py::test_no_path[pyloop] PASSED                         [ 36%]\nr2e_tests/test_1.py::test_ipv6_default_http_port[pyloop] PASSED          [ 37%]\nr2e_tests/test_1.py::test_ipv6_default_https_port[pyloop] PASSED         [ 37%]\nr2e_tests/test_1.py::test_ipv6_nondefault_http_port[pyloop] PASSED       [ 38%]\nr2e_tests/test_1.py::test_ipv6_nondefault_https_port[pyloop] PASSED      [ 39%]\nr2e_tests/test_1.py::test_basic_auth[pyloop] PASSED                      [ 40%]\nr2e_tests/test_1.py::test_basic_auth_utf8[pyloop] PASSED                 [ 40%]\nr2e_tests/test_1.py::test_basic_auth_tuple_forbidden[pyloop] PASSED      [ 41%]\nr2e_tests/test_1.py::test_basic_auth_from_url[pyloop] PASSED             [ 42%]\nr2e_tests/test_1.py::test_basic_auth_from_url_overridden[pyloop] PASSED  [ 43%]\nr2e_tests/test_1.py::test_path_is_not_double_encoded1[pyloop] PASSED     [ 43%]\nr2e_tests/test_1.py::test_path_is_not_double_encoded2[pyloop] PASSED     [ 44%]\nr2e_tests/test_1.py::test_path_is_not_double_encoded3[pyloop] PASSED     [ 45%]\nr2e_tests/test_1.py::test_path_safe_chars_preserved[pyloop] PASSED       [ 45%]\nr2e_tests/test_1.py::test_params_are_added_before_fragment1[pyloop] PASSED [ 46%]\nr2e_tests/test_1.py::test_params_are_added_before_fragment2[pyloop] PASSED [ 47%]\nr2e_tests/test_1.py::test_path_not_contain_fragment1[pyloop] PASSED      [ 48%]\nr2e_tests/test_1.py::test_path_not_contain_fragment2[pyloop] PASSED      [ 48%]\nr2e_tests/test_1.py::test_cookies[pyloop] PASSED                         [ 49%]\nr2e_tests/test_1.py::test_cookies_is_quoted_with_special_characters[pyloop] PASSED [ 50%]\nr2e_tests/test_1.py::test_cookies_merge_with_headers[pyloop] PASSED      [ 51%]\nr2e_tests/test_1.py::test_unicode_get1[pyloop] PASSED                    [ 51%]\nr2e_tests/test_1.py::test_unicode_get2[pyloop] PASSED                    [ 52%]\nr2e_tests/test_1.py::test_unicode_get3[pyloop] PASSED                    [ 53%]\nr2e_tests/test_1.py::test_unicode_get4[pyloop] PASSED                    [ 54%]\nr2e_tests/test_1.py::test_query_multivalued_param[pyloop] PASSED         [ 54%]\nr2e_tests/test_1.py::test_query_str_param[pyloop] PASSED                 [ 55%]\nr2e_tests/test_1.py::test_query_bytes_param_raises[pyloop] PASSED        [ 56%]\nr2e_tests/test_1.py::test_query_str_param_is_not_encoded[pyloop] PASSED  [ 56%]\nr2e_tests/test_1.py::test_params_update_path_and_url[pyloop] PASSED      [ 57%]\nr2e_tests/test_1.py::test_params_empty_path_and_url[pyloop] PASSED       [ 58%]\nr2e_tests/test_1.py::test_gen_netloc_all[pyloop] PASSED                  [ 59%]\nr2e_tests/test_1.py::test_gen_netloc_no_port[pyloop] PASSED              [ 59%]\nr2e_tests/test_1.py::test_connection_header[pyloop] PASSED               [ 60%]\nr2e_tests/test_1.py::test_no_content_length[pyloop] PASSED               [ 61%]\nr2e_tests/test_1.py::test_no_content_length_head[pyloop] PASSED          [ 62%]\nr2e_tests/test_1.py::test_content_type_auto_header_get[pyloop] PASSED    [ 62%]\nr2e_tests/test_1.py::test_content_type_auto_header_form[pyloop] PASSED   [ 63%]\nr2e_tests/test_1.py::test_content_type_auto_header_bytes[pyloop] PASSED  [ 64%]\nr2e_tests/test_1.py::test_content_type_skip_auto_header_bytes[pyloop] PASSED [ 64%]\nr2e_tests/test_1.py::test_content_type_skip_auto_header_form[pyloop] PASSED [ 65%]\nr2e_tests/test_1.py::test_content_type_auto_header_content_length_no_skip[pyloop] PASSED [ 66%]\nr2e_tests/test_1.py::test_urlencoded_formdata_charset[pyloop] PASSED     [ 67%]\nr2e_tests/test_1.py::test_post_data[pyloop] PASSED                       [ 67%]\nr2e_tests/test_1.py::test_pass_falsy_data[pyloop] PASSED                 [ 68%]\nr2e_tests/test_1.py::test_pass_falsy_data_file[pyloop] PASSED            [ 69%]\nr2e_tests/test_1.py::test_get_with_data[pyloop] PASSED                   [ 70%]\nr2e_tests/test_1.py::test_bytes_data[pyloop] PASSED                      [ 70%]\nr2e_tests/test_1.py::test_content_encoding[pyloop] PASSED                [ 71%]\nr2e_tests/test_1.py::test_content_encoding_dont_set_headers_if_no_body[pyloop] PASSED [ 72%]\nr2e_tests/test_1.py::test_content_encoding_header[pyloop] PASSED         [ 72%]\nr2e_tests/test_1.py::test_compress_and_content_encoding[pyloop] PASSED   [ 73%]\nr2e_tests/test_1.py::test_chunked[pyloop] PASSED                         [ 74%]\nr2e_tests/test_1.py::test_chunked2[pyloop] PASSED                        [ 75%]\nr2e_tests/test_1.py::test_chunked_explicit[pyloop] PASSED                [ 75%]\nr2e_tests/test_1.py::test_chunked_length[pyloop] PASSED                  [ 76%]\nr2e_tests/test_1.py::test_chunked_transfer_encoding[pyloop] PASSED       [ 77%]\nr2e_tests/test_1.py::test_file_upload_not_chunked[pyloop] FAILED         [ 78%]\nr2e_tests/test_1.py::test_precompressed_data_stays_intact[pyloop] PASSED [ 78%]\nr2e_tests/test_1.py::test_file_upload_not_chunked_seek[pyloop] FAILED    [ 79%]\nr2e_tests/test_1.py::test_file_upload_force_chunked[pyloop] FAILED       [ 80%]\nr2e_tests/test_1.py::test_expect100[pyloop] PASSED                       [ 81%]\nr2e_tests/test_1.py::test_expect_100_continue_header[pyloop] PASSED      [ 81%]\nr2e_tests/test_1.py::test_data_stream[pyloop] PASSED                     [ 82%]\nr2e_tests/test_1.py::test_data_stream_deprecated[pyloop] PASSED          [ 83%]\nr2e_tests/test_1.py::test_data_file[pyloop] PASSED                       [ 83%]\nr2e_tests/test_1.py::test_data_stream_exc[pyloop] PASSED                 [ 84%]\nr2e_tests/test_1.py::test_data_stream_exc_chain[pyloop] PASSED           [ 85%]\nr2e_tests/test_1.py::test_data_stream_continue[pyloop] PASSED            [ 86%]\nr2e_tests/test_1.py::test_data_continue[pyloop] PASSED                   [ 86%]\nr2e_tests/test_1.py::test_close[pyloop] PASSED                           [ 87%]\nr2e_tests/test_1.py::test_bad_version[pyloop] FAILED                     [ 88%]\nr2e_tests/test_1.py::test_custom_response_class[pyloop] PASSED           [ 89%]\nr2e_tests/test_1.py::test_oserror_on_write_bytes[pyloop] PASSED          [ 89%]\nr2e_tests/test_1.py::test_terminate[pyloop] PASSED                       [ 90%]\nr2e_tests/test_1.py::test_terminate_with_closed_loop[pyloop] PASSED      [ 91%]\nr2e_tests/test_1.py::test_terminate_without_writer[pyloop] PASSED        [ 91%]\nr2e_tests/test_1.py::test_custom_req_rep[pyloop] PASSED                  [ 92%]\nr2e_tests/test_1.py::test_verify_ssl_false_with_ssl_context[pyloop] PASSED [ 93%]\nr2e_tests/test_1.py::test_bad_fingerprint[pyloop] PASSED                 [ 94%]\nr2e_tests/test_1.py::test_insecure_fingerprint_md5[pyloop] PASSED        [ 94%]\nr2e_tests/test_1.py::test_insecure_fingerprint_sha1[pyloop] PASSED       [ 95%]\nr2e_tests/test_1.py::test_loose_cookies_types[pyloop] PASSED             [ 96%]\nr2e_tests/test_1.py::test_gen_default_accept_encoding[False-gzip, deflate] PASSED [ 97%]\nr2e_tests/test_1.py::test_gen_default_accept_encoding[True-gzip, deflate, br] PASSED [ 97%]\nr2e_tests/test_1.py::test_basicauth_from_netrc_present[pyloop-machine example.com login username password pass\\n-expected_auth0] PASSED [ 98%]\nr2e_tests/test_1.py::test_basicauth_from_netrc_present_untrusted_env[pyloop-machine example.com login username password pass\\n] PASSED [ 99%]\nr2e_tests/test_1.py::test_basicauth_from_empty_netrc[pyloop-] PASSED     [100%]\n\n=================================== FAILURES ===================================\n_____________________ test_file_upload_not_chunked[pyloop] _____________________\n\nloop = <_UnixSelectorEventLoop running=False closed=False debug=False>\n\n    async def test_file_upload_not_chunked(loop) -> None:\n        here = os.path.dirname(__file__)\n        fname = os.path.join(here, \"aiohttp.png\")\n>       with open(fname, \"rb\") as f:\nE       FileNotFoundError: [Errno 2] No such file or directory: '/home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_53476dfd4ef4fb1bb74a267714bbc39eda71b403/r2e_tests/aiohttp.png'\n\nfname      = '/home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_53476dfd4ef4fb1bb74a267714bbc39eda71b403/r2e_tests/aiohttp.png'\nhere       = '/home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_53476dfd4ef4fb1bb74a267714bbc39eda71b403/r2e_tests'\nloop       = <_UnixSelectorEventLoop running=False closed=False debug=False>\n\nr2e_tests/test_1.py:926: FileNotFoundError\n__________________ test_file_upload_not_chunked_seek[pyloop] ___________________\n\nloop = <_UnixSelectorEventLoop running=False closed=False debug=False>\n\n    async def test_file_upload_not_chunked_seek(loop) -> None:\n        here = os.path.dirname(__file__)\n        fname = os.path.join(here, \"aiohttp.png\")\n>       with open(fname, \"rb\") as f:\nE       FileNotFoundError: [Errno 2] No such file or directory: '/home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_53476dfd4ef4fb1bb74a267714bbc39eda71b403/r2e_tests/aiohttp.png'\n\nfname      = '/home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_53476dfd4ef4fb1bb74a267714bbc39eda71b403/r2e_tests/aiohttp.png'\nhere       = '/home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_53476dfd4ef4fb1bb74a267714bbc39eda71b403/r2e_tests'\nloop       = <_UnixSelectorEventLoop running=False closed=False debug=False>\n\nr2e_tests/test_1.py:952: FileNotFoundError\n____________________ test_file_upload_force_chunked[pyloop] ____________________\n\nloop = <_UnixSelectorEventLoop running=False closed=False debug=False>\n\n    async def test_file_upload_force_chunked(loop) -> None:\n        here = os.path.dirname(__file__)\n        fname = os.path.join(here, \"aiohttp.png\")\n>       with open(fname, \"rb\") as f:\nE       FileNotFoundError: [Errno 2] No such file or directory: '/home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_53476dfd4ef4fb1bb74a267714bbc39eda71b403/r2e_tests/aiohttp.png'\n\nfname      = '/home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_53476dfd4ef4fb1bb74a267714bbc39eda71b403/r2e_tests/aiohttp.png'\nhere       = '/home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_53476dfd4ef4fb1bb74a267714bbc39eda71b403/r2e_tests'\nloop       = <_UnixSelectorEventLoop running=False closed=False debug=False>\n\nr2e_tests/test_1.py:962: FileNotFoundError\n___________________________ test_bad_version[pyloop] ___________________________\n\nloop = <_UnixSelectorEventLoop running=False closed=False debug=False>\nconn = <Mock id='132894857291712'>\n\n    async def test_bad_version(loop, conn) -> None:\n        req = ClientRequest(\n            \"GET\",\n            URL(\"http://python.org\"),\n            loop=loop,\n            headers={\"Connection\": \"Close\"},\n            version=(\"1\", \"1\\r\\nInjected-Header: not allowed\"),\n        )\n    \n        with pytest.raises(AttributeError):\n>           await req.send(conn)\nE           Failed: DID NOT RAISE <class 'AttributeError'>\n\nconn       = <Mock id='132894857291712'>\nloop       = <_UnixSelectorEventLoop running=False closed=False debug=False>\nreq        = <aiohttp.client_reqrep.ClientRequest object at 0x78ddfec2e940>\n\nr2e_tests/test_1.py:1175: Failed\n==================================== PASSES ====================================\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                              90      7      0      0    92%\naiohttp/base_protocol.py                    66     51     22      0    17%\naiohttp/client.py                          491    243    180     49    45%\naiohttp/client_exceptions.py               135     60     16      0    50%\naiohttp/client_proto.py                    149    120     54      0    14%\naiohttp/client_reqrep.py                   676    184    288     29    70%\naiohttp/client_ws.py                       210    168     66      1    16%\naiohttp/compression_utils.py                68     22     14      3    60%\naiohttp/connector.py                       713    486    311     31    25%\naiohttp/cookiejar.py                       262    180    123      9    24%\naiohttp/formdata.py                         93     39     46     12    52%\naiohttp/hdrs.py                             90      0      0      0   100%\naiohttp/helpers.py                         521    261    178     24    43%\naiohttp/http.py                             11      0      2      0   100%\naiohttp/http_exceptions.py                  50     20      4      0    56%\naiohttp/http_parser.py                     497    398    200      1    14%\naiohttp/http_websocket.py                  386    285    152      0    19%\naiohttp/http_writer.py                     118     29     50     14    68%\naiohttp/locks.py                            24     16      4      0    29%\naiohttp/log.py                               7      0      0      0   100%\naiohttp/multipart.py                       562    446    232      1    15%\naiohttp/payload.py                         219     43     56     12    75%\naiohttp/payload_streamer.py                 29      2      4      0    94%\naiohttp/pytest_plugin.py                   167     81     42      5    49%\naiohttp/resolver.py                         68     48     22      0    22%\naiohttp/streams.py                         396    313    144      0    15%\naiohttp/tcp_helpers.py                      19     11      6      0    32%\naiohttp/test_utils.py                      313    190     52      3    35%\naiohttp/tracing.py                         191     69     32      0    69%\naiohttp/typedefs.py                         23      0      0      0   100%\naiohttp/web.py                             135     95     54      0    22%\naiohttp/web_app.py                         302    196     74      0    28%\naiohttp/web_exceptions.py                  157     25      8      0    80%\naiohttp/web_fileresponse.py                141    118     50      0    12%\naiohttp/web_log.py                         102     58     20      0    36%\naiohttp/web_middlewares.py                  55     42     20      0    17%\naiohttp/web_protocol.py                    343    283    157      0    12%\naiohttp/web_request.py                     435    285    128      1    28%\naiohttp/web_response.py                    483    370    218      0    16%\naiohttp/web_routedef.py                    106     46     10      0    55%\naiohttp/web_runner.py                      215    132     38      0    33%\naiohttp/web_server.py                       41     22      8      0    39%\naiohttp/web_urldispatcher.py               708    451    161      0    30%\naiohttp/web_ws.py                          327    262    112      1    15%\naiohttp/worker.py                          126    126     30      0     0%\ntests/__init__.py                            0      0      0      0   100%\ntests/conftest.py                          105    105     16      0     0%\ntests/test_base_protocol.py                198    198      2      0     0%\ntests/test_circular_imports.py              31     31     15      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            183    183     14      0     0%\ntests/test_client_fingerprint.py            59     59      0      0     0%\ntests/test_client_functional.py           2307   2307     74      0     0%\ntests/test_client_proto.py                  99     99      0      0     0%\ntests/test_client_request.py               782    782     18      0     0%\ntests/test_client_response.py              464    464      4      0     0%\ntests/test_client_session.py               482    482     23      0     0%\ntests/test_client_ws.py                    415    415      2      0     0%\ntests/test_client_ws_functional.py         605    605     16      0     0%\ntests/test_connector.py                   1520   1520     76      0     0%\ntests/test_cookiejar.py                    356    356     22      0     0%\ntests/test_flowcontrol_streams.py          100    100      0      0     0%\ntests/test_formdata.py                      72     72      6      0     0%\ntests/test_helpers.py                      464    464     24      0     0%\ntests/test_http_exceptions.py              109    109     10      0     0%\ntests/test_http_parser.py                  957    957     50      0     0%\ntests/test_http_writer.py                  182    182     10      0     0%\ntests/test_imports.py                       31     31      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                    747    747     22      0     0%\ntests/test_multipart_helpers.py            446    446      0      0     0%\ntests/test_payload.py                       94     94      0      0     0%\ntests/test_proxy.py                        285    285      0      0     0%\ntests/test_proxy_functional.py             473    473     22      0     0%\ntests/test_pytest_plugin.py                 27     27      0      0     0%\ntests/test_resolver.py                     176    176     12      0     0%\ntests/test_route_def.py                    210    210      0      0     0%\ntests/test_run_app.py                      522    522     30      0     0%\ntests/test_streams.py                     1077   1077     40      0     0%\ntests/test_tcp_helpers.py                   52     52      2      0     0%\ntests/test_test_utils.py                   242    242      6      0     0%\ntests/test_tracing.py                       48     48      0      0     0%\ntests/test_urldispatch.py                  844    844     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              1547   1547     36      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           40     40      0      0     0%\ntests/test_web_response.py                 863    863      4      0     0%\ntests/test_web_runner.py                   146    146      4      0     0%\ntests/test_web_sendfile.py                  76     76      0      0     0%\ntests/test_web_sendfile_functional.py      634    634     18      0     0%\ntests/test_web_server.py                   160    160      0      0     0%\ntests/test_web_urldispatcher.py            306    306     14      0     0%\ntests/test_web_websocket.py                313    313      6      0     0%\ntests/test_web_websocket_functional.py     542    542     16      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              68     68      0      0     0%\ntests/test_worker.py                       193    193      4      0     0%\n--------------------------------------------------------------------------\nTOTAL                                    32236  28180   4114    197    12%\n\n============================= slowest 10 durations =============================\n0.05s call     r2e_tests/test_1.py::test_terminate_with_closed_loop[pyloop]\n0.02s teardown r2e_tests/test_1.py::test_basicauth_from_empty_netrc[pyloop-]\n0.02s teardown r2e_tests/test_1.py::test_bad_version[pyloop]\n0.02s teardown r2e_tests/test_1.py::test_data_stream_exc[pyloop]\n0.02s teardown r2e_tests/test_1.py::test_data_stream_exc_chain[pyloop]\n0.02s teardown r2e_tests/test_1.py::test_terminate_with_closed_loop[pyloop]\n0.02s teardown r2e_tests/test_1.py::test_file_upload_not_chunked_seek[pyloop]\n0.02s teardown r2e_tests/test_1.py::test_file_upload_force_chunked[pyloop]\n0.01s teardown r2e_tests/test_1.py::test_data_file[pyloop]\n0.01s teardown r2e_tests/test_1.py::test_content_encoding_dont_set_headers_if_no_body[pyloop]\n=========================== short test summary info ============================\nPASSED r2e_tests/test_1.py::test_method1[pyloop]\nPASSED r2e_tests/test_1.py::test_method2[pyloop]\nPASSED r2e_tests/test_1.py::test_method3[pyloop]\nPASSED r2e_tests/test_1.py::test_method_invalid[pyloop]\nPASSED r2e_tests/test_1.py::test_version_1_0[pyloop]\nPASSED r2e_tests/test_1.py::test_version_default[pyloop]\nPASSED r2e_tests/test_1.py::test_request_info[pyloop]\nPASSED r2e_tests/test_1.py::test_request_info_with_fragment[pyloop]\nPASSED r2e_tests/test_1.py::test_version_err[pyloop]\nPASSED r2e_tests/test_1.py::test_keep_alive[pyloop]\nPASSED r2e_tests/test_1.py::test_host_port_default_http[pyloop]\nPASSED r2e_tests/test_1.py::test_host_port_default_https[pyloop]\nPASSED r2e_tests/test_1.py::test_host_port_nondefault_http[pyloop]\nPASSED r2e_tests/test_1.py::test_host_port_nondefault_https[pyloop]\nPASSED r2e_tests/test_1.py::test_host_port_default_ws[pyloop]\nPASSED r2e_tests/test_1.py::test_host_port_default_wss[pyloop]\nPASSED r2e_tests/test_1.py::test_host_port_nondefault_ws[pyloop]\nPASSED r2e_tests/test_1.py::test_host_port_nondefault_wss[pyloop]\nPASSED r2e_tests/test_1.py::test_host_port_none_port[pyloop]\nPASSED r2e_tests/test_1.py::test_host_port_err[pyloop]\nPASSED r2e_tests/test_1.py::test_hostname_err[pyloop]\nPASSED r2e_tests/test_1.py::test_host_header_host_first[pyloop]\nPASSED r2e_tests/test_1.py::test_host_header_host_without_port[pyloop]\nPASSED r2e_tests/test_1.py::test_host_header_host_with_default_port[pyloop]\nPASSED r2e_tests/test_1.py::test_host_header_host_with_nondefault_port[pyloop]\nPASSED r2e_tests/test_1.py::test_host_header_host_idna_encode[pyloop]\nPASSED r2e_tests/test_1.py::test_host_header_host_unicode[pyloop]\nPASSED r2e_tests/test_1.py::test_host_header_explicit_host[pyloop]\nPASSED r2e_tests/test_1.py::test_host_header_explicit_host_with_port[pyloop]\nPASSED r2e_tests/test_1.py::test_host_header_ipv4[pyloop]\nPASSED r2e_tests/test_1.py::test_host_header_ipv6[pyloop]\nPASSED r2e_tests/test_1.py::test_host_header_ipv4_with_port[pyloop]\nPASSED r2e_tests/test_1.py::test_host_header_ipv6_with_port[pyloop]\nPASSED r2e_tests/test_1.py::test_default_loop[pyloop]\nPASSED r2e_tests/test_1.py::test_host_header_fqdn[pyloop-dot only at the end]\nPASSED r2e_tests/test_1.py::test_host_header_fqdn[pyloop-single dot]\nPASSED r2e_tests/test_1.py::test_host_header_fqdn[pyloop-single dot with port]\nPASSED r2e_tests/test_1.py::test_host_header_fqdn[pyloop-multiple dots with port]\nPASSED r2e_tests/test_1.py::test_host_header_fqdn[pyloop-explicit host header]\nPASSED r2e_tests/test_1.py::test_host_header_fqdn[pyloop-https]\nPASSED r2e_tests/test_1.py::test_host_header_fqdn[pyloop-only dots]\nPASSED r2e_tests/test_1.py::test_host_header_fqdn[pyloop-single dot with port idna]\nPASSED r2e_tests/test_1.py::test_default_headers_useragent[pyloop]\nPASSED r2e_tests/test_1.py::test_default_headers_useragent_custom[pyloop]\nPASSED r2e_tests/test_1.py::test_skip_default_useragent_header[pyloop]\nPASSED r2e_tests/test_1.py::test_headers[pyloop]\nPASSED r2e_tests/test_1.py::test_headers_list[pyloop]\nPASSED r2e_tests/test_1.py::test_headers_default[pyloop]\nPASSED r2e_tests/test_1.py::test_invalid_url[pyloop]\nPASSED r2e_tests/test_1.py::test_no_path[pyloop]\nPASSED r2e_tests/test_1.py::test_ipv6_default_http_port[pyloop]\nPASSED r2e_tests/test_1.py::test_ipv6_default_https_port[pyloop]\nPASSED r2e_tests/test_1.py::test_ipv6_nondefault_http_port[pyloop]\nPASSED r2e_tests/test_1.py::test_ipv6_nondefault_https_port[pyloop]\nPASSED r2e_tests/test_1.py::test_basic_auth[pyloop]\nPASSED r2e_tests/test_1.py::test_basic_auth_utf8[pyloop]\nPASSED r2e_tests/test_1.py::test_basic_auth_tuple_forbidden[pyloop]\nPASSED r2e_tests/test_1.py::test_basic_auth_from_url[pyloop]\nPASSED r2e_tests/test_1.py::test_basic_auth_from_url_overridden[pyloop]\nPASSED r2e_tests/test_1.py::test_path_is_not_double_encoded1[pyloop]\nPASSED r2e_tests/test_1.py::test_path_is_not_double_encoded2[pyloop]\nPASSED r2e_tests/test_1.py::test_path_is_not_double_encoded3[pyloop]\nPASSED r2e_tests/test_1.py::test_path_safe_chars_preserved[pyloop]\nPASSED r2e_tests/test_1.py::test_params_are_added_before_fragment1[pyloop]\nPASSED r2e_tests/test_1.py::test_params_are_added_before_fragment2[pyloop]\nPASSED r2e_tests/test_1.py::test_path_not_contain_fragment1[pyloop]\nPASSED r2e_tests/test_1.py::test_path_not_contain_fragment2[pyloop]\nPASSED r2e_tests/test_1.py::test_cookies[pyloop]\nPASSED r2e_tests/test_1.py::test_cookies_is_quoted_with_special_characters[pyloop]\nPASSED r2e_tests/test_1.py::test_cookies_merge_with_headers[pyloop]\nPASSED r2e_tests/test_1.py::test_unicode_get1[pyloop]\nPASSED r2e_tests/test_1.py::test_unicode_get2[pyloop]\nPASSED r2e_tests/test_1.py::test_unicode_get3[pyloop]\nPASSED r2e_tests/test_1.py::test_unicode_get4[pyloop]\nPASSED r2e_tests/test_1.py::test_query_multivalued_param[pyloop]\nPASSED r2e_tests/test_1.py::test_query_str_param[pyloop]\nPASSED r2e_tests/test_1.py::test_query_bytes_param_raises[pyloop]\nPASSED r2e_tests/test_1.py::test_query_str_param_is_not_encoded[pyloop]\nPASSED r2e_tests/test_1.py::test_params_update_path_and_url[pyloop]\nPASSED r2e_tests/test_1.py::test_params_empty_path_and_url[pyloop]\nPASSED r2e_tests/test_1.py::test_gen_netloc_all[pyloop]\nPASSED r2e_tests/test_1.py::test_gen_netloc_no_port[pyloop]\nPASSED r2e_tests/test_1.py::test_connection_header[pyloop]\nPASSED r2e_tests/test_1.py::test_no_content_length[pyloop]\nPASSED r2e_tests/test_1.py::test_no_content_length_head[pyloop]\nPASSED r2e_tests/test_1.py::test_content_type_auto_header_get[pyloop]\nPASSED r2e_tests/test_1.py::test_content_type_auto_header_form[pyloop]\nPASSED r2e_tests/test_1.py::test_content_type_auto_header_bytes[pyloop]\nPASSED r2e_tests/test_1.py::test_content_type_skip_auto_header_bytes[pyloop]\nPASSED r2e_tests/test_1.py::test_content_type_skip_auto_header_form[pyloop]\nPASSED r2e_tests/test_1.py::test_content_type_auto_header_content_length_no_skip[pyloop]\nPASSED r2e_tests/test_1.py::test_urlencoded_formdata_charset[pyloop]\nPASSED r2e_tests/test_1.py::test_post_data[pyloop]\nPASSED r2e_tests/test_1.py::test_pass_falsy_data[pyloop]\nPASSED r2e_tests/test_1.py::test_pass_falsy_data_file[pyloop]\nPASSED r2e_tests/test_1.py::test_get_with_data[pyloop]\nPASSED r2e_tests/test_1.py::test_bytes_data[pyloop]\nPASSED r2e_tests/test_1.py::test_content_encoding[pyloop]\nPASSED r2e_tests/test_1.py::test_content_encoding_dont_set_headers_if_no_body[pyloop]\nPASSED r2e_tests/test_1.py::test_content_encoding_header[pyloop]\nPASSED r2e_tests/test_1.py::test_compress_and_content_encoding[pyloop]\nPASSED r2e_tests/test_1.py::test_chunked[pyloop]\nPASSED r2e_tests/test_1.py::test_chunked2[pyloop]\nPASSED r2e_tests/test_1.py::test_chunked_explicit[pyloop]\nPASSED r2e_tests/test_1.py::test_chunked_length[pyloop]\nPASSED r2e_tests/test_1.py::test_chunked_transfer_encoding[pyloop]\nPASSED r2e_tests/test_1.py::test_precompressed_data_stays_intact[pyloop]\nPASSED r2e_tests/test_1.py::test_expect100[pyloop]\nPASSED r2e_tests/test_1.py::test_expect_100_continue_header[pyloop]\nPASSED r2e_tests/test_1.py::test_data_stream[pyloop]\nPASSED r2e_tests/test_1.py::test_data_stream_deprecated[pyloop]\nPASSED r2e_tests/test_1.py::test_data_file[pyloop]\nPASSED r2e_tests/test_1.py::test_data_stream_exc[pyloop]\nPASSED r2e_tests/test_1.py::test_data_stream_exc_chain[pyloop]\nPASSED r2e_tests/test_1.py::test_data_stream_continue[pyloop]\nPASSED r2e_tests/test_1.py::test_data_continue[pyloop]\nPASSED r2e_tests/test_1.py::test_close[pyloop]\nPASSED r2e_tests/test_1.py::test_custom_response_class[pyloop]\nPASSED r2e_tests/test_1.py::test_oserror_on_write_bytes[pyloop]\nPASSED r2e_tests/test_1.py::test_terminate[pyloop]\nPASSED r2e_tests/test_1.py::test_terminate_with_closed_loop[pyloop]\nPASSED r2e_tests/test_1.py::test_terminate_without_writer[pyloop]\nPASSED r2e_tests/test_1.py::test_custom_req_rep[pyloop]\nPASSED r2e_tests/test_1.py::test_verify_ssl_false_with_ssl_context[pyloop]\nPASSED r2e_tests/test_1.py::test_bad_fingerprint[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_loose_cookies_types[pyloop]\nPASSED r2e_tests/test_1.py::test_gen_default_accept_encoding[False-gzip, deflate]\nPASSED r2e_tests/test_1.py::test_gen_default_accept_encoding[True-gzip, deflate, br]\nPASSED r2e_tests/test_1.py::test_basicauth_from_netrc_present[pyloop-machine example.com login username password pass\\n-expected_auth0]\nPASSED r2e_tests/test_1.py::test_basicauth_from_netrc_present_untrusted_env[pyloop-machine example.com login username password pass\\n]\nPASSED r2e_tests/test_1.py::test_basicauth_from_empty_netrc[pyloop-]\nFAILED r2e_tests/test_1.py::test_file_upload_not_chunked[pyloop] - FileNotFou...\nFAILED r2e_tests/test_1.py::test_file_upload_not_chunked_seek[pyloop] - FileN...\nFAILED r2e_tests/test_1.py::test_file_upload_force_chunked[pyloop] - FileNotF...\nFAILED r2e_tests/test_1.py::test_bad_version[pyloop] - Failed: DID NOT RAISE ...\n======================== 4 failed, 133 passed in 6.26s =========================\n",
    "old_commit_res_stderr": ""
}
CHANGES/7835.bugfix aiohttp/client_reqrep.py tests/test_client_request.py
We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
[ISSUE]
**Title:** ClientRequest Accepts Arbitrary Sequence Types for HTTP Version, Causing Unexpected Behavior

**Description:**
When creating a `ClientRequest`, setting the `version` attribute to an arbitrary sequence allows the inclusion of malformed data, which can lead to unexpected behavior or potential security vulnerabilities.

**Example Buggy Code:**
```python
from aiohttp.client_reqrep import ClientRequest
from aiohttp import URL

async def create_request(loop, conn):
    req = ClientRequest(
        "GET",
        URL("http://example.com"),
        loop=loop,
        headers={"Connection": "Close"},
        version=("1", "1\r\nInjected-Header: not allowed"),
    )
    await req.send(conn)
```
In this example, the `version` is set to a tuple containing a newline character and an injected header. This malformed version string can manipulate the HTTP response headers unexpectedly.

**Expected Behavior:**
Assigning an invalid or improperly formatted `version` should raise an error, preventing the creation of malformed HTTP requests and ensuring that only valid HTTP versions are used.

**Actual Behavior:**
No error is raised when an arbitrary or improperly formatted sequence is assigned to `version`, allowing the construction of potentially malformed HTTP requests.

[/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/client_reqrep.py
import asyncio
import codecs
import contextlib
import functools
import io
import re
import sys
import traceback
import warnings
from hashlib import md5, sha1, sha256
from http.cookies import CookieError, Morsel, SimpleCookie
from types import MappingProxyType, TracebackType
from typing import (
    TYPE_CHECKING,
    Any,
    Callable,
    Dict,
    Iterable,
    List,
    Literal,
    Mapping,
    Optional,
    Tuple,
    Type,
    Union,
    cast,
)

import attr
from multidict import CIMultiDict, CIMultiDictProxy, MultiDict, MultiDictProxy
from yarl import URL

from . import hdrs, helpers, http, multipart, payload
from .abc import AbstractStreamWriter
from .client_exceptions import (
    ClientConnectionError,
    ClientOSError,
    ClientResponseError,
    ContentTypeError,
    InvalidURL,
    ServerFingerprintMismatch,
)
from .compression_utils import HAS_BROTLI
from .formdata import FormData
from .helpers import (
    BaseTimerContext,
    BasicAuth,
    HeadersMixin,
    TimerNoop,
    basicauth_from_netrc,
    netrc_from_env,
    noop,
    reify,
    set_result,
)
from .http import (
    SERVER_SOFTWARE,
    HttpVersion,
    HttpVersion10,
    HttpVersion11,
    StreamWriter,
)
from .log import client_logger
from .streams import StreamReader
from .typedefs import (
    DEFAULT_JSON_DECODER,
    JSONDecoder,
    LooseCookies,
    LooseHeaders,
    RawHeaders,
)

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


__all__ = ("ClientRequest", "ClientResponse", "RequestInfo", "Fingerprint")


if TYPE_CHECKING:  # pragma: no cover
    from .client import ClientSession
    from .connector import Connection
    from .tracing import Trace


_CONTAINS_CONTROL_CHAR_RE = re.compile(r"[^-!#$%&'*+.^_`|~0-9a-zA-Z]")
json_re = re.compile(r"^application/(?:[\w.+-]+?\+)?json")


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


@attr.s(auto_attribs=True, frozen=True, slots=True)
class ContentDisposition:
    type: Optional[str]
    parameters: "MappingProxyType[str, str]"
    filename: Optional[str]


@attr.s(auto_attribs=True, frozen=True, slots=True)
class RequestInfo:
    url: URL
    method: str
    headers: "CIMultiDictProxy[str]"
    real_url: URL = attr.ib()

    @real_url.default
    def real_url_default(self) -> URL:
        return self.url


class Fingerprint:
    HASHFUNC_BY_DIGESTLEN = {
        16: md5,
        20: sha1,
        32: sha256,
    }

    def __init__(self, fingerprint: bytes) -> None:
        digestlen = len(fingerprint)
        hashfunc = self.HASHFUNC_BY_DIGESTLEN.get(digestlen)
        if not hashfunc:
            raise ValueError("fingerprint has invalid length")
        elif hashfunc is md5 or hashfunc is sha1:
            raise ValueError(
                "md5 and sha1 are insecure and " "not supported. Use sha256."
            )
        self._hashfunc = hashfunc
        self._fingerprint = fingerprint

    @property
    def fingerprint(self) -> bytes:
        return self._fingerprint

    def check(self, transport: asyncio.Transport) -> None:
        if not transport.get_extra_info("sslcontext"):
            return
        sslobj = transport.get_extra_info("ssl_object")
        cert = sslobj.getpeercert(binary_form=True)
        got = self._hashfunc(cert).digest()
        if got != self._fingerprint:
            host, port, *_ = transport.get_extra_info("peername")
            raise ServerFingerprintMismatch(self._fingerprint, got, host, port)


if ssl is not None:
    SSL_ALLOWED_TYPES = (ssl.SSLContext, bool, Fingerprint, type(None))
else:  # pragma: no cover
    SSL_ALLOWED_TYPES = type(None)


def _merge_ssl_params(
    ssl: Union["SSLContext", Literal[False], Fingerprint, None],
    verify_ssl: Optional[bool],
    ssl_context: Optional["SSLContext"],
    fingerprint: Optional[bytes],
) -> Union["SSLContext", Literal[False], Fingerprint, None]:
    if verify_ssl is not None and not verify_ssl:
        warnings.warn(
            "verify_ssl is deprecated, use ssl=False instead",
            DeprecationWarning,
            stacklevel=3,
        )
        if ssl is not None:
            raise ValueError(
                "verify_ssl, ssl_context, fingerprint and ssl "
                "parameters are mutually exclusive"
            )
        else:
            ssl = False
    if ssl_context is not None:
        warnings.warn(
            "ssl_context is deprecated, use ssl=context instead",
            DeprecationWarning,
            stacklevel=3,
        )
        if ssl is not None:
            raise ValueError(
                "verify_ssl, ssl_context, fingerprint and ssl "
                "parameters are mutually exclusive"
            )
        else:
            ssl = ssl_context
    if fingerprint is not None:
        warnings.warn(
            "fingerprint is deprecated, " "use ssl=Fingerprint(fingerprint) instead",
            DeprecationWarning,
            stacklevel=3,
        )
        if ssl is not None:
            raise ValueError(
                "verify_ssl, ssl_context, fingerprint and ssl "
                "parameters are mutually exclusive"
            )
        else:
            ssl = Fingerprint(fingerprint)
    if not isinstance(ssl, SSL_ALLOWED_TYPES):
        raise TypeError(
            "ssl should be SSLContext, bool, Fingerprint or None, "
            "got {!r} instead.".format(ssl)
        )
    return ssl


@attr.s(auto_attribs=True, slots=True, frozen=True)
class ConnectionKey:
    # the key should contain an information about used proxy / TLS
    # to prevent reusing wrong connections from a pool
    host: str
    port: Optional[int]
    is_ssl: bool
    ssl: Union[SSLContext, None, Literal[False], Fingerprint]
    proxy: Optional[URL]
    proxy_auth: Optional[BasicAuth]
    proxy_headers_hash: Optional[int]  # hash(CIMultiDict)


def _is_expected_content_type(
    response_content_type: str, expected_content_type: str
) -> bool:
    if expected_content_type == "application/json":
        return json_re.match(response_content_type) is not None
    return expected_content_type in response_content_type


class ClientRequest:
    GET_METHODS = {
        hdrs.METH_GET,
        hdrs.METH_HEAD,
        hdrs.METH_OPTIONS,
        hdrs.METH_TRACE,
    }
    POST_METHODS = {hdrs.METH_PATCH, hdrs.METH_POST, hdrs.METH_PUT}
    ALL_METHODS = GET_METHODS.union(POST_METHODS).union({hdrs.METH_DELETE})

    DEFAULT_HEADERS = {
        hdrs.ACCEPT: "*/*",
        hdrs.ACCEPT_ENCODING: _gen_default_accept_encoding(),
    }

    body = b""
    auth = None
    response = None

    __writer = None  # async task for streaming data
    _continue = None  # waiter future for '100 Continue' response

    # N.B.
    # Adding __del__ method with self._writer closing doesn't make sense
    # because _writer is instance method, thus it keeps a reference to self.
    # Until writer has finished finalizer will not be called.

    def __init__(
        self,
        method: str,
        url: URL,
        *,
        params: Optional[Mapping[str, str]] = None,
        headers: Optional[LooseHeaders] = None,
        skip_auto_headers: Iterable[str] = frozenset(),
        data: Any = None,
        cookies: Optional[LooseCookies] = None,
        auth: Optional[BasicAuth] = None,
        version: http.HttpVersion = http.HttpVersion11,
        compress: Optional[str] = None,
        chunked: Optional[bool] = None,
        expect100: bool = False,
        loop: Optional[asyncio.AbstractEventLoop] = None,
        response_class: Optional[Type["ClientResponse"]] = None,
        proxy: Optional[URL] = None,
        proxy_auth: Optional[BasicAuth] = None,
        timer: Optional[BaseTimerContext] = None,
        session: Optional["ClientSession"] = None,
        ssl: Union[SSLContext, Literal[False], Fingerprint, None] = None,
        proxy_headers: Optional[LooseHeaders] = None,
        traces: Optional[List["Trace"]] = None,
        trust_env: bool = False,
        server_hostname: Optional[str] = None,
    ):
        if loop is None:
            loop = asyncio.get_event_loop()

        match = _CONTAINS_CONTROL_CHAR_RE.search(method)
        if match:
            raise ValueError(
                f"Method cannot contain non-token characters {method!r} "
                "(found at least {match.group()!r})"
            )

        assert isinstance(url, URL), url
        assert isinstance(proxy, (URL, type(None))), proxy
        # FIXME: session is None in tests only, need to fix tests
        # assert session is not None
        self._session = cast("ClientSession", session)
        if params:
            q = MultiDict(url.query)
            url2 = url.with_query(params)
            q.extend(url2.query)
            url = url.with_query(q)
        self.original_url = url
        self.url = url.with_fragment(None)
        self.method = method.upper()
        self.chunked = chunked
        self.compress = compress
        self.loop = loop
        self.length = None
        if response_class is None:
            real_response_class = ClientResponse
        else:
            real_response_class = response_class
        self.response_class: Type[ClientResponse] = real_response_class
        self._timer = timer if timer is not None else TimerNoop()
        self._ssl = ssl
        self.server_hostname = server_hostname

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

        self.update_version(version)
        self.update_host(url)
        self.update_headers(headers)
        self.update_auto_headers(skip_auto_headers)
        self.update_cookies(cookies)
        self.update_content_encoding(data)
        self.update_auth(auth, trust_env)
        self.update_proxy(proxy, proxy_auth, proxy_headers)

        self.update_body_from_data(data)
        if data is not None or self.method not in self.GET_METHODS:
            self.update_transfer_encoding()
        self.update_expect_continue(expect100)
        if traces is None:
            traces = []
        self._traces = traces

    def __reset_writer(self, _: object = None) -> None:
        self.__writer = None

    @property
    def _writer(self) -> Optional["asyncio.Task[None]"]:
        return self.__writer

    @_writer.setter
    def _writer(self, writer: Optional["asyncio.Task[None]"]) -> None:
        if self.__writer is not None:
            self.__writer.remove_done_callback(self.__reset_writer)
        self.__writer = writer
        if writer is not None:
            writer.add_done_callback(self.__reset_writer)

    def is_ssl(self) -> bool:
        return self.url.scheme in ("https", "wss")

    @property
    def ssl(self) -> Union["SSLContext", None, Literal[False], Fingerprint]:
        return self._ssl

    @property
    def connection_key(self) -> ConnectionKey:
        proxy_headers = self.proxy_headers
        if proxy_headers:
            h: Optional[int] = hash(tuple((k, v) for k, v in proxy_headers.items()))
        else:
            h = None
        return ConnectionKey(
            self.host,
            self.port,
            self.is_ssl(),
            self.ssl,
            self.proxy,
            self.proxy_auth,
            h,
        )

    @property
    def host(self) -> str:
        ret = self.url.raw_host
        assert ret is not None
        return ret

    @property
    def port(self) -> Optional[int]:
        return self.url.port

    @property
    def request_info(self) -> RequestInfo:
        headers: CIMultiDictProxy[str] = CIMultiDictProxy(self.headers)
        return RequestInfo(self.url, self.method, headers, self.original_url)

    def update_host(self, url: URL) -> None:
        """Update destination host, port and connection type (ssl)."""
        # get host/port
        if not url.raw_host:
            raise InvalidURL(url)

        # basic auth info
        username, password = url.user, url.password
        if username:
            self.auth = helpers.BasicAuth(username, password or "")

    def update_version(self, version: Union[http.HttpVersion, str]) -> None:
        """Convert request version to two elements tuple.

        parser HTTP version '1.1' => (1, 1)
        """
        if isinstance(version, str):
            v = [part.strip() for part in version.split(".", 1)]
            try:
                version = http.HttpVersion(int(v[0]), int(v[1]))
            except ValueError:
                raise ValueError(
                    f"Can not parse http version number: {version}"
                ) from None
        self.version = version

    def update_headers(self, headers: Optional[LooseHeaders]) -> None:
        """Update request headers."""
        self.headers: CIMultiDict[str] = CIMultiDict()

        # add host
        netloc = cast(str, self.url.raw_host)
        if helpers.is_ipv6_address(netloc):
            netloc = f"[{netloc}]"
        # See https://github.com/aio-libs/aiohttp/issues/3636.
        netloc = netloc.rstrip(".")
        if self.url.port is not None and not self.url.is_default_port():
            netloc += ":" + str(self.url.port)
        self.headers[hdrs.HOST] = netloc

        if headers:
            if isinstance(headers, (dict, MultiDictProxy, MultiDict)):
                headers = headers.items()  # type: ignore[assignment]

            for key, value in headers:  # type: ignore[misc]
                # A special case for Host header
                if key.lower() == "host":
                    self.headers[key] = value
                else:
                    self.headers.add(key, value)

    def update_auto_headers(self, skip_auto_headers: Iterable[str]) -> None:
        self.skip_auto_headers = CIMultiDict(
            (hdr, None) for hdr in sorted(skip_auto_headers)
        )
        used_headers = self.headers.copy()
        used_headers.extend(self.skip_auto_headers)  # type: ignore[arg-type]

        for hdr, val in self.DEFAULT_HEADERS.items():
            if hdr not in used_headers:
                self.headers.add(hdr, val)

        if hdrs.USER_AGENT not in used_headers:
            self.headers[hdrs.USER_AGENT] = SERVER_SOFTWARE

    def update_cookies(self, cookies: Optional[LooseCookies]) -> None:
        """Update request cookies header."""
        if not cookies:
            return

        c = SimpleCookie()
        if hdrs.COOKIE in self.headers:
            c.load(self.headers.get(hdrs.COOKIE, ""))
            del self.headers[hdrs.COOKIE]

        if isinstance(cookies, Mapping):
            iter_cookies = cookies.items()
        else:
            iter_cookies = cookies  # type: ignore[assignment]
        for name, value in iter_cookies:
            if isinstance(value, Morsel):
                # Preserve coded_value
                mrsl_val = value.get(value.key, Morsel())
                mrsl_val.set(value.key, value.value, value.coded_value)
                c[name] = mrsl_val
            else:
                c[name] = value  # type: ignore[assignment]

        self.headers[hdrs.COOKIE] = c.output(header="", sep=";").strip()

    def update_content_encoding(self, data: Any) -> None:
        """Set request content encoding."""
        if data is None:
            return

        enc = self.headers.get(hdrs.CONTENT_ENCODING, "").lower()
        if enc:
            if self.compress:
                raise ValueError(
                    "compress can not be set " "if Content-Encoding header is set"
                )
        elif self.compress:
            if not isinstance(self.compress, str):
                self.compress = "deflate"
            self.headers[hdrs.CONTENT_ENCODING] = self.compress
            self.chunked = True  # enable chunked, no need to deal with length

    def update_transfer_encoding(self) -> None:
        """Analyze transfer-encoding header."""
        te = self.headers.get(hdrs.TRANSFER_ENCODING, "").lower()

        if "chunked" in te:
            if self.chunked:
                raise ValueError(
                    "chunked can not be set "
                    'if "Transfer-Encoding: chunked" header is set'
                )

        elif self.chunked:
            if hdrs.CONTENT_LENGTH in self.headers:
                raise ValueError(
                    "chunked can not be set " "if Content-Length header is set"
                )

            self.headers[hdrs.TRANSFER_ENCODING] = "chunked"
        else:
            if hdrs.CONTENT_LENGTH not in self.headers:
                self.headers[hdrs.CONTENT_LENGTH] = str(len(self.body))

    def update_auth(self, auth: Optional[BasicAuth], trust_env: bool = False) -> None:
        """Set basic auth."""
        if auth is None:
            auth = self.auth
        if auth is None and trust_env and self.url.host is not None:
            netrc_obj = netrc_from_env()
            with contextlib.suppress(LookupError):
                auth = basicauth_from_netrc(netrc_obj, self.url.host)
        if auth is None:
            return

        if not isinstance(auth, helpers.BasicAuth):
            raise TypeError("BasicAuth() tuple is required instead")

        self.headers[hdrs.AUTHORIZATION] = auth.encode()

    def update_body_from_data(self, body: Any) -> None:
        if body is None:
            return

        # FormData
        if isinstance(body, FormData):
            body = body()

        try:
            body = payload.PAYLOAD_REGISTRY.get(body, disposition=None)
        except payload.LookupError:
            body = FormData(body)()

        self.body = body

        # enable chunked encoding if needed
        if not self.chunked:
            if hdrs.CONTENT_LENGTH not in self.headers:
                size = body.size
                if size is None:
                    self.chunked = True
                else:
                    if hdrs.CONTENT_LENGTH not in self.headers:
                        self.headers[hdrs.CONTENT_LENGTH] = str(size)

        # copy payload headers
        assert body.headers
        for (key, value) in body.headers.items():
            if key in self.headers:
                continue
            if key in self.skip_auto_headers:
                continue
            self.headers[key] = value

    def update_expect_continue(self, expect: bool = False) -> None:
        if expect:
            self.headers[hdrs.EXPECT] = "100-continue"
        elif self.headers.get(hdrs.EXPECT, "").lower() == "100-continue":
            expect = True

        if expect:
            self._continue = self.loop.create_future()

    def update_proxy(
        self,
        proxy: Optional[URL],
        proxy_auth: Optional[BasicAuth],
        proxy_headers: Optional[LooseHeaders],
    ) -> None:
        if proxy_auth and not isinstance(proxy_auth, helpers.BasicAuth):
            raise ValueError("proxy_auth must be None or BasicAuth() tuple")
        self.proxy = proxy
        self.proxy_auth = proxy_auth
        self.proxy_headers = proxy_headers

    def keep_alive(self) -> bool:
        if self.version < HttpVersion10:
            # keep alive not supported at all
            return False
        if self.version == HttpVersion10:
            if self.headers.get(hdrs.CONNECTION) == "keep-alive":
                return True
            else:  # no headers means we close for Http 1.0
                return False
        elif self.headers.get(hdrs.CONNECTION) == "close":
            return False

        return True

    async def write_bytes(
        self, writer: AbstractStreamWriter, conn: "Connection"
    ) -> None:
        """Support coroutines that yields bytes objects."""
        # 100 response
        if self._continue is not None:
            try:
                await writer.drain()
                await self._continue
            except asyncio.CancelledError:
                return

        protocol = conn.protocol
        assert protocol is not None
        try:
            if isinstance(self.body, payload.Payload):
                await self.body.write(writer)
            else:
                if isinstance(self.body, (bytes, bytearray)):
                    self.body = (self.body,)  # type: ignore[assignment]

                for chunk in self.body:
                    await writer.write(chunk)  # type: ignore[arg-type]
        except OSError as exc:
            if exc.errno is None and isinstance(exc, asyncio.TimeoutError):
                protocol.set_exception(exc)
            else:
                new_exc = ClientOSError(
                    exc.errno, "Can not write request body for %s" % self.url
                )
                new_exc.__context__ = exc
                new_exc.__cause__ = exc
                protocol.set_exception(new_exc)
        except asyncio.CancelledError:
            await writer.write_eof()
        except Exception as exc:
            protocol.set_exception(exc)
        else:
            await writer.write_eof()
            protocol.start_timeout()

    async def send(self, conn: "Connection") -> "ClientResponse":
        # Specify request target:
        # - CONNECT request must send authority form URI
        # - not CONNECT proxy must send absolute form URI
        # - most common is origin form URI
        if self.method == hdrs.METH_CONNECT:
            connect_host = self.url.raw_host
            assert connect_host is not None
            if helpers.is_ipv6_address(connect_host):
                connect_host = f"[{connect_host}]"
            path = f"{connect_host}:{self.url.port}"
        elif self.proxy and not self.is_ssl():
            path = str(self.url)
        else:
            path = self.url.raw_path
            if self.url.raw_query_string:
                path += "?" + self.url.raw_query_string

        protocol = conn.protocol
        assert protocol is not None
        writer = StreamWriter(
            protocol,
            self.loop,
            on_chunk_sent=functools.partial(
                self._on_chunk_request_sent, self.method, self.url
            ),
            on_headers_sent=functools.partial(
                self._on_headers_request_sent, self.method, self.url
            ),
        )

        if self.compress:
            writer.enable_compression(self.compress)

        if self.chunked is not None:
            writer.enable_chunking()

        # set default content-type
        if (
            self.method in self.POST_METHODS
            and hdrs.CONTENT_TYPE not in self.skip_auto_headers
            and hdrs.CONTENT_TYPE not in self.headers
        ):
            self.headers[hdrs.CONTENT_TYPE] = "application/octet-stream"

        # set the connection header
        connection = self.headers.get(hdrs.CONNECTION)
        if not connection:
            if self.keep_alive():
                if self.version == HttpVersion10:
                    connection = "keep-alive"
            else:
                if self.version == HttpVersion11:
                    connection = "close"

        if connection is not None:
            self.headers[hdrs.CONNECTION] = connection

        # status + headers
        status_line = "{0} {1} HTTP/{2[0]}.{2[1]}".format(
            self.method, path, self.version
        )
        await writer.write_headers(status_line, self.headers)

        self._writer = self.loop.create_task(self.write_bytes(writer, conn))

        response_class = self.response_class
        assert response_class is not None
        self.response = response_class(
            self.method,
            self.original_url,
            writer=self._writer,
            continue100=self._continue,
            timer=self._timer,
            request_info=self.request_info,
            traces=self._traces,
            loop=self.loop,
            session=self._session,
        )
        return self.response

    async def close(self) -> None:
        if self._writer is not None:
            with contextlib.suppress(asyncio.CancelledError):
                await self._writer

    def terminate(self) -> None:
        if self._writer is not None:
            if not self.loop.is_closed():
                self._writer.cancel()
            self._writer.remove_done_callback(self.__reset_writer)
            self._writer = None

    async def _on_chunk_request_sent(self, method: str, url: URL, chunk: bytes) -> None:
        for trace in self._traces:
            await trace.send_request_chunk_sent(method, url, chunk)

    async def _on_headers_request_sent(
        self, method: str, url: URL, headers: "CIMultiDict[str]"
    ) -> None:
        for trace in self._traces:
            await trace.send_request_headers(method, url, headers)


class ClientResponse(HeadersMixin):

    # Some of these attributes are None when created,
    # but will be set by the start() method.
    # As the end user will likely never see the None values, we cheat the types below.
    # from the Status-Line of the response
    version: Optional[HttpVersion] = None  # HTTP-Version
    status: int = None  # type: ignore[assignment] # Status-Code
    reason: Optional[str] = None  # Reason-Phrase

    content: StreamReader = None  # type: ignore[assignment]  # Payload stream
    _headers: CIMultiDictProxy[str] = None  # type: ignore[assignment]
    _raw_headers: RawHeaders = None  # type: ignore[assignment]

    _connection = None  # current connection
    _source_traceback: Optional[traceback.StackSummary] = None
    # set up by ClientRequest after ClientResponse object creation
    # post-init stage allows to not change ctor signature
    _closed = True  # to allow __del__ for non-initialized properly response
    _released = False
    __writer = None

    def __init__(
        self,
        method: str,
        url: URL,
        *,
        writer: "asyncio.Task[None]",
        continue100: Optional["asyncio.Future[bool]"],
        timer: BaseTimerContext,
        request_info: RequestInfo,
        traces: List["Trace"],
        loop: asyncio.AbstractEventLoop,
        session: "ClientSession",
    ) -> None:
        assert isinstance(url, URL)

        self.method = method
        self.cookies = SimpleCookie()

        self._real_url = url
        self._url = url.with_fragment(None)
        self._body: Any = None
        self._writer: Optional[asyncio.Task[None]] = writer
        self._continue = continue100  # None by default
        self._closed = True
        self._history: Tuple[ClientResponse, ...] = ()
        self._request_info = request_info
        self._timer = timer if timer is not None else TimerNoop()
        self._cache: Dict[str, Any] = {}
        self._traces = traces
        self._loop = loop
        # store a reference to session #1985
        self._session: Optional[ClientSession] = session
        # Save reference to _resolve_charset, so that get_encoding() will still
        # work after the response has finished reading the body.
        if session is None:
            # TODO: Fix session=None in tests (see ClientRequest.__init__).
            self._resolve_charset: Callable[
                ["ClientResponse", bytes], str
            ] = lambda *_: "utf-8"
        else:
            self._resolve_charset = session._resolve_charset
        if loop.get_debug():
            self._source_traceback = traceback.extract_stack(sys._getframe(1))

    def __reset_writer(self, _: object = None) -> None:
        self.__writer = None

    @property
    def _writer(self) -> Optional["asyncio.Task[None]"]:
        return self.__writer

    @_writer.setter
    def _writer(self, writer: Optional["asyncio.Task[None]"]) -> None:
        if self.__writer is not None:
            self.__writer.remove_done_callback(self.__reset_writer)
        self.__writer = writer
        if writer is not None:
            writer.add_done_callback(self.__reset_writer)

    @reify
    def url(self) -> URL:
        return self._url

    @reify
    def url_obj(self) -> URL:
        warnings.warn("Deprecated, use .url #1654", DeprecationWarning, stacklevel=2)
        return self._url

    @reify
    def real_url(self) -> URL:
        return self._real_url

    @reify
    def host(self) -> str:
        assert self._url.host is not None
        return self._url.host

    @reify
    def headers(self) -> "CIMultiDictProxy[str]":
        return self._headers

    @reify
    def raw_headers(self) -> RawHeaders:
        return self._raw_headers

    @reify
    def request_info(self) -> RequestInfo:
        return self._request_info

    @reify
    def content_disposition(self) -> Optional[ContentDisposition]:
        raw = self._headers.get(hdrs.CONTENT_DISPOSITION)
        if raw is None:
            return None
        disposition_type, params_dct = multipart.parse_content_disposition(raw)
        params = MappingProxyType(params_dct)
        filename = multipart.content_disposition_filename(params)
        return ContentDisposition(disposition_type, params, filename)

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

        if self._connection is not None:
            self._connection.release()
            self._cleanup_writer()

            if self._loop.get_debug():
                kwargs = {"source": self}
                _warnings.warn(f"Unclosed response {self!r}", ResourceWarning, **kwargs)
                context = {"client_response": self, "message": "Unclosed response"}
                if self._source_traceback:
                    context["source_traceback"] = self._source_traceback
                self._loop.call_exception_handler(context)

    def __repr__(self) -> str:
        out = io.StringIO()
        ascii_encodable_url = str(self.url)
        if self.reason:
            ascii_encodable_reason = self.reason.encode(
                "ascii", "backslashreplace"
            ).decode("ascii")
        else:
            ascii_encodable_reason = "None"
        print(
            "<ClientResponse({}) [{} {}]>".format(
                ascii_encodable_url, self.status, ascii_encodable_reason
            ),
            file=out,
        )
        print(self.headers, file=out)
        return out.getvalue()

    @property
    def connection(self) -> Optional["Connection"]:
        return self._connection

    @reify
    def history(self) -> Tuple["ClientResponse", ...]:
        """A sequence of of responses, if redirects occurred."""
        return self._history

    @reify
    def links(self) -> "MultiDictProxy[MultiDictProxy[Union[str, URL]]]":
        links_str = ", ".join(self.headers.getall("link", []))

        if not links_str:
            return MultiDictProxy(MultiDict())

        links: MultiDict[MultiDictProxy[Union[str, URL]]] = MultiDict()

        for val in re.split(r",(?=\s*<)", links_str):
            match = re.match(r"\s*<(.*)>(.*)", val)
            if match is None:  # pragma: no cover
                # the check exists to suppress mypy error
                continue
            url, params_str = match.groups()
            params = params_str.split(";")[1:]

            link: MultiDict[Union[str, URL]] = MultiDict()

            for param in params:
                match = re.match(r"^\s*(\S*)\s*=\s*(['\"]?)(.*?)(\2)\s*$", param, re.M)
                if match is None:  # pragma: no cover
                    # the check exists to suppress mypy error
                    continue
                key, _, value, _ = match.groups()

                link.add(key, value)

            key = link.get("rel", url)

            link.add("url", self.url.join(URL(url)))

            links.add(str(key), MultiDictProxy(link))

        return MultiDictProxy(links)

    async def start(self, connection: "Connection") -> "ClientResponse":
        """Start response processing."""
        self._closed = False
        self._protocol = connection.protocol
        self._connection = connection

        with self._timer:
            while True:
                # read response
                try:
                    protocol = self._protocol
                    message, payload = await protocol.read()  # type: ignore[union-attr]
                except http.HttpProcessingError as exc:
                    raise ClientResponseError(
                        self.request_info,
                        self.history,
                        status=exc.code,
                        message=exc.message,
                        headers=exc.headers,
                    ) from exc

                if message.code < 100 or message.code > 199 or message.code == 101:
                    break

                if self._continue is not None:
                    set_result(self._continue, True)
                    self._continue = None

        # payload eof handler
        payload.on_eof(self._response_eof)

        # response status
        self.version = message.version
        self.status = message.code
        self.reason = message.reason

        # headers
        self._headers = message.headers  # type is CIMultiDictProxy
        self._raw_headers = message.raw_headers  # type is Tuple[bytes, bytes]

        # payload
        self.content = payload

        # cookies
        for hdr in self.headers.getall(hdrs.SET_COOKIE, ()):
            try:
                self.cookies.load(hdr)
            except CookieError as exc:
                client_logger.warning("Can not load response cookies: %s", exc)
        return self

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

        if self._connection is not None:
            # websocket, protocol could be None because
            # connection could be detached
            if (
                self._connection.protocol is not None
                and self._connection.protocol.upgraded
            ):
                return

            self._release_connection()

        self._closed = True
        self._cleanup_writer()

    @property
    def closed(self) -> bool:
        return self._closed

    def close(self) -> None:
        if not self._released:
            self._notify_content()

        self._closed = True
        if self._loop is None or self._loop.is_closed():
            return

        self._cleanup_writer()
        self._release_connection()

    def release(self) -> Any:
        if not self._released:
            self._notify_content()

        self._closed = True

        self._cleanup_writer()
        self._release_connection()
        return noop()

    @property
    def ok(self) -> bool:
        """Returns ``True`` if ``status`` is less than ``400``, ``False`` if not.

        This is **not** a check for ``200 OK`` but a check that the response
        status is under 400.
        """
        return 400 > self.status

    def raise_for_status(self) -> None:
        if not self.ok:
            # reason should always be not None for a started response
            assert self.reason is not None
            self.release()
            raise ClientResponseError(
                self.request_info,
                self.history,
                status=self.status,
                message=self.reason,
                headers=self.headers,
            )

    def _release_connection(self) -> None:
        if self._connection is not None:
            if self._writer is None:
                self._connection.release()
                self._connection = None
            else:
                self._writer.add_done_callback(lambda f: self._release_connection())

    async def _wait_released(self) -> None:
        if self._writer is not None:
            await self._writer
        self._release_connection()

    def _cleanup_writer(self) -> None:
        if self._writer is not None:
            self._writer.cancel()
        self._session = None

    def _notify_content(self) -> None:
        content = self.content
        if content and content.exception() is None:
            content.set_exception(ClientConnectionError("Connection closed"))
        self._released = True

    async def wait_for_close(self) -> None:
        if self._writer is not None:
            await self._writer
        self.release()

    async def read(self) -> bytes:
        """Read response payload."""
        if self._body is None:
            try:
                self._body = await self.content.read()
                for trace in self._traces:
                    await trace.send_response_chunk_received(
                        self.method, self.url, self._body
                    )
            except BaseException:
                self.close()
                raise
        elif self._released:  # Response explicitly released
            raise ClientConnectionError("Connection closed")

        await self._wait_released()  # Underlying connection released
        return self._body  # type: ignore[no-any-return]

    def get_encoding(self) -> str:
        ctype = self.headers.get(hdrs.CONTENT_TYPE, "").lower()
        mimetype = helpers.parse_mimetype(ctype)

        encoding = mimetype.parameters.get("charset")
        if encoding:
            with contextlib.suppress(LookupError):
                return codecs.lookup(encoding).name

        if mimetype.type == "application" and (
            mimetype.subtype == "json" or mimetype.subtype == "rdap"
        ):
            # RFC 7159 states that the default encoding is UTF-8.
            # RFC 7483 defines application/rdap+json
            return "utf-8"

        if self._body is None:
            raise RuntimeError(
                "Cannot compute fallback encoding of a not yet read body"
            )

        return self._resolve_charset(self, self._body)

    async def text(self, encoding: Optional[str] = None, errors: str = "strict") -> str:
        """Read response payload and decode."""
        if self._body is None:
            await self.read()

        if encoding is None:
            encoding = self.get_encoding()

        return self._body.decode(  # type: ignore[no-any-return,union-attr]
            encoding, errors=errors
        )

    async def json(
        self,
        *,
        encoding: Optional[str] = None,
        loads: JSONDecoder = DEFAULT_JSON_DECODER,
        content_type: Optional[str] = "application/json",
    ) -> Any:
        """Read and decodes JSON response."""
        if self._body is None:
            await self.read()

        if content_type:
            ctype = self.headers.get(hdrs.CONTENT_TYPE, "").lower()
            if not _is_expected_content_type(ctype, content_type):
                raise ContentTypeError(
                    self.request_info,
                    self.history,
                    message=(
                        "Attempt to decode JSON with " "unexpected mimetype: %s" % ctype
                    ),
                    headers=self.headers,
                )

        stripped = self._body.strip()  # type: ignore[union-attr]
        if not stripped:
            return None

        if encoding is None:
            encoding = self.get_encoding()

        return loads(stripped.decode(encoding))

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

    async def __aexit__(
        self,
        exc_type: Optional[Type[BaseException]],
        exc_val: Optional[BaseException],
        exc_tb: Optional[TracebackType],
    ) -> None:
        # similar to _RequestContextManager, we do not need to check
        # for exceptions, response object can close connection
        # if state is broken
        self.release()
        await self.wait_for_close()

```
--- 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:** ClientRequest Accepts Arbitrary Sequence Types for HTTP Version, Causing Unexpected Behavior

**Description:**
When creating a `ClientRequest`, setting the `version` attribute to an arbitrary sequence allows the inclusion of malformed data, which can lead to unexpected behavior or potential security vulnerabilities.

**Example Buggy Code:**
```python
from aiohttp.client_reqrep import ClientRequest
from aiohttp import URL

async def create_request(loop, conn):
    req = ClientRequest(
        "GET",
        URL("http://example.com"),
        loop=loop,
        headers={"Connection": "Close"},
        version=("1", "1\r\nInjected-Header: not allowed"),
    )
    await req.send(conn)
```
In this example, the `version` is set to a tuple containing a newline character and an injected header. This malformed version string can manipulate the HTTP response headers unexpectedly.

**Expected Behavior:**
Assigning an invalid or improperly formatted `version` should raise an error, preventing the creation of malformed HTTP requests and ensuring that only valid HTTP versions are used.

**Actual Behavior:**
No error is raised when an arbitrary or improperly formatted sequence is assigned to `version`, allowing the construction of potentially malformed HTTP requests.

[/ISSUE]
{
    "test_method1[pyloop]": "PASSED",
    "test_method2[pyloop]": "PASSED",
    "test_method3[pyloop]": "PASSED",
    "test_method_invalid[pyloop]": "PASSED",
    "test_version_1_0[pyloop]": "PASSED",
    "test_version_default[pyloop]": "PASSED",
    "test_request_info[pyloop]": "PASSED",
    "test_request_info_with_fragment[pyloop]": "PASSED",
    "test_version_err[pyloop]": "PASSED",
    "test_keep_alive[pyloop]": "PASSED",
    "test_host_port_default_http[pyloop]": "PASSED",
    "test_host_port_default_https[pyloop]": "PASSED",
    "test_host_port_nondefault_http[pyloop]": "PASSED",
    "test_host_port_nondefault_https[pyloop]": "PASSED",
    "test_host_port_default_ws[pyloop]": "PASSED",
    "test_host_port_default_wss[pyloop]": "PASSED",
    "test_host_port_nondefault_ws[pyloop]": "PASSED",
    "test_host_port_nondefault_wss[pyloop]": "PASSED",
    "test_host_port_none_port[pyloop]": "PASSED",
    "test_host_port_err[pyloop]": "PASSED",
    "test_hostname_err[pyloop]": "PASSED",
    "test_host_header_host_first[pyloop]": "PASSED",
    "test_host_header_host_without_port[pyloop]": "PASSED",
    "test_host_header_host_with_default_port[pyloop]": "PASSED",
    "test_host_header_host_with_nondefault_port[pyloop]": "PASSED",
    "test_host_header_host_idna_encode[pyloop]": "PASSED",
    "test_host_header_host_unicode[pyloop]": "PASSED",
    "test_host_header_explicit_host[pyloop]": "PASSED",
    "test_host_header_explicit_host_with_port[pyloop]": "PASSED",
    "test_host_header_ipv4[pyloop]": "PASSED",
    "test_host_header_ipv6[pyloop]": "PASSED",
    "test_host_header_ipv4_with_port[pyloop]": "PASSED",
    "test_host_header_ipv6_with_port[pyloop]": "PASSED",
    "test_default_loop[pyloop]": "PASSED",
    "test_host_header_fqdn[pyloop-dot only at the end]": "PASSED",
    "test_host_header_fqdn[pyloop-single dot]": "PASSED",
    "test_host_header_fqdn[pyloop-single dot with port]": "PASSED",
    "test_host_header_fqdn[pyloop-multiple dots with port]": "PASSED",
    "test_host_header_fqdn[pyloop-explicit host header]": "PASSED",
    "test_host_header_fqdn[pyloop-https]": "PASSED",
    "test_host_header_fqdn[pyloop-only dots]": "PASSED",
    "test_host_header_fqdn[pyloop-single dot with port idna]": "PASSED",
    "test_default_headers_useragent[pyloop]": "PASSED",
    "test_default_headers_useragent_custom[pyloop]": "PASSED",
    "test_skip_default_useragent_header[pyloop]": "PASSED",
    "test_headers[pyloop]": "PASSED",
    "test_headers_list[pyloop]": "PASSED",
    "test_headers_default[pyloop]": "PASSED",
    "test_invalid_url[pyloop]": "PASSED",
    "test_no_path[pyloop]": "PASSED",
    "test_ipv6_default_http_port[pyloop]": "PASSED",
    "test_ipv6_default_https_port[pyloop]": "PASSED",
    "test_ipv6_nondefault_http_port[pyloop]": "PASSED",
    "test_ipv6_nondefault_https_port[pyloop]": "PASSED",
    "test_basic_auth[pyloop]": "PASSED",
    "test_basic_auth_utf8[pyloop]": "PASSED",
    "test_basic_auth_tuple_forbidden[pyloop]": "PASSED",
    "test_basic_auth_from_url[pyloop]": "PASSED",
    "test_basic_auth_from_url_overridden[pyloop]": "PASSED",
    "test_path_is_not_double_encoded1[pyloop]": "PASSED",
    "test_path_is_not_double_encoded2[pyloop]": "PASSED",
    "test_path_is_not_double_encoded3[pyloop]": "PASSED",
    "test_path_safe_chars_preserved[pyloop]": "PASSED",
    "test_params_are_added_before_fragment1[pyloop]": "PASSED",
    "test_params_are_added_before_fragment2[pyloop]": "PASSED",
    "test_path_not_contain_fragment1[pyloop]": "PASSED",
    "test_path_not_contain_fragment2[pyloop]": "PASSED",
    "test_cookies[pyloop]": "PASSED",
    "test_cookies_is_quoted_with_special_characters[pyloop]": "PASSED",
    "test_cookies_merge_with_headers[pyloop]": "PASSED",
    "test_unicode_get1[pyloop]": "PASSED",
    "test_unicode_get2[pyloop]": "PASSED",
    "test_unicode_get3[pyloop]": "PASSED",
    "test_unicode_get4[pyloop]": "PASSED",
    "test_query_multivalued_param[pyloop]": "PASSED",
    "test_query_str_param[pyloop]": "PASSED",
    "test_query_bytes_param_raises[pyloop]": "PASSED",
    "test_query_str_param_is_not_encoded[pyloop]": "PASSED",
    "test_params_update_path_and_url[pyloop]": "PASSED",
    "test_params_empty_path_and_url[pyloop]": "PASSED",
    "test_gen_netloc_all[pyloop]": "PASSED",
    "test_gen_netloc_no_port[pyloop]": "PASSED",
    "test_connection_header[pyloop]": "PASSED",
    "test_no_content_length[pyloop]": "PASSED",
    "test_no_content_length_head[pyloop]": "PASSED",
    "test_content_type_auto_header_get[pyloop]": "PASSED",
    "test_content_type_auto_header_form[pyloop]": "PASSED",
    "test_content_type_auto_header_bytes[pyloop]": "PASSED",
    "test_content_type_skip_auto_header_bytes[pyloop]": "PASSED",
    "test_content_type_skip_auto_header_form[pyloop]": "PASSED",
    "test_content_type_auto_header_content_length_no_skip[pyloop]": "PASSED",
    "test_urlencoded_formdata_charset[pyloop]": "PASSED",
    "test_post_data[pyloop]": "PASSED",
    "test_pass_falsy_data[pyloop]": "PASSED",
    "test_pass_falsy_data_file[pyloop]": "PASSED",
    "test_get_with_data[pyloop]": "PASSED",
    "test_bytes_data[pyloop]": "PASSED",
    "test_content_encoding[pyloop]": "PASSED",
    "test_content_encoding_dont_set_headers_if_no_body[pyloop]": "PASSED",
    "test_content_encoding_header[pyloop]": "PASSED",
    "test_compress_and_content_encoding[pyloop]": "PASSED",
    "test_chunked[pyloop]": "PASSED",
    "test_chunked2[pyloop]": "PASSED",
    "test_chunked_explicit[pyloop]": "PASSED",
    "test_chunked_length[pyloop]": "PASSED",
    "test_chunked_transfer_encoding[pyloop]": "PASSED",
    "test_precompressed_data_stays_intact[pyloop]": "PASSED",
    "test_expect100[pyloop]": "PASSED",
    "test_expect_100_continue_header[pyloop]": "PASSED",
    "test_data_stream[pyloop]": "PASSED",
    "test_data_stream_deprecated[pyloop]": "PASSED",
    "test_data_file[pyloop]": "PASSED",
    "test_data_stream_exc[pyloop]": "PASSED",
    "test_data_stream_exc_chain[pyloop]": "PASSED",
    "test_data_stream_continue[pyloop]": "PASSED",
    "test_data_continue[pyloop]": "PASSED",
    "test_close[pyloop]": "PASSED",
    "test_bad_version[pyloop]": "PASSED",
    "test_custom_response_class[pyloop]": "PASSED",
    "test_oserror_on_write_bytes[pyloop]": "PASSED",
    "test_terminate[pyloop]": "PASSED",
    "test_terminate_with_closed_loop[pyloop]": "PASSED",
    "test_terminate_without_writer[pyloop]": "PASSED",
    "test_custom_req_rep[pyloop]": "PASSED",
    "test_verify_ssl_false_with_ssl_context[pyloop]": "PASSED",
    "test_bad_fingerprint[pyloop]": "PASSED",
    "test_insecure_fingerprint_md5[pyloop]": "PASSED",
    "test_insecure_fingerprint_sha1[pyloop]": "PASSED",
    "test_loose_cookies_types[pyloop]": "PASSED",
    "test_gen_default_accept_encoding[False-gzip, deflate]": "PASSED",
    "test_gen_default_accept_encoding[True-gzip, deflate, br]": "PASSED",
    "test_basicauth_from_netrc_present[pyloop-machine example.com login username password pass\\n-expected_auth0]": "PASSED",
    "test_basicauth_from_netrc_present_untrusted_env[pyloop-machine example.com login username password pass\\n]": "PASSED",
    "test_basicauth_from_empty_netrc[pyloop-]": "PASSED",
    "test_file_upload_not_chunked[pyloop]": "FAILED",
    "test_file_upload_not_chunked_seek[pyloop]": "FAILED",
    "test_file_upload_force_chunked[pyloop]": "FAILED"
}
diff --git a/aiohttp/client_reqrep.py b/aiohttp/client_reqrep.py
index 851ab220..4cea7466 100644
--- a/aiohttp/client_reqrep.py
+++ b/aiohttp/client_reqrep.py
@@ -706,8 +706,8 @@ class ClientRequest:
             self.headers[hdrs.CONNECTION] = connection
 
         # status + headers
-        status_line = "{0} {1} HTTP/{2[0]}.{2[1]}".format(
-            self.method, path, self.version
+        status_line = "{0} {1} HTTP/{v.major}.{v.minor}".format(
+            self.method, path, v=self.version
         )
         await writer.write_headers(status_line, self.headers)
 

{"aiohttp/client_reqrep.py": "import asyncio\nimport codecs\nimport contextlib\nimport functools\nimport io\nimport re\nimport sys\nimport traceback\nimport warnings\nfrom hashlib import md5, sha1, sha256\nfrom http.cookies import CookieError, Morsel, SimpleCookie\nfrom types import MappingProxyType, TracebackType\nfrom typing import (\n    TYPE_CHECKING,\n    Any,\n    Callable,\n    Dict,\n    Iterable,\n    List,\n    Literal,\n    Mapping,\n    Optional,\n    Tuple,\n    Type,\n    Union,\n    cast,\n)\n\nimport attr\nfrom multidict import CIMultiDict, CIMultiDictProxy, MultiDict, MultiDictProxy\nfrom yarl import URL\n\nfrom . import hdrs, helpers, http, multipart, payload\nfrom .abc import AbstractStreamWriter\nfrom .client_exceptions import (\n    ClientConnectionError,\n    ClientOSError,\n    ClientResponseError,\n    ContentTypeError,\n    InvalidURL,\n    ServerFingerprintMismatch,\n)\nfrom .compression_utils import HAS_BROTLI\nfrom .formdata import FormData\nfrom .helpers import (\n    BaseTimerContext,\n    BasicAuth,\n    HeadersMixin,\n    TimerNoop,\n    basicauth_from_netrc,\n    netrc_from_env,\n    noop,\n    reify,\n    set_result,\n)\nfrom .http import (\n    SERVER_SOFTWARE,\n    HttpVersion,\n    HttpVersion10,\n    HttpVersion11,\n    StreamWriter,\n)\nfrom .log import client_logger\nfrom .streams import StreamReader\nfrom .typedefs import (\n    DEFAULT_JSON_DECODER,\n    JSONDecoder,\n    LooseCookies,\n    LooseHeaders,\n    RawHeaders,\n)\n\ntry:\n    import ssl\n    from ssl import SSLContext\nexcept ImportError:  # pragma: no cover\n    ssl = None  # type: ignore[assignment]\n    SSLContext = object  # type: ignore[misc,assignment]\n\n\n__all__ = (\"ClientRequest\", \"ClientResponse\", \"RequestInfo\", \"Fingerprint\")\n\n\nif TYPE_CHECKING:  # pragma: no cover\n    from .client import ClientSession\n    from .connector import Connection\n    from .tracing import Trace\n\n\n_CONTAINS_CONTROL_CHAR_RE = re.compile(r\"[^-!#$%&'*+.^_`|~0-9a-zA-Z]\")\njson_re = re.compile(r\"^application/(?:[\\w.+-]+?\\+)?json\")\n\n\ndef _gen_default_accept_encoding() -> str:\n    return \"gzip, deflate, br\" if HAS_BROTLI else \"gzip, deflate\"\n\n\n@attr.s(auto_attribs=True, frozen=True, slots=True)\nclass ContentDisposition:\n    type: Optional[str]\n    parameters: \"MappingProxyType[str, str]\"\n    filename: Optional[str]\n\n\n@attr.s(auto_attribs=True, frozen=True, slots=True)\nclass RequestInfo:\n    url: URL\n    method: str\n    headers: \"CIMultiDictProxy[str]\"\n    real_url: URL = attr.ib()\n\n    @real_url.default\n    def real_url_default(self) -> URL:\n        return self.url\n\n\nclass Fingerprint:\n    HASHFUNC_BY_DIGESTLEN = {\n        16: md5,\n        20: sha1,\n        32: sha256,\n    }\n\n    def __init__(self, fingerprint: bytes) -> None:\n        digestlen = len(fingerprint)\n        hashfunc = self.HASHFUNC_BY_DIGESTLEN.get(digestlen)\n        if not hashfunc:\n            raise ValueError(\"fingerprint has invalid length\")\n        elif hashfunc is md5 or hashfunc is sha1:\n            raise ValueError(\n                \"md5 and sha1 are insecure and \" \"not supported. Use sha256.\"\n            )\n        self._hashfunc = hashfunc\n        self._fingerprint = fingerprint\n\n    @property\n    def fingerprint(self) -> bytes:\n        return self._fingerprint\n\n    def check(self, transport: asyncio.Transport) -> None:\n        if not transport.get_extra_info(\"sslcontext\"):\n            return\n        sslobj = transport.get_extra_info(\"ssl_object\")\n        cert = sslobj.getpeercert(binary_form=True)\n        got = self._hashfunc(cert).digest()\n        if got != self._fingerprint:\n            host, port, *_ = transport.get_extra_info(\"peername\")\n            raise ServerFingerprintMismatch(self._fingerprint, got, host, port)\n\n\nif ssl is not None:\n    SSL_ALLOWED_TYPES = (ssl.SSLContext, bool, Fingerprint, type(None))\nelse:  # pragma: no cover\n    SSL_ALLOWED_TYPES = type(None)\n\n\ndef _merge_ssl_params(\n    ssl: Union[\"SSLContext\", Literal[False], Fingerprint, None],\n    verify_ssl: Optional[bool],\n    ssl_context: Optional[\"SSLContext\"],\n    fingerprint: Optional[bytes],\n) -> Union[\"SSLContext\", Literal[False], Fingerprint, None]:\n    if verify_ssl is not None and not verify_ssl:\n        warnings.warn(\n            \"verify_ssl is deprecated, use ssl=False instead\",\n            DeprecationWarning,\n            stacklevel=3,\n        )\n        if ssl is not None:\n            raise ValueError(\n                \"verify_ssl, ssl_context, fingerprint and ssl \"\n                \"parameters are mutually exclusive\"\n            )\n        else:\n            ssl = False\n    if ssl_context is not None:\n        warnings.warn(\n            \"ssl_context is deprecated, use ssl=context instead\",\n            DeprecationWarning,\n            stacklevel=3,\n        )\n        if ssl is not None:\n            raise ValueError(\n                \"verify_ssl, ssl_context, fingerprint and ssl \"\n                \"parameters are mutually exclusive\"\n            )\n        else:\n            ssl = ssl_context\n    if fingerprint is not None:\n        warnings.warn(\n            \"fingerprint is deprecated, \" \"use ssl=Fingerprint(fingerprint) instead\",\n            DeprecationWarning,\n            stacklevel=3,\n        )\n        if ssl is not None:\n            raise ValueError(\n                \"verify_ssl, ssl_context, fingerprint and ssl \"\n                \"parameters are mutually exclusive\"\n            )\n        else:\n            ssl = Fingerprint(fingerprint)\n    if not isinstance(ssl, SSL_ALLOWED_TYPES):\n        raise TypeError(\n            \"ssl should be SSLContext, bool, Fingerprint or None, \"\n            \"got {!r} instead.\".format(ssl)\n        )\n    return ssl\n\n\n@attr.s(auto_attribs=True, slots=True, frozen=True)\nclass ConnectionKey:\n    # the key should contain an information about used proxy / TLS\n    # to prevent reusing wrong connections from a pool\n    host: str\n    port: Optional[int]\n    is_ssl: bool\n    ssl: Union[SSLContext, None, Literal[False], Fingerprint]\n    proxy: Optional[URL]\n    proxy_auth: Optional[BasicAuth]\n    proxy_headers_hash: Optional[int]  # hash(CIMultiDict)\n\n\ndef _is_expected_content_type(\n    response_content_type: str, expected_content_type: str\n) -> bool:\n    if expected_content_type == \"application/json\":\n        return json_re.match(response_content_type) is not None\n    return expected_content_type in response_content_type\n\n\nclass ClientRequest:\n    GET_METHODS = {\n        hdrs.METH_GET,\n        hdrs.METH_HEAD,\n        hdrs.METH_OPTIONS,\n        hdrs.METH_TRACE,\n    }\n    POST_METHODS = {hdrs.METH_PATCH, hdrs.METH_POST, hdrs.METH_PUT}\n    ALL_METHODS = GET_METHODS.union(POST_METHODS).union({hdrs.METH_DELETE})\n\n    DEFAULT_HEADERS = {\n        hdrs.ACCEPT: \"*/*\",\n        hdrs.ACCEPT_ENCODING: _gen_default_accept_encoding(),\n    }\n\n    body = b\"\"\n    auth = None\n    response = None\n\n    __writer = None  # async task for streaming data\n    _continue = None  # waiter future for '100 Continue' response\n\n    # N.B.\n    # Adding __del__ method with self._writer closing doesn't make sense\n    # because _writer is instance method, thus it keeps a reference to self.\n    # Until writer has finished finalizer will not be called.\n\n    def __init__(\n        self,\n        method: str,\n        url: URL,\n        *,\n        params: Optional[Mapping[str, str]] = None,\n        headers: Optional[LooseHeaders] = None,\n        skip_auto_headers: Iterable[str] = frozenset(),\n        data: Any = None,\n        cookies: Optional[LooseCookies] = None,\n        auth: Optional[BasicAuth] = None,\n        version: http.HttpVersion = http.HttpVersion11,\n        compress: Optional[str] = None,\n        chunked: Optional[bool] = None,\n        expect100: bool = False,\n        loop: Optional[asyncio.AbstractEventLoop] = None,\n        response_class: Optional[Type[\"ClientResponse\"]] = None,\n        proxy: Optional[URL] = None,\n        proxy_auth: Optional[BasicAuth] = None,\n        timer: Optional[BaseTimerContext] = None,\n        session: Optional[\"ClientSession\"] = None,\n        ssl: Union[SSLContext, Literal[False], Fingerprint, None] = None,\n        proxy_headers: Optional[LooseHeaders] = None,\n        traces: Optional[List[\"Trace\"]] = None,\n        trust_env: bool = False,\n        server_hostname: Optional[str] = None,\n    ):\n        if loop is None:\n            loop = asyncio.get_event_loop()\n\n        match = _CONTAINS_CONTROL_CHAR_RE.search(method)\n        if match:\n            raise ValueError(\n                f\"Method cannot contain non-token characters {method!r} \"\n                \"(found at least {match.group()!r})\"\n            )\n\n        assert isinstance(url, URL), url\n        assert isinstance(proxy, (URL, type(None))), proxy\n        # FIXME: session is None in tests only, need to fix tests\n        # assert session is not None\n        self._session = cast(\"ClientSession\", session)\n        if params:\n            q = MultiDict(url.query)\n            url2 = url.with_query(params)\n            q.extend(url2.query)\n            url = url.with_query(q)\n        self.original_url = url\n        self.url = url.with_fragment(None)\n        self.method = method.upper()\n        self.chunked = chunked\n        self.compress = compress\n        self.loop = loop\n        self.length = None\n        if response_class is None:\n            real_response_class = ClientResponse\n        else:\n            real_response_class = response_class\n        self.response_class: Type[ClientResponse] = real_response_class\n        self._timer = timer if timer is not None else TimerNoop()\n        self._ssl = ssl\n        self.server_hostname = server_hostname\n\n        if loop.get_debug():\n            self._source_traceback = traceback.extract_stack(sys._getframe(1))\n\n        self.update_version(version)\n        self.update_host(url)\n        self.update_headers(headers)\n        self.update_auto_headers(skip_auto_headers)\n        self.update_cookies(cookies)\n        self.update_content_encoding(data)\n        self.update_auth(auth, trust_env)\n        self.update_proxy(proxy, proxy_auth, proxy_headers)\n\n        self.update_body_from_data(data)\n        if data is not None or self.method not in self.GET_METHODS:\n            self.update_transfer_encoding()\n        self.update_expect_continue(expect100)\n        if traces is None:\n            traces = []\n        self._traces = traces\n\n    def __reset_writer(self, _: object = None) -> None:\n        self.__writer = None\n\n    @property\n    def _writer(self) -> Optional[\"asyncio.Task[None]\"]:\n        return self.__writer\n\n    @_writer.setter\n    def _writer(self, writer: Optional[\"asyncio.Task[None]\"]) -> None:\n        if self.__writer is not None:\n            self.__writer.remove_done_callback(self.__reset_writer)\n        self.__writer = writer\n        if writer is not None:\n            writer.add_done_callback(self.__reset_writer)\n\n    def is_ssl(self) -> bool:\n        return self.url.scheme in (\"https\", \"wss\")\n\n    @property\n    def ssl(self) -> Union[\"SSLContext\", None, Literal[False], Fingerprint]:\n        return self._ssl\n\n    @property\n    def connection_key(self) -> ConnectionKey:\n        proxy_headers = self.proxy_headers\n        if proxy_headers:\n            h: Optional[int] = hash(tuple((k, v) for k, v in proxy_headers.items()))\n        else:\n            h = None\n        return ConnectionKey(\n            self.host,\n            self.port,\n            self.is_ssl(),\n            self.ssl,\n            self.proxy,\n            self.proxy_auth,\n            h,\n        )\n\n    @property\n    def host(self) -> str:\n        ret = self.url.raw_host\n        assert ret is not None\n        return ret\n\n    @property\n    def port(self) -> Optional[int]:\n        return self.url.port\n\n    @property\n    def request_info(self) -> RequestInfo:\n        headers: CIMultiDictProxy[str] = CIMultiDictProxy(self.headers)\n        return RequestInfo(self.url, self.method, headers, self.original_url)\n\n    def update_host(self, url: URL) -> None:\n        \"\"\"Update destination host, port and connection type (ssl).\"\"\"\n        # get host/port\n        if not url.raw_host:\n            raise InvalidURL(url)\n\n        # basic auth info\n        username, password = url.user, url.password\n        if username:\n            self.auth = helpers.BasicAuth(username, password or \"\")\n\n    def update_version(self, version: Union[http.HttpVersion, str]) -> None:\n        \"\"\"Convert request version to two elements tuple.\n\n        parser HTTP version '1.1' => (1, 1)\n        \"\"\"\n        if isinstance(version, str):\n            v = [part.strip() for part in version.split(\".\", 1)]\n            try:\n                version = http.HttpVersion(int(v[0]), int(v[1]))\n            except ValueError:\n                raise ValueError(\n                    f\"Can not parse http version number: {version}\"\n                ) from None\n        self.version = version\n\n    def update_headers(self, headers: Optional[LooseHeaders]) -> None:\n        \"\"\"Update request headers.\"\"\"\n        self.headers: CIMultiDict[str] = CIMultiDict()\n\n        # add host\n        netloc = cast(str, self.url.raw_host)\n        if helpers.is_ipv6_address(netloc):\n            netloc = f\"[{netloc}]\"\n        # See https://github.com/aio-libs/aiohttp/issues/3636.\n        netloc = netloc.rstrip(\".\")\n        if self.url.port is not None and not self.url.is_default_port():\n            netloc += \":\" + str(self.url.port)\n        self.headers[hdrs.HOST] = netloc\n\n        if headers:\n            if isinstance(headers, (dict, MultiDictProxy, MultiDict)):\n                headers = headers.items()  # type: ignore[assignment]\n\n            for key, value in headers:  # type: ignore[misc]\n                # A special case for Host header\n                if key.lower() == \"host\":\n                    self.headers[key] = value\n                else:\n                    self.headers.add(key, value)\n\n    def update_auto_headers(self, skip_auto_headers: Iterable[str]) -> None:\n        self.skip_auto_headers = CIMultiDict(\n            (hdr, None) for hdr in sorted(skip_auto_headers)\n        )\n        used_headers = self.headers.copy()\n        used_headers.extend(self.skip_auto_headers)  # type: ignore[arg-type]\n\n        for hdr, val in self.DEFAULT_HEADERS.items():\n            if hdr not in used_headers:\n                self.headers.add(hdr, val)\n\n        if hdrs.USER_AGENT not in used_headers:\n            self.headers[hdrs.USER_AGENT] = SERVER_SOFTWARE\n\n    def update_cookies(self, cookies: Optional[LooseCookies]) -> None:\n        \"\"\"Update request cookies header.\"\"\"\n        if not cookies:\n            return\n\n        c = SimpleCookie()\n        if hdrs.COOKIE in self.headers:\n            c.load(self.headers.get(hdrs.COOKIE, \"\"))\n            del self.headers[hdrs.COOKIE]\n\n        if isinstance(cookies, Mapping):\n            iter_cookies = cookies.items()\n        else:\n            iter_cookies = cookies  # type: ignore[assignment]\n        for name, value in iter_cookies:\n            if isinstance(value, Morsel):\n                # Preserve coded_value\n                mrsl_val = value.get(value.key, Morsel())\n                mrsl_val.set(value.key, value.value, value.coded_value)\n                c[name] = mrsl_val\n            else:\n                c[name] = value  # type: ignore[assignment]\n\n        self.headers[hdrs.COOKIE] = c.output(header=\"\", sep=\";\").strip()\n\n    def update_content_encoding(self, data: Any) -> None:\n        \"\"\"Set request content encoding.\"\"\"\n        if data is None:\n            return\n\n        enc = self.headers.get(hdrs.CONTENT_ENCODING, \"\").lower()\n        if enc:\n            if self.compress:\n                raise ValueError(\n                    \"compress can not be set \" \"if Content-Encoding header is set\"\n                )\n        elif self.compress:\n            if not isinstance(self.compress, str):\n                self.compress = \"deflate\"\n            self.headers[hdrs.CONTENT_ENCODING] = self.compress\n            self.chunked = True  # enable chunked, no need to deal with length\n\n    def update_transfer_encoding(self) -> None:\n        \"\"\"Analyze transfer-encoding header.\"\"\"\n        te = self.headers.get(hdrs.TRANSFER_ENCODING, \"\").lower()\n\n        if \"chunked\" in te:\n            if self.chunked:\n                raise ValueError(\n                    \"chunked can not be set \"\n                    'if \"Transfer-Encoding: chunked\" header is set'\n                )\n\n        elif self.chunked:\n            if hdrs.CONTENT_LENGTH in self.headers:\n                raise ValueError(\n                    \"chunked can not be set \" \"if Content-Length header is set\"\n                )\n\n            self.headers[hdrs.TRANSFER_ENCODING] = \"chunked\"\n        else:\n            if hdrs.CONTENT_LENGTH not in self.headers:\n                self.headers[hdrs.CONTENT_LENGTH] = str(len(self.body))\n\n    def update_auth(self, auth: Optional[BasicAuth], trust_env: bool = False) -> None:\n        \"\"\"Set basic auth.\"\"\"\n        if auth is None:\n            auth = self.auth\n        if auth is None and trust_env and self.url.host is not None:\n            netrc_obj = netrc_from_env()\n            with contextlib.suppress(LookupError):\n                auth = basicauth_from_netrc(netrc_obj, self.url.host)\n        if auth is None:\n            return\n\n        if not isinstance(auth, helpers.BasicAuth):\n            raise TypeError(\"BasicAuth() tuple is required instead\")\n\n        self.headers[hdrs.AUTHORIZATION] = auth.encode()\n\n    def update_body_from_data(self, body: Any) -> None:\n        if body is None:\n            return\n\n        # FormData\n        if isinstance(body, FormData):\n            body = body()\n\n        try:\n            body = payload.PAYLOAD_REGISTRY.get(body, disposition=None)\n        except payload.LookupError:\n            body = FormData(body)()\n\n        self.body = body\n\n        # enable chunked encoding if needed\n        if not self.chunked:\n            if hdrs.CONTENT_LENGTH not in self.headers:\n                size = body.size\n                if size is None:\n                    self.chunked = True\n                else:\n                    if hdrs.CONTENT_LENGTH not in self.headers:\n                        self.headers[hdrs.CONTENT_LENGTH] = str(size)\n\n        # copy payload headers\n        assert body.headers\n        for (key, value) in body.headers.items():\n            if key in self.headers:\n                continue\n            if key in self.skip_auto_headers:\n                continue\n            self.headers[key] = value\n\n    def update_expect_continue(self, expect: bool = False) -> None:\n        if expect:\n            self.headers[hdrs.EXPECT] = \"100-continue\"\n        elif self.headers.get(hdrs.EXPECT, \"\").lower() == \"100-continue\":\n            expect = True\n\n        if expect:\n            self._continue = self.loop.create_future()\n\n    def update_proxy(\n        self,\n        proxy: Optional[URL],\n        proxy_auth: Optional[BasicAuth],\n        proxy_headers: Optional[LooseHeaders],\n    ) -> None:\n        if proxy_auth and not isinstance(proxy_auth, helpers.BasicAuth):\n            raise ValueError(\"proxy_auth must be None or BasicAuth() tuple\")\n        self.proxy = proxy\n        self.proxy_auth = proxy_auth\n        self.proxy_headers = proxy_headers\n\n    def keep_alive(self) -> bool:\n        if self.version < HttpVersion10:\n            # keep alive not supported at all\n            return False\n        if self.version == HttpVersion10:\n            if self.headers.get(hdrs.CONNECTION) == \"keep-alive\":\n                return True\n            else:  # no headers means we close for Http 1.0\n                return False\n        elif self.headers.get(hdrs.CONNECTION) == \"close\":\n            return False\n\n        return True\n\n    async def write_bytes(\n        self, writer: AbstractStreamWriter, conn: \"Connection\"\n    ) -> None:\n        \"\"\"Support coroutines that yields bytes objects.\"\"\"\n        # 100 response\n        if self._continue is not None:\n            try:\n                await writer.drain()\n                await self._continue\n            except asyncio.CancelledError:\n                return\n\n        protocol = conn.protocol\n        assert protocol is not None\n        try:\n            if isinstance(self.body, payload.Payload):\n                await self.body.write(writer)\n            else:\n                if isinstance(self.body, (bytes, bytearray)):\n                    self.body = (self.body,)  # type: ignore[assignment]\n\n                for chunk in self.body:\n                    await writer.write(chunk)  # type: ignore[arg-type]\n        except OSError as exc:\n            if exc.errno is None and isinstance(exc, asyncio.TimeoutError):\n                protocol.set_exception(exc)\n            else:\n                new_exc = ClientOSError(\n                    exc.errno, \"Can not write request body for %s\" % self.url\n                )\n                new_exc.__context__ = exc\n                new_exc.__cause__ = exc\n                protocol.set_exception(new_exc)\n        except asyncio.CancelledError:\n            await writer.write_eof()\n        except Exception as exc:\n            protocol.set_exception(exc)\n        else:\n            await writer.write_eof()\n            protocol.start_timeout()\n\n    async def send(self, conn: \"Connection\") -> \"ClientResponse\":\n        # Specify request target:\n        # - CONNECT request must send authority form URI\n        # - not CONNECT proxy must send absolute form URI\n        # - most common is origin form URI\n        if self.method == hdrs.METH_CONNECT:\n            connect_host = self.url.raw_host\n            assert connect_host is not None\n            if helpers.is_ipv6_address(connect_host):\n                connect_host = f\"[{connect_host}]\"\n            path = f\"{connect_host}:{self.url.port}\"\n        elif self.proxy and not self.is_ssl():\n            path = str(self.url)\n        else:\n            path = self.url.raw_path\n            if self.url.raw_query_string:\n                path += \"?\" + self.url.raw_query_string\n\n        protocol = conn.protocol\n        assert protocol is not None\n        writer = StreamWriter(\n            protocol,\n            self.loop,\n            on_chunk_sent=functools.partial(\n                self._on_chunk_request_sent, self.method, self.url\n            ),\n            on_headers_sent=functools.partial(\n                self._on_headers_request_sent, self.method, self.url\n            ),\n        )\n\n        if self.compress:\n            writer.enable_compression(self.compress)\n\n        if self.chunked is not None:\n            writer.enable_chunking()\n\n        # set default content-type\n        if (\n            self.method in self.POST_METHODS\n            and hdrs.CONTENT_TYPE not in self.skip_auto_headers\n            and hdrs.CONTENT_TYPE not in self.headers\n        ):\n            self.headers[hdrs.CONTENT_TYPE] = \"application/octet-stream\"\n\n        # set the connection header\n        connection = self.headers.get(hdrs.CONNECTION)\n        if not connection:\n            if self.keep_alive():\n                if self.version == HttpVersion10:\n                    connection = \"keep-alive\"\n            else:\n                if self.version == HttpVersion11:\n                    connection = \"close\"\n\n        if connection is not None:\n            self.headers[hdrs.CONNECTION] = connection\n\n        # status + headers\n        status_line = \"{0} {1} HTTP/{2[0]}.{2[1]}\".format(\n            self.method, path, self.version\n        )\n        await writer.write_headers(status_line, self.headers)\n\n        self._writer = self.loop.create_task(self.write_bytes(writer, conn))\n\n        response_class = self.response_class\n        assert response_class is not None\n        self.response = response_class(\n            self.method,\n            self.original_url,\n            writer=self._writer,\n            continue100=self._continue,\n            timer=self._timer,\n            request_info=self.request_info,\n            traces=self._traces,\n            loop=self.loop,\n            session=self._session,\n        )\n        return self.response\n\n    async def close(self) -> None:\n        if self._writer is not None:\n            with contextlib.suppress(asyncio.CancelledError):\n                await self._writer\n\n    def terminate(self) -> None:\n        if self._writer is not None:\n            if not self.loop.is_closed():\n                self._writer.cancel()\n            self._writer.remove_done_callback(self.__reset_writer)\n            self._writer = None\n\n    async def _on_chunk_request_sent(self, method: str, url: URL, chunk: bytes) -> None:\n        for trace in self._traces:\n            await trace.send_request_chunk_sent(method, url, chunk)\n\n    async def _on_headers_request_sent(\n        self, method: str, url: URL, headers: \"CIMultiDict[str]\"\n    ) -> None:\n        for trace in self._traces:\n            await trace.send_request_headers(method, url, headers)\n\n\nclass ClientResponse(HeadersMixin):\n\n    # Some of these attributes are None when created,\n    # but will be set by the start() method.\n    # As the end user will likely never see the None values, we cheat the types below.\n    # from the Status-Line of the response\n    version: Optional[HttpVersion] = None  # HTTP-Version\n    status: int = None  # type: ignore[assignment] # Status-Code\n    reason: Optional[str] = None  # Reason-Phrase\n\n    content: StreamReader = None  # type: ignore[assignment]  # Payload stream\n    _headers: CIMultiDictProxy[str] = None  # type: ignore[assignment]\n    _raw_headers: RawHeaders = None  # type: ignore[assignment]\n\n    _connection = None  # current connection\n    _source_traceback: Optional[traceback.StackSummary] = None\n    # set up by ClientRequest after ClientResponse object creation\n    # post-init stage allows to not change ctor signature\n    _closed = True  # to allow __del__ for non-initialized properly response\n    _released = False\n    __writer = None\n\n    def __init__(\n        self,\n        method: str,\n        url: URL,\n        *,\n        writer: \"asyncio.Task[None]\",\n        continue100: Optional[\"asyncio.Future[bool]\"],\n        timer: BaseTimerContext,\n        request_info: RequestInfo,\n        traces: List[\"Trace\"],\n        loop: asyncio.AbstractEventLoop,\n        session: \"ClientSession\",\n    ) -> None:\n        assert isinstance(url, URL)\n\n        self.method = method\n        self.cookies = SimpleCookie()\n\n        self._real_url = url\n        self._url = url.with_fragment(None)\n        self._body: Any = None\n        self._writer: Optional[asyncio.Task[None]] = writer\n        self._continue = continue100  # None by default\n        self._closed = True\n        self._history: Tuple[ClientResponse, ...] = ()\n        self._request_info = request_info\n        self._timer = timer if timer is not None else TimerNoop()\n        self._cache: Dict[str, Any] = {}\n        self._traces = traces\n        self._loop = loop\n        # store a reference to session #1985\n        self._session: Optional[ClientSession] = session\n        # Save reference to _resolve_charset, so that get_encoding() will still\n        # work after the response has finished reading the body.\n        if session is None:\n            # TODO: Fix session=None in tests (see ClientRequest.__init__).\n            self._resolve_charset: Callable[\n                [\"ClientResponse\", bytes], str\n            ] = lambda *_: \"utf-8\"\n        else:\n            self._resolve_charset = session._resolve_charset\n        if loop.get_debug():\n            self._source_traceback = traceback.extract_stack(sys._getframe(1))\n\n    def __reset_writer(self, _: object = None) -> None:\n        self.__writer = None\n\n    @property\n    def _writer(self) -> Optional[\"asyncio.Task[None]\"]:\n        return self.__writer\n\n    @_writer.setter\n    def _writer(self, writer: Optional[\"asyncio.Task[None]\"]) -> None:\n        if self.__writer is not None:\n            self.__writer.remove_done_callback(self.__reset_writer)\n        self.__writer = writer\n        if writer is not None:\n            writer.add_done_callback(self.__reset_writer)\n\n    @reify\n    def url(self) -> URL:\n        return self._url\n\n    @reify\n    def url_obj(self) -> URL:\n        warnings.warn(\"Deprecated, use .url #1654\", DeprecationWarning, stacklevel=2)\n        return self._url\n\n    @reify\n    def real_url(self) -> URL:\n        return self._real_url\n\n    @reify\n    def host(self) -> str:\n        assert self._url.host is not None\n        return self._url.host\n\n    @reify\n    def headers(self) -> \"CIMultiDictProxy[str]\":\n        return self._headers\n\n    @reify\n    def raw_headers(self) -> RawHeaders:\n        return self._raw_headers\n\n    @reify\n    def request_info(self) -> RequestInfo:\n        return self._request_info\n\n    @reify\n    def content_disposition(self) -> Optional[ContentDisposition]:\n        raw = self._headers.get(hdrs.CONTENT_DISPOSITION)\n        if raw is None:\n            return None\n        disposition_type, params_dct = multipart.parse_content_disposition(raw)\n        params = MappingProxyType(params_dct)\n        filename = multipart.content_disposition_filename(params)\n        return ContentDisposition(disposition_type, params, filename)\n\n    def __del__(self, _warnings: Any = warnings) -> None:\n        if self._closed:\n            return\n\n        if self._connection is not None:\n            self._connection.release()\n            self._cleanup_writer()\n\n            if self._loop.get_debug():\n                kwargs = {\"source\": self}\n                _warnings.warn(f\"Unclosed response {self!r}\", ResourceWarning, **kwargs)\n                context = {\"client_response\": self, \"message\": \"Unclosed response\"}\n                if self._source_traceback:\n                    context[\"source_traceback\"] = self._source_traceback\n                self._loop.call_exception_handler(context)\n\n    def __repr__(self) -> str:\n        out = io.StringIO()\n        ascii_encodable_url = str(self.url)\n        if self.reason:\n            ascii_encodable_reason = self.reason.encode(\n                \"ascii\", \"backslashreplace\"\n            ).decode(\"ascii\")\n        else:\n            ascii_encodable_reason = \"None\"\n        print(\n            \"<ClientResponse({}) [{} {}]>\".format(\n                ascii_encodable_url, self.status, ascii_encodable_reason\n            ),\n            file=out,\n        )\n        print(self.headers, file=out)\n        return out.getvalue()\n\n    @property\n    def connection(self) -> Optional[\"Connection\"]:\n        return self._connection\n\n    @reify\n    def history(self) -> Tuple[\"ClientResponse\", ...]:\n        \"\"\"A sequence of of responses, if redirects occurred.\"\"\"\n        return self._history\n\n    @reify\n    def links(self) -> \"MultiDictProxy[MultiDictProxy[Union[str, URL]]]\":\n        links_str = \", \".join(self.headers.getall(\"link\", []))\n\n        if not links_str:\n            return MultiDictProxy(MultiDict())\n\n        links: MultiDict[MultiDictProxy[Union[str, URL]]] = MultiDict()\n\n        for val in re.split(r\",(?=\\s*<)\", links_str):\n            match = re.match(r\"\\s*<(.*)>(.*)\", val)\n            if match is None:  # pragma: no cover\n                # the check exists to suppress mypy error\n                continue\n            url, params_str = match.groups()\n            params = params_str.split(\";\")[1:]\n\n            link: MultiDict[Union[str, URL]] = MultiDict()\n\n            for param in params:\n                match = re.match(r\"^\\s*(\\S*)\\s*=\\s*(['\\\"]?)(.*?)(\\2)\\s*$\", param, re.M)\n                if match is None:  # pragma: no cover\n                    # the check exists to suppress mypy error\n                    continue\n                key, _, value, _ = match.groups()\n\n                link.add(key, value)\n\n            key = link.get(\"rel\", url)\n\n            link.add(\"url\", self.url.join(URL(url)))\n\n            links.add(str(key), MultiDictProxy(link))\n\n        return MultiDictProxy(links)\n\n    async def start(self, connection: \"Connection\") -> \"ClientResponse\":\n        \"\"\"Start response processing.\"\"\"\n        self._closed = False\n        self._protocol = connection.protocol\n        self._connection = connection\n\n        with self._timer:\n            while True:\n                # read response\n                try:\n                    protocol = self._protocol\n                    message, payload = await protocol.read()  # type: ignore[union-attr]\n                except http.HttpProcessingError as exc:\n                    raise ClientResponseError(\n                        self.request_info,\n                        self.history,\n                        status=exc.code,\n                        message=exc.message,\n                        headers=exc.headers,\n                    ) from exc\n\n                if message.code < 100 or message.code > 199 or message.code == 101:\n                    break\n\n                if self._continue is not None:\n                    set_result(self._continue, True)\n                    self._continue = None\n\n        # payload eof handler\n        payload.on_eof(self._response_eof)\n\n        # response status\n        self.version = message.version\n        self.status = message.code\n        self.reason = message.reason\n\n        # headers\n        self._headers = message.headers  # type is CIMultiDictProxy\n        self._raw_headers = message.raw_headers  # type is Tuple[bytes, bytes]\n\n        # payload\n        self.content = payload\n\n        # cookies\n        for hdr in self.headers.getall(hdrs.SET_COOKIE, ()):\n            try:\n                self.cookies.load(hdr)\n            except CookieError as exc:\n                client_logger.warning(\"Can not load response cookies: %s\", exc)\n        return self\n\n    def _response_eof(self) -> None:\n        if self._closed:\n            return\n\n        if self._connection is not None:\n            # websocket, protocol could be None because\n            # connection could be detached\n            if (\n                self._connection.protocol is not None\n                and self._connection.protocol.upgraded\n            ):\n                return\n\n            self._release_connection()\n\n        self._closed = True\n        self._cleanup_writer()\n\n    @property\n    def closed(self) -> bool:\n        return self._closed\n\n    def close(self) -> None:\n        if not self._released:\n            self._notify_content()\n\n        self._closed = True\n        if self._loop is None or self._loop.is_closed():\n            return\n\n        self._cleanup_writer()\n        self._release_connection()\n\n    def release(self) -> Any:\n        if not self._released:\n            self._notify_content()\n\n        self._closed = True\n\n        self._cleanup_writer()\n        self._release_connection()\n        return noop()\n\n    @property\n    def ok(self) -> bool:\n        \"\"\"Returns ``True`` if ``status`` is less than ``400``, ``False`` if not.\n\n        This is **not** a check for ``200 OK`` but a check that the response\n        status is under 400.\n        \"\"\"\n        return 400 > self.status\n\n    def raise_for_status(self) -> None:\n        if not self.ok:\n            # reason should always be not None for a started response\n            assert self.reason is not None\n            self.release()\n            raise ClientResponseError(\n                self.request_info,\n                self.history,\n                status=self.status,\n                message=self.reason,\n                headers=self.headers,\n            )\n\n    def _release_connection(self) -> None:\n        if self._connection is not None:\n            if self._writer is None:\n                self._connection.release()\n                self._connection = None\n            else:\n                self._writer.add_done_callback(lambda f: self._release_connection())\n\n    async def _wait_released(self) -> None:\n        if self._writer is not None:\n            await self._writer\n        self._release_connection()\n\n    def _cleanup_writer(self) -> None:\n        if self._writer is not None:\n            self._writer.cancel()\n        self._session = None\n\n    def _notify_content(self) -> None:\n        content = self.content\n        if content and content.exception() is None:\n            content.set_exception(ClientConnectionError(\"Connection closed\"))\n        self._released = True\n\n    async def wait_for_close(self) -> None:\n        if self._writer is not None:\n            await self._writer\n        self.release()\n\n    async def read(self) -> bytes:\n        \"\"\"Read response payload.\"\"\"\n        if self._body is None:\n            try:\n                self._body = await self.content.read()\n                for trace in self._traces:\n                    await trace.send_response_chunk_received(\n                        self.method, self.url, self._body\n                    )\n            except BaseException:\n                self.close()\n                raise\n        elif self._released:  # Response explicitly released\n            raise ClientConnectionError(\"Connection closed\")\n\n        await self._wait_released()  # Underlying connection released\n        return self._body  # type: ignore[no-any-return]\n\n    def get_encoding(self) -> str:\n        ctype = self.headers.get(hdrs.CONTENT_TYPE, \"\").lower()\n        mimetype = helpers.parse_mimetype(ctype)\n\n        encoding = mimetype.parameters.get(\"charset\")\n        if encoding:\n            with contextlib.suppress(LookupError):\n                return codecs.lookup(encoding).name\n\n        if mimetype.type == \"application\" and (\n            mimetype.subtype == \"json\" or mimetype.subtype == \"rdap\"\n        ):\n            # RFC 7159 states that the default encoding is UTF-8.\n            # RFC 7483 defines application/rdap+json\n            return \"utf-8\"\n\n        if self._body is None:\n            raise RuntimeError(\n                \"Cannot compute fallback encoding of a not yet read body\"\n            )\n\n        return self._resolve_charset(self, self._body)\n\n    async def text(self, encoding: Optional[str] = None, errors: str = \"strict\") -> str:\n        \"\"\"Read response payload and decode.\"\"\"\n        if self._body is None:\n            await self.read()\n\n        if encoding is None:\n            encoding = self.get_encoding()\n\n        return self._body.decode(  # type: ignore[no-any-return,union-attr]\n            encoding, errors=errors\n        )\n\n    async def json(\n        self,\n        *,\n        encoding: Optional[str] = None,\n        loads: JSONDecoder = DEFAULT_JSON_DECODER,\n        content_type: Optional[str] = \"application/json\",\n    ) -> Any:\n        \"\"\"Read and decodes JSON response.\"\"\"\n        if self._body is None:\n            await self.read()\n\n        if content_type:\n            ctype = self.headers.get(hdrs.CONTENT_TYPE, \"\").lower()\n            if not _is_expected_content_type(ctype, content_type):\n                raise ContentTypeError(\n                    self.request_info,\n                    self.history,\n                    message=(\n                        \"Attempt to decode JSON with \" \"unexpected mimetype: %s\" % ctype\n                    ),\n                    headers=self.headers,\n                )\n\n        stripped = self._body.strip()  # type: ignore[union-attr]\n        if not stripped:\n            return None\n\n        if encoding is None:\n            encoding = self.get_encoding()\n\n        return loads(stripped.decode(encoding))\n\n    async def __aenter__(self) -> \"ClientResponse\":\n        return self\n\n    async def __aexit__(\n        self,\n        exc_type: Optional[Type[BaseException]],\n        exc_val: Optional[BaseException],\n        exc_tb: Optional[TracebackType],\n    ) -> None:\n        # similar to _RequestContextManager, we do not need to check\n        # for exceptions, response object can close connection\n        # if state is broken\n        self.release()\n        await self.wait_for_close()\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:** ClientRequest Accepts Arbitrary Sequence Types for HTTP Version, Causing Unexpected Behavior

**Description:**
When creating a `ClientRequest`, setting the `version` attribute to an arbitrary sequence allows the inclusion of malformed data, which can lead to unexpected behavior or potential security vulnerabilities.

**Example Buggy Code:**
```python
from aiohttp.client_reqrep import ClientRequest
from aiohttp import URL

async def create_request(loop, conn):
    req = ClientRequest(
        "GET",
        URL("http://example.com"),
        loop=loop,
        headers={"Connection": "Close"},
        version=("1", "1\r\nInjected-Header: not allowed"),
    )
    await req.send(conn)
```
In this example, the `version` is set to a tuple containing a newline character and an injected header. This malformed version string can manipulate the HTTP response headers unexpectedly.

**Expected Behavior:**
Assigning an invalid or improperly formatted `version` should raise an error, preventing the creation of malformed HTTP requests and ensuring that only valid HTTP versions are used.

**Actual Behavior:**
No error is raised when an arbitrary or improperly formatted sequence is assigned to `version`, allowing the construction of potentially malformed HTTP requests.

[/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/client_reqrep.py
import asyncio
import codecs
import contextlib
import functools
import io
import re
import sys
import traceback
import warnings
from hashlib import md5, sha1, sha256
from http.cookies import CookieError, Morsel, SimpleCookie
from types import MappingProxyType, TracebackType
from typing import (
    TYPE_CHECKING,
    Any,
    Callable,
    Dict,
    Iterable,
    List,
    Literal,
    Mapping,
    Optional,
    Tuple,
    Type,
    Union,
    cast,
)

import attr
from multidict import CIMultiDict, CIMultiDictProxy, MultiDict, MultiDictProxy
from yarl import URL

from . import hdrs, helpers, http, multipart, payload
from .abc import AbstractStreamWriter
from .client_exceptions import (
    ClientConnectionError,
    ClientOSError,
    ClientResponseError,
    ContentTypeError,
    InvalidURL,
    ServerFingerprintMismatch,
)
from .compression_utils import HAS_BROTLI
from .formdata import FormData
from .helpers import (
    BaseTimerContext,
    BasicAuth,
    HeadersMixin,
    TimerNoop,
    basicauth_from_netrc,
    netrc_from_env,
    noop,
    reify,
    set_result,
)
from .http import (
    SERVER_SOFTWARE,
    HttpVersion,
    HttpVersion10,
    HttpVersion11,
    StreamWriter,
)
from .log import client_logger
from .streams import StreamReader
from .typedefs import (
    DEFAULT_JSON_DECODER,
    JSONDecoder,
    LooseCookies,
    LooseHeaders,
    RawHeaders,
)

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


__all__ = ("ClientRequest", "ClientResponse", "RequestInfo", "Fingerprint")


if TYPE_CHECKING:  # pragma: no cover
    from .client import ClientSession
    from .connector import Connection
    from .tracing import Trace


_CONTAINS_CONTROL_CHAR_RE = re.compile(r"[^-!#$%&'*+.^_`|~0-9a-zA-Z]")
json_re = re.compile(r"^application/(?:[\w.+-]+?\+)?json")


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


@attr.s(auto_attribs=True, frozen=True, slots=True)
class ContentDisposition:
    type: Optional[str]
    parameters: "MappingProxyType[str, str]"
    filename: Optional[str]


@attr.s(auto_attribs=True, frozen=True, slots=True)
class RequestInfo:
    url: URL
    method: str
    headers: "CIMultiDictProxy[str]"
    real_url: URL = attr.ib()

    @real_url.default
    def real_url_default(self) -> URL:
        return self.url


class Fingerprint:
    HASHFUNC_BY_DIGESTLEN = {
        16: md5,
        20: sha1,
        32: sha256,
    }

    def __init__(self, fingerprint: bytes) -> None:
        digestlen = len(fingerprint)
        hashfunc = self.HASHFUNC_BY_DIGESTLEN.get(digestlen)
        if not hashfunc:
            raise ValueError("fingerprint has invalid length")
        elif hashfunc is md5 or hashfunc is sha1:
            raise ValueError(
                "md5 and sha1 are insecure and " "not supported. Use sha256."
            )
        self._hashfunc = hashfunc
        self._fingerprint = fingerprint

    @property
    def fingerprint(self) -> bytes:
        return self._fingerprint

    def check(self, transport: asyncio.Transport) -> None:
        if not transport.get_extra_info("sslcontext"):
            return
        sslobj = transport.get_extra_info("ssl_object")
        cert = sslobj.getpeercert(binary_form=True)
        got = self._hashfunc(cert).digest()
        if got != self._fingerprint:
            host, port, *_ = transport.get_extra_info("peername")
            raise ServerFingerprintMismatch(self._fingerprint, got, host, port)


if ssl is not None:
    SSL_ALLOWED_TYPES = (ssl.SSLContext, bool, Fingerprint, type(None))
else:  # pragma: no cover
    SSL_ALLOWED_TYPES = type(None)


def _merge_ssl_params(
    ssl: Union["SSLContext", Literal[False], Fingerprint, None],
    verify_ssl: Optional[bool],
    ssl_context: Optional["SSLContext"],
    fingerprint: Optional[bytes],
) -> Union["SSLContext", Literal[False], Fingerprint, None]:
    if verify_ssl is not None and not verify_ssl:
        warnings.warn(
            "verify_ssl is deprecated, use ssl=False instead",
            DeprecationWarning,
            stacklevel=3,
        )
        if ssl is not None:
            raise ValueError(
                "verify_ssl, ssl_context, fingerprint and ssl "
                "parameters are mutually exclusive"
            )
        else:
            ssl = False
    if ssl_context is not None:
        warnings.warn(
            "ssl_context is deprecated, use ssl=context instead",
            DeprecationWarning,
            stacklevel=3,
        )
        if ssl is not None:
            raise ValueError(
                "verify_ssl, ssl_context, fingerprint and ssl "
                "parameters are mutually exclusive"
            )
        else:
            ssl = ssl_context
    if fingerprint is not None:
        warnings.warn(
            "fingerprint is deprecated, " "use ssl=Fingerprint(fingerprint) instead",
            DeprecationWarning,
            stacklevel=3,
        )
        if ssl is not None:
            raise ValueError(
                "verify_ssl, ssl_context, fingerprint and ssl "
                "parameters are mutually exclusive"
            )
        else:
            ssl = Fingerprint(fingerprint)
    if not isinstance(ssl, SSL_ALLOWED_TYPES):
        raise TypeError(
            "ssl should be SSLContext, bool, Fingerprint or None, "
            "got {!r} instead.".format(ssl)
        )
    return ssl


@attr.s(auto_attribs=True, slots=True, frozen=True)
class ConnectionKey:
    # the key should contain an information about used proxy / TLS
    # to prevent reusing wrong connections from a pool
    host: str
    port: Optional[int]
    is_ssl: bool
    ssl: Union[SSLContext, None, Literal[False], Fingerprint]
    proxy: Optional[URL]
    proxy_auth: Optional[BasicAuth]
    proxy_headers_hash: Optional[int]  # hash(CIMultiDict)


def _is_expected_content_type(
    response_content_type: str, expected_content_type: str
) -> bool:
    if expected_content_type == "application/json":
        return json_re.match(response_content_type) is not None
    return expected_content_type in response_content_type


class ClientRequest:
    GET_METHODS = {
        hdrs.METH_GET,
        hdrs.METH_HEAD,
        hdrs.METH_OPTIONS,
        hdrs.METH_TRACE,
    }
    POST_METHODS = {hdrs.METH_PATCH, hdrs.METH_POST, hdrs.METH_PUT}
    ALL_METHODS = GET_METHODS.union(POST_METHODS).union({hdrs.METH_DELETE})

    DEFAULT_HEADERS = {
        hdrs.ACCEPT: "*/*",
        hdrs.ACCEPT_ENCODING: _gen_default_accept_encoding(),
    }

    body = b""
    auth = None
    response = None

    __writer = None  # async task for streaming data
    _continue = None  # waiter future for '100 Continue' response

    # N.B.
    # Adding __del__ method with self._writer closing doesn't make sense
    # because _writer is instance method, thus it keeps a reference to self.
    # Until writer has finished finalizer will not be called.

    def __init__(
        self,
        method: str,
        url: URL,
        *,
        params: Optional[Mapping[str, str]] = None,
        headers: Optional[LooseHeaders] = None,
        skip_auto_headers: Iterable[str] = frozenset(),
        data: Any = None,
        cookies: Optional[LooseCookies] = None,
        auth: Optional[BasicAuth] = None,
        version: http.HttpVersion = http.HttpVersion11,
        compress: Optional[str] = None,
        chunked: Optional[bool] = None,
        expect100: bool = False,
        loop: Optional[asyncio.AbstractEventLoop] = None,
        response_class: Optional[Type["ClientResponse"]] = None,
        proxy: Optional[URL] = None,
        proxy_auth: Optional[BasicAuth] = None,
        timer: Optional[BaseTimerContext] = None,
        session: Optional["ClientSession"] = None,
        ssl: Union[SSLContext, Literal[False], Fingerprint, None] = None,
        proxy_headers: Optional[LooseHeaders] = None,
        traces: Optional[List["Trace"]] = None,
        trust_env: bool = False,
        server_hostname: Optional[str] = None,
    ):
        if loop is None:
            loop = asyncio.get_event_loop()

        match = _CONTAINS_CONTROL_CHAR_RE.search(method)
        if match:
            raise ValueError(
                f"Method cannot contain non-token characters {method!r} "
                "(found at least {match.group()!r})"
            )

        assert isinstance(url, URL), url
        assert isinstance(proxy, (URL, type(None))), proxy
        # FIXME: session is None in tests only, need to fix tests
        # assert session is not None
        self._session = cast("ClientSession", session)
        if params:
            q = MultiDict(url.query)
            url2 = url.with_query(params)
            q.extend(url2.query)
            url = url.with_query(q)
        self.original_url = url
        self.url = url.with_fragment(None)
        self.method = method.upper()
        self.chunked = chunked
        self.compress = compress
        self.loop = loop
        self.length = None
        if response_class is None:
            real_response_class = ClientResponse
        else:
            real_response_class = response_class
        self.response_class: Type[ClientResponse] = real_response_class
        self._timer = timer if timer is not None else TimerNoop()
        self._ssl = ssl
        self.server_hostname = server_hostname

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

        self.update_version(version)
        self.update_host(url)
        self.update_headers(headers)
        self.update_auto_headers(skip_auto_headers)
        self.update_cookies(cookies)
        self.update_content_encoding(data)
        self.update_auth(auth, trust_env)
        self.update_proxy(proxy, proxy_auth, proxy_headers)

        self.update_body_from_data(data)
        if data is not None or self.method not in self.GET_METHODS:
            self.update_transfer_encoding()
        self.update_expect_continue(expect100)
        if traces is None:
            traces = []
        self._traces = traces

    def __reset_writer(self, _: object = None) -> None:
        self.__writer = None

    @property
    def _writer(self) -> Optional["asyncio.Task[None]"]:
        return self.__writer

    @_writer.setter
    def _writer(self, writer: Optional["asyncio.Task[None]"]) -> None:
        if self.__writer is not None:
            self.__writer.remove_done_callback(self.__reset_writer)
        self.__writer = writer
        if writer is not None:
            writer.add_done_callback(self.__reset_writer)

    def is_ssl(self) -> bool:
        return self.url.scheme in ("https", "wss")

    @property
    def ssl(self) -> Union["SSLContext", None, Literal[False], Fingerprint]:
        return self._ssl

    @property
    def connection_key(self) -> ConnectionKey:
        proxy_headers = self.proxy_headers
        if proxy_headers:
            h: Optional[int] = hash(tuple((k, v) for k, v in proxy_headers.items()))
        else:
            h = None
        return ConnectionKey(
            self.host,
            self.port,
            self.is_ssl(),
            self.ssl,
            self.proxy,
            self.proxy_auth,
            h,
        )

    @property
    def host(self) -> str:
        ret = self.url.raw_host
        assert ret is not None
        return ret

    @property
    def port(self) -> Optional[int]:
        return self.url.port

    @property
    def request_info(self) -> RequestInfo:
        headers: CIMultiDictProxy[str] = CIMultiDictProxy(self.headers)
        return RequestInfo(self.url, self.method, headers, self.original_url)

    def update_host(self, url: URL) -> None:
        """Update destination host, port and connection type (ssl)."""
        # get host/port
        if not url.raw_host:
            raise InvalidURL(url)

        # basic auth info
        username, password = url.user, url.password
        if username:
            self.auth = helpers.BasicAuth(username, password or "")

    def update_version(self, version: Union[http.HttpVersion, str]) -> None:
        """Convert request version to two elements tuple.

        parser HTTP version '1.1' => (1, 1)
        """
        if isinstance(version, str):
            v = [part.strip() for part in version.split(".", 1)]
            try:
                version = http.HttpVersion(int(v[0]), int(v[1]))
            except ValueError:
                raise ValueError(
                    f"Can not parse http version number: {version}"
                ) from None
        self.version = version

    def update_headers(self, headers: Optional[LooseHeaders]) -> None:
        """Update request headers."""
        self.headers: CIMultiDict[str] = CIMultiDict()

        # add host
        netloc = cast(str, self.url.raw_host)
        if helpers.is_ipv6_address(netloc):
            netloc = f"[{netloc}]"
        # See https://github.com/aio-libs/aiohttp/issues/3636.
        netloc = netloc.rstrip(".")
        if self.url.port is not None and not self.url.is_default_port():
            netloc += ":" + str(self.url.port)
        self.headers[hdrs.HOST] = netloc

        if headers:
            if isinstance(headers, (dict, MultiDictProxy, MultiDict)):
                headers = headers.items()  # type: ignore[assignment]

            for key, value in headers:  # type: ignore[misc]
                # A special case for Host header
                if key.lower() == "host":
                    self.headers[key] = value
                else:
                    self.headers.add(key, value)

    def update_auto_headers(self, skip_auto_headers: Iterable[str]) -> None:
        self.skip_auto_headers = CIMultiDict(
            (hdr, None) for hdr in sorted(skip_auto_headers)
        )
        used_headers = self.headers.copy()
        used_headers.extend(self.skip_auto_headers)  # type: ignore[arg-type]

        for hdr, val in self.DEFAULT_HEADERS.items():
            if hdr not in used_headers:
                self.headers.add(hdr, val)

        if hdrs.USER_AGENT not in used_headers:
            self.headers[hdrs.USER_AGENT] = SERVER_SOFTWARE

    def update_cookies(self, cookies: Optional[LooseCookies]) -> None:
        """Update request cookies header."""
        if not cookies:
            return

        c = SimpleCookie()
        if hdrs.COOKIE in self.headers:
            c.load(self.headers.get(hdrs.COOKIE, ""))
            del self.headers[hdrs.COOKIE]

        if isinstance(cookies, Mapping):
            iter_cookies = cookies.items()
        else:
            iter_cookies = cookies  # type: ignore[assignment]
        for name, value in iter_cookies:
            if isinstance(value, Morsel):
                # Preserve coded_value
                mrsl_val = value.get(value.key, Morsel())
                mrsl_val.set(value.key, value.value, value.coded_value)
                c[name] = mrsl_val
            else:
                c[name] = value  # type: ignore[assignment]

        self.headers[hdrs.COOKIE] = c.output(header="", sep=";").strip()

    def update_content_encoding(self, data: Any) -> None:
        """Set request content encoding."""
        if data is None:
            return

        enc = self.headers.get(hdrs.CONTENT_ENCODING, "").lower()
        if enc:
            if self.compress:
                raise ValueError(
                    "compress can not be set " "if Content-Encoding header is set"
                )
        elif self.compress:
            if not isinstance(self.compress, str):
                self.compress = "deflate"
            self.headers[hdrs.CONTENT_ENCODING] = self.compress
            self.chunked = True  # enable chunked, no need to deal with length

    def update_transfer_encoding(self) -> None:
        """Analyze transfer-encoding header."""
        te = self.headers.get(hdrs.TRANSFER_ENCODING, "").lower()

        if "chunked" in te:
            if self.chunked:
                raise ValueError(
                    "chunked can not be set "
                    'if "Transfer-Encoding: chunked" header is set'
                )

        elif self.chunked:
            if hdrs.CONTENT_LENGTH in self.headers:
                raise ValueError(
                    "chunked can not be set " "if Content-Length header is set"
                )

            self.headers[hdrs.TRANSFER_ENCODING] = "chunked"
        else:
            if hdrs.CONTENT_LENGTH not in self.headers:
                self.headers[hdrs.CONTENT_LENGTH] = str(len(self.body))

    def update_auth(self, auth: Optional[BasicAuth], trust_env: bool = False) -> None:
        """Set basic auth."""
        if auth is None:
            auth = self.auth
        if auth is None and trust_env and self.url.host is not None:
            netrc_obj = netrc_from_env()
            with contextlib.suppress(LookupError):
                auth = basicauth_from_netrc(netrc_obj, self.url.host)
        if auth is None:
            return

        if not isinstance(auth, helpers.BasicAuth):
            raise TypeError("BasicAuth() tuple is required instead")

        self.headers[hdrs.AUTHORIZATION] = auth.encode()

    def update_body_from_data(self, body: Any) -> None:
        if body is None:
            return

        # FormData
        if isinstance(body, FormData):
            body = body()

        try:
            body = payload.PAYLOAD_REGISTRY.get(body, disposition=None)
        except payload.LookupError:
            body = FormData(body)()

        self.body = body

        # enable chunked encoding if needed
        if not self.chunked:
            if hdrs.CONTENT_LENGTH not in self.headers:
                size = body.size
                if size is None:
                    self.chunked = True
                else:
                    if hdrs.CONTENT_LENGTH not in self.headers:
                        self.headers[hdrs.CONTENT_LENGTH] = str(size)

        # copy payload headers
        assert body.headers
        for (key, value) in body.headers.items():
            if key in self.headers:
                continue
            if key in self.skip_auto_headers:
                continue
            self.headers[key] = value

    def update_expect_continue(self, expect: bool = False) -> None:
        if expect:
            self.headers[hdrs.EXPECT] = "100-continue"
        elif self.headers.get(hdrs.EXPECT, "").lower() == "100-continue":
            expect = True

        if expect:
            self._continue = self.loop.create_future()

    def update_proxy(
        self,
        proxy: Optional[URL],
        proxy_auth: Optional[BasicAuth],
        proxy_headers: Optional[LooseHeaders],
    ) -> None:
        if proxy_auth and not isinstance(proxy_auth, helpers.BasicAuth):
            raise ValueError("proxy_auth must be None or BasicAuth() tuple")
        self.proxy = proxy
        self.proxy_auth = proxy_auth
        self.proxy_headers = proxy_headers

    def keep_alive(self) -> bool:
        if self.version < HttpVersion10:
            # keep alive not supported at all
            return False
        if self.version == HttpVersion10:
            if self.headers.get(hdrs.CONNECTION) == "keep-alive":
                return True
            else:  # no headers means we close for Http 1.0
                return False
        elif self.headers.get(hdrs.CONNECTION) == "close":
            return False

        return True

    async def write_bytes(
        self, writer: AbstractStreamWriter, conn: "Connection"
    ) -> None:
        """Support coroutines that yields bytes objects."""
        # 100 response
        if self._continue is not None:
            try:
                await writer.drain()
                await self._continue
            except asyncio.CancelledError:
                return

        protocol = conn.protocol
        assert protocol is not None
        try:
            if isinstance(self.body, payload.Payload):
                await self.body.write(writer)
            else:
                if isinstance(self.body, (bytes, bytearray)):
                    self.body = (self.body,)  # type: ignore[assignment]

                for chunk in self.body:
                    await writer.write(chunk)  # type: ignore[arg-type]
        except OSError as exc:
            if exc.errno is None and isinstance(exc, asyncio.TimeoutError):
                protocol.set_exception(exc)
            else:
                new_exc = ClientOSError(
                    exc.errno, "Can not write request body for %s" % self.url
                )
                new_exc.__context__ = exc
                new_exc.__cause__ = exc
                protocol.set_exception(new_exc)
        except asyncio.CancelledError:
            await writer.write_eof()
        except Exception as exc:
            protocol.set_exception(exc)
        else:
            await writer.write_eof()
            protocol.start_timeout()

    async def send(self, conn: "Connection") -> "ClientResponse":
        # Specify request target:
        # - CONNECT request must send authority form URI
        # - not CONNECT proxy must send absolute form URI
        # - most common is origin form URI
        if self.method == hdrs.METH_CONNECT:
            connect_host = self.url.raw_host
            assert connect_host is not None
            if helpers.is_ipv6_address(connect_host):
                connect_host = f"[{connect_host}]"
            path = f"{connect_host}:{self.url.port}"
        elif self.proxy and not self.is_ssl():
            path = str(self.url)
        else:
            path = self.url.raw_path
            if self.url.raw_query_string:
                path += "?" + self.url.raw_query_string

        protocol = conn.protocol
        assert protocol is not None
        writer = StreamWriter(
            protocol,
            self.loop,
            on_chunk_sent=functools.partial(
                self._on_chunk_request_sent, self.method, self.url
            ),
            on_headers_sent=functools.partial(
                self._on_headers_request_sent, self.method, self.url
            ),
        )

        if self.compress:
            writer.enable_compression(self.compress)

        if self.chunked is not None:
            writer.enable_chunking()

        # set default content-type
        if (
            self.method in self.POST_METHODS
            and hdrs.CONTENT_TYPE not in self.skip_auto_headers
            and hdrs.CONTENT_TYPE not in self.headers
        ):
            self.headers[hdrs.CONTENT_TYPE] = "application/octet-stream"

        # set the connection header
        connection = self.headers.get(hdrs.CONNECTION)
        if not connection:
            if self.keep_alive():
                if self.version == HttpVersion10:
                    connection = "keep-alive"
            else:
                if self.version == HttpVersion11:
                    connection = "close"

        if connection is not None:
            self.headers[hdrs.CONNECTION] = connection

        # status + headers
        status_line = "{0} {1} HTTP/{2[0]}.{2[1]}".format(
            self.method, path, self.version
        )
        await writer.write_headers(status_line, self.headers)

        self._writer = self.loop.create_task(self.write_bytes(writer, conn))

        response_class = self.response_class
        assert response_class is not None
        self.response = response_class(
            self.method,
            self.original_url,
            writer=self._writer,
            continue100=self._continue,
            timer=self._timer,
            request_info=self.request_info,
            traces=self._traces,
            loop=self.loop,
            session=self._session,
        )
        return self.response

    async def close(self) -> None:
        if self._writer is not None:
            with contextlib.suppress(asyncio.CancelledError):
                await self._writer

    def terminate(self) -> None:
        if self._writer is not None:
            if not self.loop.is_closed():
                self._writer.cancel()
            self._writer.remove_done_callback(self.__reset_writer)
            self._writer = None

    async def _on_chunk_request_sent(self, method: str, url: URL, chunk: bytes) -> None:
        for trace in self._traces:
            await trace.send_request_chunk_sent(method, url, chunk)

    async def _on_headers_request_sent(
        self, method: str, url: URL, headers: "CIMultiDict[str]"
    ) -> None:
        for trace in self._traces:
            await trace.send_request_headers(method, url, headers)


class ClientResponse(HeadersMixin):

    # Some of these attributes are None when created,
    # but will be set by the start() method.
    # As the end user will likely never see the None values, we cheat the types below.
    # from the Status-Line of the response
    version: Optional[HttpVersion] = None  # HTTP-Version
    status: int = None  # type: ignore[assignment] # Status-Code
    reason: Optional[str] = None  # Reason-Phrase

    content: StreamReader = None  # type: ignore[assignment]  # Payload stream
    _headers: CIMultiDictProxy[str] = None  # type: ignore[assignment]
    _raw_headers: RawHeaders = None  # type: ignore[assignment]

    _connection = None  # current connection
    _source_traceback: Optional[traceback.StackSummary] = None
    # set up by ClientRequest after ClientResponse object creation
    # post-init stage allows to not change ctor signature
    _closed = True  # to allow __del__ for non-initialized properly response
    _released = False
    __writer = None

    def __init__(
        self,
        method: str,
        url: URL,
        *,
        writer: "asyncio.Task[None]",
        continue100: Optional["asyncio.Future[bool]"],
        timer: BaseTimerContext,
        request_info: RequestInfo,
        traces: List["Trace"],
        loop: asyncio.AbstractEventLoop,
        session: "ClientSession",
    ) -> None:
        assert isinstance(url, URL)

        self.method = method
        self.cookies = SimpleCookie()

        self._real_url = url
        self._url = url.with_fragment(None)
        self._body: Any = None
        self._writer: Optional[asyncio.Task[None]] = writer
        self._continue = continue100  # None by default
        self._closed = True
        self._history: Tuple[ClientResponse, ...] = ()
        self._request_info = request_info
        self._timer = timer if timer is not None else TimerNoop()
        self._cache: Dict[str, Any] = {}
        self._traces = traces
        self._loop = loop
        # store a reference to session #1985
        self._session: Optional[ClientSession] = session
        # Save reference to _resolve_charset, so that get_encoding() will still
        # work after the response has finished reading the body.
        if session is None:
            # TODO: Fix session=None in tests (see ClientRequest.__init__).
            self._resolve_charset: Callable[
                ["ClientResponse", bytes], str
            ] = lambda *_: "utf-8"
        else:
            self._resolve_charset = session._resolve_charset
        if loop.get_debug():
            self._source_traceback = traceback.extract_stack(sys._getframe(1))

    def __reset_writer(self, _: object = None) -> None:
        self.__writer = None

    @property
    def _writer(self) -> Optional["asyncio.Task[None]"]:
        return self.__writer

    @_writer.setter
    def _writer(self, writer: Optional["asyncio.Task[None]"]) -> None:
        if self.__writer is not None:
            self.__writer.remove_done_callback(self.__reset_writer)
        self.__writer = writer
        if writer is not None:
            writer.add_done_callback(self.__reset_writer)

    @reify
    def url(self) -> URL:
        return self._url

    @reify
    def url_obj(self) -> URL:
        warnings.warn("Deprecated, use .url #1654", DeprecationWarning, stacklevel=2)
        return self._url

    @reify
    def real_url(self) -> URL:
        return self._real_url

    @reify
    def host(self) -> str:
        assert self._url.host is not None
        return self._url.host

    @reify
    def headers(self) -> "CIMultiDictProxy[str]":
        return self._headers

    @reify
    def raw_headers(self) -> RawHeaders:
        return self._raw_headers

    @reify
    def request_info(self) -> RequestInfo:
        return self._request_info

    @reify
    def content_disposition(self) -> Optional[ContentDisposition]:
        raw = self._headers.get(hdrs.CONTENT_DISPOSITION)
        if raw is None:
            return None
        disposition_type, params_dct = multipart.parse_content_disposition(raw)
        params = MappingProxyType(params_dct)
        filename = multipart.content_disposition_filename(params)
        return ContentDisposition(disposition_type, params, filename)

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

        if self._connection is not None:
            self._connection.release()
            self._cleanup_writer()

            if self._loop.get_debug():
                kwargs = {"source": self}
                _warnings.warn(f"Unclosed response {self!r}", ResourceWarning, **kwargs)
                context = {"client_response": self, "message": "Unclosed response"}
                if self._source_traceback:
                    context["source_traceback"] = self._source_traceback
                self._loop.call_exception_handler(context)

    def __repr__(self) -> str:
        out = io.StringIO()
        ascii_encodable_url = str(self.url)
        if self.reason:
            ascii_encodable_reason = self.reason.encode(
                "ascii", "backslashreplace"
            ).decode("ascii")
        else:
            ascii_encodable_reason = "None"
        print(
            "<ClientResponse({}) [{} {}]>".format(
                ascii_encodable_url, self.status, ascii_encodable_reason
            ),
            file=out,
        )
        print(self.headers, file=out)
        return out.getvalue()

    @property
    def connection(self) -> Optional["Connection"]:
        return self._connection

    @reify
    def history(self) -> Tuple["ClientResponse", ...]:
        """A sequence of of responses, if redirects occurred."""
        return self._history

    @reify
    def links(self) -> "MultiDictProxy[MultiDictProxy[Union[str, URL]]]":
        links_str = ", ".join(self.headers.getall("link", []))

        if not links_str:
            return MultiDictProxy(MultiDict())

        links: MultiDict[MultiDictProxy[Union[str, URL]]] = MultiDict()

        for val in re.split(r",(?=\s*<)", links_str):
            match = re.match(r"\s*<(.*)>(.*)", val)
            if match is None:  # pragma: no cover
                # the check exists to suppress mypy error
                continue
            url, params_str = match.groups()
            params = params_str.split(";")[1:]

            link: MultiDict[Union[str, URL]] = MultiDict()

            for param in params:
                match = re.match(r"^\s*(\S*)\s*=\s*(['\"]?)(.*?)(\2)\s*$", param, re.M)
                if match is None:  # pragma: no cover
                    # the check exists to suppress mypy error
                    continue
                key, _, value, _ = match.groups()

                link.add(key, value)

            key = link.get("rel", url)

            link.add("url", self.url.join(URL(url)))

            links.add(str(key), MultiDictProxy(link))

        return MultiDictProxy(links)

    async def start(self, connection: "Connection") -> "ClientResponse":
        """Start response processing."""
        self._closed = False
        self._protocol = connection.protocol
        self._connection = connection

        with self._timer:
            while True:
                # read response
                try:
                    protocol = self._protocol
                    message, payload = await protocol.read()  # type: ignore[union-attr]
                except http.HttpProcessingError as exc:
                    raise ClientResponseError(
                        self.request_info,
                        self.history,
                        status=exc.code,
                        message=exc.message,
                        headers=exc.headers,
                    ) from exc

                if message.code < 100 or message.code > 199 or message.code == 101:
                    break

                if self._continue is not None:
                    set_result(self._continue, True)
                    self._continue = None

        # payload eof handler
        payload.on_eof(self._response_eof)

        # response status
        self.version = message.version
        self.status = message.code
        self.reason = message.reason

        # headers
        self._headers = message.headers  # type is CIMultiDictProxy
        self._raw_headers = message.raw_headers  # type is Tuple[bytes, bytes]

        # payload
        self.content = payload

        # cookies
        for hdr in self.headers.getall(hdrs.SET_COOKIE, ()):
            try:
                self.cookies.load(hdr)
            except CookieError as exc:
                client_logger.warning("Can not load response cookies: %s", exc)
        return self

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

        if self._connection is not None:
            # websocket, protocol could be None because
            # connection could be detached
            if (
                self._connection.protocol is not None
                and self._connection.protocol.upgraded
            ):
                return

            self._release_connection()

        self._closed = True
        self._cleanup_writer()

    @property
    def closed(self) -> bool:
        return self._closed

    def close(self) -> None:
        if not self._released:
            self._notify_content()

        self._closed = True
        if self._loop is None or self._loop.is_closed():
            return

        self._cleanup_writer()
        self._release_connection()

    def release(self) -> Any:
        if not self._released:
            self._notify_content()

        self._closed = True

        self._cleanup_writer()
        self._release_connection()
        return noop()

    @property
    def ok(self) -> bool:
        """Returns ``True`` if ``status`` is less than ``400``, ``False`` if not.

        This is **not** a check for ``200 OK`` but a check that the response
        status is under 400.
        """
        return 400 > self.status

    def raise_for_status(self) -> None:
        if not self.ok:
            # reason should always be not None for a started response
            assert self.reason is not None
            self.release()
            raise ClientResponseError(
                self.request_info,
                self.history,
                status=self.status,
                message=self.reason,
                headers=self.headers,
            )

    def _release_connection(self) -> None:
        if self._connection is not None:
            if self._writer is None:
                self._connection.release()
                self._connection = None
            else:
                self._writer.add_done_callback(lambda f: self._release_connection())

    async def _wait_released(self) -> None:
        if self._writer is not None:
            await self._writer
        self._release_connection()

    def _cleanup_writer(self) -> None:
        if self._writer is not None:
            self._writer.cancel()
        self._session = None

    def _notify_content(self) -> None:
        content = self.content
        if content and content.exception() is None:
            content.set_exception(ClientConnectionError("Connection closed"))
        self._released = True

    async def wait_for_close(self) -> None:
        if self._writer is not None:
            await self._writer
        self.release()

    async def read(self) -> bytes:
        """Read response payload."""
        if self._body is None:
            try:
                self._body = await self.content.read()
                for trace in self._traces:
                    await trace.send_response_chunk_received(
                        self.method, self.url, self._body
                    )
            except BaseException:
                self.close()
                raise
        elif self._released:  # Response explicitly released
            raise ClientConnectionError("Connection closed")

        await self._wait_released()  # Underlying connection released
        return self._body  # type: ignore[no-any-return]

    def get_encoding(self) -> str:
        ctype = self.headers.get(hdrs.CONTENT_TYPE, "").lower()
        mimetype = helpers.parse_mimetype(ctype)

        encoding = mimetype.parameters.get("charset")
        if encoding:
            with contextlib.suppress(LookupError):
                return codecs.lookup(encoding).name

        if mimetype.type == "application" and (
            mimetype.subtype == "json" or mimetype.subtype == "rdap"
        ):
            # RFC 7159 states that the default encoding is UTF-8.
            # RFC 7483 defines application/rdap+json
            return "utf-8"

        if self._body is None:
            raise RuntimeError(
                "Cannot compute fallback encoding of a not yet read body"
            )

        return self._resolve_charset(self, self._body)

    async def text(self, encoding: Optional[str] = None, errors: str = "strict") -> str:
        """Read response payload and decode."""
        if self._body is None:
            await self.read()

        if encoding is None:
            encoding = self.get_encoding()

        return self._body.decode(  # type: ignore[no-any-return,union-attr]
            encoding, errors=errors
        )

    async def json(
        self,
        *,
        encoding: Optional[str] = None,
        loads: JSONDecoder = DEFAULT_JSON_DECODER,
        content_type: Optional[str] = "application/json",
    ) -> Any:
        """Read and decodes JSON response."""
        if self._body is None:
            await self.read()

        if content_type:
            ctype = self.headers.get(hdrs.CONTENT_TYPE, "").lower()
            if not _is_expected_content_type(ctype, content_type):
                raise ContentTypeError(
                    self.request_info,
                    self.history,
                    message=(
                        "Attempt to decode JSON with " "unexpected mimetype: %s" % ctype
                    ),
                    headers=self.headers,
                )

        stripped = self._body.strip()  # type: ignore[union-attr]
        if not stripped:
            return None

        if encoding is None:
            encoding = self.get_encoding()

        return loads(stripped.decode(encoding))

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

    async def __aexit__(
        self,
        exc_type: Optional[Type[BaseException]],
        exc_val: Optional[BaseException],
        exc_tb: Optional[TracebackType],
    ) -> None:
        # similar to _RequestContextManager, we do not need to check
        # for exceptions, response object can close connection
        # if state is broken
        self.release()
        await self.wait_for_close()

```
--- 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