{
    "file_diffs": [
        {
            "old_file_content": "\"\"\"Http related parsers and protocol.\"\"\"\n\nimport collections\nimport functools\nimport http.server\nimport itertools\nimport re\nimport string\nimport sys\nimport zlib\nfrom wsgiref.handlers import format_date_time\n\nimport aiohttp\nfrom . import errors, hdrs\nfrom .multidict import CIMultiDict\nfrom .log import internal_logger\n\n__all__ = ('HttpMessage', 'Request', 'Response',\n           'HttpVersion', 'HttpVersion10', 'HttpVersion11',\n           'RawRequestMessage', 'RawResponseMessage',\n           'HttpPrefixParser', 'HttpRequestParser', 'HttpResponseParser',\n           'HttpPayloadParser')\n\nASCIISET = set(string.printable)\nMETHRE = re.compile('[A-Z0-9$-_.]+')\nVERSRE = re.compile('HTTP/(\\d+).(\\d+)')\nHDRRE = re.compile('[\\x00-\\x1F\\x7F()<>@,;:\\[\\]={} \\t\\\\\\\\\\\"]')\nCONTINUATION = (' ', '\\t')\nEOF_MARKER = object()\nEOL_MARKER = object()\nSTATUS_LINE_READY = object()\n\nRESPONSES = http.server.BaseHTTPRequestHandler.responses\n\nHttpVersion = collections.namedtuple(\n    'HttpVersion', ['major', 'minor'])\nHttpVersion10 = HttpVersion(1, 0)\nHttpVersion11 = HttpVersion(1, 1)\n\nRawStatusLineMessage = collections.namedtuple(\n    'RawStatusLineMessage', ['method', 'path', 'version'])\n\nRawRequestMessage = collections.namedtuple(\n    'RawRequestMessage',\n    ['method', 'path', 'version', 'headers', 'should_close', 'compression'])\n\n\nRawResponseMessage = collections.namedtuple(\n    'RawResponseMessage',\n    ['version', 'code', 'reason', 'headers', 'should_close', 'compression'])\n\n\nclass HttpParser:\n\n    def __init__(self, max_line_size=8190, max_headers=32768,\n                 max_field_size=8190):\n        self.max_line_size = max_line_size\n        self.max_headers = max_headers\n        self.max_field_size = max_field_size\n\n    def parse_headers(self, lines):\n        \"\"\"Parses RFC2822 headers from a stream.\n\n        Line continuations are supported. Returns list of header name\n        and value pairs. Header name is in upper case.\n        \"\"\"\n        close_conn = None\n        encoding = None\n        headers = CIMultiDict()\n\n        lines_idx = 1\n        line = lines[1]\n\n        while line:\n            header_length = len(line)\n\n            # Parse initial header name : value pair.\n            try:\n                name, value = line.split(':', 1)\n            except ValueError:\n                raise errors.InvalidHeader(line) from None\n\n            name = name.strip(' \\t').upper()\n            if HDRRE.search(name):\n                raise errors.InvalidHeader(name)\n\n            # next line\n            lines_idx += 1\n            line = lines[lines_idx]\n\n            # consume continuation lines\n            continuation = line and line[0] in CONTINUATION\n\n            if continuation:\n                value = [value]\n                while continuation:\n                    header_length += len(line)\n                    if header_length > self.max_field_size:\n                        raise errors.LineTooLong(\n                            'limit request headers fields size')\n                    value.append(line)\n\n                    # next line\n                    lines_idx += 1\n                    line = lines[lines_idx]\n                    continuation = line[0] in CONTINUATION\n                value = '\\r\\n'.join(value)\n            else:\n                if header_length > self.max_field_size:\n                    raise errors.LineTooLong(\n                        'limit request headers fields size')\n\n            value = value.strip()\n\n            # keep-alive and encoding\n            if name == hdrs.CONNECTION:\n                v = value.lower()\n                if v == 'close':\n                    close_conn = True\n                elif v == 'keep-alive':\n                    close_conn = False\n            elif name == hdrs.CONTENT_ENCODING:\n                enc = value.lower()\n                if enc in ('gzip', 'deflate'):\n                    encoding = enc\n\n            headers.add(name, value)\n\n        return headers, close_conn, encoding\n\n\nclass HttpPrefixParser:\n    \"\"\"Waits for 'HTTP' prefix (non destructive)\"\"\"\n\n    def __init__(self, allowed_methods=()):\n        self.allowed_methods = [m.upper() for m in allowed_methods]\n\n    def __call__(self, out, buf):\n        raw_data = yield from buf.waituntil(b' ', 12)\n        method = raw_data.decode('ascii', 'surrogateescape').strip()\n\n        # method\n        method = method.upper()\n        if not METHRE.match(method):\n            raise errors.BadStatusLine(method)\n\n        # allowed method\n        if self.allowed_methods and method not in self.allowed_methods:\n            raise errors.HttpMethodNotAllowed(message=method)\n\n        out.feed_data(method, len(method))\n        out.feed_eof()\n\n\nclass HttpRequestParser(HttpParser):\n    \"\"\"Read request status line. Exception errors.BadStatusLine\n    could be raised in case of any errors in status line.\n    Returns RawRequestMessage.\n    \"\"\"\n\n    def __call__(self, out, buf):\n        # read http message (request line + headers)\n        try:\n            raw_data = yield from buf.readuntil(\n                b'\\r\\n\\r\\n', self.max_headers)\n        except errors.LineLimitExceededParserError as exc:\n            raise errors.LineTooLong(exc.limit) from None\n\n        lines = raw_data.decode(\n            'utf-8', 'surrogateescape').split('\\r\\n')\n\n        # request line\n        line = lines[0]\n        try:\n            method, path, version = line.split(None, 2)\n        except ValueError:\n            raise errors.BadStatusLine(line) from None\n\n        # method\n        method = method.upper()\n        if not METHRE.match(method):\n            raise errors.BadStatusLine(method)\n\n        # version\n        try:\n            if version.startswith('HTTP/'):\n                n1, n2 = version[5:].split('.', 1)\n                version = HttpVersion(int(n1), int(n2))\n            else:\n                raise errors.BadStatusLine(version)\n        except:\n            raise errors.BadStatusLine(version)\n\n        # read headers\n        headers, close, compression = self.parse_headers(lines)\n        if close is None:  # then the headers weren't set in the request\n            if version <= HttpVersion10:  # HTTP 1.0 must asks to not close\n                close = True\n            else:  # HTTP 1.1 must ask to close.\n                close = False\n\n        out.feed_data(\n            RawRequestMessage(\n                method, path, version, headers, close, compression),\n            len(raw_data))\n        out.feed_eof()\n\n\nclass HttpResponseParser(HttpParser):\n    \"\"\"Read response status line and headers.\n\n    BadStatusLine could be raised in case of any errors in status line.\n    Returns RawResponseMessage\"\"\"\n\n    def __call__(self, out, buf):\n        # read http message (response line + headers)\n        try:\n            raw_data = yield from buf.readuntil(\n                b'\\r\\n\\r\\n', self.max_line_size + self.max_headers)\n        except errors.LineLimitExceededParserError as exc:\n            raise errors.LineTooLong(exc.limit) from None\n\n        lines = raw_data.decode(\n            'utf-8', 'surrogateescape').split('\\r\\n')\n\n        line = lines[0]\n        try:\n            version, status = line.split(None, 1)\n        except ValueError:\n            raise errors.BadStatusLine(line) from None\n        else:\n            try:\n                status, reason = status.split(None, 1)\n            except ValueError:\n                reason = ''\n\n        # version\n        match = VERSRE.match(version)\n        if match is None:\n            raise errors.BadStatusLine(line)\n        version = HttpVersion(int(match.group(1)), int(match.group(2)))\n\n        # The status code is a three-digit number\n        try:\n            status = int(status)\n        except ValueError:\n            raise errors.BadStatusLine(line) from None\n\n        if status < 100 or status > 999:\n            raise errors.BadStatusLine(line)\n\n        # read headers\n        headers, close, compression = self.parse_headers(lines)\n\n        if close is None:\n            close = version <= HttpVersion10\n\n        out.feed_data(\n            RawResponseMessage(\n                version, status, reason.strip(),\n                headers, close, compression),\n            len(raw_data))\n        out.feed_eof()\n\n\nclass HttpPayloadParser:\n\n    def __init__(self, message, length=None, compression=True,\n                 readall=False, response_with_body=True):\n        self.message = message\n        self.length = length\n        self.compression = compression\n        self.readall = readall\n        self.response_with_body = response_with_body\n\n    def __call__(self, out, buf):\n        # payload params\n        length = self.message.headers.get(hdrs.CONTENT_LENGTH, self.length)\n        if hdrs.SEC_WEBSOCKET_KEY1 in self.message.headers:\n            length = 8\n\n        # payload decompression wrapper\n        if self.compression and self.message.compression:\n            out = DeflateBuffer(out, self.message.compression)\n\n        # payload parser\n        if not self.response_with_body:\n            # don't parse payload if it's not expected to be received\n            pass\n\n        elif 'chunked' in self.message.headers.get(\n                hdrs.TRANSFER_ENCODING, ''):\n            yield from self.parse_chunked_payload(out, buf)\n\n        elif length is not None:\n            try:\n                length = int(length)\n            except ValueError:\n                raise errors.InvalidHeader(hdrs.CONTENT_LENGTH) from None\n\n            if length < 0:\n                raise errors.InvalidHeader(hdrs.CONTENT_LENGTH)\n            elif length > 0:\n                yield from self.parse_length_payload(out, buf, length)\n        else:\n            if self.readall and getattr(self.message, 'code', 0) != 204:\n                yield from self.parse_eof_payload(out, buf)\n            elif getattr(self.message, 'method', None) in ('PUT', 'POST'):\n                internal_logger.warning(  # pragma: no cover\n                    'Content-Length or Transfer-Encoding header is required')\n\n        out.feed_eof()\n\n    def parse_chunked_payload(self, out, buf):\n        \"\"\"Chunked transfer encoding parser.\"\"\"\n        while True:\n            # read next chunk size\n            line = yield from buf.readuntil(b'\\r\\n', 8192)\n\n            i = line.find(b';')\n            if i >= 0:\n                line = line[:i]  # strip chunk-extensions\n            else:\n                line = line.strip()\n            try:\n                size = int(line, 16)\n            except ValueError:\n                raise errors.TransferEncodingError(line) from None\n\n            if size == 0:  # eof marker\n                break\n\n            # read chunk and feed buffer\n            while size:\n                chunk = yield from buf.readsome(size)\n                out.feed_data(chunk, len(chunk))\n                size = size - len(chunk)\n\n            # toss the CRLF at the end of the chunk\n            yield from buf.skip(2)\n\n        # read and discard trailer up to the CRLF terminator\n        yield from buf.skipuntil(b'\\r\\n')\n\n    def parse_length_payload(self, out, buf, length=0):\n        \"\"\"Read specified amount of bytes.\"\"\"\n        required = length\n        while required:\n            chunk = yield from buf.readsome(required)\n            out.feed_data(chunk, len(chunk))\n            required -= len(chunk)\n\n    def parse_eof_payload(self, out, buf):\n        \"\"\"Read all bytes until eof.\"\"\"\n        try:\n            while True:\n                chunk = yield from buf.readsome()\n                out.feed_data(chunk, len(chunk))\n        except aiohttp.EofStream:\n            pass\n\n\nclass DeflateBuffer:\n    \"\"\"DeflateStream decompress stream and feed data into specified stream.\"\"\"\n\n    def __init__(self, out, encoding):\n        self.out = out\n        zlib_mode = (16 + zlib.MAX_WBITS\n                     if encoding == 'gzip' else -zlib.MAX_WBITS)\n\n        self.zlib = zlib.decompressobj(wbits=zlib_mode)\n\n    def feed_data(self, chunk, size):\n        try:\n            chunk = self.zlib.decompress(chunk)\n        except Exception:\n            raise errors.ContentEncodingError('deflate')\n\n        if chunk:\n            self.out.feed_data(chunk, len(chunk))\n\n    def feed_eof(self):\n        chunk = self.zlib.flush()\n        self.out.feed_data(chunk, len(chunk))\n        if not self.zlib.eof:\n            raise errors.ContentEncodingError('deflate')\n\n        self.out.feed_eof()\n\n\ndef wrap_payload_filter(func):\n    \"\"\"Wraps payload filter and piped filters.\n\n    Filter is a generator that accepts arbitrary chunks of data,\n    modify data and emit new stream of data.\n\n    For example we have stream of chunks: ['1', '2', '3', '4', '5'],\n    we can apply chunking filter to this stream:\n\n    ['1', '2', '3', '4', '5']\n      |\n    response.add_chunking_filter(2)\n      |\n    ['12', '34', '5']\n\n    It is possible to use different filters at the same time.\n\n    For a example to compress incoming stream with 'deflate' encoding\n    and then split data and emit chunks of 8192 bytes size chunks:\n\n      >>> response.add_compression_filter('deflate')\n      >>> response.add_chunking_filter(8192)\n\n    Filters do not alter transfer encoding.\n\n    Filter can receive types types of data, bytes object or EOF_MARKER.\n\n      1. If filter receives bytes object, it should process data\n         and yield processed data then yield EOL_MARKER object.\n      2. If Filter received EOF_MARKER, it should yield remaining\n         data (buffered) and then yield EOF_MARKER.\n    \"\"\"\n    @functools.wraps(func)\n    def wrapper(self, *args, **kw):\n        new_filter = func(self, *args, **kw)\n\n        filter = self.filter\n        if filter is not None:\n            next(new_filter)\n            self.filter = filter_pipe(filter, new_filter)\n        else:\n            self.filter = new_filter\n\n        next(self.filter)\n\n    return wrapper\n\n\ndef filter_pipe(filter, filter2, *,\n                EOF_MARKER=EOF_MARKER, EOL_MARKER=EOL_MARKER):\n    \"\"\"Creates pipe between two filters.\n\n    filter_pipe() feeds first filter with incoming data and then\n    send yielded from first filter data into filter2, results of\n    filter2 are being emitted.\n\n      1. If filter_pipe receives bytes object, it sends it to the first filter.\n      2. Reads yielded values from the first filter until it receives\n         EOF_MARKER or EOL_MARKER.\n      3. Each of this values is being send to second filter.\n      4. Reads yielded values from second filter until it receives EOF_MARKER\n         or EOL_MARKER. Each of this values yields to writer.\n    \"\"\"\n    chunk = yield\n\n    while True:\n        eof = chunk is EOF_MARKER\n        chunk = filter.send(chunk)\n\n        while chunk is not EOL_MARKER:\n            chunk = filter2.send(chunk)\n\n            while chunk not in (EOF_MARKER, EOL_MARKER):\n                yield chunk\n                chunk = next(filter2)\n\n            if chunk is not EOF_MARKER:\n                if eof:\n                    chunk = EOF_MARKER\n                else:\n                    chunk = next(filter)\n            else:\n                break\n\n        chunk = yield EOL_MARKER\n\n\nclass HttpMessage:\n    \"\"\"HttpMessage allows to write headers and payload to a stream.\n\n    For example, lets say we want to read file then compress it with deflate\n    compression and then send it with chunked transfer encoding, code may look\n    like this:\n\n       >>> response = aiohttp.Response(transport, 200)\n\n    We have to use deflate compression first:\n\n      >>> response.add_compression_filter('deflate')\n\n    Then we want to split output stream into chunks of 1024 bytes size:\n\n      >>> response.add_chunking_filter(1024)\n\n    We can add headers to response with add_headers() method. add_headers()\n    does not send data to transport, send_headers() sends request/response\n    line and then sends headers:\n\n      >>> response.add_headers(\n      ...     ('Content-Disposition', 'attachment; filename=\"...\"'))\n      >>> response.send_headers()\n\n    Now we can use chunked writer to write stream to a network stream.\n    First call to write() method sends response status line and headers,\n    add_header() and add_headers() method unavailable at this stage:\n\n    >>> with open('...', 'rb') as f:\n    ...     chunk = fp.read(8192)\n    ...     while chunk:\n    ...         response.write(chunk)\n    ...         chunk = fp.read(8192)\n\n    >>> response.write_eof()\n\n    \"\"\"\n\n    writer = None\n\n    # 'filter' is being used for altering write() behaviour,\n    # add_chunking_filter adds deflate/gzip compression and\n    # add_compression_filter splits incoming data into a chunks.\n    filter = None\n\n    HOP_HEADERS = None  # Must be set by subclass.\n\n    SERVER_SOFTWARE = 'Python/{0[0]}.{0[1]} aiohttp/{1}'.format(\n        sys.version_info, aiohttp.__version__)\n\n    status = None\n    status_line = b''\n    upgrade = False  # Connection: UPGRADE\n    websocket = False  # Upgrade: WEBSOCKET\n    has_chunked_hdr = False  # Transfer-encoding: chunked\n\n    # subclass can enable auto sending headers with write() call,\n    # this is useful for wsgi's start_response implementation.\n    _send_headers = False\n\n    def __init__(self, transport, version, close):\n        self.transport = transport\n        self.version = version\n        self.closing = close\n        self.keepalive = None\n        self.chunked = False\n        self.length = None\n        self.headers = CIMultiDict()\n        self.headers_sent = False\n        self.output_length = 0\n        self._output_size = 0\n\n    def force_close(self):\n        self.closing = True\n        self.keepalive = False\n\n    def enable_chunked_encoding(self):\n        self.chunked = True\n\n    def keep_alive(self):\n        if self.keepalive is None:\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            else:\n                return not self.closing\n        else:\n            return self.keepalive\n\n    def is_headers_sent(self):\n        return self.headers_sent\n\n    def add_header(self, name, value):\n        \"\"\"Analyze headers. Calculate content length,\n        removes hop headers, etc.\"\"\"\n        assert not self.headers_sent, 'headers have been sent already'\n        assert isinstance(name, str), \\\n            'Header name should be a string, got {!r}'.format(name)\n        assert set(name).issubset(ASCIISET), \\\n            'Header name should contain ASCII chars, got {!r}'.format(name)\n        assert isinstance(value, str), \\\n            'Header {!r} should have string value, got {!r}'.format(\n                name, value)\n\n        name = name.strip().upper()\n        value = value.strip()\n\n        if name == hdrs.CONTENT_LENGTH:\n            self.length = int(value)\n\n        if name == hdrs.TRANSFER_ENCODING:\n            self.has_chunked_hdr = value.lower().strip() == 'chunked'\n\n        if name == hdrs.CONNECTION:\n            val = value.lower()\n            # handle websocket\n            if 'upgrade' in val:\n                self.upgrade = True\n            # connection keep-alive\n            elif 'close' in val:\n                self.keepalive = False\n            elif 'keep-alive' in val:\n                self.keepalive = True\n\n        elif name == hdrs.UPGRADE:\n            if 'websocket' in value.lower():\n                self.websocket = True\n                self.headers[name] = value\n\n        elif name not in self.HOP_HEADERS:\n            # ignore hop-by-hop headers\n            self.headers.add(name, value)\n\n    def add_headers(self, *headers):\n        \"\"\"Adds headers to a http message.\"\"\"\n        for name, value in headers:\n            self.add_header(name, value)\n\n    def send_headers(self, _sep=': ', _end='\\r\\n'):\n        \"\"\"Writes headers to a stream. Constructs payload writer.\"\"\"\n        # Chunked response is only for HTTP/1.1 clients or newer\n        # and there is no Content-Length header is set.\n        # Do not use chunked responses when the response is guaranteed to\n        # not have a response body (304, 204).\n        assert not self.headers_sent, 'headers have been sent already'\n        self.headers_sent = True\n\n        if self.chunked or (self.length is None and\n                            self.version >= HttpVersion11 and\n                            self.status not in (304, 204)):\n            self.writer = self._write_chunked_payload()\n            self.headers[hdrs.TRANSFER_ENCODING] = 'chunked'\n\n        elif self.length is not None:\n            self.writer = self._write_length_payload(self.length)\n\n        else:\n            self.writer = self._write_eof_payload()\n\n        next(self.writer)\n\n        self._add_default_headers()\n\n        # status + headers\n        headers = ''.join(itertools.chain(\n            (self.status_line,),\n            *((k, _sep, v, _end) for k, v in self.headers.items())))\n        headers = headers.encode('utf-8') + b'\\r\\n'\n\n        self.output_length += len(headers)\n        self.transport.write(headers)\n\n    def _add_default_headers(self):\n        # set the connection header\n        if self.upgrade:\n            connection = 'upgrade'\n        elif not self.closing if self.keepalive is None else self.keepalive:\n            connection = 'keep-alive'\n        else:\n            connection = 'close'\n\n        self.headers[hdrs.CONNECTION] = connection\n\n    def write(self, chunk, *,\n              drain=False, EOF_MARKER=EOF_MARKER, EOL_MARKER=EOL_MARKER):\n        \"\"\"Writes chunk of data to a stream by using different writers.\n\n        writer uses filter to modify chunk of data.\n        write_eof() indicates end of stream.\n        writer can't be used after write_eof() method being called.\n        write() return drain future.\n        \"\"\"\n        assert (isinstance(chunk, (bytes, bytearray)) or\n                chunk is EOF_MARKER), chunk\n\n        size = self.output_length\n\n        if self._send_headers and not self.headers_sent:\n            self.send_headers()\n\n        assert self.writer is not None, 'send_headers() is not called.'\n\n        if self.filter:\n            chunk = self.filter.send(chunk)\n            while chunk not in (EOF_MARKER, EOL_MARKER):\n                self.writer.send(chunk)\n                chunk = next(self.filter)\n        else:\n            if chunk is not EOF_MARKER:\n                self.writer.send(chunk)\n\n        self._output_size += self.output_length - size\n\n        if self._output_size > 64 * 1024:\n            if drain:\n                self._output_size = 0\n                return self.transport.drain()\n\n        return ()\n\n    def write_eof(self):\n        self.write(EOF_MARKER)\n        try:\n            self.writer.throw(aiohttp.EofStream())\n        except StopIteration:\n            pass\n\n        return self.transport.drain()\n\n    def _write_chunked_payload(self):\n        \"\"\"Write data in chunked transfer encoding.\"\"\"\n        while True:\n            try:\n                chunk = yield\n            except aiohttp.EofStream:\n                self.transport.write(b'0\\r\\n\\r\\n')\n                self.output_length += 5\n                break\n\n            chunk = bytes(chunk)\n            chunk_len = '{:x}\\r\\n'.format(len(chunk)).encode('ascii')\n            self.transport.write(chunk_len)\n            self.transport.write(chunk)\n            self.transport.write(b'\\r\\n')\n            self.output_length += len(chunk_len) + len(chunk) + 2\n\n    def _write_length_payload(self, length):\n        \"\"\"Write specified number of bytes to a stream.\"\"\"\n        while True:\n            try:\n                chunk = yield\n            except aiohttp.EofStream:\n                break\n\n            if length:\n                l = len(chunk)\n                if length >= l:\n                    self.transport.write(chunk)\n                    self.output_length += l\n                    length = length-l\n                else:\n                    self.transport.write(chunk[:length])\n                    self.output_length += length\n                    length = 0\n\n    def _write_eof_payload(self):\n        while True:\n            try:\n                chunk = yield\n            except aiohttp.EofStream:\n                break\n\n            self.transport.write(chunk)\n            self.output_length += len(chunk)\n\n    @wrap_payload_filter\n    def add_chunking_filter(self, chunk_size=16*1024, *,\n                            EOF_MARKER=EOF_MARKER, EOL_MARKER=EOL_MARKER):\n        \"\"\"Split incoming stream into chunks.\"\"\"\n        buf = bytearray()\n        chunk = yield\n\n        while True:\n            if chunk is EOF_MARKER:\n                if buf:\n                    yield buf\n\n                yield EOF_MARKER\n\n            else:\n                buf.extend(chunk)\n\n                while len(buf) >= chunk_size:\n                    chunk = bytes(buf[:chunk_size])\n                    del buf[:chunk_size]\n                    yield chunk\n\n                chunk = yield EOL_MARKER\n\n    @wrap_payload_filter\n    def add_compression_filter(self, encoding='deflate', *,\n                               EOF_MARKER=EOF_MARKER, EOL_MARKER=EOL_MARKER):\n        \"\"\"Compress incoming stream with deflate or gzip encoding.\"\"\"\n        zlib_mode = (16 + zlib.MAX_WBITS\n                     if encoding == 'gzip' else -zlib.MAX_WBITS)\n        zcomp = zlib.compressobj(wbits=zlib_mode)\n\n        chunk = yield\n        while True:\n            if chunk is EOF_MARKER:\n                yield zcomp.flush()\n                chunk = yield EOF_MARKER\n\n            else:\n                yield zcomp.compress(chunk)\n                chunk = yield EOL_MARKER\n\n\nclass Response(HttpMessage):\n    \"\"\"Create http response message.\n\n    Transport is a socket stream transport. status is a response status code,\n    status has to be integer value. http_version is a tuple that represents\n    http version, (1, 0) stands for HTTP/1.0 and (1, 1) is for HTTP/1.1\n    \"\"\"\n\n    HOP_HEADERS = ()\n\n    @staticmethod\n    def calc_reason(status):\n        record = RESPONSES.get(status)\n        if record is not None:\n            reason = record[0]\n        else:\n            reason = str(status)\n        return reason\n\n    def __init__(self, transport, status,\n                 http_version=HttpVersion11, close=False, reason=None):\n        super().__init__(transport, http_version, close)\n\n        self.status = status\n        if reason is None:\n            reason = self.calc_reason(status)\n\n        self.reason = reason\n        self.status_line = 'HTTP/{}.{} {} {}\\r\\n'.format(\n            http_version[0], http_version[1], status, reason)\n\n    def _add_default_headers(self):\n        super()._add_default_headers()\n\n        if hdrs.DATE not in self.headers:\n            # format_date_time(None) is quite expensive\n            self.headers.setdefault(hdrs.DATE, format_date_time(None))\n        self.headers.setdefault(hdrs.SERVER, self.SERVER_SOFTWARE)\n\n\nclass Request(HttpMessage):\n\n    HOP_HEADERS = ()\n\n    def __init__(self, transport, method, path,\n                 http_version=HttpVersion11, close=False):\n        # set the default for HTTP 1.0 to be different\n        # will only be overwritten with keep-alive header\n        if http_version < HttpVersion11:\n            close = True\n\n        super().__init__(transport, http_version, close)\n\n        self.method = method\n        self.path = path\n        self.status_line = '{0} {1} HTTP/{2[0]}.{2[1]}\\r\\n'.format(\n            method, path, http_version)\n\n    def _add_default_headers(self):\n        super()._add_default_headers()\n\n        self.headers.setdefault(hdrs.USER_AGENT, self.SERVER_SOFTWARE)\n",
            "new_file_content": "\"\"\"Http related parsers and protocol.\"\"\"\n\nimport collections\nimport functools\nimport http.server\nimport itertools\nimport re\nimport string\nimport sys\nimport zlib\nfrom wsgiref.handlers import format_date_time\n\nimport aiohttp\nfrom . import errors, hdrs\nfrom .multidict import CIMultiDict\nfrom .log import internal_logger\n\n__all__ = ('HttpMessage', 'Request', 'Response',\n           'HttpVersion', 'HttpVersion10', 'HttpVersion11',\n           'RawRequestMessage', 'RawResponseMessage',\n           'HttpPrefixParser', 'HttpRequestParser', 'HttpResponseParser',\n           'HttpPayloadParser')\n\nASCIISET = set(string.printable)\nMETHRE = re.compile('[A-Z0-9$-_.]+')\nVERSRE = re.compile('HTTP/(\\d+).(\\d+)')\nHDRRE = re.compile('[\\x00-\\x1F\\x7F()<>@,;:\\[\\]={} \\t\\\\\\\\\\\"]')\nCONTINUATION = (' ', '\\t')\nEOF_MARKER = object()\nEOL_MARKER = object()\nSTATUS_LINE_READY = object()\n\nRESPONSES = http.server.BaseHTTPRequestHandler.responses\n\nHttpVersion = collections.namedtuple(\n    'HttpVersion', ['major', 'minor'])\nHttpVersion10 = HttpVersion(1, 0)\nHttpVersion11 = HttpVersion(1, 1)\n\nRawStatusLineMessage = collections.namedtuple(\n    'RawStatusLineMessage', ['method', 'path', 'version'])\n\nRawRequestMessage = collections.namedtuple(\n    'RawRequestMessage',\n    ['method', 'path', 'version', 'headers', 'should_close', 'compression'])\n\n\nRawResponseMessage = collections.namedtuple(\n    'RawResponseMessage',\n    ['version', 'code', 'reason', 'headers', 'should_close', 'compression'])\n\n\nclass HttpParser:\n\n    def __init__(self, max_line_size=8190, max_headers=32768,\n                 max_field_size=8190):\n        self.max_line_size = max_line_size\n        self.max_headers = max_headers\n        self.max_field_size = max_field_size\n\n    def parse_headers(self, lines):\n        \"\"\"Parses RFC2822 headers from a stream.\n\n        Line continuations are supported. Returns list of header name\n        and value pairs. Header name is in upper case.\n        \"\"\"\n        close_conn = None\n        encoding = None\n        headers = CIMultiDict()\n\n        lines_idx = 1\n        line = lines[1]\n\n        while line:\n            header_length = len(line)\n\n            # Parse initial header name : value pair.\n            try:\n                name, value = line.split(':', 1)\n            except ValueError:\n                raise errors.InvalidHeader(line) from None\n\n            name = name.strip(' \\t').upper()\n            if HDRRE.search(name):\n                raise errors.InvalidHeader(name)\n\n            # next line\n            lines_idx += 1\n            line = lines[lines_idx]\n\n            # consume continuation lines\n            continuation = line and line[0] in CONTINUATION\n\n            if continuation:\n                value = [value]\n                while continuation:\n                    header_length += len(line)\n                    if header_length > self.max_field_size:\n                        raise errors.LineTooLong(\n                            'limit request headers fields size')\n                    value.append(line)\n\n                    # next line\n                    lines_idx += 1\n                    line = lines[lines_idx]\n                    continuation = line[0] in CONTINUATION\n                value = '\\r\\n'.join(value)\n            else:\n                if header_length > self.max_field_size:\n                    raise errors.LineTooLong(\n                        'limit request headers fields size')\n\n            value = value.strip()\n\n            # keep-alive and encoding\n            if name == hdrs.CONNECTION:\n                v = value.lower()\n                if v == 'close':\n                    close_conn = True\n                elif v == 'keep-alive':\n                    close_conn = False\n            elif name == hdrs.CONTENT_ENCODING:\n                enc = value.lower()\n                if enc in ('gzip', 'deflate'):\n                    encoding = enc\n\n            headers.add(name, value)\n\n        return headers, close_conn, encoding\n\n\nclass HttpPrefixParser:\n    \"\"\"Waits for 'HTTP' prefix (non destructive)\"\"\"\n\n    def __init__(self, allowed_methods=()):\n        self.allowed_methods = [m.upper() for m in allowed_methods]\n\n    def __call__(self, out, buf):\n        raw_data = yield from buf.waituntil(b' ', 12)\n        method = raw_data.decode('ascii', 'surrogateescape').strip()\n\n        # method\n        method = method.upper()\n        if not METHRE.match(method):\n            raise errors.BadStatusLine(method)\n\n        # allowed method\n        if self.allowed_methods and method not in self.allowed_methods:\n            raise errors.HttpMethodNotAllowed(message=method)\n\n        out.feed_data(method, len(method))\n        out.feed_eof()\n\n\nclass HttpRequestParser(HttpParser):\n    \"\"\"Read request status line. Exception errors.BadStatusLine\n    could be raised in case of any errors in status line.\n    Returns RawRequestMessage.\n    \"\"\"\n\n    def __call__(self, out, buf):\n        # read http message (request line + headers)\n        try:\n            raw_data = yield from buf.readuntil(\n                b'\\r\\n\\r\\n', self.max_headers)\n        except errors.LineLimitExceededParserError as exc:\n            raise errors.LineTooLong(exc.limit) from None\n\n        lines = raw_data.decode(\n            'utf-8', 'surrogateescape').split('\\r\\n')\n\n        # request line\n        line = lines[0]\n        try:\n            method, path, version = line.split(None, 2)\n        except ValueError:\n            raise errors.BadStatusLine(line) from None\n\n        # method\n        method = method.upper()\n        if not METHRE.match(method):\n            raise errors.BadStatusLine(method)\n\n        # version\n        try:\n            if version.startswith('HTTP/'):\n                n1, n2 = version[5:].split('.', 1)\n                version = HttpVersion(int(n1), int(n2))\n            else:\n                raise errors.BadStatusLine(version)\n        except:\n            raise errors.BadStatusLine(version)\n\n        # read headers\n        headers, close, compression = self.parse_headers(lines)\n        if close is None:  # then the headers weren't set in the request\n            if version <= HttpVersion10:  # HTTP 1.0 must asks to not close\n                close = True\n            else:  # HTTP 1.1 must ask to close.\n                close = False\n\n        out.feed_data(\n            RawRequestMessage(\n                method, path, version, headers, close, compression),\n            len(raw_data))\n        out.feed_eof()\n\n\nclass HttpResponseParser(HttpParser):\n    \"\"\"Read response status line and headers.\n\n    BadStatusLine could be raised in case of any errors in status line.\n    Returns RawResponseMessage\"\"\"\n\n    def __call__(self, out, buf):\n        # read http message (response line + headers)\n        try:\n            raw_data = yield from buf.readuntil(\n                b'\\r\\n\\r\\n', self.max_line_size + self.max_headers)\n        except errors.LineLimitExceededParserError as exc:\n            raise errors.LineTooLong(exc.limit) from None\n\n        lines = raw_data.decode(\n            'utf-8', 'surrogateescape').split('\\r\\n')\n\n        line = lines[0]\n        try:\n            version, status = line.split(None, 1)\n        except ValueError:\n            raise errors.BadStatusLine(line) from None\n        else:\n            try:\n                status, reason = status.split(None, 1)\n            except ValueError:\n                reason = ''\n\n        # version\n        match = VERSRE.match(version)\n        if match is None:\n            raise errors.BadStatusLine(line)\n        version = HttpVersion(int(match.group(1)), int(match.group(2)))\n\n        # The status code is a three-digit number\n        try:\n            status = int(status)\n        except ValueError:\n            raise errors.BadStatusLine(line) from None\n\n        if status < 100 or status > 999:\n            raise errors.BadStatusLine(line)\n\n        # read headers\n        headers, close, compression = self.parse_headers(lines)\n\n        if close is None:\n            close = version <= HttpVersion10\n\n        out.feed_data(\n            RawResponseMessage(\n                version, status, reason.strip(),\n                headers, close, compression),\n            len(raw_data))\n        out.feed_eof()\n\n\nclass HttpPayloadParser:\n\n    def __init__(self, message, length=None, compression=True,\n                 readall=False, response_with_body=True):\n        self.message = message\n        self.length = length\n        self.compression = compression\n        self.readall = readall\n        self.response_with_body = response_with_body\n\n    def __call__(self, out, buf):\n        # payload params\n        length = self.message.headers.get(hdrs.CONTENT_LENGTH, self.length)\n        if hdrs.SEC_WEBSOCKET_KEY1 in self.message.headers:\n            length = 8\n\n        # payload decompression wrapper\n        if self.compression and self.message.compression:\n            out = DeflateBuffer(out, self.message.compression)\n\n        # payload parser\n        if not self.response_with_body:\n            # don't parse payload if it's not expected to be received\n            pass\n\n        elif 'chunked' in self.message.headers.get(\n                hdrs.TRANSFER_ENCODING, ''):\n            yield from self.parse_chunked_payload(out, buf)\n\n        elif length is not None:\n            try:\n                length = int(length)\n            except ValueError:\n                raise errors.InvalidHeader(hdrs.CONTENT_LENGTH) from None\n\n            if length < 0:\n                raise errors.InvalidHeader(hdrs.CONTENT_LENGTH)\n            elif length > 0:\n                yield from self.parse_length_payload(out, buf, length)\n        else:\n            if self.readall and getattr(self.message, 'code', 0) != 204:\n                yield from self.parse_eof_payload(out, buf)\n            elif getattr(self.message, 'method', None) in ('PUT', 'POST'):\n                internal_logger.warning(  # pragma: no cover\n                    'Content-Length or Transfer-Encoding header is required')\n\n        out.feed_eof()\n\n    def parse_chunked_payload(self, out, buf):\n        \"\"\"Chunked transfer encoding parser.\"\"\"\n        while True:\n            # read next chunk size\n            line = yield from buf.readuntil(b'\\r\\n', 8192)\n\n            i = line.find(b';')\n            if i >= 0:\n                line = line[:i]  # strip chunk-extensions\n            else:\n                line = line.strip()\n            try:\n                size = int(line, 16)\n            except ValueError:\n                raise errors.TransferEncodingError(line) from None\n\n            if size == 0:  # eof marker\n                break\n\n            # read chunk and feed buffer\n            while size:\n                chunk = yield from buf.readsome(size)\n                out.feed_data(chunk, len(chunk))\n                size = size - len(chunk)\n\n            # toss the CRLF at the end of the chunk\n            yield from buf.skip(2)\n\n        # read and discard trailer up to the CRLF terminator\n        yield from buf.skipuntil(b'\\r\\n')\n\n    def parse_length_payload(self, out, buf, length=0):\n        \"\"\"Read specified amount of bytes.\"\"\"\n        required = length\n        while required:\n            chunk = yield from buf.readsome(required)\n            out.feed_data(chunk, len(chunk))\n            required -= len(chunk)\n\n    def parse_eof_payload(self, out, buf):\n        \"\"\"Read all bytes until eof.\"\"\"\n        try:\n            while True:\n                chunk = yield from buf.readsome()\n                out.feed_data(chunk, len(chunk))\n        except aiohttp.EofStream:\n            pass\n\n\nclass DeflateBuffer:\n    \"\"\"DeflateStream decompress stream and feed data into specified stream.\"\"\"\n\n    def __init__(self, out, encoding):\n        self.out = out\n        zlib_mode = (16 + zlib.MAX_WBITS\n                     if encoding == 'gzip' else -zlib.MAX_WBITS)\n\n        self.zlib = zlib.decompressobj(wbits=zlib_mode)\n\n    def feed_data(self, chunk, size):\n        try:\n            chunk = self.zlib.decompress(chunk)\n        except Exception:\n            raise errors.ContentEncodingError('deflate')\n\n        if chunk:\n            self.out.feed_data(chunk, len(chunk))\n\n    def feed_eof(self):\n        chunk = self.zlib.flush()\n        self.out.feed_data(chunk, len(chunk))\n        if not self.zlib.eof:\n            raise errors.ContentEncodingError('deflate')\n\n        self.out.feed_eof()\n\n\ndef wrap_payload_filter(func):\n    \"\"\"Wraps payload filter and piped filters.\n\n    Filter is a generator that accepts arbitrary chunks of data,\n    modify data and emit new stream of data.\n\n    For example we have stream of chunks: ['1', '2', '3', '4', '5'],\n    we can apply chunking filter to this stream:\n\n    ['1', '2', '3', '4', '5']\n      |\n    response.add_chunking_filter(2)\n      |\n    ['12', '34', '5']\n\n    It is possible to use different filters at the same time.\n\n    For a example to compress incoming stream with 'deflate' encoding\n    and then split data and emit chunks of 8192 bytes size chunks:\n\n      >>> response.add_compression_filter('deflate')\n      >>> response.add_chunking_filter(8192)\n\n    Filters do not alter transfer encoding.\n\n    Filter can receive types types of data, bytes object or EOF_MARKER.\n\n      1. If filter receives bytes object, it should process data\n         and yield processed data then yield EOL_MARKER object.\n      2. If Filter received EOF_MARKER, it should yield remaining\n         data (buffered) and then yield EOF_MARKER.\n    \"\"\"\n    @functools.wraps(func)\n    def wrapper(self, *args, **kw):\n        new_filter = func(self, *args, **kw)\n\n        filter = self.filter\n        if filter is not None:\n            next(new_filter)\n            self.filter = filter_pipe(filter, new_filter)\n        else:\n            self.filter = new_filter\n\n        next(self.filter)\n\n    return wrapper\n\n\ndef filter_pipe(filter, filter2, *,\n                EOF_MARKER=EOF_MARKER, EOL_MARKER=EOL_MARKER):\n    \"\"\"Creates pipe between two filters.\n\n    filter_pipe() feeds first filter with incoming data and then\n    send yielded from first filter data into filter2, results of\n    filter2 are being emitted.\n\n      1. If filter_pipe receives bytes object, it sends it to the first filter.\n      2. Reads yielded values from the first filter until it receives\n         EOF_MARKER or EOL_MARKER.\n      3. Each of this values is being send to second filter.\n      4. Reads yielded values from second filter until it receives EOF_MARKER\n         or EOL_MARKER. Each of this values yields to writer.\n    \"\"\"\n    chunk = yield\n\n    while True:\n        eof = chunk is EOF_MARKER\n        chunk = filter.send(chunk)\n\n        while chunk is not EOL_MARKER:\n            chunk = filter2.send(chunk)\n\n            while chunk not in (EOF_MARKER, EOL_MARKER):\n                yield chunk\n                chunk = next(filter2)\n\n            if chunk is not EOF_MARKER:\n                if eof:\n                    chunk = EOF_MARKER\n                else:\n                    chunk = next(filter)\n            else:\n                break\n\n        chunk = yield EOL_MARKER\n\n\nclass HttpMessage:\n    \"\"\"HttpMessage allows to write headers and payload to a stream.\n\n    For example, lets say we want to read file then compress it with deflate\n    compression and then send it with chunked transfer encoding, code may look\n    like this:\n\n       >>> response = aiohttp.Response(transport, 200)\n\n    We have to use deflate compression first:\n\n      >>> response.add_compression_filter('deflate')\n\n    Then we want to split output stream into chunks of 1024 bytes size:\n\n      >>> response.add_chunking_filter(1024)\n\n    We can add headers to response with add_headers() method. add_headers()\n    does not send data to transport, send_headers() sends request/response\n    line and then sends headers:\n\n      >>> response.add_headers(\n      ...     ('Content-Disposition', 'attachment; filename=\"...\"'))\n      >>> response.send_headers()\n\n    Now we can use chunked writer to write stream to a network stream.\n    First call to write() method sends response status line and headers,\n    add_header() and add_headers() method unavailable at this stage:\n\n    >>> with open('...', 'rb') as f:\n    ...     chunk = fp.read(8192)\n    ...     while chunk:\n    ...         response.write(chunk)\n    ...         chunk = fp.read(8192)\n\n    >>> response.write_eof()\n\n    \"\"\"\n\n    writer = None\n\n    # 'filter' is being used for altering write() behaviour,\n    # add_chunking_filter adds deflate/gzip compression and\n    # add_compression_filter splits incoming data into a chunks.\n    filter = None\n\n    HOP_HEADERS = None  # Must be set by subclass.\n\n    SERVER_SOFTWARE = 'Python/{0[0]}.{0[1]} aiohttp/{1}'.format(\n        sys.version_info, aiohttp.__version__)\n\n    status = None\n    status_line = b''\n    upgrade = False  # Connection: UPGRADE\n    websocket = False  # Upgrade: WEBSOCKET\n    has_chunked_hdr = False  # Transfer-encoding: chunked\n\n    # subclass can enable auto sending headers with write() call,\n    # this is useful for wsgi's start_response implementation.\n    _send_headers = False\n\n    def __init__(self, transport, version, close):\n        self.transport = transport\n        self.version = version\n        self.closing = close\n        self.keepalive = None\n        self.chunked = False\n        self.length = None\n        self.headers = CIMultiDict()\n        self.headers_sent = False\n        self.output_length = 0\n        self._output_size = 0\n\n    def force_close(self):\n        self.closing = True\n        self.keepalive = False\n\n    def enable_chunked_encoding(self):\n        self.chunked = True\n\n    def keep_alive(self):\n        if self.keepalive is None:\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            else:\n                return not self.closing\n        else:\n            return self.keepalive\n\n    def is_headers_sent(self):\n        return self.headers_sent\n\n    def add_header(self, name, value):\n        \"\"\"Analyze headers. Calculate content length,\n        removes hop headers, etc.\"\"\"\n        assert not self.headers_sent, 'headers have been sent already'\n        assert isinstance(name, str), \\\n            'Header name should be a string, got {!r}'.format(name)\n        assert set(name).issubset(ASCIISET), \\\n            'Header name should contain ASCII chars, got {!r}'.format(name)\n        assert isinstance(value, str), \\\n            'Header {!r} should have string value, got {!r}'.format(\n                name, value)\n\n        name = name.strip().upper()\n        value = value.strip()\n\n        if name == hdrs.CONTENT_LENGTH:\n            self.length = int(value)\n\n        if name == hdrs.TRANSFER_ENCODING:\n            self.has_chunked_hdr = value.lower().strip() == 'chunked'\n\n        if name == hdrs.CONNECTION:\n            val = value.lower()\n            # handle websocket\n            if 'upgrade' in val:\n                self.upgrade = True\n            # connection keep-alive\n            elif 'close' in val:\n                self.keepalive = False\n            elif 'keep-alive' in val:\n                self.keepalive = True\n\n        elif name == hdrs.UPGRADE:\n            if 'websocket' in value.lower():\n                self.websocket = True\n                self.headers[name] = value\n\n        elif name not in self.HOP_HEADERS:\n            # ignore hop-by-hop headers\n            self.headers.add(name, value)\n\n    def add_headers(self, *headers):\n        \"\"\"Adds headers to a http message.\"\"\"\n        for name, value in headers:\n            self.add_header(name, value)\n\n    def send_headers(self, _sep=': ', _end='\\r\\n'):\n        \"\"\"Writes headers to a stream. Constructs payload writer.\"\"\"\n        # Chunked response is only for HTTP/1.1 clients or newer\n        # and there is no Content-Length header is set.\n        # Do not use chunked responses when the response is guaranteed to\n        # not have a response body (304, 204).\n        assert not self.headers_sent, 'headers have been sent already'\n        self.headers_sent = True\n\n        if self.chunked or (self.length is None and\n                            self.version >= HttpVersion11 and\n                            self.status not in (304, 204)):\n            self.writer = self._write_chunked_payload()\n            self.headers[hdrs.TRANSFER_ENCODING] = 'chunked'\n\n        elif self.length is not None:\n            self.writer = self._write_length_payload(self.length)\n\n        else:\n            self.writer = self._write_eof_payload()\n\n        next(self.writer)\n\n        self._add_default_headers()\n\n        # status + headers\n        headers = ''.join(itertools.chain(\n            (self.status_line,),\n            *((k, _sep, v, _end) for k, v in self.headers.items())))\n        headers = headers.encode('utf-8') + b'\\r\\n'\n\n        self.output_length += len(headers)\n        self.transport.write(headers)\n\n    def _add_default_headers(self):\n        # set the connection header\n        if self.upgrade:\n            connection = 'upgrade'\n        elif not self.closing if self.keepalive is None else self.keepalive:\n            connection = 'keep-alive'\n        else:\n            connection = 'close'\n\n        self.headers[hdrs.CONNECTION] = connection\n\n    def write(self, chunk, *,\n              drain=False, EOF_MARKER=EOF_MARKER, EOL_MARKER=EOL_MARKER):\n        \"\"\"Writes chunk of data to a stream by using different writers.\n\n        writer uses filter to modify chunk of data.\n        write_eof() indicates end of stream.\n        writer can't be used after write_eof() method being called.\n        write() return drain future.\n        \"\"\"\n        assert (isinstance(chunk, (bytes, bytearray)) or\n                chunk is EOF_MARKER), chunk\n\n        size = self.output_length\n\n        if self._send_headers and not self.headers_sent:\n            self.send_headers()\n\n        assert self.writer is not None, 'send_headers() is not called.'\n\n        if self.filter:\n            chunk = self.filter.send(chunk)\n            while chunk not in (EOF_MARKER, EOL_MARKER):\n                if chunk:\n                    self.writer.send(chunk)\n                chunk = next(self.filter)\n        else:\n            if chunk is not EOF_MARKER:\n                self.writer.send(chunk)\n\n        self._output_size += self.output_length - size\n\n        if self._output_size > 64 * 1024:\n            if drain:\n                self._output_size = 0\n                return self.transport.drain()\n\n        return ()\n\n    def write_eof(self):\n        self.write(EOF_MARKER)\n        try:\n            self.writer.throw(aiohttp.EofStream())\n        except StopIteration:\n            pass\n\n        return self.transport.drain()\n\n    def _write_chunked_payload(self):\n        \"\"\"Write data in chunked transfer encoding.\"\"\"\n        while True:\n            try:\n                chunk = yield\n            except aiohttp.EofStream:\n                self.transport.write(b'0\\r\\n\\r\\n')\n                self.output_length += 5\n                break\n\n            chunk = bytes(chunk)\n            chunk_len = '{:x}\\r\\n'.format(len(chunk)).encode('ascii')\n            self.transport.write(chunk_len)\n            self.transport.write(chunk)\n            self.transport.write(b'\\r\\n')\n            self.output_length += len(chunk_len) + len(chunk) + 2\n\n    def _write_length_payload(self, length):\n        \"\"\"Write specified number of bytes to a stream.\"\"\"\n        while True:\n            try:\n                chunk = yield\n            except aiohttp.EofStream:\n                break\n\n            if length:\n                l = len(chunk)\n                if length >= l:\n                    self.transport.write(chunk)\n                    self.output_length += l\n                    length = length-l\n                else:\n                    self.transport.write(chunk[:length])\n                    self.output_length += length\n                    length = 0\n\n    def _write_eof_payload(self):\n        while True:\n            try:\n                chunk = yield\n            except aiohttp.EofStream:\n                break\n\n            self.transport.write(chunk)\n            self.output_length += len(chunk)\n\n    @wrap_payload_filter\n    def add_chunking_filter(self, chunk_size=16*1024, *,\n                            EOF_MARKER=EOF_MARKER, EOL_MARKER=EOL_MARKER):\n        \"\"\"Split incoming stream into chunks.\"\"\"\n        buf = bytearray()\n        chunk = yield\n\n        while True:\n            if chunk is EOF_MARKER:\n                if buf:\n                    yield buf\n\n                yield EOF_MARKER\n\n            else:\n                buf.extend(chunk)\n\n                while len(buf) >= chunk_size:\n                    chunk = bytes(buf[:chunk_size])\n                    del buf[:chunk_size]\n                    yield chunk\n\n                chunk = yield EOL_MARKER\n\n    @wrap_payload_filter\n    def add_compression_filter(self, encoding='deflate', *,\n                               EOF_MARKER=EOF_MARKER, EOL_MARKER=EOL_MARKER):\n        \"\"\"Compress incoming stream with deflate or gzip encoding.\"\"\"\n        zlib_mode = (16 + zlib.MAX_WBITS\n                     if encoding == 'gzip' else -zlib.MAX_WBITS)\n        zcomp = zlib.compressobj(wbits=zlib_mode)\n\n        chunk = yield\n        while True:\n            if chunk is EOF_MARKER:\n                yield zcomp.flush()\n                chunk = yield EOF_MARKER\n\n            else:\n                yield zcomp.compress(chunk)\n                chunk = yield EOL_MARKER\n\n\nclass Response(HttpMessage):\n    \"\"\"Create http response message.\n\n    Transport is a socket stream transport. status is a response status code,\n    status has to be integer value. http_version is a tuple that represents\n    http version, (1, 0) stands for HTTP/1.0 and (1, 1) is for HTTP/1.1\n    \"\"\"\n\n    HOP_HEADERS = ()\n\n    @staticmethod\n    def calc_reason(status):\n        record = RESPONSES.get(status)\n        if record is not None:\n            reason = record[0]\n        else:\n            reason = str(status)\n        return reason\n\n    def __init__(self, transport, status,\n                 http_version=HttpVersion11, close=False, reason=None):\n        super().__init__(transport, http_version, close)\n\n        self.status = status\n        if reason is None:\n            reason = self.calc_reason(status)\n\n        self.reason = reason\n        self.status_line = 'HTTP/{}.{} {} {}\\r\\n'.format(\n            http_version[0], http_version[1], status, reason)\n\n    def _add_default_headers(self):\n        super()._add_default_headers()\n\n        if hdrs.DATE not in self.headers:\n            # format_date_time(None) is quite expensive\n            self.headers.setdefault(hdrs.DATE, format_date_time(None))\n        self.headers.setdefault(hdrs.SERVER, self.SERVER_SOFTWARE)\n\n\nclass Request(HttpMessage):\n\n    HOP_HEADERS = ()\n\n    def __init__(self, transport, method, path,\n                 http_version=HttpVersion11, close=False):\n        # set the default for HTTP 1.0 to be different\n        # will only be overwritten with keep-alive header\n        if http_version < HttpVersion11:\n            close = True\n\n        super().__init__(transport, http_version, close)\n\n        self.method = method\n        self.path = path\n        self.status_line = '{0} {1} HTTP/{2[0]}.{2[1]}\\r\\n'.format(\n            method, path, http_version)\n\n    def _add_default_headers(self):\n        super()._add_default_headers()\n\n        self.headers.setdefault(hdrs.USER_AGENT, self.SERVER_SOFTWARE)\n",
            "header": {
                "file": {
                    "path": "aiohttp/protocol.py"
                },
                "misc_line": null
            },
            "index_line": {
                "old_commit_hash": "43094961",
                "new_commit_hash": "e8c4e4d3",
                "mode": "100644"
            },
            "is_binary_file": false,
            "binary_line": null,
            "minus_file": {
                "path": "a/aiohttp/protocol.py"
            },
            "plus_file": {
                "path": "b/aiohttp/protocol.py"
            },
            "hunks": [
                {
                    "descriptor": {
                        "old_range": {
                            "start": 686,
                            "length": 7
                        },
                        "new_range": {
                            "start": 686,
                            "length": 8
                        },
                        "section": "class HttpMessage:"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "        if self.filter:",
                                "type": "context"
                            },
                            {
                                "content": "            chunk = self.filter.send(chunk)",
                                "type": "context"
                            },
                            {
                                "content": "            while chunk not in (EOF_MARKER, EOL_MARKER):",
                                "type": "context"
                            },
                            {
                                "content": "                self.writer.send(chunk)",
                                "type": "deleted"
                            },
                            {
                                "content": "                if chunk:",
                                "type": "added"
                            },
                            {
                                "content": "                    self.writer.send(chunk)",
                                "type": "added"
                            },
                            {
                                "content": "                chunk = next(self.filter)",
                                "type": "context"
                            },
                            {
                                "content": "        else:",
                                "type": "context"
                            },
                            {
                                "content": "            if chunk is not EOF_MARKER:",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [
                        {
                            "file_name": "aiohttp/protocol.py",
                            "type": "method",
                            "name": "HttpMessage.write",
                            "content": "class HttpMessage:\n    \"\"\"HttpMessage allows to write headers and payload to a stream.\n\n    For example, lets say we want to read file then compress it with deflate\n    compression and then send it with chunked transfer encoding, code may look\n    like this:\n\n       >>> response = aiohttp.Response(transport, 200)\n\n    We have to use deflate compression first:\n\n      >>> response.add_compression_filter('deflate')\n\n    Then we want to split output stream into chunks of 1024 bytes size:\n\n      >>> response.add_chunking_filter(1024)\n\n    We can add headers to response with add_headers() method. add_headers()\n    does not send data to transport, send_headers() sends request/response\n    line and then sends headers:\n\n      >>> response.add_headers(\n      ...     ('Content-Disposition', 'attachment; filename=\"...\"'))\n      >>> response.send_headers()\n\n    Now we can use chunked writer to write stream to a network stream.\n    First call to write() method sends response status line and headers,\n    add_header() and add_headers() method unavailable at this stage:\n\n    >>> with open('...', 'rb') as f:\n    ...     chunk = fp.read(8192)\n    ...     while chunk:\n    ...         response.write(chunk)\n    ...         chunk = fp.read(8192)\n\n    >>> response.write_eof()\n\n    \"\"\"\n\n    writer = None\n\n    # 'filter' is being used for altering write() behaviour,\n    # add_chunking_filter adds deflate/gzip compression and\n    # add_compression_filter splits incoming data into a chunks.\n    filter = None\n\n    HOP_HEADERS = None  # Must be set by subclass.\n\n    SERVER_SOFTWARE = 'Python/{0[0]}.{0[1]} aiohttp/{1}'.format(\n        sys.version_info, aiohttp.__version__)\n\n    status = None\n    status_line = b''\n    upgrade = False  # Connection: UPGRADE\n    websocket = False  # Upgrade: WEBSOCKET\n    has_chunked_hdr = False  # Transfer-encoding: chunked\n\n    # subclass can enable auto sending headers with write() call,\n    # this is useful for wsgi's start_response implementation.\n    _send_headers = False\n\n    def __init__(self, transport, version, close):\n        self.transport = transport\n        self.version = version\n        self.closing = close\n        self.keepalive = None\n        self.chunked = False\n        self.length = None\n        self.headers = CIMultiDict()\n        self.headers_sent = False\n        self.output_length = 0\n        self._output_size = 0\n\n    def force_close(self):\n        self.closing = True\n        self.keepalive = False\n\n    def enable_chunked_encoding(self):\n        self.chunked = True\n\n    def keep_alive(self):\n        if self.keepalive is None:\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            else:\n                return not self.closing\n        else:\n            return self.keepalive\n\n    def is_headers_sent(self):\n        return self.headers_sent\n\n    def add_header(self, name, value):\n        \"\"\"Analyze headers. Calculate content length,\n        removes hop headers, etc.\"\"\"\n        assert not self.headers_sent, 'headers have been sent already'\n        assert isinstance(name, str), \\\n            'Header name should be a string, got {!r}'.format(name)\n        assert set(name).issubset(ASCIISET), \\\n            'Header name should contain ASCII chars, got {!r}'.format(name)\n        assert isinstance(value, str), \\\n            'Header {!r} should have string value, got {!r}'.format(\n                name, value)\n\n        name = name.strip().upper()\n        value = value.strip()\n\n        if name == hdrs.CONTENT_LENGTH:\n            self.length = int(value)\n\n        if name == hdrs.TRANSFER_ENCODING:\n            self.has_chunked_hdr = value.lower().strip() == 'chunked'\n\n        if name == hdrs.CONNECTION:\n            val = value.lower()\n            # handle websocket\n            if 'upgrade' in val:\n                self.upgrade = True\n            # connection keep-alive\n            elif 'close' in val:\n                self.keepalive = False\n            elif 'keep-alive' in val:\n                self.keepalive = True\n\n        elif name == hdrs.UPGRADE:\n            if 'websocket' in value.lower():\n                self.websocket = True\n                self.headers[name] = value\n\n        elif name not in self.HOP_HEADERS:\n            # ignore hop-by-hop headers\n            self.headers.add(name, value)\n\n    def add_headers(self, *headers):\n        \"\"\"Adds headers to a http message.\"\"\"\n        for name, value in headers:\n            self.add_header(name, value)\n\n    def send_headers(self, _sep=': ', _end='\\r\\n'):\n        \"\"\"Writes headers to a stream. Constructs payload writer.\"\"\"\n        # Chunked response is only for HTTP/1.1 clients or newer\n        # and there is no Content-Length header is set.\n        # Do not use chunked responses when the response is guaranteed to\n        # not have a response body (304, 204).\n        assert not self.headers_sent, 'headers have been sent already'\n        self.headers_sent = True\n\n        if self.chunked or (self.length is None and\n                            self.version >= HttpVersion11 and\n                            self.status not in (304, 204)):\n            self.writer = self._write_chunked_payload()\n            self.headers[hdrs.TRANSFER_ENCODING] = 'chunked'\n\n        elif self.length is not None:\n            self.writer = self._write_length_payload(self.length)\n\n        else:\n            self.writer = self._write_eof_payload()\n\n        next(self.writer)\n\n        self._add_default_headers()\n\n        # status + headers\n        headers = ''.join(itertools.chain(\n            (self.status_line,),\n            *((k, _sep, v, _end) for k, v in self.headers.items())))\n        headers = headers.encode('utf-8') + b'\\r\\n'\n\n        self.output_length += len(headers)\n        self.transport.write(headers)\n\n    def _add_default_headers(self):\n        # set the connection header\n        if self.upgrade:\n            connection = 'upgrade'\n        elif not self.closing if self.keepalive is None else self.keepalive:\n            connection = 'keep-alive'\n        else:\n            connection = 'close'\n\n        self.headers[hdrs.CONNECTION] = connection\n\n    def write(self, chunk, *,\n              drain=False, EOF_MARKER=EOF_MARKER, EOL_MARKER=EOL_MARKER):\n        \"\"\"Writes chunk of data to a stream by using different writers.\n\n        writer uses filter to modify chunk of data.\n        write_eof() indicates end of stream.\n        writer can't be used after write_eof() method being called.\n        write() return drain future.\n        \"\"\"\n        assert (isinstance(chunk, (bytes, bytearray)) or\n                chunk is EOF_MARKER), chunk\n\n        size = self.output_length\n\n        if self._send_headers and not self.headers_sent:\n            self.send_headers()\n\n        assert self.writer is not None, 'send_headers() is not called.'\n\n        if self.filter:\n            chunk = self.filter.send(chunk)\n            while chunk not in (EOF_MARKER, EOL_MARKER):\n                self.writer.send(chunk)\n                chunk = next(self.filter)\n        else:\n            if chunk is not EOF_MARKER:\n                self.writer.send(chunk)\n\n        self._output_size += self.output_length - size\n\n        if self._output_size > 64 * 1024:\n            if drain:\n                self._output_size = 0\n                return self.transport.drain()\n\n        return ()\n\n    def write_eof(self):\n        self.write(EOF_MARKER)\n        try:\n            self.writer.throw(aiohttp.EofStream())\n        except StopIteration:\n            pass\n\n        return self.transport.drain()\n\n    def _write_chunked_payload(self):\n        \"\"\"Write data in chunked transfer encoding.\"\"\"\n        while True:\n            try:\n                chunk = yield\n            except aiohttp.EofStream:\n                self.transport.write(b'0\\r\\n\\r\\n')\n                self.output_length += 5\n                break\n\n            chunk = bytes(chunk)\n            chunk_len = '{:x}\\r\\n'.format(len(chunk)).encode('ascii')\n            self.transport.write(chunk_len)\n            self.transport.write(chunk)\n            self.transport.write(b'\\r\\n')\n            self.output_length += len(chunk_len) + len(chunk) + 2\n\n    def _write_length_payload(self, length):\n        \"\"\"Write specified number of bytes to a stream.\"\"\"\n        while True:\n            try:\n                chunk = yield\n            except aiohttp.EofStream:\n                break\n\n            if length:\n                l = len(chunk)\n                if length >= l:\n                    self.transport.write(chunk)\n                    self.output_length += l\n                    length = length-l\n                else:\n                    self.transport.write(chunk[:length])\n                    self.output_length += length\n                    length = 0\n\n    def _write_eof_payload(self):\n        while True:\n            try:\n                chunk = yield\n            except aiohttp.EofStream:\n                break\n\n            self.transport.write(chunk)\n            self.output_length += len(chunk)\n\n    @wrap_payload_filter\n    def add_chunking_filter(self, chunk_size=16*1024, *,\n                            EOF_MARKER=EOF_MARKER, EOL_MARKER=EOL_MARKER):\n        \"\"\"Split incoming stream into chunks.\"\"\"\n        buf = bytearray()\n        chunk = yield\n\n        while True:\n            if chunk is EOF_MARKER:\n                if buf:\n                    yield buf\n\n                yield EOF_MARKER\n\n            else:\n                buf.extend(chunk)\n\n                while len(buf) >= chunk_size:\n                    chunk = bytes(buf[:chunk_size])\n                    del buf[:chunk_size]\n                    yield chunk\n\n                chunk = yield EOL_MARKER\n\n    @wrap_payload_filter\n    def add_compression_filter(self, encoding='deflate', *,\n                               EOF_MARKER=EOF_MARKER, EOL_MARKER=EOL_MARKER):\n        \"\"\"Compress incoming stream with deflate or gzip encoding.\"\"\"\n        zlib_mode = (16 + zlib.MAX_WBITS\n                     if encoding == 'gzip' else -zlib.MAX_WBITS)\n        zcomp = zlib.compressobj(wbits=zlib_mode)\n\n        chunk = yield\n        while True:\n            if chunk is EOF_MARKER:\n                yield zcomp.flush()\n                chunk = yield EOF_MARKER\n\n            else:\n                yield zcomp.compress(chunk)\n                chunk = yield EOL_MARKER",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 667,
                            "end_lineno": 702,
                            "parent": {
                                "file_name": "aiohttp/protocol.py",
                                "type": "class",
                                "name": "HttpMessage",
                                "content": "class HttpMessage:\n    \"\"\"HttpMessage allows to write headers and payload to a stream.\n\n    For example, lets say we want to read file then compress it with deflate\n    compression and then send it with chunked transfer encoding, code may look\n    like this:\n\n       >>> response = aiohttp.Response(transport, 200)\n\n    We have to use deflate compression first:\n\n      >>> response.add_compression_filter('deflate')\n\n    Then we want to split output stream into chunks of 1024 bytes size:\n\n      >>> response.add_chunking_filter(1024)\n\n    We can add headers to response with add_headers() method. add_headers()\n    does not send data to transport, send_headers() sends request/response\n    line and then sends headers:\n\n      >>> response.add_headers(\n      ...     ('Content-Disposition', 'attachment; filename=\"...\"'))\n      >>> response.send_headers()\n\n    Now we can use chunked writer to write stream to a network stream.\n    First call to write() method sends response status line and headers,\n    add_header() and add_headers() method unavailable at this stage:\n\n    >>> with open('...', 'rb') as f:\n    ...     chunk = fp.read(8192)\n    ...     while chunk:\n    ...         response.write(chunk)\n    ...         chunk = fp.read(8192)\n\n    >>> response.write_eof()\n\n    \"\"\"\n\n    writer = None\n\n    # 'filter' is being used for altering write() behaviour,\n    # add_chunking_filter adds deflate/gzip compression and\n    # add_compression_filter splits incoming data into a chunks.\n    filter = None\n\n    HOP_HEADERS = None  # Must be set by subclass.\n\n    SERVER_SOFTWARE = 'Python/{0[0]}.{0[1]} aiohttp/{1}'.format(\n        sys.version_info, aiohttp.__version__)\n\n    status = None\n    status_line = b''\n    upgrade = False  # Connection: UPGRADE\n    websocket = False  # Upgrade: WEBSOCKET\n    has_chunked_hdr = False  # Transfer-encoding: chunked\n\n    # subclass can enable auto sending headers with write() call,\n    # this is useful for wsgi's start_response implementation.\n    _send_headers = False\n\n    def __init__(self, transport, version, close):\n        self.transport = transport\n        self.version = version\n        self.closing = close\n        self.keepalive = None\n        self.chunked = False\n        self.length = None\n        self.headers = CIMultiDict()\n        self.headers_sent = False\n        self.output_length = 0\n        self._output_size = 0\n\n    def force_close(self):\n        self.closing = True\n        self.keepalive = False\n\n    def enable_chunked_encoding(self):\n        self.chunked = True\n\n    def keep_alive(self):\n        if self.keepalive is None:\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            else:\n                return not self.closing\n        else:\n            return self.keepalive\n\n    def is_headers_sent(self):\n        return self.headers_sent\n\n    def add_header(self, name, value):\n        \"\"\"Analyze headers. Calculate content length,\n        removes hop headers, etc.\"\"\"\n        assert not self.headers_sent, 'headers have been sent already'\n        assert isinstance(name, str), \\\n            'Header name should be a string, got {!r}'.format(name)\n        assert set(name).issubset(ASCIISET), \\\n            'Header name should contain ASCII chars, got {!r}'.format(name)\n        assert isinstance(value, str), \\\n            'Header {!r} should have string value, got {!r}'.format(\n                name, value)\n\n        name = name.strip().upper()\n        value = value.strip()\n\n        if name == hdrs.CONTENT_LENGTH:\n            self.length = int(value)\n\n        if name == hdrs.TRANSFER_ENCODING:\n            self.has_chunked_hdr = value.lower().strip() == 'chunked'\n\n        if name == hdrs.CONNECTION:\n            val = value.lower()\n            # handle websocket\n            if 'upgrade' in val:\n                self.upgrade = True\n            # connection keep-alive\n            elif 'close' in val:\n                self.keepalive = False\n            elif 'keep-alive' in val:\n                self.keepalive = True\n\n        elif name == hdrs.UPGRADE:\n            if 'websocket' in value.lower():\n                self.websocket = True\n                self.headers[name] = value\n\n        elif name not in self.HOP_HEADERS:\n            # ignore hop-by-hop headers\n            self.headers.add(name, value)\n\n    def add_headers(self, *headers):\n        \"\"\"Adds headers to a http message.\"\"\"\n        for name, value in headers:\n            self.add_header(name, value)\n\n    def send_headers(self, _sep=': ', _end='\\r\\n'):\n        \"\"\"Writes headers to a stream. Constructs payload writer.\"\"\"\n        # Chunked response is only for HTTP/1.1 clients or newer\n        # and there is no Content-Length header is set.\n        # Do not use chunked responses when the response is guaranteed to\n        # not have a response body (304, 204).\n        assert not self.headers_sent, 'headers have been sent already'\n        self.headers_sent = True\n\n        if self.chunked or (self.length is None and\n                            self.version >= HttpVersion11 and\n                            self.status not in (304, 204)):\n            self.writer = self._write_chunked_payload()\n            self.headers[hdrs.TRANSFER_ENCODING] = 'chunked'\n\n        elif self.length is not None:\n            self.writer = self._write_length_payload(self.length)\n\n        else:\n            self.writer = self._write_eof_payload()\n\n        next(self.writer)\n\n        self._add_default_headers()\n\n        # status + headers\n        headers = ''.join(itertools.chain(\n            (self.status_line,),\n            *((k, _sep, v, _end) for k, v in self.headers.items())))\n        headers = headers.encode('utf-8') + b'\\r\\n'\n\n        self.output_length += len(headers)\n        self.transport.write(headers)\n\n    def _add_default_headers(self):\n        # set the connection header\n        if self.upgrade:\n            connection = 'upgrade'\n        elif not self.closing if self.keepalive is None else self.keepalive:\n            connection = 'keep-alive'\n        else:\n            connection = 'close'\n\n        self.headers[hdrs.CONNECTION] = connection\n\n    def write(self, chunk, *,\n              drain=False, EOF_MARKER=EOF_MARKER, EOL_MARKER=EOL_MARKER):\n        \"\"\"Writes chunk of data to a stream by using different writers.\n\n        writer uses filter to modify chunk of data.\n        write_eof() indicates end of stream.\n        writer can't be used after write_eof() method being called.\n        write() return drain future.\n        \"\"\"\n        assert (isinstance(chunk, (bytes, bytearray)) or\n                chunk is EOF_MARKER), chunk\n\n        size = self.output_length\n\n        if self._send_headers and not self.headers_sent:\n            self.send_headers()\n\n        assert self.writer is not None, 'send_headers() is not called.'\n\n        if self.filter:\n            chunk = self.filter.send(chunk)\n            while chunk not in (EOF_MARKER, EOL_MARKER):\n                self.writer.send(chunk)\n                chunk = next(self.filter)\n        else:\n            if chunk is not EOF_MARKER:\n                self.writer.send(chunk)\n\n        self._output_size += self.output_length - size\n\n        if self._output_size > 64 * 1024:\n            if drain:\n                self._output_size = 0\n                return self.transport.drain()\n\n        return ()\n\n    def write_eof(self):\n        self.write(EOF_MARKER)\n        try:\n            self.writer.throw(aiohttp.EofStream())\n        except StopIteration:\n            pass\n\n        return self.transport.drain()\n\n    def _write_chunked_payload(self):\n        \"\"\"Write data in chunked transfer encoding.\"\"\"\n        while True:\n            try:\n                chunk = yield\n            except aiohttp.EofStream:\n                self.transport.write(b'0\\r\\n\\r\\n')\n                self.output_length += 5\n                break\n\n            chunk = bytes(chunk)\n            chunk_len = '{:x}\\r\\n'.format(len(chunk)).encode('ascii')\n            self.transport.write(chunk_len)\n            self.transport.write(chunk)\n            self.transport.write(b'\\r\\n')\n            self.output_length += len(chunk_len) + len(chunk) + 2\n\n    def _write_length_payload(self, length):\n        \"\"\"Write specified number of bytes to a stream.\"\"\"\n        while True:\n            try:\n                chunk = yield\n            except aiohttp.EofStream:\n                break\n\n            if length:\n                l = len(chunk)\n                if length >= l:\n                    self.transport.write(chunk)\n                    self.output_length += l\n                    length = length-l\n                else:\n                    self.transport.write(chunk[:length])\n                    self.output_length += length\n                    length = 0\n\n    def _write_eof_payload(self):\n        while True:\n            try:\n                chunk = yield\n            except aiohttp.EofStream:\n                break\n\n            self.transport.write(chunk)\n            self.output_length += len(chunk)\n\n    @wrap_payload_filter\n    def add_chunking_filter(self, chunk_size=16*1024, *,\n                            EOF_MARKER=EOF_MARKER, EOL_MARKER=EOL_MARKER):\n        \"\"\"Split incoming stream into chunks.\"\"\"\n        buf = bytearray()\n        chunk = yield\n\n        while True:\n            if chunk is EOF_MARKER:\n                if buf:\n                    yield buf\n\n                yield EOF_MARKER\n\n            else:\n                buf.extend(chunk)\n\n                while len(buf) >= chunk_size:\n                    chunk = bytes(buf[:chunk_size])\n                    del buf[:chunk_size]\n                    yield chunk\n\n                chunk = yield EOL_MARKER\n\n    @wrap_payload_filter\n    def add_compression_filter(self, encoding='deflate', *,\n                               EOF_MARKER=EOF_MARKER, EOL_MARKER=EOL_MARKER):\n        \"\"\"Compress incoming stream with deflate or gzip encoding.\"\"\"\n        zlib_mode = (16 + zlib.MAX_WBITS\n                     if encoding == 'gzip' else -zlib.MAX_WBITS)\n        zcomp = zlib.compressobj(wbits=zlib_mode)\n\n        chunk = yield\n        while True:\n            if chunk is EOF_MARKER:\n                yield zcomp.flush()\n                chunk = yield EOF_MARKER\n\n            else:\n                yield zcomp.compress(chunk)\n                chunk = yield EOL_MARKER",
                                "ast_type_str": "ClassDef",
                                "start_lineno": 478,
                                "end_lineno": 799,
                                "parent": null
                            }
                        },
                        {
                            "file_name": "aiohttp/protocol.py",
                            "type": "class",
                            "name": "HttpMessage",
                            "content": "class HttpMessage:\n    \"\"\"HttpMessage allows to write headers and payload to a stream.\n\n    For example, lets say we want to read file then compress it with deflate\n    compression and then send it with chunked transfer encoding, code may look\n    like this:\n\n       >>> response = aiohttp.Response(transport, 200)\n\n    We have to use deflate compression first:\n\n      >>> response.add_compression_filter('deflate')\n\n    Then we want to split output stream into chunks of 1024 bytes size:\n\n      >>> response.add_chunking_filter(1024)\n\n    We can add headers to response with add_headers() method. add_headers()\n    does not send data to transport, send_headers() sends request/response\n    line and then sends headers:\n\n      >>> response.add_headers(\n      ...     ('Content-Disposition', 'attachment; filename=\"...\"'))\n      >>> response.send_headers()\n\n    Now we can use chunked writer to write stream to a network stream.\n    First call to write() method sends response status line and headers,\n    add_header() and add_headers() method unavailable at this stage:\n\n    >>> with open('...', 'rb') as f:\n    ...     chunk = fp.read(8192)\n    ...     while chunk:\n    ...         response.write(chunk)\n    ...         chunk = fp.read(8192)\n\n    >>> response.write_eof()\n\n    \"\"\"\n\n    writer = None\n\n    # 'filter' is being used for altering write() behaviour,\n    # add_chunking_filter adds deflate/gzip compression and\n    # add_compression_filter splits incoming data into a chunks.\n    filter = None\n\n    HOP_HEADERS = None  # Must be set by subclass.\n\n    SERVER_SOFTWARE = 'Python/{0[0]}.{0[1]} aiohttp/{1}'.format(\n        sys.version_info, aiohttp.__version__)\n\n    status = None\n    status_line = b''\n    upgrade = False  # Connection: UPGRADE\n    websocket = False  # Upgrade: WEBSOCKET\n    has_chunked_hdr = False  # Transfer-encoding: chunked\n\n    # subclass can enable auto sending headers with write() call,\n    # this is useful for wsgi's start_response implementation.\n    _send_headers = False\n\n    def __init__(self, transport, version, close):\n        self.transport = transport\n        self.version = version\n        self.closing = close\n        self.keepalive = None\n        self.chunked = False\n        self.length = None\n        self.headers = CIMultiDict()\n        self.headers_sent = False\n        self.output_length = 0\n        self._output_size = 0\n\n    def force_close(self):\n        self.closing = True\n        self.keepalive = False\n\n    def enable_chunked_encoding(self):\n        self.chunked = True\n\n    def keep_alive(self):\n        if self.keepalive is None:\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            else:\n                return not self.closing\n        else:\n            return self.keepalive\n\n    def is_headers_sent(self):\n        return self.headers_sent\n\n    def add_header(self, name, value):\n        \"\"\"Analyze headers. Calculate content length,\n        removes hop headers, etc.\"\"\"\n        assert not self.headers_sent, 'headers have been sent already'\n        assert isinstance(name, str), \\\n            'Header name should be a string, got {!r}'.format(name)\n        assert set(name).issubset(ASCIISET), \\\n            'Header name should contain ASCII chars, got {!r}'.format(name)\n        assert isinstance(value, str), \\\n            'Header {!r} should have string value, got {!r}'.format(\n                name, value)\n\n        name = name.strip().upper()\n        value = value.strip()\n\n        if name == hdrs.CONTENT_LENGTH:\n            self.length = int(value)\n\n        if name == hdrs.TRANSFER_ENCODING:\n            self.has_chunked_hdr = value.lower().strip() == 'chunked'\n\n        if name == hdrs.CONNECTION:\n            val = value.lower()\n            # handle websocket\n            if 'upgrade' in val:\n                self.upgrade = True\n            # connection keep-alive\n            elif 'close' in val:\n                self.keepalive = False\n            elif 'keep-alive' in val:\n                self.keepalive = True\n\n        elif name == hdrs.UPGRADE:\n            if 'websocket' in value.lower():\n                self.websocket = True\n                self.headers[name] = value\n\n        elif name not in self.HOP_HEADERS:\n            # ignore hop-by-hop headers\n            self.headers.add(name, value)\n\n    def add_headers(self, *headers):\n        \"\"\"Adds headers to a http message.\"\"\"\n        for name, value in headers:\n            self.add_header(name, value)\n\n    def send_headers(self, _sep=': ', _end='\\r\\n'):\n        \"\"\"Writes headers to a stream. Constructs payload writer.\"\"\"\n        # Chunked response is only for HTTP/1.1 clients or newer\n        # and there is no Content-Length header is set.\n        # Do not use chunked responses when the response is guaranteed to\n        # not have a response body (304, 204).\n        assert not self.headers_sent, 'headers have been sent already'\n        self.headers_sent = True\n\n        if self.chunked or (self.length is None and\n                            self.version >= HttpVersion11 and\n                            self.status not in (304, 204)):\n            self.writer = self._write_chunked_payload()\n            self.headers[hdrs.TRANSFER_ENCODING] = 'chunked'\n\n        elif self.length is not None:\n            self.writer = self._write_length_payload(self.length)\n\n        else:\n            self.writer = self._write_eof_payload()\n\n        next(self.writer)\n\n        self._add_default_headers()\n\n        # status + headers\n        headers = ''.join(itertools.chain(\n            (self.status_line,),\n            *((k, _sep, v, _end) for k, v in self.headers.items())))\n        headers = headers.encode('utf-8') + b'\\r\\n'\n\n        self.output_length += len(headers)\n        self.transport.write(headers)\n\n    def _add_default_headers(self):\n        # set the connection header\n        if self.upgrade:\n            connection = 'upgrade'\n        elif not self.closing if self.keepalive is None else self.keepalive:\n            connection = 'keep-alive'\n        else:\n            connection = 'close'\n\n        self.headers[hdrs.CONNECTION] = connection\n\n    def write(self, chunk, *,\n              drain=False, EOF_MARKER=EOF_MARKER, EOL_MARKER=EOL_MARKER):\n        \"\"\"Writes chunk of data to a stream by using different writers.\n\n        writer uses filter to modify chunk of data.\n        write_eof() indicates end of stream.\n        writer can't be used after write_eof() method being called.\n        write() return drain future.\n        \"\"\"\n        assert (isinstance(chunk, (bytes, bytearray)) or\n                chunk is EOF_MARKER), chunk\n\n        size = self.output_length\n\n        if self._send_headers and not self.headers_sent:\n            self.send_headers()\n\n        assert self.writer is not None, 'send_headers() is not called.'\n\n        if self.filter:\n            chunk = self.filter.send(chunk)\n            while chunk not in (EOF_MARKER, EOL_MARKER):\n                self.writer.send(chunk)\n                chunk = next(self.filter)\n        else:\n            if chunk is not EOF_MARKER:\n                self.writer.send(chunk)\n\n        self._output_size += self.output_length - size\n\n        if self._output_size > 64 * 1024:\n            if drain:\n                self._output_size = 0\n                return self.transport.drain()\n\n        return ()\n\n    def write_eof(self):\n        self.write(EOF_MARKER)\n        try:\n            self.writer.throw(aiohttp.EofStream())\n        except StopIteration:\n            pass\n\n        return self.transport.drain()\n\n    def _write_chunked_payload(self):\n        \"\"\"Write data in chunked transfer encoding.\"\"\"\n        while True:\n            try:\n                chunk = yield\n            except aiohttp.EofStream:\n                self.transport.write(b'0\\r\\n\\r\\n')\n                self.output_length += 5\n                break\n\n            chunk = bytes(chunk)\n            chunk_len = '{:x}\\r\\n'.format(len(chunk)).encode('ascii')\n            self.transport.write(chunk_len)\n            self.transport.write(chunk)\n            self.transport.write(b'\\r\\n')\n            self.output_length += len(chunk_len) + len(chunk) + 2\n\n    def _write_length_payload(self, length):\n        \"\"\"Write specified number of bytes to a stream.\"\"\"\n        while True:\n            try:\n                chunk = yield\n            except aiohttp.EofStream:\n                break\n\n            if length:\n                l = len(chunk)\n                if length >= l:\n                    self.transport.write(chunk)\n                    self.output_length += l\n                    length = length-l\n                else:\n                    self.transport.write(chunk[:length])\n                    self.output_length += length\n                    length = 0\n\n    def _write_eof_payload(self):\n        while True:\n            try:\n                chunk = yield\n            except aiohttp.EofStream:\n                break\n\n            self.transport.write(chunk)\n            self.output_length += len(chunk)\n\n    @wrap_payload_filter\n    def add_chunking_filter(self, chunk_size=16*1024, *,\n                            EOF_MARKER=EOF_MARKER, EOL_MARKER=EOL_MARKER):\n        \"\"\"Split incoming stream into chunks.\"\"\"\n        buf = bytearray()\n        chunk = yield\n\n        while True:\n            if chunk is EOF_MARKER:\n                if buf:\n                    yield buf\n\n                yield EOF_MARKER\n\n            else:\n                buf.extend(chunk)\n\n                while len(buf) >= chunk_size:\n                    chunk = bytes(buf[:chunk_size])\n                    del buf[:chunk_size]\n                    yield chunk\n\n                chunk = yield EOL_MARKER\n\n    @wrap_payload_filter\n    def add_compression_filter(self, encoding='deflate', *,\n                               EOF_MARKER=EOF_MARKER, EOL_MARKER=EOL_MARKER):\n        \"\"\"Compress incoming stream with deflate or gzip encoding.\"\"\"\n        zlib_mode = (16 + zlib.MAX_WBITS\n                     if encoding == 'gzip' else -zlib.MAX_WBITS)\n        zcomp = zlib.compressobj(wbits=zlib_mode)\n\n        chunk = yield\n        while True:\n            if chunk is EOF_MARKER:\n                yield zcomp.flush()\n                chunk = yield EOF_MARKER\n\n            else:\n                yield zcomp.compress(chunk)\n                chunk = yield EOL_MARKER",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 478,
                            "end_lineno": 799,
                            "parent": null
                        }
                    ],
                    "added_entities": [],
                    "deleted_entities": []
                }
            ]
        },
        {
            "old_file_content": "\"\"\"Tests for aiohttp/protocol.py\"\"\"\n\nimport unittest\nimport unittest.mock\nimport asyncio\nimport zlib\n\nfrom aiohttp import hdrs, protocol\n\n\nclass TestHttpMessage(unittest.TestCase):\n\n    def setUp(self):\n        self.transport = unittest.mock.Mock()\n        asyncio.set_event_loop(None)\n\n    def test_start_request(self):\n        msg = protocol.Request(\n            self.transport, 'GET', '/index.html', close=True)\n\n        self.assertIs(msg.transport, self.transport)\n        self.assertIsNone(msg.status)\n        self.assertTrue(msg.closing)\n        self.assertEqual(msg.status_line, 'GET /index.html HTTP/1.1\\r\\n')\n\n    def test_start_response(self):\n        msg = protocol.Response(self.transport, 200, close=True)\n\n        self.assertIs(msg.transport, self.transport)\n        self.assertEqual(msg.status, 200)\n        self.assertEqual(msg.reason, \"OK\")\n        self.assertTrue(msg.closing)\n        self.assertEqual(msg.status_line, 'HTTP/1.1 200 OK\\r\\n')\n\n    def test_start_response_with_reason(self):\n        msg = protocol.Response(self.transport, 333, close=True,\n                                reason=\"My Reason\")\n\n        self.assertEqual(msg.status, 333)\n        self.assertEqual(msg.reason, \"My Reason\")\n        self.assertEqual(msg.status_line, 'HTTP/1.1 333 My Reason\\r\\n')\n\n    def test_start_response_with_unknown_reason(self):\n        msg = protocol.Response(self.transport, 777, close=True)\n\n        self.assertEqual(msg.status, 777)\n        self.assertEqual(msg.reason, \"777\")\n        self.assertEqual(msg.status_line, 'HTTP/1.1 777 777\\r\\n')\n\n    def test_force_close(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertFalse(msg.closing)\n        msg.force_close()\n        self.assertTrue(msg.closing)\n\n    def test_force_chunked(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertFalse(msg.chunked)\n        msg.enable_chunked_encoding()\n        self.assertTrue(msg.chunked)\n\n    def test_keep_alive(self):\n        msg = protocol.Response(self.transport, 200, close=True)\n        self.assertFalse(msg.keep_alive())\n        msg.keepalive = True\n        self.assertTrue(msg.keep_alive())\n\n        msg.force_close()\n        self.assertFalse(msg.keep_alive())\n\n    def test_keep_alive_http10(self):\n        msg = protocol.Response(self.transport, 200, http_version=(1, 0))\n        self.assertFalse(msg.keepalive)\n        self.assertFalse(msg.keep_alive())\n\n        msg = protocol.Response(self.transport, 200, http_version=(1, 1))\n        self.assertIsNone(msg.keepalive)\n\n    def test_add_header(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertEqual([], list(msg.headers))\n\n        msg.add_header('content-type', 'plain/html')\n        self.assertEqual(\n            [('CONTENT-TYPE', 'plain/html')], list(msg.headers.items()))\n\n    def test_add_header_with_spaces(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertEqual([], list(msg.headers))\n\n        msg.add_header('content-type', '  plain/html  ')\n        self.assertEqual(\n            [('CONTENT-TYPE', 'plain/html')], list(msg.headers.items()))\n\n    def test_add_header_non_ascii(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertEqual([], list(msg.headers))\n\n        with self.assertRaises(AssertionError):\n            msg.add_header('тип-контента', 'текст/плейн')\n\n    def test_add_header_invalid_value_type(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertEqual([], list(msg.headers))\n\n        with self.assertRaises(AssertionError):\n            msg.add_header('content-type', {'test': 'plain'})\n\n        with self.assertRaises(AssertionError):\n            msg.add_header(list('content-type'), 'text/plain')\n\n    def test_add_headers(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertEqual([], list(msg.headers))\n\n        msg.add_headers(('content-type', 'plain/html'))\n        self.assertEqual(\n            [('CONTENT-TYPE', 'plain/html')], list(msg.headers.items()))\n\n    def test_add_headers_length(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertIsNone(msg.length)\n\n        msg.add_headers(('content-length', '42'))\n        self.assertEqual(42, msg.length)\n\n    def test_add_headers_upgrade(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertFalse(msg.upgrade)\n\n        msg.add_headers(('connection', 'upgrade'))\n        self.assertTrue(msg.upgrade)\n\n    def test_add_headers_upgrade_websocket(self):\n        msg = protocol.Response(self.transport, 200)\n\n        msg.add_headers(('upgrade', 'test'))\n        self.assertEqual([], list(msg.headers))\n\n        msg.add_headers(('upgrade', 'websocket'))\n        self.assertEqual(\n            [('UPGRADE', 'websocket')], list(msg.headers.items()))\n\n    def test_add_headers_connection_keepalive(self):\n        msg = protocol.Response(self.transport, 200)\n\n        msg.add_headers(('connection', 'keep-alive'))\n        self.assertEqual([], list(msg.headers))\n        self.assertTrue(msg.keepalive)\n\n        msg.add_headers(('connection', 'close'))\n        self.assertFalse(msg.keepalive)\n\n    def test_add_headers_hop_headers(self):\n        msg = protocol.Response(self.transport, 200)\n        msg.HOP_HEADERS = (hdrs.TRANSFER_ENCODING,)\n\n        msg.add_headers(('connection', 'test'), ('transfer-encoding', 't'))\n        self.assertEqual([], list(msg.headers))\n\n    def test_default_headers(self):\n        msg = protocol.Response(self.transport, 200)\n        msg._add_default_headers()\n\n        headers = [r for r, _ in msg.headers.items()]\n        self.assertIn('DATE', headers)\n        self.assertIn('CONNECTION', headers)\n\n    def test_default_headers_server(self):\n        msg = protocol.Response(self.transport, 200)\n        msg._add_default_headers()\n\n        self.assertIn('SERVER', msg.headers)\n\n    def test_default_headers_useragent(self):\n        msg = protocol.Request(self.transport, 'GET', '/')\n        msg._add_default_headers()\n\n        self.assertNotIn('SERVER', msg.headers)\n        self.assertIn('USER-AGENT', msg.headers)\n\n    def test_default_headers_useragent_custom(self):\n        msg = protocol.Request(self.transport, 'GET', '/')\n        msg.add_headers(('user-agent', 'my custom agent'))\n        msg._add_default_headers()\n\n        headers = [r for r, _ in msg.headers.items()\n                   if r.lower() == 'user-agent']\n        self.assertEqual(len(headers), 1)\n\n    def test_default_headers_chunked(self):\n        msg = protocol.Response(self.transport, 200)\n        msg._add_default_headers()\n\n        headers = [r for r, _ in msg.headers.items()]\n        self.assertNotIn('TRANSFER-ENCODING', headers)\n\n        msg = protocol.Response(self.transport, 200)\n        msg.enable_chunked_encoding()\n        msg.send_headers()\n\n        headers = [r for r, _ in msg.headers.items()]\n        self.assertIn('TRANSFER-ENCODING', headers)\n\n    def test_default_headers_connection_upgrade(self):\n        msg = protocol.Response(self.transport, 200)\n        msg.upgrade = True\n        msg._add_default_headers()\n\n        headers = [r for r in msg.headers.items() if r[0] == 'CONNECTION']\n        self.assertEqual([('CONNECTION', 'upgrade')], headers)\n\n    def test_default_headers_connection_close(self):\n        msg = protocol.Response(self.transport, 200)\n        msg.force_close()\n        msg._add_default_headers()\n\n        headers = [r for r in msg.headers.items() if r[0] == 'CONNECTION']\n        self.assertEqual([('CONNECTION', 'close')], headers)\n\n    def test_default_headers_connection_keep_alive(self):\n        msg = protocol.Response(self.transport, 200)\n        msg.keepalive = True\n        msg._add_default_headers()\n\n        headers = [r for r in msg.headers.items() if r[0] == 'CONNECTION']\n        self.assertEqual([('CONNECTION', 'keep-alive')], headers)\n\n    def test_send_headers(self):\n        write = self.transport.write = unittest.mock.Mock()\n\n        msg = protocol.Response(self.transport, 200)\n        msg.add_headers(('content-type', 'plain/html'))\n        self.assertFalse(msg.is_headers_sent())\n\n        msg.send_headers()\n\n        content = b''.join([arg[1][0] for arg in list(write.mock_calls)])\n\n        self.assertTrue(content.startswith(b'HTTP/1.1 200 OK\\r\\n'))\n        self.assertIn(b'CONTENT-TYPE: plain/html', content)\n        self.assertTrue(msg.headers_sent)\n        self.assertTrue(msg.is_headers_sent())\n        # cleanup\n        msg.writer.close()\n\n    def test_send_headers_non_ascii(self):\n        write = self.transport.write = unittest.mock.Mock()\n\n        msg = protocol.Response(self.transport, 200)\n        msg.add_headers(('x-header', 'текст'))\n        self.assertFalse(msg.is_headers_sent())\n\n        msg.send_headers()\n\n        content = b''.join([arg[1][0] for arg in list(write.mock_calls)])\n\n        self.assertTrue(content.startswith(b'HTTP/1.1 200 OK\\r\\n'))\n        self.assertIn(b'X-HEADER: \\xd1\\x82\\xd0\\xb5\\xd0\\xba\\xd1\\x81\\xd1\\x82',\n                      content)\n        self.assertTrue(msg.headers_sent)\n        self.assertTrue(msg.is_headers_sent())\n        # cleanup\n        msg.writer.close()\n\n    def test_send_headers_nomore_add(self):\n        msg = protocol.Response(self.transport, 200)\n        msg.add_headers(('content-type', 'plain/html'))\n        msg.send_headers()\n\n        self.assertRaises(AssertionError,\n                          msg.add_header, 'content-type', 'plain/html')\n        # cleanup\n        msg.writer.close()\n\n    def test_prepare_length(self):\n        msg = protocol.Response(self.transport, 200)\n        w_l_p = msg._write_length_payload = unittest.mock.Mock()\n        w_l_p.return_value = iter([1, 2, 3])\n\n        msg.add_headers(('content-length', '42'))\n        msg.send_headers()\n\n        self.assertTrue(w_l_p.called)\n        self.assertEqual((42,), w_l_p.call_args[0])\n\n    def test_prepare_chunked_force(self):\n        msg = protocol.Response(self.transport, 200)\n        msg.enable_chunked_encoding()\n\n        chunked = msg._write_chunked_payload = unittest.mock.Mock()\n        chunked.return_value = iter([1, 2, 3])\n\n        msg.add_headers(('content-length', '42'))\n        msg.send_headers()\n        self.assertTrue(chunked.called)\n\n    def test_prepare_chunked_no_length(self):\n        msg = protocol.Response(self.transport, 200)\n\n        chunked = msg._write_chunked_payload = unittest.mock.Mock()\n        chunked.return_value = iter([1, 2, 3])\n\n        msg.send_headers()\n        self.assertTrue(chunked.called)\n\n    def test_prepare_eof(self):\n        msg = protocol.Response(self.transport, 200, http_version=(1, 0))\n\n        eof = msg._write_eof_payload = unittest.mock.Mock()\n        eof.return_value = iter([1, 2, 3])\n\n        msg.send_headers()\n        self.assertTrue(eof.called)\n\n    def test_write_auto_send_headers(self):\n        msg = protocol.Response(self.transport, 200, http_version=(1, 0))\n        msg._send_headers = True\n\n        msg.write(b'data1')\n        self.assertTrue(msg.headers_sent)\n        # cleanup\n        msg.writer.close()\n\n    def test_write_payload_eof(self):\n        write = self.transport.write = unittest.mock.Mock()\n        msg = protocol.Response(self.transport, 200, http_version=(1, 0))\n        msg.send_headers()\n\n        msg.write(b'data1')\n        self.assertTrue(msg.headers_sent)\n\n        msg.write(b'data2')\n        msg.write_eof()\n\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertEqual(\n            b'data1data2', content.split(b'\\r\\n\\r\\n', 1)[-1])\n\n    def test_write_payload_chunked(self):\n        write = self.transport.write = unittest.mock.Mock()\n\n        msg = protocol.Response(self.transport, 200)\n        msg.enable_chunked_encoding()\n        msg.send_headers()\n\n        msg.write(b'data')\n        msg.write_eof()\n\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertEqual(\n            b'4\\r\\ndata\\r\\n0\\r\\n\\r\\n',\n            content.split(b'\\r\\n\\r\\n', 1)[-1])\n\n    def test_write_payload_chunked_multiple(self):\n        write = self.transport.write = unittest.mock.Mock()\n\n        msg = protocol.Response(self.transport, 200)\n        msg.enable_chunked_encoding()\n        msg.send_headers()\n\n        msg.write(b'data1')\n        msg.write(b'data2')\n        msg.write_eof()\n\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertEqual(\n            b'5\\r\\ndata1\\r\\n5\\r\\ndata2\\r\\n0\\r\\n\\r\\n',\n            content.split(b'\\r\\n\\r\\n', 1)[-1])\n\n    def test_write_payload_length(self):\n        write = self.transport.write = unittest.mock.Mock()\n\n        msg = protocol.Response(self.transport, 200)\n        msg.add_headers(('content-length', '2'))\n        msg.send_headers()\n\n        msg.write(b'd')\n        msg.write(b'ata')\n        msg.write_eof()\n\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertEqual(\n            b'da', content.split(b'\\r\\n\\r\\n', 1)[-1])\n\n    def test_write_payload_chunked_filter(self):\n        write = self.transport.write = unittest.mock.Mock()\n\n        msg = protocol.Response(self.transport, 200)\n        msg.send_headers()\n\n        msg.add_chunking_filter(2)\n        msg.write(b'data')\n        msg.write_eof()\n\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertTrue(content.endswith(b'2\\r\\nda\\r\\n2\\r\\nta\\r\\n0\\r\\n\\r\\n'))\n\n    def test_write_payload_chunked_filter_mutiple_chunks(self):\n        write = self.transport.write = unittest.mock.Mock()\n        msg = protocol.Response(self.transport, 200)\n        msg.send_headers()\n\n        msg.add_chunking_filter(2)\n        msg.write(b'data1')\n        msg.write(b'data2')\n        msg.write_eof()\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertTrue(content.endswith(\n            b'2\\r\\nda\\r\\n2\\r\\nta\\r\\n2\\r\\n1d\\r\\n2\\r\\nat\\r\\n'\n            b'2\\r\\na2\\r\\n0\\r\\n\\r\\n'))\n\n    def test_write_payload_chunked_large_chunk(self):\n        write = self.transport.write = unittest.mock.Mock()\n        msg = protocol.Response(self.transport, 200)\n        msg.send_headers()\n\n        msg.add_chunking_filter(1024)\n        msg.write(b'data')\n        msg.write_eof()\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertTrue(content.endswith(b'4\\r\\ndata\\r\\n0\\r\\n\\r\\n'))\n\n    _comp = zlib.compressobj(wbits=-zlib.MAX_WBITS)\n    _COMPRESSED = b''.join([_comp.compress(b'data'), _comp.flush()])\n\n    def test_write_payload_deflate_filter(self):\n        write = self.transport.write = unittest.mock.Mock()\n        msg = protocol.Response(self.transport, 200)\n        msg.add_headers(('content-length', '{}'.format(len(self._COMPRESSED))))\n        msg.send_headers()\n\n        msg.add_compression_filter('deflate')\n        msg.write(b'data')\n        msg.write_eof()\n\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertEqual(\n            self._COMPRESSED, content.split(b'\\r\\n\\r\\n', 1)[-1])\n\n    def test_write_payload_deflate_and_chunked(self):\n        write = self.transport.write = unittest.mock.Mock()\n        msg = protocol.Response(self.transport, 200)\n        msg.send_headers()\n\n        msg.add_compression_filter('deflate')\n        msg.add_chunking_filter(2)\n\n        msg.write(b'data')\n        msg.write_eof()\n\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertEqual(\n            b'2\\r\\nKI\\r\\n2\\r\\n,I\\r\\n2\\r\\n\\x04\\x00\\r\\n0\\r\\n\\r\\n',\n            content.split(b'\\r\\n\\r\\n', 1)[-1])\n\n    def test_write_payload_chunked_and_deflate(self):\n        write = self.transport.write = unittest.mock.Mock()\n        msg = protocol.Response(self.transport, 200)\n        msg.add_headers(('content-length', '{}'.format(len(self._COMPRESSED))))\n\n        msg.add_chunking_filter(2)\n        msg.add_compression_filter('deflate')\n        msg.send_headers()\n\n        msg.write(b'data')\n        msg.write_eof()\n\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertEqual(\n            self._COMPRESSED, content.split(b'\\r\\n\\r\\n', 1)[-1])\n\n    def test_write_drain(self):\n        msg = protocol.Response(self.transport, 200, http_version=(1, 0))\n        msg._send_headers = True\n\n        msg.write(b'1' * (64 * 1024 * 2))\n        self.assertFalse(self.transport.drain.called)\n\n        msg.write(b'1', drain=True)\n        self.assertTrue(self.transport.drain.called)\n        self.assertEqual(msg._output_size, 0)\n\n    def test_dont_override_request_headers_with_default_values(self):\n        msg = protocol.Request(\n            self.transport, 'GET', '/index.html', close=True)\n        msg.add_header('USER-AGENT', 'custom')\n        msg._add_default_headers()\n        self.assertEqual('custom', msg.headers['USER-AGENT'])\n\n    def test_dont_override_response_headers_with_default_values(self):\n        msg = protocol.Response(self.transport, 200, http_version=(1, 0))\n        msg.add_header('DATE', 'now')\n        msg.add_header('SERVER', 'custom')\n        msg._add_default_headers()\n        self.assertEqual('custom', msg.headers['SERVER'])\n        self.assertEqual('now', msg.headers['DATE'])\n",
            "new_file_content": "\"\"\"Tests for aiohttp/protocol.py\"\"\"\n\nimport unittest\nimport unittest.mock\nimport asyncio\nimport zlib\n\nfrom aiohttp import hdrs, protocol\n\n\nclass TestHttpMessage(unittest.TestCase):\n\n    def setUp(self):\n        self.transport = unittest.mock.Mock()\n        asyncio.set_event_loop(None)\n\n    def test_start_request(self):\n        msg = protocol.Request(\n            self.transport, 'GET', '/index.html', close=True)\n\n        self.assertIs(msg.transport, self.transport)\n        self.assertIsNone(msg.status)\n        self.assertTrue(msg.closing)\n        self.assertEqual(msg.status_line, 'GET /index.html HTTP/1.1\\r\\n')\n\n    def test_start_response(self):\n        msg = protocol.Response(self.transport, 200, close=True)\n\n        self.assertIs(msg.transport, self.transport)\n        self.assertEqual(msg.status, 200)\n        self.assertEqual(msg.reason, \"OK\")\n        self.assertTrue(msg.closing)\n        self.assertEqual(msg.status_line, 'HTTP/1.1 200 OK\\r\\n')\n\n    def test_start_response_with_reason(self):\n        msg = protocol.Response(self.transport, 333, close=True,\n                                reason=\"My Reason\")\n\n        self.assertEqual(msg.status, 333)\n        self.assertEqual(msg.reason, \"My Reason\")\n        self.assertEqual(msg.status_line, 'HTTP/1.1 333 My Reason\\r\\n')\n\n    def test_start_response_with_unknown_reason(self):\n        msg = protocol.Response(self.transport, 777, close=True)\n\n        self.assertEqual(msg.status, 777)\n        self.assertEqual(msg.reason, \"777\")\n        self.assertEqual(msg.status_line, 'HTTP/1.1 777 777\\r\\n')\n\n    def test_force_close(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertFalse(msg.closing)\n        msg.force_close()\n        self.assertTrue(msg.closing)\n\n    def test_force_chunked(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertFalse(msg.chunked)\n        msg.enable_chunked_encoding()\n        self.assertTrue(msg.chunked)\n\n    def test_keep_alive(self):\n        msg = protocol.Response(self.transport, 200, close=True)\n        self.assertFalse(msg.keep_alive())\n        msg.keepalive = True\n        self.assertTrue(msg.keep_alive())\n\n        msg.force_close()\n        self.assertFalse(msg.keep_alive())\n\n    def test_keep_alive_http10(self):\n        msg = protocol.Response(self.transport, 200, http_version=(1, 0))\n        self.assertFalse(msg.keepalive)\n        self.assertFalse(msg.keep_alive())\n\n        msg = protocol.Response(self.transport, 200, http_version=(1, 1))\n        self.assertIsNone(msg.keepalive)\n\n    def test_add_header(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertEqual([], list(msg.headers))\n\n        msg.add_header('content-type', 'plain/html')\n        self.assertEqual(\n            [('CONTENT-TYPE', 'plain/html')], list(msg.headers.items()))\n\n    def test_add_header_with_spaces(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertEqual([], list(msg.headers))\n\n        msg.add_header('content-type', '  plain/html  ')\n        self.assertEqual(\n            [('CONTENT-TYPE', 'plain/html')], list(msg.headers.items()))\n\n    def test_add_header_non_ascii(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertEqual([], list(msg.headers))\n\n        with self.assertRaises(AssertionError):\n            msg.add_header('тип-контента', 'текст/плейн')\n\n    def test_add_header_invalid_value_type(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertEqual([], list(msg.headers))\n\n        with self.assertRaises(AssertionError):\n            msg.add_header('content-type', {'test': 'plain'})\n\n        with self.assertRaises(AssertionError):\n            msg.add_header(list('content-type'), 'text/plain')\n\n    def test_add_headers(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertEqual([], list(msg.headers))\n\n        msg.add_headers(('content-type', 'plain/html'))\n        self.assertEqual(\n            [('CONTENT-TYPE', 'plain/html')], list(msg.headers.items()))\n\n    def test_add_headers_length(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertIsNone(msg.length)\n\n        msg.add_headers(('content-length', '42'))\n        self.assertEqual(42, msg.length)\n\n    def test_add_headers_upgrade(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertFalse(msg.upgrade)\n\n        msg.add_headers(('connection', 'upgrade'))\n        self.assertTrue(msg.upgrade)\n\n    def test_add_headers_upgrade_websocket(self):\n        msg = protocol.Response(self.transport, 200)\n\n        msg.add_headers(('upgrade', 'test'))\n        self.assertEqual([], list(msg.headers))\n\n        msg.add_headers(('upgrade', 'websocket'))\n        self.assertEqual(\n            [('UPGRADE', 'websocket')], list(msg.headers.items()))\n\n    def test_add_headers_connection_keepalive(self):\n        msg = protocol.Response(self.transport, 200)\n\n        msg.add_headers(('connection', 'keep-alive'))\n        self.assertEqual([], list(msg.headers))\n        self.assertTrue(msg.keepalive)\n\n        msg.add_headers(('connection', 'close'))\n        self.assertFalse(msg.keepalive)\n\n    def test_add_headers_hop_headers(self):\n        msg = protocol.Response(self.transport, 200)\n        msg.HOP_HEADERS = (hdrs.TRANSFER_ENCODING,)\n\n        msg.add_headers(('connection', 'test'), ('transfer-encoding', 't'))\n        self.assertEqual([], list(msg.headers))\n\n    def test_default_headers(self):\n        msg = protocol.Response(self.transport, 200)\n        msg._add_default_headers()\n\n        headers = [r for r, _ in msg.headers.items()]\n        self.assertIn('DATE', headers)\n        self.assertIn('CONNECTION', headers)\n\n    def test_default_headers_server(self):\n        msg = protocol.Response(self.transport, 200)\n        msg._add_default_headers()\n\n        self.assertIn('SERVER', msg.headers)\n\n    def test_default_headers_useragent(self):\n        msg = protocol.Request(self.transport, 'GET', '/')\n        msg._add_default_headers()\n\n        self.assertNotIn('SERVER', msg.headers)\n        self.assertIn('USER-AGENT', msg.headers)\n\n    def test_default_headers_useragent_custom(self):\n        msg = protocol.Request(self.transport, 'GET', '/')\n        msg.add_headers(('user-agent', 'my custom agent'))\n        msg._add_default_headers()\n\n        headers = [r for r, _ in msg.headers.items()\n                   if r.lower() == 'user-agent']\n        self.assertEqual(len(headers), 1)\n\n    def test_default_headers_chunked(self):\n        msg = protocol.Response(self.transport, 200)\n        msg._add_default_headers()\n\n        headers = [r for r, _ in msg.headers.items()]\n        self.assertNotIn('TRANSFER-ENCODING', headers)\n\n        msg = protocol.Response(self.transport, 200)\n        msg.enable_chunked_encoding()\n        msg.send_headers()\n\n        headers = [r for r, _ in msg.headers.items()]\n        self.assertIn('TRANSFER-ENCODING', headers)\n\n    def test_default_headers_connection_upgrade(self):\n        msg = protocol.Response(self.transport, 200)\n        msg.upgrade = True\n        msg._add_default_headers()\n\n        headers = [r for r in msg.headers.items() if r[0] == 'CONNECTION']\n        self.assertEqual([('CONNECTION', 'upgrade')], headers)\n\n    def test_default_headers_connection_close(self):\n        msg = protocol.Response(self.transport, 200)\n        msg.force_close()\n        msg._add_default_headers()\n\n        headers = [r for r in msg.headers.items() if r[0] == 'CONNECTION']\n        self.assertEqual([('CONNECTION', 'close')], headers)\n\n    def test_default_headers_connection_keep_alive(self):\n        msg = protocol.Response(self.transport, 200)\n        msg.keepalive = True\n        msg._add_default_headers()\n\n        headers = [r for r in msg.headers.items() if r[0] == 'CONNECTION']\n        self.assertEqual([('CONNECTION', 'keep-alive')], headers)\n\n    def test_send_headers(self):\n        write = self.transport.write = unittest.mock.Mock()\n\n        msg = protocol.Response(self.transport, 200)\n        msg.add_headers(('content-type', 'plain/html'))\n        self.assertFalse(msg.is_headers_sent())\n\n        msg.send_headers()\n\n        content = b''.join([arg[1][0] for arg in list(write.mock_calls)])\n\n        self.assertTrue(content.startswith(b'HTTP/1.1 200 OK\\r\\n'))\n        self.assertIn(b'CONTENT-TYPE: plain/html', content)\n        self.assertTrue(msg.headers_sent)\n        self.assertTrue(msg.is_headers_sent())\n        # cleanup\n        msg.writer.close()\n\n    def test_send_headers_non_ascii(self):\n        write = self.transport.write = unittest.mock.Mock()\n\n        msg = protocol.Response(self.transport, 200)\n        msg.add_headers(('x-header', 'текст'))\n        self.assertFalse(msg.is_headers_sent())\n\n        msg.send_headers()\n\n        content = b''.join([arg[1][0] for arg in list(write.mock_calls)])\n\n        self.assertTrue(content.startswith(b'HTTP/1.1 200 OK\\r\\n'))\n        self.assertIn(b'X-HEADER: \\xd1\\x82\\xd0\\xb5\\xd0\\xba\\xd1\\x81\\xd1\\x82',\n                      content)\n        self.assertTrue(msg.headers_sent)\n        self.assertTrue(msg.is_headers_sent())\n        # cleanup\n        msg.writer.close()\n\n    def test_send_headers_nomore_add(self):\n        msg = protocol.Response(self.transport, 200)\n        msg.add_headers(('content-type', 'plain/html'))\n        msg.send_headers()\n\n        self.assertRaises(AssertionError,\n                          msg.add_header, 'content-type', 'plain/html')\n        # cleanup\n        msg.writer.close()\n\n    def test_prepare_length(self):\n        msg = protocol.Response(self.transport, 200)\n        w_l_p = msg._write_length_payload = unittest.mock.Mock()\n        w_l_p.return_value = iter([1, 2, 3])\n\n        msg.add_headers(('content-length', '42'))\n        msg.send_headers()\n\n        self.assertTrue(w_l_p.called)\n        self.assertEqual((42,), w_l_p.call_args[0])\n\n    def test_prepare_chunked_force(self):\n        msg = protocol.Response(self.transport, 200)\n        msg.enable_chunked_encoding()\n\n        chunked = msg._write_chunked_payload = unittest.mock.Mock()\n        chunked.return_value = iter([1, 2, 3])\n\n        msg.add_headers(('content-length', '42'))\n        msg.send_headers()\n        self.assertTrue(chunked.called)\n\n    def test_prepare_chunked_no_length(self):\n        msg = protocol.Response(self.transport, 200)\n\n        chunked = msg._write_chunked_payload = unittest.mock.Mock()\n        chunked.return_value = iter([1, 2, 3])\n\n        msg.send_headers()\n        self.assertTrue(chunked.called)\n\n    def test_prepare_eof(self):\n        msg = protocol.Response(self.transport, 200, http_version=(1, 0))\n\n        eof = msg._write_eof_payload = unittest.mock.Mock()\n        eof.return_value = iter([1, 2, 3])\n\n        msg.send_headers()\n        self.assertTrue(eof.called)\n\n    def test_write_auto_send_headers(self):\n        msg = protocol.Response(self.transport, 200, http_version=(1, 0))\n        msg._send_headers = True\n\n        msg.write(b'data1')\n        self.assertTrue(msg.headers_sent)\n        # cleanup\n        msg.writer.close()\n\n    def test_write_payload_eof(self):\n        write = self.transport.write = unittest.mock.Mock()\n        msg = protocol.Response(self.transport, 200, http_version=(1, 0))\n        msg.send_headers()\n\n        msg.write(b'data1')\n        self.assertTrue(msg.headers_sent)\n\n        msg.write(b'data2')\n        msg.write_eof()\n\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertEqual(\n            b'data1data2', content.split(b'\\r\\n\\r\\n', 1)[-1])\n\n    def test_write_payload_chunked(self):\n        write = self.transport.write = unittest.mock.Mock()\n\n        msg = protocol.Response(self.transport, 200)\n        msg.enable_chunked_encoding()\n        msg.send_headers()\n\n        msg.write(b'data')\n        msg.write_eof()\n\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertEqual(\n            b'4\\r\\ndata\\r\\n0\\r\\n\\r\\n',\n            content.split(b'\\r\\n\\r\\n', 1)[-1])\n\n    def test_write_payload_chunked_multiple(self):\n        write = self.transport.write = unittest.mock.Mock()\n\n        msg = protocol.Response(self.transport, 200)\n        msg.enable_chunked_encoding()\n        msg.send_headers()\n\n        msg.write(b'data1')\n        msg.write(b'data2')\n        msg.write_eof()\n\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertEqual(\n            b'5\\r\\ndata1\\r\\n5\\r\\ndata2\\r\\n0\\r\\n\\r\\n',\n            content.split(b'\\r\\n\\r\\n', 1)[-1])\n\n    def test_write_payload_length(self):\n        write = self.transport.write = unittest.mock.Mock()\n\n        msg = protocol.Response(self.transport, 200)\n        msg.add_headers(('content-length', '2'))\n        msg.send_headers()\n\n        msg.write(b'd')\n        msg.write(b'ata')\n        msg.write_eof()\n\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertEqual(\n            b'da', content.split(b'\\r\\n\\r\\n', 1)[-1])\n\n    def test_write_payload_chunked_filter(self):\n        write = self.transport.write = unittest.mock.Mock()\n\n        msg = protocol.Response(self.transport, 200)\n        msg.send_headers()\n\n        msg.add_chunking_filter(2)\n        msg.write(b'data')\n        msg.write_eof()\n\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertTrue(content.endswith(b'2\\r\\nda\\r\\n2\\r\\nta\\r\\n0\\r\\n\\r\\n'))\n\n    def test_write_payload_chunked_filter_mutiple_chunks(self):\n        write = self.transport.write = unittest.mock.Mock()\n        msg = protocol.Response(self.transport, 200)\n        msg.send_headers()\n\n        msg.add_chunking_filter(2)\n        msg.write(b'data1')\n        msg.write(b'data2')\n        msg.write_eof()\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertTrue(content.endswith(\n            b'2\\r\\nda\\r\\n2\\r\\nta\\r\\n2\\r\\n1d\\r\\n2\\r\\nat\\r\\n'\n            b'2\\r\\na2\\r\\n0\\r\\n\\r\\n'))\n\n    def test_write_payload_chunked_large_chunk(self):\n        write = self.transport.write = unittest.mock.Mock()\n        msg = protocol.Response(self.transport, 200)\n        msg.send_headers()\n\n        msg.add_chunking_filter(1024)\n        msg.write(b'data')\n        msg.write_eof()\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertTrue(content.endswith(b'4\\r\\ndata\\r\\n0\\r\\n\\r\\n'))\n\n    _comp = zlib.compressobj(wbits=-zlib.MAX_WBITS)\n    _COMPRESSED = b''.join([_comp.compress(b'data'), _comp.flush()])\n\n    def test_write_payload_deflate_filter(self):\n        write = self.transport.write = unittest.mock.Mock()\n        msg = protocol.Response(self.transport, 200)\n        msg.add_headers(('content-length', '{}'.format(len(self._COMPRESSED))))\n        msg.send_headers()\n\n        msg.add_compression_filter('deflate')\n        msg.write(b'data')\n        msg.write_eof()\n\n        chunks = [c[1][0] for c in list(write.mock_calls)]\n        self.assertTrue(all(chunks))\n        content = b''.join(chunks)\n        self.assertEqual(\n            self._COMPRESSED, content.split(b'\\r\\n\\r\\n', 1)[-1])\n\n    def test_write_payload_deflate_and_chunked(self):\n        write = self.transport.write = unittest.mock.Mock()\n        msg = protocol.Response(self.transport, 200)\n        msg.send_headers()\n\n        msg.add_compression_filter('deflate')\n        msg.add_chunking_filter(2)\n\n        msg.write(b'data')\n        msg.write_eof()\n\n        chunks = [c[1][0] for c in list(write.mock_calls)]\n        self.assertTrue(all(chunks))\n        content = b''.join(chunks)\n        self.assertEqual(\n            b'2\\r\\nKI\\r\\n2\\r\\n,I\\r\\n2\\r\\n\\x04\\x00\\r\\n0\\r\\n\\r\\n',\n            content.split(b'\\r\\n\\r\\n', 1)[-1])\n\n    def test_write_payload_chunked_and_deflate(self):\n        write = self.transport.write = unittest.mock.Mock()\n        msg = protocol.Response(self.transport, 200)\n        msg.add_headers(('content-length', '{}'.format(len(self._COMPRESSED))))\n\n        msg.add_chunking_filter(2)\n        msg.add_compression_filter('deflate')\n        msg.send_headers()\n\n        msg.write(b'data')\n        msg.write_eof()\n\n        chunks = [c[1][0] for c in list(write.mock_calls)]\n        self.assertTrue(all(chunks))\n        content = b''.join(chunks)\n        self.assertEqual(\n            self._COMPRESSED, content.split(b'\\r\\n\\r\\n', 1)[-1])\n\n    def test_write_drain(self):\n        msg = protocol.Response(self.transport, 200, http_version=(1, 0))\n        msg._send_headers = True\n\n        msg.write(b'1' * (64 * 1024 * 2))\n        self.assertFalse(self.transport.drain.called)\n\n        msg.write(b'1', drain=True)\n        self.assertTrue(self.transport.drain.called)\n        self.assertEqual(msg._output_size, 0)\n\n    def test_dont_override_request_headers_with_default_values(self):\n        msg = protocol.Request(\n            self.transport, 'GET', '/index.html', close=True)\n        msg.add_header('USER-AGENT', 'custom')\n        msg._add_default_headers()\n        self.assertEqual('custom', msg.headers['USER-AGENT'])\n\n    def test_dont_override_response_headers_with_default_values(self):\n        msg = protocol.Response(self.transport, 200, http_version=(1, 0))\n        msg.add_header('DATE', 'now')\n        msg.add_header('SERVER', 'custom')\n        msg._add_default_headers()\n        self.assertEqual('custom', msg.headers['SERVER'])\n        self.assertEqual('now', msg.headers['DATE'])\n",
            "header": {
                "file": {
                    "path": "tests/test_http_protocol.py"
                },
                "misc_line": null
            },
            "index_line": {
                "old_commit_hash": "18af83de",
                "new_commit_hash": "f472026a",
                "mode": "100644"
            },
            "is_binary_file": false,
            "binary_line": null,
            "minus_file": {
                "path": "a/tests/test_http_protocol.py"
            },
            "plus_file": {
                "path": "b/tests/test_http_protocol.py"
            },
            "hunks": [
                {
                    "descriptor": {
                        "old_range": {
                            "start": 434,
                            "length": 7
                        },
                        "new_range": {
                            "start": 434,
                            "length": 9
                        },
                        "section": "class TestHttpMessage(unittest.TestCase):"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "        msg.write(b'data')",
                                "type": "context"
                            },
                            {
                                "content": "        msg.write_eof()",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "        content = b''.join([c[1][0] for c in list(write.mock_calls)])",
                                "type": "deleted"
                            },
                            {
                                "content": "        chunks = [c[1][0] for c in list(write.mock_calls)]",
                                "type": "added"
                            },
                            {
                                "content": "        self.assertTrue(all(chunks))",
                                "type": "added"
                            },
                            {
                                "content": "        content = b''.join(chunks)",
                                "type": "added"
                            },
                            {
                                "content": "        self.assertEqual(",
                                "type": "context"
                            },
                            {
                                "content": "            self._COMPRESSED, content.split(b'\\r\\n\\r\\n', 1)[-1])",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [
                        {
                            "file_name": "tests/test_http_protocol.py",
                            "type": "method",
                            "name": "TestHttpMessage.test_write_payload_deflate_filter",
                            "content": "class TestHttpMessage(unittest.TestCase):\n\n    def setUp(self):\n        self.transport = unittest.mock.Mock()\n        asyncio.set_event_loop(None)\n\n    def test_start_request(self):\n        msg = protocol.Request(\n            self.transport, 'GET', '/index.html', close=True)\n\n        self.assertIs(msg.transport, self.transport)\n        self.assertIsNone(msg.status)\n        self.assertTrue(msg.closing)\n        self.assertEqual(msg.status_line, 'GET /index.html HTTP/1.1\\r\\n')\n\n    def test_start_response(self):\n        msg = protocol.Response(self.transport, 200, close=True)\n\n        self.assertIs(msg.transport, self.transport)\n        self.assertEqual(msg.status, 200)\n        self.assertEqual(msg.reason, \"OK\")\n        self.assertTrue(msg.closing)\n        self.assertEqual(msg.status_line, 'HTTP/1.1 200 OK\\r\\n')\n\n    def test_start_response_with_reason(self):\n        msg = protocol.Response(self.transport, 333, close=True,\n                                reason=\"My Reason\")\n\n        self.assertEqual(msg.status, 333)\n        self.assertEqual(msg.reason, \"My Reason\")\n        self.assertEqual(msg.status_line, 'HTTP/1.1 333 My Reason\\r\\n')\n\n    def test_start_response_with_unknown_reason(self):\n        msg = protocol.Response(self.transport, 777, close=True)\n\n        self.assertEqual(msg.status, 777)\n        self.assertEqual(msg.reason, \"777\")\n        self.assertEqual(msg.status_line, 'HTTP/1.1 777 777\\r\\n')\n\n    def test_force_close(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertFalse(msg.closing)\n        msg.force_close()\n        self.assertTrue(msg.closing)\n\n    def test_force_chunked(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertFalse(msg.chunked)\n        msg.enable_chunked_encoding()\n        self.assertTrue(msg.chunked)\n\n    def test_keep_alive(self):\n        msg = protocol.Response(self.transport, 200, close=True)\n        self.assertFalse(msg.keep_alive())\n        msg.keepalive = True\n        self.assertTrue(msg.keep_alive())\n\n        msg.force_close()\n        self.assertFalse(msg.keep_alive())\n\n    def test_keep_alive_http10(self):\n        msg = protocol.Response(self.transport, 200, http_version=(1, 0))\n        self.assertFalse(msg.keepalive)\n        self.assertFalse(msg.keep_alive())\n\n        msg = protocol.Response(self.transport, 200, http_version=(1, 1))\n        self.assertIsNone(msg.keepalive)\n\n    def test_add_header(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertEqual([], list(msg.headers))\n\n        msg.add_header('content-type', 'plain/html')\n        self.assertEqual(\n            [('CONTENT-TYPE', 'plain/html')], list(msg.headers.items()))\n\n    def test_add_header_with_spaces(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertEqual([], list(msg.headers))\n\n        msg.add_header('content-type', '  plain/html  ')\n        self.assertEqual(\n            [('CONTENT-TYPE', 'plain/html')], list(msg.headers.items()))\n\n    def test_add_header_non_ascii(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertEqual([], list(msg.headers))\n\n        with self.assertRaises(AssertionError):\n            msg.add_header('тип-контента', 'текст/плейн')\n\n    def test_add_header_invalid_value_type(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertEqual([], list(msg.headers))\n\n        with self.assertRaises(AssertionError):\n            msg.add_header('content-type', {'test': 'plain'})\n\n        with self.assertRaises(AssertionError):\n            msg.add_header(list('content-type'), 'text/plain')\n\n    def test_add_headers(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertEqual([], list(msg.headers))\n\n        msg.add_headers(('content-type', 'plain/html'))\n        self.assertEqual(\n            [('CONTENT-TYPE', 'plain/html')], list(msg.headers.items()))\n\n    def test_add_headers_length(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertIsNone(msg.length)\n\n        msg.add_headers(('content-length', '42'))\n        self.assertEqual(42, msg.length)\n\n    def test_add_headers_upgrade(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertFalse(msg.upgrade)\n\n        msg.add_headers(('connection', 'upgrade'))\n        self.assertTrue(msg.upgrade)\n\n    def test_add_headers_upgrade_websocket(self):\n        msg = protocol.Response(self.transport, 200)\n\n        msg.add_headers(('upgrade', 'test'))\n        self.assertEqual([], list(msg.headers))\n\n        msg.add_headers(('upgrade', 'websocket'))\n        self.assertEqual(\n            [('UPGRADE', 'websocket')], list(msg.headers.items()))\n\n    def test_add_headers_connection_keepalive(self):\n        msg = protocol.Response(self.transport, 200)\n\n        msg.add_headers(('connection', 'keep-alive'))\n        self.assertEqual([], list(msg.headers))\n        self.assertTrue(msg.keepalive)\n\n        msg.add_headers(('connection', 'close'))\n        self.assertFalse(msg.keepalive)\n\n    def test_add_headers_hop_headers(self):\n        msg = protocol.Response(self.transport, 200)\n        msg.HOP_HEADERS = (hdrs.TRANSFER_ENCODING,)\n\n        msg.add_headers(('connection', 'test'), ('transfer-encoding', 't'))\n        self.assertEqual([], list(msg.headers))\n\n    def test_default_headers(self):\n        msg = protocol.Response(self.transport, 200)\n        msg._add_default_headers()\n\n        headers = [r for r, _ in msg.headers.items()]\n        self.assertIn('DATE', headers)\n        self.assertIn('CONNECTION', headers)\n\n    def test_default_headers_server(self):\n        msg = protocol.Response(self.transport, 200)\n        msg._add_default_headers()\n\n        self.assertIn('SERVER', msg.headers)\n\n    def test_default_headers_useragent(self):\n        msg = protocol.Request(self.transport, 'GET', '/')\n        msg._add_default_headers()\n\n        self.assertNotIn('SERVER', msg.headers)\n        self.assertIn('USER-AGENT', msg.headers)\n\n    def test_default_headers_useragent_custom(self):\n        msg = protocol.Request(self.transport, 'GET', '/')\n        msg.add_headers(('user-agent', 'my custom agent'))\n        msg._add_default_headers()\n\n        headers = [r for r, _ in msg.headers.items()\n                   if r.lower() == 'user-agent']\n        self.assertEqual(len(headers), 1)\n\n    def test_default_headers_chunked(self):\n        msg = protocol.Response(self.transport, 200)\n        msg._add_default_headers()\n\n        headers = [r for r, _ in msg.headers.items()]\n        self.assertNotIn('TRANSFER-ENCODING', headers)\n\n        msg = protocol.Response(self.transport, 200)\n        msg.enable_chunked_encoding()\n        msg.send_headers()\n\n        headers = [r for r, _ in msg.headers.items()]\n        self.assertIn('TRANSFER-ENCODING', headers)\n\n    def test_default_headers_connection_upgrade(self):\n        msg = protocol.Response(self.transport, 200)\n        msg.upgrade = True\n        msg._add_default_headers()\n\n        headers = [r for r in msg.headers.items() if r[0] == 'CONNECTION']\n        self.assertEqual([('CONNECTION', 'upgrade')], headers)\n\n    def test_default_headers_connection_close(self):\n        msg = protocol.Response(self.transport, 200)\n        msg.force_close()\n        msg._add_default_headers()\n\n        headers = [r for r in msg.headers.items() if r[0] == 'CONNECTION']\n        self.assertEqual([('CONNECTION', 'close')], headers)\n\n    def test_default_headers_connection_keep_alive(self):\n        msg = protocol.Response(self.transport, 200)\n        msg.keepalive = True\n        msg._add_default_headers()\n\n        headers = [r for r in msg.headers.items() if r[0] == 'CONNECTION']\n        self.assertEqual([('CONNECTION', 'keep-alive')], headers)\n\n    def test_send_headers(self):\n        write = self.transport.write = unittest.mock.Mock()\n\n        msg = protocol.Response(self.transport, 200)\n        msg.add_headers(('content-type', 'plain/html'))\n        self.assertFalse(msg.is_headers_sent())\n\n        msg.send_headers()\n\n        content = b''.join([arg[1][0] for arg in list(write.mock_calls)])\n\n        self.assertTrue(content.startswith(b'HTTP/1.1 200 OK\\r\\n'))\n        self.assertIn(b'CONTENT-TYPE: plain/html', content)\n        self.assertTrue(msg.headers_sent)\n        self.assertTrue(msg.is_headers_sent())\n        # cleanup\n        msg.writer.close()\n\n    def test_send_headers_non_ascii(self):\n        write = self.transport.write = unittest.mock.Mock()\n\n        msg = protocol.Response(self.transport, 200)\n        msg.add_headers(('x-header', 'текст'))\n        self.assertFalse(msg.is_headers_sent())\n\n        msg.send_headers()\n\n        content = b''.join([arg[1][0] for arg in list(write.mock_calls)])\n\n        self.assertTrue(content.startswith(b'HTTP/1.1 200 OK\\r\\n'))\n        self.assertIn(b'X-HEADER: \\xd1\\x82\\xd0\\xb5\\xd0\\xba\\xd1\\x81\\xd1\\x82',\n                      content)\n        self.assertTrue(msg.headers_sent)\n        self.assertTrue(msg.is_headers_sent())\n        # cleanup\n        msg.writer.close()\n\n    def test_send_headers_nomore_add(self):\n        msg = protocol.Response(self.transport, 200)\n        msg.add_headers(('content-type', 'plain/html'))\n        msg.send_headers()\n\n        self.assertRaises(AssertionError,\n                          msg.add_header, 'content-type', 'plain/html')\n        # cleanup\n        msg.writer.close()\n\n    def test_prepare_length(self):\n        msg = protocol.Response(self.transport, 200)\n        w_l_p = msg._write_length_payload = unittest.mock.Mock()\n        w_l_p.return_value = iter([1, 2, 3])\n\n        msg.add_headers(('content-length', '42'))\n        msg.send_headers()\n\n        self.assertTrue(w_l_p.called)\n        self.assertEqual((42,), w_l_p.call_args[0])\n\n    def test_prepare_chunked_force(self):\n        msg = protocol.Response(self.transport, 200)\n        msg.enable_chunked_encoding()\n\n        chunked = msg._write_chunked_payload = unittest.mock.Mock()\n        chunked.return_value = iter([1, 2, 3])\n\n        msg.add_headers(('content-length', '42'))\n        msg.send_headers()\n        self.assertTrue(chunked.called)\n\n    def test_prepare_chunked_no_length(self):\n        msg = protocol.Response(self.transport, 200)\n\n        chunked = msg._write_chunked_payload = unittest.mock.Mock()\n        chunked.return_value = iter([1, 2, 3])\n\n        msg.send_headers()\n        self.assertTrue(chunked.called)\n\n    def test_prepare_eof(self):\n        msg = protocol.Response(self.transport, 200, http_version=(1, 0))\n\n        eof = msg._write_eof_payload = unittest.mock.Mock()\n        eof.return_value = iter([1, 2, 3])\n\n        msg.send_headers()\n        self.assertTrue(eof.called)\n\n    def test_write_auto_send_headers(self):\n        msg = protocol.Response(self.transport, 200, http_version=(1, 0))\n        msg._send_headers = True\n\n        msg.write(b'data1')\n        self.assertTrue(msg.headers_sent)\n        # cleanup\n        msg.writer.close()\n\n    def test_write_payload_eof(self):\n        write = self.transport.write = unittest.mock.Mock()\n        msg = protocol.Response(self.transport, 200, http_version=(1, 0))\n        msg.send_headers()\n\n        msg.write(b'data1')\n        self.assertTrue(msg.headers_sent)\n\n        msg.write(b'data2')\n        msg.write_eof()\n\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertEqual(\n            b'data1data2', content.split(b'\\r\\n\\r\\n', 1)[-1])\n\n    def test_write_payload_chunked(self):\n        write = self.transport.write = unittest.mock.Mock()\n\n        msg = protocol.Response(self.transport, 200)\n        msg.enable_chunked_encoding()\n        msg.send_headers()\n\n        msg.write(b'data')\n        msg.write_eof()\n\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertEqual(\n            b'4\\r\\ndata\\r\\n0\\r\\n\\r\\n',\n            content.split(b'\\r\\n\\r\\n', 1)[-1])\n\n    def test_write_payload_chunked_multiple(self):\n        write = self.transport.write = unittest.mock.Mock()\n\n        msg = protocol.Response(self.transport, 200)\n        msg.enable_chunked_encoding()\n        msg.send_headers()\n\n        msg.write(b'data1')\n        msg.write(b'data2')\n        msg.write_eof()\n\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertEqual(\n            b'5\\r\\ndata1\\r\\n5\\r\\ndata2\\r\\n0\\r\\n\\r\\n',\n            content.split(b'\\r\\n\\r\\n', 1)[-1])\n\n    def test_write_payload_length(self):\n        write = self.transport.write = unittest.mock.Mock()\n\n        msg = protocol.Response(self.transport, 200)\n        msg.add_headers(('content-length', '2'))\n        msg.send_headers()\n\n        msg.write(b'd')\n        msg.write(b'ata')\n        msg.write_eof()\n\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertEqual(\n            b'da', content.split(b'\\r\\n\\r\\n', 1)[-1])\n\n    def test_write_payload_chunked_filter(self):\n        write = self.transport.write = unittest.mock.Mock()\n\n        msg = protocol.Response(self.transport, 200)\n        msg.send_headers()\n\n        msg.add_chunking_filter(2)\n        msg.write(b'data')\n        msg.write_eof()\n\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertTrue(content.endswith(b'2\\r\\nda\\r\\n2\\r\\nta\\r\\n0\\r\\n\\r\\n'))\n\n    def test_write_payload_chunked_filter_mutiple_chunks(self):\n        write = self.transport.write = unittest.mock.Mock()\n        msg = protocol.Response(self.transport, 200)\n        msg.send_headers()\n\n        msg.add_chunking_filter(2)\n        msg.write(b'data1')\n        msg.write(b'data2')\n        msg.write_eof()\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertTrue(content.endswith(\n            b'2\\r\\nda\\r\\n2\\r\\nta\\r\\n2\\r\\n1d\\r\\n2\\r\\nat\\r\\n'\n            b'2\\r\\na2\\r\\n0\\r\\n\\r\\n'))\n\n    def test_write_payload_chunked_large_chunk(self):\n        write = self.transport.write = unittest.mock.Mock()\n        msg = protocol.Response(self.transport, 200)\n        msg.send_headers()\n\n        msg.add_chunking_filter(1024)\n        msg.write(b'data')\n        msg.write_eof()\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertTrue(content.endswith(b'4\\r\\ndata\\r\\n0\\r\\n\\r\\n'))\n\n    _comp = zlib.compressobj(wbits=-zlib.MAX_WBITS)\n    _COMPRESSED = b''.join([_comp.compress(b'data'), _comp.flush()])\n\n    def test_write_payload_deflate_filter(self):\n        write = self.transport.write = unittest.mock.Mock()\n        msg = protocol.Response(self.transport, 200)\n        msg.add_headers(('content-length', '{}'.format(len(self._COMPRESSED))))\n        msg.send_headers()\n\n        msg.add_compression_filter('deflate')\n        msg.write(b'data')\n        msg.write_eof()\n\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertEqual(\n            self._COMPRESSED, content.split(b'\\r\\n\\r\\n', 1)[-1])\n\n    def test_write_payload_deflate_and_chunked(self):\n        write = self.transport.write = unittest.mock.Mock()\n        msg = protocol.Response(self.transport, 200)\n        msg.send_headers()\n\n        msg.add_compression_filter('deflate')\n        msg.add_chunking_filter(2)\n\n        msg.write(b'data')\n        msg.write_eof()\n\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertEqual(\n            b'2\\r\\nKI\\r\\n2\\r\\n,I\\r\\n2\\r\\n\\x04\\x00\\r\\n0\\r\\n\\r\\n',\n            content.split(b'\\r\\n\\r\\n', 1)[-1])\n\n    def test_write_payload_chunked_and_deflate(self):\n        write = self.transport.write = unittest.mock.Mock()\n        msg = protocol.Response(self.transport, 200)\n        msg.add_headers(('content-length', '{}'.format(len(self._COMPRESSED))))\n\n        msg.add_chunking_filter(2)\n        msg.add_compression_filter('deflate')\n        msg.send_headers()\n\n        msg.write(b'data')\n        msg.write_eof()\n\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertEqual(\n            self._COMPRESSED, content.split(b'\\r\\n\\r\\n', 1)[-1])\n\n    def test_write_drain(self):\n        msg = protocol.Response(self.transport, 200, http_version=(1, 0))\n        msg._send_headers = True\n\n        msg.write(b'1' * (64 * 1024 * 2))\n        self.assertFalse(self.transport.drain.called)\n\n        msg.write(b'1', drain=True)\n        self.assertTrue(self.transport.drain.called)\n        self.assertEqual(msg._output_size, 0)\n\n    def test_dont_override_request_headers_with_default_values(self):\n        msg = protocol.Request(\n            self.transport, 'GET', '/index.html', close=True)\n        msg.add_header('USER-AGENT', 'custom')\n        msg._add_default_headers()\n        self.assertEqual('custom', msg.headers['USER-AGENT'])\n\n    def test_dont_override_response_headers_with_default_values(self):\n        msg = protocol.Response(self.transport, 200, http_version=(1, 0))\n        msg.add_header('DATE', 'now')\n        msg.add_header('SERVER', 'custom')\n        msg._add_default_headers()\n        self.assertEqual('custom', msg.headers['SERVER'])\n        self.assertEqual('now', msg.headers['DATE'])",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 427,
                            "end_lineno": 439,
                            "parent": {
                                "file_name": "tests/test_http_protocol.py",
                                "type": "class",
                                "name": "TestHttpMessage",
                                "content": "class TestHttpMessage(unittest.TestCase):\n\n    def setUp(self):\n        self.transport = unittest.mock.Mock()\n        asyncio.set_event_loop(None)\n\n    def test_start_request(self):\n        msg = protocol.Request(\n            self.transport, 'GET', '/index.html', close=True)\n\n        self.assertIs(msg.transport, self.transport)\n        self.assertIsNone(msg.status)\n        self.assertTrue(msg.closing)\n        self.assertEqual(msg.status_line, 'GET /index.html HTTP/1.1\\r\\n')\n\n    def test_start_response(self):\n        msg = protocol.Response(self.transport, 200, close=True)\n\n        self.assertIs(msg.transport, self.transport)\n        self.assertEqual(msg.status, 200)\n        self.assertEqual(msg.reason, \"OK\")\n        self.assertTrue(msg.closing)\n        self.assertEqual(msg.status_line, 'HTTP/1.1 200 OK\\r\\n')\n\n    def test_start_response_with_reason(self):\n        msg = protocol.Response(self.transport, 333, close=True,\n                                reason=\"My Reason\")\n\n        self.assertEqual(msg.status, 333)\n        self.assertEqual(msg.reason, \"My Reason\")\n        self.assertEqual(msg.status_line, 'HTTP/1.1 333 My Reason\\r\\n')\n\n    def test_start_response_with_unknown_reason(self):\n        msg = protocol.Response(self.transport, 777, close=True)\n\n        self.assertEqual(msg.status, 777)\n        self.assertEqual(msg.reason, \"777\")\n        self.assertEqual(msg.status_line, 'HTTP/1.1 777 777\\r\\n')\n\n    def test_force_close(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertFalse(msg.closing)\n        msg.force_close()\n        self.assertTrue(msg.closing)\n\n    def test_force_chunked(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertFalse(msg.chunked)\n        msg.enable_chunked_encoding()\n        self.assertTrue(msg.chunked)\n\n    def test_keep_alive(self):\n        msg = protocol.Response(self.transport, 200, close=True)\n        self.assertFalse(msg.keep_alive())\n        msg.keepalive = True\n        self.assertTrue(msg.keep_alive())\n\n        msg.force_close()\n        self.assertFalse(msg.keep_alive())\n\n    def test_keep_alive_http10(self):\n        msg = protocol.Response(self.transport, 200, http_version=(1, 0))\n        self.assertFalse(msg.keepalive)\n        self.assertFalse(msg.keep_alive())\n\n        msg = protocol.Response(self.transport, 200, http_version=(1, 1))\n        self.assertIsNone(msg.keepalive)\n\n    def test_add_header(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertEqual([], list(msg.headers))\n\n        msg.add_header('content-type', 'plain/html')\n        self.assertEqual(\n            [('CONTENT-TYPE', 'plain/html')], list(msg.headers.items()))\n\n    def test_add_header_with_spaces(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertEqual([], list(msg.headers))\n\n        msg.add_header('content-type', '  plain/html  ')\n        self.assertEqual(\n            [('CONTENT-TYPE', 'plain/html')], list(msg.headers.items()))\n\n    def test_add_header_non_ascii(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertEqual([], list(msg.headers))\n\n        with self.assertRaises(AssertionError):\n            msg.add_header('тип-контента', 'текст/плейн')\n\n    def test_add_header_invalid_value_type(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertEqual([], list(msg.headers))\n\n        with self.assertRaises(AssertionError):\n            msg.add_header('content-type', {'test': 'plain'})\n\n        with self.assertRaises(AssertionError):\n            msg.add_header(list('content-type'), 'text/plain')\n\n    def test_add_headers(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertEqual([], list(msg.headers))\n\n        msg.add_headers(('content-type', 'plain/html'))\n        self.assertEqual(\n            [('CONTENT-TYPE', 'plain/html')], list(msg.headers.items()))\n\n    def test_add_headers_length(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertIsNone(msg.length)\n\n        msg.add_headers(('content-length', '42'))\n        self.assertEqual(42, msg.length)\n\n    def test_add_headers_upgrade(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertFalse(msg.upgrade)\n\n        msg.add_headers(('connection', 'upgrade'))\n        self.assertTrue(msg.upgrade)\n\n    def test_add_headers_upgrade_websocket(self):\n        msg = protocol.Response(self.transport, 200)\n\n        msg.add_headers(('upgrade', 'test'))\n        self.assertEqual([], list(msg.headers))\n\n        msg.add_headers(('upgrade', 'websocket'))\n        self.assertEqual(\n            [('UPGRADE', 'websocket')], list(msg.headers.items()))\n\n    def test_add_headers_connection_keepalive(self):\n        msg = protocol.Response(self.transport, 200)\n\n        msg.add_headers(('connection', 'keep-alive'))\n        self.assertEqual([], list(msg.headers))\n        self.assertTrue(msg.keepalive)\n\n        msg.add_headers(('connection', 'close'))\n        self.assertFalse(msg.keepalive)\n\n    def test_add_headers_hop_headers(self):\n        msg = protocol.Response(self.transport, 200)\n        msg.HOP_HEADERS = (hdrs.TRANSFER_ENCODING,)\n\n        msg.add_headers(('connection', 'test'), ('transfer-encoding', 't'))\n        self.assertEqual([], list(msg.headers))\n\n    def test_default_headers(self):\n        msg = protocol.Response(self.transport, 200)\n        msg._add_default_headers()\n\n        headers = [r for r, _ in msg.headers.items()]\n        self.assertIn('DATE', headers)\n        self.assertIn('CONNECTION', headers)\n\n    def test_default_headers_server(self):\n        msg = protocol.Response(self.transport, 200)\n        msg._add_default_headers()\n\n        self.assertIn('SERVER', msg.headers)\n\n    def test_default_headers_useragent(self):\n        msg = protocol.Request(self.transport, 'GET', '/')\n        msg._add_default_headers()\n\n        self.assertNotIn('SERVER', msg.headers)\n        self.assertIn('USER-AGENT', msg.headers)\n\n    def test_default_headers_useragent_custom(self):\n        msg = protocol.Request(self.transport, 'GET', '/')\n        msg.add_headers(('user-agent', 'my custom agent'))\n        msg._add_default_headers()\n\n        headers = [r for r, _ in msg.headers.items()\n                   if r.lower() == 'user-agent']\n        self.assertEqual(len(headers), 1)\n\n    def test_default_headers_chunked(self):\n        msg = protocol.Response(self.transport, 200)\n        msg._add_default_headers()\n\n        headers = [r for r, _ in msg.headers.items()]\n        self.assertNotIn('TRANSFER-ENCODING', headers)\n\n        msg = protocol.Response(self.transport, 200)\n        msg.enable_chunked_encoding()\n        msg.send_headers()\n\n        headers = [r for r, _ in msg.headers.items()]\n        self.assertIn('TRANSFER-ENCODING', headers)\n\n    def test_default_headers_connection_upgrade(self):\n        msg = protocol.Response(self.transport, 200)\n        msg.upgrade = True\n        msg._add_default_headers()\n\n        headers = [r for r in msg.headers.items() if r[0] == 'CONNECTION']\n        self.assertEqual([('CONNECTION', 'upgrade')], headers)\n\n    def test_default_headers_connection_close(self):\n        msg = protocol.Response(self.transport, 200)\n        msg.force_close()\n        msg._add_default_headers()\n\n        headers = [r for r in msg.headers.items() if r[0] == 'CONNECTION']\n        self.assertEqual([('CONNECTION', 'close')], headers)\n\n    def test_default_headers_connection_keep_alive(self):\n        msg = protocol.Response(self.transport, 200)\n        msg.keepalive = True\n        msg._add_default_headers()\n\n        headers = [r for r in msg.headers.items() if r[0] == 'CONNECTION']\n        self.assertEqual([('CONNECTION', 'keep-alive')], headers)\n\n    def test_send_headers(self):\n        write = self.transport.write = unittest.mock.Mock()\n\n        msg = protocol.Response(self.transport, 200)\n        msg.add_headers(('content-type', 'plain/html'))\n        self.assertFalse(msg.is_headers_sent())\n\n        msg.send_headers()\n\n        content = b''.join([arg[1][0] for arg in list(write.mock_calls)])\n\n        self.assertTrue(content.startswith(b'HTTP/1.1 200 OK\\r\\n'))\n        self.assertIn(b'CONTENT-TYPE: plain/html', content)\n        self.assertTrue(msg.headers_sent)\n        self.assertTrue(msg.is_headers_sent())\n        # cleanup\n        msg.writer.close()\n\n    def test_send_headers_non_ascii(self):\n        write = self.transport.write = unittest.mock.Mock()\n\n        msg = protocol.Response(self.transport, 200)\n        msg.add_headers(('x-header', 'текст'))\n        self.assertFalse(msg.is_headers_sent())\n\n        msg.send_headers()\n\n        content = b''.join([arg[1][0] for arg in list(write.mock_calls)])\n\n        self.assertTrue(content.startswith(b'HTTP/1.1 200 OK\\r\\n'))\n        self.assertIn(b'X-HEADER: \\xd1\\x82\\xd0\\xb5\\xd0\\xba\\xd1\\x81\\xd1\\x82',\n                      content)\n        self.assertTrue(msg.headers_sent)\n        self.assertTrue(msg.is_headers_sent())\n        # cleanup\n        msg.writer.close()\n\n    def test_send_headers_nomore_add(self):\n        msg = protocol.Response(self.transport, 200)\n        msg.add_headers(('content-type', 'plain/html'))\n        msg.send_headers()\n\n        self.assertRaises(AssertionError,\n                          msg.add_header, 'content-type', 'plain/html')\n        # cleanup\n        msg.writer.close()\n\n    def test_prepare_length(self):\n        msg = protocol.Response(self.transport, 200)\n        w_l_p = msg._write_length_payload = unittest.mock.Mock()\n        w_l_p.return_value = iter([1, 2, 3])\n\n        msg.add_headers(('content-length', '42'))\n        msg.send_headers()\n\n        self.assertTrue(w_l_p.called)\n        self.assertEqual((42,), w_l_p.call_args[0])\n\n    def test_prepare_chunked_force(self):\n        msg = protocol.Response(self.transport, 200)\n        msg.enable_chunked_encoding()\n\n        chunked = msg._write_chunked_payload = unittest.mock.Mock()\n        chunked.return_value = iter([1, 2, 3])\n\n        msg.add_headers(('content-length', '42'))\n        msg.send_headers()\n        self.assertTrue(chunked.called)\n\n    def test_prepare_chunked_no_length(self):\n        msg = protocol.Response(self.transport, 200)\n\n        chunked = msg._write_chunked_payload = unittest.mock.Mock()\n        chunked.return_value = iter([1, 2, 3])\n\n        msg.send_headers()\n        self.assertTrue(chunked.called)\n\n    def test_prepare_eof(self):\n        msg = protocol.Response(self.transport, 200, http_version=(1, 0))\n\n        eof = msg._write_eof_payload = unittest.mock.Mock()\n        eof.return_value = iter([1, 2, 3])\n\n        msg.send_headers()\n        self.assertTrue(eof.called)\n\n    def test_write_auto_send_headers(self):\n        msg = protocol.Response(self.transport, 200, http_version=(1, 0))\n        msg._send_headers = True\n\n        msg.write(b'data1')\n        self.assertTrue(msg.headers_sent)\n        # cleanup\n        msg.writer.close()\n\n    def test_write_payload_eof(self):\n        write = self.transport.write = unittest.mock.Mock()\n        msg = protocol.Response(self.transport, 200, http_version=(1, 0))\n        msg.send_headers()\n\n        msg.write(b'data1')\n        self.assertTrue(msg.headers_sent)\n\n        msg.write(b'data2')\n        msg.write_eof()\n\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertEqual(\n            b'data1data2', content.split(b'\\r\\n\\r\\n', 1)[-1])\n\n    def test_write_payload_chunked(self):\n        write = self.transport.write = unittest.mock.Mock()\n\n        msg = protocol.Response(self.transport, 200)\n        msg.enable_chunked_encoding()\n        msg.send_headers()\n\n        msg.write(b'data')\n        msg.write_eof()\n\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertEqual(\n            b'4\\r\\ndata\\r\\n0\\r\\n\\r\\n',\n            content.split(b'\\r\\n\\r\\n', 1)[-1])\n\n    def test_write_payload_chunked_multiple(self):\n        write = self.transport.write = unittest.mock.Mock()\n\n        msg = protocol.Response(self.transport, 200)\n        msg.enable_chunked_encoding()\n        msg.send_headers()\n\n        msg.write(b'data1')\n        msg.write(b'data2')\n        msg.write_eof()\n\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertEqual(\n            b'5\\r\\ndata1\\r\\n5\\r\\ndata2\\r\\n0\\r\\n\\r\\n',\n            content.split(b'\\r\\n\\r\\n', 1)[-1])\n\n    def test_write_payload_length(self):\n        write = self.transport.write = unittest.mock.Mock()\n\n        msg = protocol.Response(self.transport, 200)\n        msg.add_headers(('content-length', '2'))\n        msg.send_headers()\n\n        msg.write(b'd')\n        msg.write(b'ata')\n        msg.write_eof()\n\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertEqual(\n            b'da', content.split(b'\\r\\n\\r\\n', 1)[-1])\n\n    def test_write_payload_chunked_filter(self):\n        write = self.transport.write = unittest.mock.Mock()\n\n        msg = protocol.Response(self.transport, 200)\n        msg.send_headers()\n\n        msg.add_chunking_filter(2)\n        msg.write(b'data')\n        msg.write_eof()\n\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertTrue(content.endswith(b'2\\r\\nda\\r\\n2\\r\\nta\\r\\n0\\r\\n\\r\\n'))\n\n    def test_write_payload_chunked_filter_mutiple_chunks(self):\n        write = self.transport.write = unittest.mock.Mock()\n        msg = protocol.Response(self.transport, 200)\n        msg.send_headers()\n\n        msg.add_chunking_filter(2)\n        msg.write(b'data1')\n        msg.write(b'data2')\n        msg.write_eof()\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertTrue(content.endswith(\n            b'2\\r\\nda\\r\\n2\\r\\nta\\r\\n2\\r\\n1d\\r\\n2\\r\\nat\\r\\n'\n            b'2\\r\\na2\\r\\n0\\r\\n\\r\\n'))\n\n    def test_write_payload_chunked_large_chunk(self):\n        write = self.transport.write = unittest.mock.Mock()\n        msg = protocol.Response(self.transport, 200)\n        msg.send_headers()\n\n        msg.add_chunking_filter(1024)\n        msg.write(b'data')\n        msg.write_eof()\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertTrue(content.endswith(b'4\\r\\ndata\\r\\n0\\r\\n\\r\\n'))\n\n    _comp = zlib.compressobj(wbits=-zlib.MAX_WBITS)\n    _COMPRESSED = b''.join([_comp.compress(b'data'), _comp.flush()])\n\n    def test_write_payload_deflate_filter(self):\n        write = self.transport.write = unittest.mock.Mock()\n        msg = protocol.Response(self.transport, 200)\n        msg.add_headers(('content-length', '{}'.format(len(self._COMPRESSED))))\n        msg.send_headers()\n\n        msg.add_compression_filter('deflate')\n        msg.write(b'data')\n        msg.write_eof()\n\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertEqual(\n            self._COMPRESSED, content.split(b'\\r\\n\\r\\n', 1)[-1])\n\n    def test_write_payload_deflate_and_chunked(self):\n        write = self.transport.write = unittest.mock.Mock()\n        msg = protocol.Response(self.transport, 200)\n        msg.send_headers()\n\n        msg.add_compression_filter('deflate')\n        msg.add_chunking_filter(2)\n\n        msg.write(b'data')\n        msg.write_eof()\n\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertEqual(\n            b'2\\r\\nKI\\r\\n2\\r\\n,I\\r\\n2\\r\\n\\x04\\x00\\r\\n0\\r\\n\\r\\n',\n            content.split(b'\\r\\n\\r\\n', 1)[-1])\n\n    def test_write_payload_chunked_and_deflate(self):\n        write = self.transport.write = unittest.mock.Mock()\n        msg = protocol.Response(self.transport, 200)\n        msg.add_headers(('content-length', '{}'.format(len(self._COMPRESSED))))\n\n        msg.add_chunking_filter(2)\n        msg.add_compression_filter('deflate')\n        msg.send_headers()\n\n        msg.write(b'data')\n        msg.write_eof()\n\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertEqual(\n            self._COMPRESSED, content.split(b'\\r\\n\\r\\n', 1)[-1])\n\n    def test_write_drain(self):\n        msg = protocol.Response(self.transport, 200, http_version=(1, 0))\n        msg._send_headers = True\n\n        msg.write(b'1' * (64 * 1024 * 2))\n        self.assertFalse(self.transport.drain.called)\n\n        msg.write(b'1', drain=True)\n        self.assertTrue(self.transport.drain.called)\n        self.assertEqual(msg._output_size, 0)\n\n    def test_dont_override_request_headers_with_default_values(self):\n        msg = protocol.Request(\n            self.transport, 'GET', '/index.html', close=True)\n        msg.add_header('USER-AGENT', 'custom')\n        msg._add_default_headers()\n        self.assertEqual('custom', msg.headers['USER-AGENT'])\n\n    def test_dont_override_response_headers_with_default_values(self):\n        msg = protocol.Response(self.transport, 200, http_version=(1, 0))\n        msg.add_header('DATE', 'now')\n        msg.add_header('SERVER', 'custom')\n        msg._add_default_headers()\n        self.assertEqual('custom', msg.headers['SERVER'])\n        self.assertEqual('now', msg.headers['DATE'])",
                                "ast_type_str": "ClassDef",
                                "start_lineno": 11,
                                "end_lineno": 497,
                                "parent": null
                            }
                        },
                        {
                            "file_name": "tests/test_http_protocol.py",
                            "type": "class",
                            "name": "TestHttpMessage",
                            "content": "class TestHttpMessage(unittest.TestCase):\n\n    def setUp(self):\n        self.transport = unittest.mock.Mock()\n        asyncio.set_event_loop(None)\n\n    def test_start_request(self):\n        msg = protocol.Request(\n            self.transport, 'GET', '/index.html', close=True)\n\n        self.assertIs(msg.transport, self.transport)\n        self.assertIsNone(msg.status)\n        self.assertTrue(msg.closing)\n        self.assertEqual(msg.status_line, 'GET /index.html HTTP/1.1\\r\\n')\n\n    def test_start_response(self):\n        msg = protocol.Response(self.transport, 200, close=True)\n\n        self.assertIs(msg.transport, self.transport)\n        self.assertEqual(msg.status, 200)\n        self.assertEqual(msg.reason, \"OK\")\n        self.assertTrue(msg.closing)\n        self.assertEqual(msg.status_line, 'HTTP/1.1 200 OK\\r\\n')\n\n    def test_start_response_with_reason(self):\n        msg = protocol.Response(self.transport, 333, close=True,\n                                reason=\"My Reason\")\n\n        self.assertEqual(msg.status, 333)\n        self.assertEqual(msg.reason, \"My Reason\")\n        self.assertEqual(msg.status_line, 'HTTP/1.1 333 My Reason\\r\\n')\n\n    def test_start_response_with_unknown_reason(self):\n        msg = protocol.Response(self.transport, 777, close=True)\n\n        self.assertEqual(msg.status, 777)\n        self.assertEqual(msg.reason, \"777\")\n        self.assertEqual(msg.status_line, 'HTTP/1.1 777 777\\r\\n')\n\n    def test_force_close(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertFalse(msg.closing)\n        msg.force_close()\n        self.assertTrue(msg.closing)\n\n    def test_force_chunked(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertFalse(msg.chunked)\n        msg.enable_chunked_encoding()\n        self.assertTrue(msg.chunked)\n\n    def test_keep_alive(self):\n        msg = protocol.Response(self.transport, 200, close=True)\n        self.assertFalse(msg.keep_alive())\n        msg.keepalive = True\n        self.assertTrue(msg.keep_alive())\n\n        msg.force_close()\n        self.assertFalse(msg.keep_alive())\n\n    def test_keep_alive_http10(self):\n        msg = protocol.Response(self.transport, 200, http_version=(1, 0))\n        self.assertFalse(msg.keepalive)\n        self.assertFalse(msg.keep_alive())\n\n        msg = protocol.Response(self.transport, 200, http_version=(1, 1))\n        self.assertIsNone(msg.keepalive)\n\n    def test_add_header(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertEqual([], list(msg.headers))\n\n        msg.add_header('content-type', 'plain/html')\n        self.assertEqual(\n            [('CONTENT-TYPE', 'plain/html')], list(msg.headers.items()))\n\n    def test_add_header_with_spaces(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertEqual([], list(msg.headers))\n\n        msg.add_header('content-type', '  plain/html  ')\n        self.assertEqual(\n            [('CONTENT-TYPE', 'plain/html')], list(msg.headers.items()))\n\n    def test_add_header_non_ascii(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertEqual([], list(msg.headers))\n\n        with self.assertRaises(AssertionError):\n            msg.add_header('тип-контента', 'текст/плейн')\n\n    def test_add_header_invalid_value_type(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertEqual([], list(msg.headers))\n\n        with self.assertRaises(AssertionError):\n            msg.add_header('content-type', {'test': 'plain'})\n\n        with self.assertRaises(AssertionError):\n            msg.add_header(list('content-type'), 'text/plain')\n\n    def test_add_headers(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertEqual([], list(msg.headers))\n\n        msg.add_headers(('content-type', 'plain/html'))\n        self.assertEqual(\n            [('CONTENT-TYPE', 'plain/html')], list(msg.headers.items()))\n\n    def test_add_headers_length(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertIsNone(msg.length)\n\n        msg.add_headers(('content-length', '42'))\n        self.assertEqual(42, msg.length)\n\n    def test_add_headers_upgrade(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertFalse(msg.upgrade)\n\n        msg.add_headers(('connection', 'upgrade'))\n        self.assertTrue(msg.upgrade)\n\n    def test_add_headers_upgrade_websocket(self):\n        msg = protocol.Response(self.transport, 200)\n\n        msg.add_headers(('upgrade', 'test'))\n        self.assertEqual([], list(msg.headers))\n\n        msg.add_headers(('upgrade', 'websocket'))\n        self.assertEqual(\n            [('UPGRADE', 'websocket')], list(msg.headers.items()))\n\n    def test_add_headers_connection_keepalive(self):\n        msg = protocol.Response(self.transport, 200)\n\n        msg.add_headers(('connection', 'keep-alive'))\n        self.assertEqual([], list(msg.headers))\n        self.assertTrue(msg.keepalive)\n\n        msg.add_headers(('connection', 'close'))\n        self.assertFalse(msg.keepalive)\n\n    def test_add_headers_hop_headers(self):\n        msg = protocol.Response(self.transport, 200)\n        msg.HOP_HEADERS = (hdrs.TRANSFER_ENCODING,)\n\n        msg.add_headers(('connection', 'test'), ('transfer-encoding', 't'))\n        self.assertEqual([], list(msg.headers))\n\n    def test_default_headers(self):\n        msg = protocol.Response(self.transport, 200)\n        msg._add_default_headers()\n\n        headers = [r for r, _ in msg.headers.items()]\n        self.assertIn('DATE', headers)\n        self.assertIn('CONNECTION', headers)\n\n    def test_default_headers_server(self):\n        msg = protocol.Response(self.transport, 200)\n        msg._add_default_headers()\n\n        self.assertIn('SERVER', msg.headers)\n\n    def test_default_headers_useragent(self):\n        msg = protocol.Request(self.transport, 'GET', '/')\n        msg._add_default_headers()\n\n        self.assertNotIn('SERVER', msg.headers)\n        self.assertIn('USER-AGENT', msg.headers)\n\n    def test_default_headers_useragent_custom(self):\n        msg = protocol.Request(self.transport, 'GET', '/')\n        msg.add_headers(('user-agent', 'my custom agent'))\n        msg._add_default_headers()\n\n        headers = [r for r, _ in msg.headers.items()\n                   if r.lower() == 'user-agent']\n        self.assertEqual(len(headers), 1)\n\n    def test_default_headers_chunked(self):\n        msg = protocol.Response(self.transport, 200)\n        msg._add_default_headers()\n\n        headers = [r for r, _ in msg.headers.items()]\n        self.assertNotIn('TRANSFER-ENCODING', headers)\n\n        msg = protocol.Response(self.transport, 200)\n        msg.enable_chunked_encoding()\n        msg.send_headers()\n\n        headers = [r for r, _ in msg.headers.items()]\n        self.assertIn('TRANSFER-ENCODING', headers)\n\n    def test_default_headers_connection_upgrade(self):\n        msg = protocol.Response(self.transport, 200)\n        msg.upgrade = True\n        msg._add_default_headers()\n\n        headers = [r for r in msg.headers.items() if r[0] == 'CONNECTION']\n        self.assertEqual([('CONNECTION', 'upgrade')], headers)\n\n    def test_default_headers_connection_close(self):\n        msg = protocol.Response(self.transport, 200)\n        msg.force_close()\n        msg._add_default_headers()\n\n        headers = [r for r in msg.headers.items() if r[0] == 'CONNECTION']\n        self.assertEqual([('CONNECTION', 'close')], headers)\n\n    def test_default_headers_connection_keep_alive(self):\n        msg = protocol.Response(self.transport, 200)\n        msg.keepalive = True\n        msg._add_default_headers()\n\n        headers = [r for r in msg.headers.items() if r[0] == 'CONNECTION']\n        self.assertEqual([('CONNECTION', 'keep-alive')], headers)\n\n    def test_send_headers(self):\n        write = self.transport.write = unittest.mock.Mock()\n\n        msg = protocol.Response(self.transport, 200)\n        msg.add_headers(('content-type', 'plain/html'))\n        self.assertFalse(msg.is_headers_sent())\n\n        msg.send_headers()\n\n        content = b''.join([arg[1][0] for arg in list(write.mock_calls)])\n\n        self.assertTrue(content.startswith(b'HTTP/1.1 200 OK\\r\\n'))\n        self.assertIn(b'CONTENT-TYPE: plain/html', content)\n        self.assertTrue(msg.headers_sent)\n        self.assertTrue(msg.is_headers_sent())\n        # cleanup\n        msg.writer.close()\n\n    def test_send_headers_non_ascii(self):\n        write = self.transport.write = unittest.mock.Mock()\n\n        msg = protocol.Response(self.transport, 200)\n        msg.add_headers(('x-header', 'текст'))\n        self.assertFalse(msg.is_headers_sent())\n\n        msg.send_headers()\n\n        content = b''.join([arg[1][0] for arg in list(write.mock_calls)])\n\n        self.assertTrue(content.startswith(b'HTTP/1.1 200 OK\\r\\n'))\n        self.assertIn(b'X-HEADER: \\xd1\\x82\\xd0\\xb5\\xd0\\xba\\xd1\\x81\\xd1\\x82',\n                      content)\n        self.assertTrue(msg.headers_sent)\n        self.assertTrue(msg.is_headers_sent())\n        # cleanup\n        msg.writer.close()\n\n    def test_send_headers_nomore_add(self):\n        msg = protocol.Response(self.transport, 200)\n        msg.add_headers(('content-type', 'plain/html'))\n        msg.send_headers()\n\n        self.assertRaises(AssertionError,\n                          msg.add_header, 'content-type', 'plain/html')\n        # cleanup\n        msg.writer.close()\n\n    def test_prepare_length(self):\n        msg = protocol.Response(self.transport, 200)\n        w_l_p = msg._write_length_payload = unittest.mock.Mock()\n        w_l_p.return_value = iter([1, 2, 3])\n\n        msg.add_headers(('content-length', '42'))\n        msg.send_headers()\n\n        self.assertTrue(w_l_p.called)\n        self.assertEqual((42,), w_l_p.call_args[0])\n\n    def test_prepare_chunked_force(self):\n        msg = protocol.Response(self.transport, 200)\n        msg.enable_chunked_encoding()\n\n        chunked = msg._write_chunked_payload = unittest.mock.Mock()\n        chunked.return_value = iter([1, 2, 3])\n\n        msg.add_headers(('content-length', '42'))\n        msg.send_headers()\n        self.assertTrue(chunked.called)\n\n    def test_prepare_chunked_no_length(self):\n        msg = protocol.Response(self.transport, 200)\n\n        chunked = msg._write_chunked_payload = unittest.mock.Mock()\n        chunked.return_value = iter([1, 2, 3])\n\n        msg.send_headers()\n        self.assertTrue(chunked.called)\n\n    def test_prepare_eof(self):\n        msg = protocol.Response(self.transport, 200, http_version=(1, 0))\n\n        eof = msg._write_eof_payload = unittest.mock.Mock()\n        eof.return_value = iter([1, 2, 3])\n\n        msg.send_headers()\n        self.assertTrue(eof.called)\n\n    def test_write_auto_send_headers(self):\n        msg = protocol.Response(self.transport, 200, http_version=(1, 0))\n        msg._send_headers = True\n\n        msg.write(b'data1')\n        self.assertTrue(msg.headers_sent)\n        # cleanup\n        msg.writer.close()\n\n    def test_write_payload_eof(self):\n        write = self.transport.write = unittest.mock.Mock()\n        msg = protocol.Response(self.transport, 200, http_version=(1, 0))\n        msg.send_headers()\n\n        msg.write(b'data1')\n        self.assertTrue(msg.headers_sent)\n\n        msg.write(b'data2')\n        msg.write_eof()\n\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertEqual(\n            b'data1data2', content.split(b'\\r\\n\\r\\n', 1)[-1])\n\n    def test_write_payload_chunked(self):\n        write = self.transport.write = unittest.mock.Mock()\n\n        msg = protocol.Response(self.transport, 200)\n        msg.enable_chunked_encoding()\n        msg.send_headers()\n\n        msg.write(b'data')\n        msg.write_eof()\n\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertEqual(\n            b'4\\r\\ndata\\r\\n0\\r\\n\\r\\n',\n            content.split(b'\\r\\n\\r\\n', 1)[-1])\n\n    def test_write_payload_chunked_multiple(self):\n        write = self.transport.write = unittest.mock.Mock()\n\n        msg = protocol.Response(self.transport, 200)\n        msg.enable_chunked_encoding()\n        msg.send_headers()\n\n        msg.write(b'data1')\n        msg.write(b'data2')\n        msg.write_eof()\n\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertEqual(\n            b'5\\r\\ndata1\\r\\n5\\r\\ndata2\\r\\n0\\r\\n\\r\\n',\n            content.split(b'\\r\\n\\r\\n', 1)[-1])\n\n    def test_write_payload_length(self):\n        write = self.transport.write = unittest.mock.Mock()\n\n        msg = protocol.Response(self.transport, 200)\n        msg.add_headers(('content-length', '2'))\n        msg.send_headers()\n\n        msg.write(b'd')\n        msg.write(b'ata')\n        msg.write_eof()\n\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertEqual(\n            b'da', content.split(b'\\r\\n\\r\\n', 1)[-1])\n\n    def test_write_payload_chunked_filter(self):\n        write = self.transport.write = unittest.mock.Mock()\n\n        msg = protocol.Response(self.transport, 200)\n        msg.send_headers()\n\n        msg.add_chunking_filter(2)\n        msg.write(b'data')\n        msg.write_eof()\n\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertTrue(content.endswith(b'2\\r\\nda\\r\\n2\\r\\nta\\r\\n0\\r\\n\\r\\n'))\n\n    def test_write_payload_chunked_filter_mutiple_chunks(self):\n        write = self.transport.write = unittest.mock.Mock()\n        msg = protocol.Response(self.transport, 200)\n        msg.send_headers()\n\n        msg.add_chunking_filter(2)\n        msg.write(b'data1')\n        msg.write(b'data2')\n        msg.write_eof()\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertTrue(content.endswith(\n            b'2\\r\\nda\\r\\n2\\r\\nta\\r\\n2\\r\\n1d\\r\\n2\\r\\nat\\r\\n'\n            b'2\\r\\na2\\r\\n0\\r\\n\\r\\n'))\n\n    def test_write_payload_chunked_large_chunk(self):\n        write = self.transport.write = unittest.mock.Mock()\n        msg = protocol.Response(self.transport, 200)\n        msg.send_headers()\n\n        msg.add_chunking_filter(1024)\n        msg.write(b'data')\n        msg.write_eof()\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertTrue(content.endswith(b'4\\r\\ndata\\r\\n0\\r\\n\\r\\n'))\n\n    _comp = zlib.compressobj(wbits=-zlib.MAX_WBITS)\n    _COMPRESSED = b''.join([_comp.compress(b'data'), _comp.flush()])\n\n    def test_write_payload_deflate_filter(self):\n        write = self.transport.write = unittest.mock.Mock()\n        msg = protocol.Response(self.transport, 200)\n        msg.add_headers(('content-length', '{}'.format(len(self._COMPRESSED))))\n        msg.send_headers()\n\n        msg.add_compression_filter('deflate')\n        msg.write(b'data')\n        msg.write_eof()\n\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertEqual(\n            self._COMPRESSED, content.split(b'\\r\\n\\r\\n', 1)[-1])\n\n    def test_write_payload_deflate_and_chunked(self):\n        write = self.transport.write = unittest.mock.Mock()\n        msg = protocol.Response(self.transport, 200)\n        msg.send_headers()\n\n        msg.add_compression_filter('deflate')\n        msg.add_chunking_filter(2)\n\n        msg.write(b'data')\n        msg.write_eof()\n\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertEqual(\n            b'2\\r\\nKI\\r\\n2\\r\\n,I\\r\\n2\\r\\n\\x04\\x00\\r\\n0\\r\\n\\r\\n',\n            content.split(b'\\r\\n\\r\\n', 1)[-1])\n\n    def test_write_payload_chunked_and_deflate(self):\n        write = self.transport.write = unittest.mock.Mock()\n        msg = protocol.Response(self.transport, 200)\n        msg.add_headers(('content-length', '{}'.format(len(self._COMPRESSED))))\n\n        msg.add_chunking_filter(2)\n        msg.add_compression_filter('deflate')\n        msg.send_headers()\n\n        msg.write(b'data')\n        msg.write_eof()\n\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertEqual(\n            self._COMPRESSED, content.split(b'\\r\\n\\r\\n', 1)[-1])\n\n    def test_write_drain(self):\n        msg = protocol.Response(self.transport, 200, http_version=(1, 0))\n        msg._send_headers = True\n\n        msg.write(b'1' * (64 * 1024 * 2))\n        self.assertFalse(self.transport.drain.called)\n\n        msg.write(b'1', drain=True)\n        self.assertTrue(self.transport.drain.called)\n        self.assertEqual(msg._output_size, 0)\n\n    def test_dont_override_request_headers_with_default_values(self):\n        msg = protocol.Request(\n            self.transport, 'GET', '/index.html', close=True)\n        msg.add_header('USER-AGENT', 'custom')\n        msg._add_default_headers()\n        self.assertEqual('custom', msg.headers['USER-AGENT'])\n\n    def test_dont_override_response_headers_with_default_values(self):\n        msg = protocol.Response(self.transport, 200, http_version=(1, 0))\n        msg.add_header('DATE', 'now')\n        msg.add_header('SERVER', 'custom')\n        msg._add_default_headers()\n        self.assertEqual('custom', msg.headers['SERVER'])\n        self.assertEqual('now', msg.headers['DATE'])",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 11,
                            "end_lineno": 497,
                            "parent": null
                        }
                    ],
                    "added_entities": [],
                    "deleted_entities": []
                },
                {
                    "descriptor": {
                        "old_range": {
                            "start": 449,
                            "length": 7
                        },
                        "new_range": {
                            "start": 451,
                            "length": 9
                        },
                        "section": "class TestHttpMessage(unittest.TestCase):"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "        msg.write(b'data')",
                                "type": "context"
                            },
                            {
                                "content": "        msg.write_eof()",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "        content = b''.join([c[1][0] for c in list(write.mock_calls)])",
                                "type": "deleted"
                            },
                            {
                                "content": "        chunks = [c[1][0] for c in list(write.mock_calls)]",
                                "type": "added"
                            },
                            {
                                "content": "        self.assertTrue(all(chunks))",
                                "type": "added"
                            },
                            {
                                "content": "        content = b''.join(chunks)",
                                "type": "added"
                            },
                            {
                                "content": "        self.assertEqual(",
                                "type": "context"
                            },
                            {
                                "content": "            b'2\\r\\nKI\\r\\n2\\r\\n,I\\r\\n2\\r\\n\\x04\\x00\\r\\n0\\r\\n\\r\\n',",
                                "type": "context"
                            },
                            {
                                "content": "            content.split(b'\\r\\n\\r\\n', 1)[-1])",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [
                        {
                            "file_name": "tests/test_http_protocol.py",
                            "type": "method",
                            "name": "TestHttpMessage.test_write_payload_deflate_and_chunked",
                            "content": "class TestHttpMessage(unittest.TestCase):\n\n    def setUp(self):\n        self.transport = unittest.mock.Mock()\n        asyncio.set_event_loop(None)\n\n    def test_start_request(self):\n        msg = protocol.Request(\n            self.transport, 'GET', '/index.html', close=True)\n\n        self.assertIs(msg.transport, self.transport)\n        self.assertIsNone(msg.status)\n        self.assertTrue(msg.closing)\n        self.assertEqual(msg.status_line, 'GET /index.html HTTP/1.1\\r\\n')\n\n    def test_start_response(self):\n        msg = protocol.Response(self.transport, 200, close=True)\n\n        self.assertIs(msg.transport, self.transport)\n        self.assertEqual(msg.status, 200)\n        self.assertEqual(msg.reason, \"OK\")\n        self.assertTrue(msg.closing)\n        self.assertEqual(msg.status_line, 'HTTP/1.1 200 OK\\r\\n')\n\n    def test_start_response_with_reason(self):\n        msg = protocol.Response(self.transport, 333, close=True,\n                                reason=\"My Reason\")\n\n        self.assertEqual(msg.status, 333)\n        self.assertEqual(msg.reason, \"My Reason\")\n        self.assertEqual(msg.status_line, 'HTTP/1.1 333 My Reason\\r\\n')\n\n    def test_start_response_with_unknown_reason(self):\n        msg = protocol.Response(self.transport, 777, close=True)\n\n        self.assertEqual(msg.status, 777)\n        self.assertEqual(msg.reason, \"777\")\n        self.assertEqual(msg.status_line, 'HTTP/1.1 777 777\\r\\n')\n\n    def test_force_close(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertFalse(msg.closing)\n        msg.force_close()\n        self.assertTrue(msg.closing)\n\n    def test_force_chunked(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertFalse(msg.chunked)\n        msg.enable_chunked_encoding()\n        self.assertTrue(msg.chunked)\n\n    def test_keep_alive(self):\n        msg = protocol.Response(self.transport, 200, close=True)\n        self.assertFalse(msg.keep_alive())\n        msg.keepalive = True\n        self.assertTrue(msg.keep_alive())\n\n        msg.force_close()\n        self.assertFalse(msg.keep_alive())\n\n    def test_keep_alive_http10(self):\n        msg = protocol.Response(self.transport, 200, http_version=(1, 0))\n        self.assertFalse(msg.keepalive)\n        self.assertFalse(msg.keep_alive())\n\n        msg = protocol.Response(self.transport, 200, http_version=(1, 1))\n        self.assertIsNone(msg.keepalive)\n\n    def test_add_header(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertEqual([], list(msg.headers))\n\n        msg.add_header('content-type', 'plain/html')\n        self.assertEqual(\n            [('CONTENT-TYPE', 'plain/html')], list(msg.headers.items()))\n\n    def test_add_header_with_spaces(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertEqual([], list(msg.headers))\n\n        msg.add_header('content-type', '  plain/html  ')\n        self.assertEqual(\n            [('CONTENT-TYPE', 'plain/html')], list(msg.headers.items()))\n\n    def test_add_header_non_ascii(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertEqual([], list(msg.headers))\n\n        with self.assertRaises(AssertionError):\n            msg.add_header('тип-контента', 'текст/плейн')\n\n    def test_add_header_invalid_value_type(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertEqual([], list(msg.headers))\n\n        with self.assertRaises(AssertionError):\n            msg.add_header('content-type', {'test': 'plain'})\n\n        with self.assertRaises(AssertionError):\n            msg.add_header(list('content-type'), 'text/plain')\n\n    def test_add_headers(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertEqual([], list(msg.headers))\n\n        msg.add_headers(('content-type', 'plain/html'))\n        self.assertEqual(\n            [('CONTENT-TYPE', 'plain/html')], list(msg.headers.items()))\n\n    def test_add_headers_length(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertIsNone(msg.length)\n\n        msg.add_headers(('content-length', '42'))\n        self.assertEqual(42, msg.length)\n\n    def test_add_headers_upgrade(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertFalse(msg.upgrade)\n\n        msg.add_headers(('connection', 'upgrade'))\n        self.assertTrue(msg.upgrade)\n\n    def test_add_headers_upgrade_websocket(self):\n        msg = protocol.Response(self.transport, 200)\n\n        msg.add_headers(('upgrade', 'test'))\n        self.assertEqual([], list(msg.headers))\n\n        msg.add_headers(('upgrade', 'websocket'))\n        self.assertEqual(\n            [('UPGRADE', 'websocket')], list(msg.headers.items()))\n\n    def test_add_headers_connection_keepalive(self):\n        msg = protocol.Response(self.transport, 200)\n\n        msg.add_headers(('connection', 'keep-alive'))\n        self.assertEqual([], list(msg.headers))\n        self.assertTrue(msg.keepalive)\n\n        msg.add_headers(('connection', 'close'))\n        self.assertFalse(msg.keepalive)\n\n    def test_add_headers_hop_headers(self):\n        msg = protocol.Response(self.transport, 200)\n        msg.HOP_HEADERS = (hdrs.TRANSFER_ENCODING,)\n\n        msg.add_headers(('connection', 'test'), ('transfer-encoding', 't'))\n        self.assertEqual([], list(msg.headers))\n\n    def test_default_headers(self):\n        msg = protocol.Response(self.transport, 200)\n        msg._add_default_headers()\n\n        headers = [r for r, _ in msg.headers.items()]\n        self.assertIn('DATE', headers)\n        self.assertIn('CONNECTION', headers)\n\n    def test_default_headers_server(self):\n        msg = protocol.Response(self.transport, 200)\n        msg._add_default_headers()\n\n        self.assertIn('SERVER', msg.headers)\n\n    def test_default_headers_useragent(self):\n        msg = protocol.Request(self.transport, 'GET', '/')\n        msg._add_default_headers()\n\n        self.assertNotIn('SERVER', msg.headers)\n        self.assertIn('USER-AGENT', msg.headers)\n\n    def test_default_headers_useragent_custom(self):\n        msg = protocol.Request(self.transport, 'GET', '/')\n        msg.add_headers(('user-agent', 'my custom agent'))\n        msg._add_default_headers()\n\n        headers = [r for r, _ in msg.headers.items()\n                   if r.lower() == 'user-agent']\n        self.assertEqual(len(headers), 1)\n\n    def test_default_headers_chunked(self):\n        msg = protocol.Response(self.transport, 200)\n        msg._add_default_headers()\n\n        headers = [r for r, _ in msg.headers.items()]\n        self.assertNotIn('TRANSFER-ENCODING', headers)\n\n        msg = protocol.Response(self.transport, 200)\n        msg.enable_chunked_encoding()\n        msg.send_headers()\n\n        headers = [r for r, _ in msg.headers.items()]\n        self.assertIn('TRANSFER-ENCODING', headers)\n\n    def test_default_headers_connection_upgrade(self):\n        msg = protocol.Response(self.transport, 200)\n        msg.upgrade = True\n        msg._add_default_headers()\n\n        headers = [r for r in msg.headers.items() if r[0] == 'CONNECTION']\n        self.assertEqual([('CONNECTION', 'upgrade')], headers)\n\n    def test_default_headers_connection_close(self):\n        msg = protocol.Response(self.transport, 200)\n        msg.force_close()\n        msg._add_default_headers()\n\n        headers = [r for r in msg.headers.items() if r[0] == 'CONNECTION']\n        self.assertEqual([('CONNECTION', 'close')], headers)\n\n    def test_default_headers_connection_keep_alive(self):\n        msg = protocol.Response(self.transport, 200)\n        msg.keepalive = True\n        msg._add_default_headers()\n\n        headers = [r for r in msg.headers.items() if r[0] == 'CONNECTION']\n        self.assertEqual([('CONNECTION', 'keep-alive')], headers)\n\n    def test_send_headers(self):\n        write = self.transport.write = unittest.mock.Mock()\n\n        msg = protocol.Response(self.transport, 200)\n        msg.add_headers(('content-type', 'plain/html'))\n        self.assertFalse(msg.is_headers_sent())\n\n        msg.send_headers()\n\n        content = b''.join([arg[1][0] for arg in list(write.mock_calls)])\n\n        self.assertTrue(content.startswith(b'HTTP/1.1 200 OK\\r\\n'))\n        self.assertIn(b'CONTENT-TYPE: plain/html', content)\n        self.assertTrue(msg.headers_sent)\n        self.assertTrue(msg.is_headers_sent())\n        # cleanup\n        msg.writer.close()\n\n    def test_send_headers_non_ascii(self):\n        write = self.transport.write = unittest.mock.Mock()\n\n        msg = protocol.Response(self.transport, 200)\n        msg.add_headers(('x-header', 'текст'))\n        self.assertFalse(msg.is_headers_sent())\n\n        msg.send_headers()\n\n        content = b''.join([arg[1][0] for arg in list(write.mock_calls)])\n\n        self.assertTrue(content.startswith(b'HTTP/1.1 200 OK\\r\\n'))\n        self.assertIn(b'X-HEADER: \\xd1\\x82\\xd0\\xb5\\xd0\\xba\\xd1\\x81\\xd1\\x82',\n                      content)\n        self.assertTrue(msg.headers_sent)\n        self.assertTrue(msg.is_headers_sent())\n        # cleanup\n        msg.writer.close()\n\n    def test_send_headers_nomore_add(self):\n        msg = protocol.Response(self.transport, 200)\n        msg.add_headers(('content-type', 'plain/html'))\n        msg.send_headers()\n\n        self.assertRaises(AssertionError,\n                          msg.add_header, 'content-type', 'plain/html')\n        # cleanup\n        msg.writer.close()\n\n    def test_prepare_length(self):\n        msg = protocol.Response(self.transport, 200)\n        w_l_p = msg._write_length_payload = unittest.mock.Mock()\n        w_l_p.return_value = iter([1, 2, 3])\n\n        msg.add_headers(('content-length', '42'))\n        msg.send_headers()\n\n        self.assertTrue(w_l_p.called)\n        self.assertEqual((42,), w_l_p.call_args[0])\n\n    def test_prepare_chunked_force(self):\n        msg = protocol.Response(self.transport, 200)\n        msg.enable_chunked_encoding()\n\n        chunked = msg._write_chunked_payload = unittest.mock.Mock()\n        chunked.return_value = iter([1, 2, 3])\n\n        msg.add_headers(('content-length', '42'))\n        msg.send_headers()\n        self.assertTrue(chunked.called)\n\n    def test_prepare_chunked_no_length(self):\n        msg = protocol.Response(self.transport, 200)\n\n        chunked = msg._write_chunked_payload = unittest.mock.Mock()\n        chunked.return_value = iter([1, 2, 3])\n\n        msg.send_headers()\n        self.assertTrue(chunked.called)\n\n    def test_prepare_eof(self):\n        msg = protocol.Response(self.transport, 200, http_version=(1, 0))\n\n        eof = msg._write_eof_payload = unittest.mock.Mock()\n        eof.return_value = iter([1, 2, 3])\n\n        msg.send_headers()\n        self.assertTrue(eof.called)\n\n    def test_write_auto_send_headers(self):\n        msg = protocol.Response(self.transport, 200, http_version=(1, 0))\n        msg._send_headers = True\n\n        msg.write(b'data1')\n        self.assertTrue(msg.headers_sent)\n        # cleanup\n        msg.writer.close()\n\n    def test_write_payload_eof(self):\n        write = self.transport.write = unittest.mock.Mock()\n        msg = protocol.Response(self.transport, 200, http_version=(1, 0))\n        msg.send_headers()\n\n        msg.write(b'data1')\n        self.assertTrue(msg.headers_sent)\n\n        msg.write(b'data2')\n        msg.write_eof()\n\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertEqual(\n            b'data1data2', content.split(b'\\r\\n\\r\\n', 1)[-1])\n\n    def test_write_payload_chunked(self):\n        write = self.transport.write = unittest.mock.Mock()\n\n        msg = protocol.Response(self.transport, 200)\n        msg.enable_chunked_encoding()\n        msg.send_headers()\n\n        msg.write(b'data')\n        msg.write_eof()\n\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertEqual(\n            b'4\\r\\ndata\\r\\n0\\r\\n\\r\\n',\n            content.split(b'\\r\\n\\r\\n', 1)[-1])\n\n    def test_write_payload_chunked_multiple(self):\n        write = self.transport.write = unittest.mock.Mock()\n\n        msg = protocol.Response(self.transport, 200)\n        msg.enable_chunked_encoding()\n        msg.send_headers()\n\n        msg.write(b'data1')\n        msg.write(b'data2')\n        msg.write_eof()\n\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertEqual(\n            b'5\\r\\ndata1\\r\\n5\\r\\ndata2\\r\\n0\\r\\n\\r\\n',\n            content.split(b'\\r\\n\\r\\n', 1)[-1])\n\n    def test_write_payload_length(self):\n        write = self.transport.write = unittest.mock.Mock()\n\n        msg = protocol.Response(self.transport, 200)\n        msg.add_headers(('content-length', '2'))\n        msg.send_headers()\n\n        msg.write(b'd')\n        msg.write(b'ata')\n        msg.write_eof()\n\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertEqual(\n            b'da', content.split(b'\\r\\n\\r\\n', 1)[-1])\n\n    def test_write_payload_chunked_filter(self):\n        write = self.transport.write = unittest.mock.Mock()\n\n        msg = protocol.Response(self.transport, 200)\n        msg.send_headers()\n\n        msg.add_chunking_filter(2)\n        msg.write(b'data')\n        msg.write_eof()\n\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertTrue(content.endswith(b'2\\r\\nda\\r\\n2\\r\\nta\\r\\n0\\r\\n\\r\\n'))\n\n    def test_write_payload_chunked_filter_mutiple_chunks(self):\n        write = self.transport.write = unittest.mock.Mock()\n        msg = protocol.Response(self.transport, 200)\n        msg.send_headers()\n\n        msg.add_chunking_filter(2)\n        msg.write(b'data1')\n        msg.write(b'data2')\n        msg.write_eof()\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertTrue(content.endswith(\n            b'2\\r\\nda\\r\\n2\\r\\nta\\r\\n2\\r\\n1d\\r\\n2\\r\\nat\\r\\n'\n            b'2\\r\\na2\\r\\n0\\r\\n\\r\\n'))\n\n    def test_write_payload_chunked_large_chunk(self):\n        write = self.transport.write = unittest.mock.Mock()\n        msg = protocol.Response(self.transport, 200)\n        msg.send_headers()\n\n        msg.add_chunking_filter(1024)\n        msg.write(b'data')\n        msg.write_eof()\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertTrue(content.endswith(b'4\\r\\ndata\\r\\n0\\r\\n\\r\\n'))\n\n    _comp = zlib.compressobj(wbits=-zlib.MAX_WBITS)\n    _COMPRESSED = b''.join([_comp.compress(b'data'), _comp.flush()])\n\n    def test_write_payload_deflate_filter(self):\n        write = self.transport.write = unittest.mock.Mock()\n        msg = protocol.Response(self.transport, 200)\n        msg.add_headers(('content-length', '{}'.format(len(self._COMPRESSED))))\n        msg.send_headers()\n\n        msg.add_compression_filter('deflate')\n        msg.write(b'data')\n        msg.write_eof()\n\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertEqual(\n            self._COMPRESSED, content.split(b'\\r\\n\\r\\n', 1)[-1])\n\n    def test_write_payload_deflate_and_chunked(self):\n        write = self.transport.write = unittest.mock.Mock()\n        msg = protocol.Response(self.transport, 200)\n        msg.send_headers()\n\n        msg.add_compression_filter('deflate')\n        msg.add_chunking_filter(2)\n\n        msg.write(b'data')\n        msg.write_eof()\n\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertEqual(\n            b'2\\r\\nKI\\r\\n2\\r\\n,I\\r\\n2\\r\\n\\x04\\x00\\r\\n0\\r\\n\\r\\n',\n            content.split(b'\\r\\n\\r\\n', 1)[-1])\n\n    def test_write_payload_chunked_and_deflate(self):\n        write = self.transport.write = unittest.mock.Mock()\n        msg = protocol.Response(self.transport, 200)\n        msg.add_headers(('content-length', '{}'.format(len(self._COMPRESSED))))\n\n        msg.add_chunking_filter(2)\n        msg.add_compression_filter('deflate')\n        msg.send_headers()\n\n        msg.write(b'data')\n        msg.write_eof()\n\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertEqual(\n            self._COMPRESSED, content.split(b'\\r\\n\\r\\n', 1)[-1])\n\n    def test_write_drain(self):\n        msg = protocol.Response(self.transport, 200, http_version=(1, 0))\n        msg._send_headers = True\n\n        msg.write(b'1' * (64 * 1024 * 2))\n        self.assertFalse(self.transport.drain.called)\n\n        msg.write(b'1', drain=True)\n        self.assertTrue(self.transport.drain.called)\n        self.assertEqual(msg._output_size, 0)\n\n    def test_dont_override_request_headers_with_default_values(self):\n        msg = protocol.Request(\n            self.transport, 'GET', '/index.html', close=True)\n        msg.add_header('USER-AGENT', 'custom')\n        msg._add_default_headers()\n        self.assertEqual('custom', msg.headers['USER-AGENT'])\n\n    def test_dont_override_response_headers_with_default_values(self):\n        msg = protocol.Response(self.transport, 200, http_version=(1, 0))\n        msg.add_header('DATE', 'now')\n        msg.add_header('SERVER', 'custom')\n        msg._add_default_headers()\n        self.assertEqual('custom', msg.headers['SERVER'])\n        self.assertEqual('now', msg.headers['DATE'])",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 441,
                            "end_lineno": 455,
                            "parent": {
                                "file_name": "tests/test_http_protocol.py",
                                "type": "class",
                                "name": "TestHttpMessage",
                                "content": "class TestHttpMessage(unittest.TestCase):\n\n    def setUp(self):\n        self.transport = unittest.mock.Mock()\n        asyncio.set_event_loop(None)\n\n    def test_start_request(self):\n        msg = protocol.Request(\n            self.transport, 'GET', '/index.html', close=True)\n\n        self.assertIs(msg.transport, self.transport)\n        self.assertIsNone(msg.status)\n        self.assertTrue(msg.closing)\n        self.assertEqual(msg.status_line, 'GET /index.html HTTP/1.1\\r\\n')\n\n    def test_start_response(self):\n        msg = protocol.Response(self.transport, 200, close=True)\n\n        self.assertIs(msg.transport, self.transport)\n        self.assertEqual(msg.status, 200)\n        self.assertEqual(msg.reason, \"OK\")\n        self.assertTrue(msg.closing)\n        self.assertEqual(msg.status_line, 'HTTP/1.1 200 OK\\r\\n')\n\n    def test_start_response_with_reason(self):\n        msg = protocol.Response(self.transport, 333, close=True,\n                                reason=\"My Reason\")\n\n        self.assertEqual(msg.status, 333)\n        self.assertEqual(msg.reason, \"My Reason\")\n        self.assertEqual(msg.status_line, 'HTTP/1.1 333 My Reason\\r\\n')\n\n    def test_start_response_with_unknown_reason(self):\n        msg = protocol.Response(self.transport, 777, close=True)\n\n        self.assertEqual(msg.status, 777)\n        self.assertEqual(msg.reason, \"777\")\n        self.assertEqual(msg.status_line, 'HTTP/1.1 777 777\\r\\n')\n\n    def test_force_close(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertFalse(msg.closing)\n        msg.force_close()\n        self.assertTrue(msg.closing)\n\n    def test_force_chunked(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertFalse(msg.chunked)\n        msg.enable_chunked_encoding()\n        self.assertTrue(msg.chunked)\n\n    def test_keep_alive(self):\n        msg = protocol.Response(self.transport, 200, close=True)\n        self.assertFalse(msg.keep_alive())\n        msg.keepalive = True\n        self.assertTrue(msg.keep_alive())\n\n        msg.force_close()\n        self.assertFalse(msg.keep_alive())\n\n    def test_keep_alive_http10(self):\n        msg = protocol.Response(self.transport, 200, http_version=(1, 0))\n        self.assertFalse(msg.keepalive)\n        self.assertFalse(msg.keep_alive())\n\n        msg = protocol.Response(self.transport, 200, http_version=(1, 1))\n        self.assertIsNone(msg.keepalive)\n\n    def test_add_header(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertEqual([], list(msg.headers))\n\n        msg.add_header('content-type', 'plain/html')\n        self.assertEqual(\n            [('CONTENT-TYPE', 'plain/html')], list(msg.headers.items()))\n\n    def test_add_header_with_spaces(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertEqual([], list(msg.headers))\n\n        msg.add_header('content-type', '  plain/html  ')\n        self.assertEqual(\n            [('CONTENT-TYPE', 'plain/html')], list(msg.headers.items()))\n\n    def test_add_header_non_ascii(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertEqual([], list(msg.headers))\n\n        with self.assertRaises(AssertionError):\n            msg.add_header('тип-контента', 'текст/плейн')\n\n    def test_add_header_invalid_value_type(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertEqual([], list(msg.headers))\n\n        with self.assertRaises(AssertionError):\n            msg.add_header('content-type', {'test': 'plain'})\n\n        with self.assertRaises(AssertionError):\n            msg.add_header(list('content-type'), 'text/plain')\n\n    def test_add_headers(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertEqual([], list(msg.headers))\n\n        msg.add_headers(('content-type', 'plain/html'))\n        self.assertEqual(\n            [('CONTENT-TYPE', 'plain/html')], list(msg.headers.items()))\n\n    def test_add_headers_length(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertIsNone(msg.length)\n\n        msg.add_headers(('content-length', '42'))\n        self.assertEqual(42, msg.length)\n\n    def test_add_headers_upgrade(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertFalse(msg.upgrade)\n\n        msg.add_headers(('connection', 'upgrade'))\n        self.assertTrue(msg.upgrade)\n\n    def test_add_headers_upgrade_websocket(self):\n        msg = protocol.Response(self.transport, 200)\n\n        msg.add_headers(('upgrade', 'test'))\n        self.assertEqual([], list(msg.headers))\n\n        msg.add_headers(('upgrade', 'websocket'))\n        self.assertEqual(\n            [('UPGRADE', 'websocket')], list(msg.headers.items()))\n\n    def test_add_headers_connection_keepalive(self):\n        msg = protocol.Response(self.transport, 200)\n\n        msg.add_headers(('connection', 'keep-alive'))\n        self.assertEqual([], list(msg.headers))\n        self.assertTrue(msg.keepalive)\n\n        msg.add_headers(('connection', 'close'))\n        self.assertFalse(msg.keepalive)\n\n    def test_add_headers_hop_headers(self):\n        msg = protocol.Response(self.transport, 200)\n        msg.HOP_HEADERS = (hdrs.TRANSFER_ENCODING,)\n\n        msg.add_headers(('connection', 'test'), ('transfer-encoding', 't'))\n        self.assertEqual([], list(msg.headers))\n\n    def test_default_headers(self):\n        msg = protocol.Response(self.transport, 200)\n        msg._add_default_headers()\n\n        headers = [r for r, _ in msg.headers.items()]\n        self.assertIn('DATE', headers)\n        self.assertIn('CONNECTION', headers)\n\n    def test_default_headers_server(self):\n        msg = protocol.Response(self.transport, 200)\n        msg._add_default_headers()\n\n        self.assertIn('SERVER', msg.headers)\n\n    def test_default_headers_useragent(self):\n        msg = protocol.Request(self.transport, 'GET', '/')\n        msg._add_default_headers()\n\n        self.assertNotIn('SERVER', msg.headers)\n        self.assertIn('USER-AGENT', msg.headers)\n\n    def test_default_headers_useragent_custom(self):\n        msg = protocol.Request(self.transport, 'GET', '/')\n        msg.add_headers(('user-agent', 'my custom agent'))\n        msg._add_default_headers()\n\n        headers = [r for r, _ in msg.headers.items()\n                   if r.lower() == 'user-agent']\n        self.assertEqual(len(headers), 1)\n\n    def test_default_headers_chunked(self):\n        msg = protocol.Response(self.transport, 200)\n        msg._add_default_headers()\n\n        headers = [r for r, _ in msg.headers.items()]\n        self.assertNotIn('TRANSFER-ENCODING', headers)\n\n        msg = protocol.Response(self.transport, 200)\n        msg.enable_chunked_encoding()\n        msg.send_headers()\n\n        headers = [r for r, _ in msg.headers.items()]\n        self.assertIn('TRANSFER-ENCODING', headers)\n\n    def test_default_headers_connection_upgrade(self):\n        msg = protocol.Response(self.transport, 200)\n        msg.upgrade = True\n        msg._add_default_headers()\n\n        headers = [r for r in msg.headers.items() if r[0] == 'CONNECTION']\n        self.assertEqual([('CONNECTION', 'upgrade')], headers)\n\n    def test_default_headers_connection_close(self):\n        msg = protocol.Response(self.transport, 200)\n        msg.force_close()\n        msg._add_default_headers()\n\n        headers = [r for r in msg.headers.items() if r[0] == 'CONNECTION']\n        self.assertEqual([('CONNECTION', 'close')], headers)\n\n    def test_default_headers_connection_keep_alive(self):\n        msg = protocol.Response(self.transport, 200)\n        msg.keepalive = True\n        msg._add_default_headers()\n\n        headers = [r for r in msg.headers.items() if r[0] == 'CONNECTION']\n        self.assertEqual([('CONNECTION', 'keep-alive')], headers)\n\n    def test_send_headers(self):\n        write = self.transport.write = unittest.mock.Mock()\n\n        msg = protocol.Response(self.transport, 200)\n        msg.add_headers(('content-type', 'plain/html'))\n        self.assertFalse(msg.is_headers_sent())\n\n        msg.send_headers()\n\n        content = b''.join([arg[1][0] for arg in list(write.mock_calls)])\n\n        self.assertTrue(content.startswith(b'HTTP/1.1 200 OK\\r\\n'))\n        self.assertIn(b'CONTENT-TYPE: plain/html', content)\n        self.assertTrue(msg.headers_sent)\n        self.assertTrue(msg.is_headers_sent())\n        # cleanup\n        msg.writer.close()\n\n    def test_send_headers_non_ascii(self):\n        write = self.transport.write = unittest.mock.Mock()\n\n        msg = protocol.Response(self.transport, 200)\n        msg.add_headers(('x-header', 'текст'))\n        self.assertFalse(msg.is_headers_sent())\n\n        msg.send_headers()\n\n        content = b''.join([arg[1][0] for arg in list(write.mock_calls)])\n\n        self.assertTrue(content.startswith(b'HTTP/1.1 200 OK\\r\\n'))\n        self.assertIn(b'X-HEADER: \\xd1\\x82\\xd0\\xb5\\xd0\\xba\\xd1\\x81\\xd1\\x82',\n                      content)\n        self.assertTrue(msg.headers_sent)\n        self.assertTrue(msg.is_headers_sent())\n        # cleanup\n        msg.writer.close()\n\n    def test_send_headers_nomore_add(self):\n        msg = protocol.Response(self.transport, 200)\n        msg.add_headers(('content-type', 'plain/html'))\n        msg.send_headers()\n\n        self.assertRaises(AssertionError,\n                          msg.add_header, 'content-type', 'plain/html')\n        # cleanup\n        msg.writer.close()\n\n    def test_prepare_length(self):\n        msg = protocol.Response(self.transport, 200)\n        w_l_p = msg._write_length_payload = unittest.mock.Mock()\n        w_l_p.return_value = iter([1, 2, 3])\n\n        msg.add_headers(('content-length', '42'))\n        msg.send_headers()\n\n        self.assertTrue(w_l_p.called)\n        self.assertEqual((42,), w_l_p.call_args[0])\n\n    def test_prepare_chunked_force(self):\n        msg = protocol.Response(self.transport, 200)\n        msg.enable_chunked_encoding()\n\n        chunked = msg._write_chunked_payload = unittest.mock.Mock()\n        chunked.return_value = iter([1, 2, 3])\n\n        msg.add_headers(('content-length', '42'))\n        msg.send_headers()\n        self.assertTrue(chunked.called)\n\n    def test_prepare_chunked_no_length(self):\n        msg = protocol.Response(self.transport, 200)\n\n        chunked = msg._write_chunked_payload = unittest.mock.Mock()\n        chunked.return_value = iter([1, 2, 3])\n\n        msg.send_headers()\n        self.assertTrue(chunked.called)\n\n    def test_prepare_eof(self):\n        msg = protocol.Response(self.transport, 200, http_version=(1, 0))\n\n        eof = msg._write_eof_payload = unittest.mock.Mock()\n        eof.return_value = iter([1, 2, 3])\n\n        msg.send_headers()\n        self.assertTrue(eof.called)\n\n    def test_write_auto_send_headers(self):\n        msg = protocol.Response(self.transport, 200, http_version=(1, 0))\n        msg._send_headers = True\n\n        msg.write(b'data1')\n        self.assertTrue(msg.headers_sent)\n        # cleanup\n        msg.writer.close()\n\n    def test_write_payload_eof(self):\n        write = self.transport.write = unittest.mock.Mock()\n        msg = protocol.Response(self.transport, 200, http_version=(1, 0))\n        msg.send_headers()\n\n        msg.write(b'data1')\n        self.assertTrue(msg.headers_sent)\n\n        msg.write(b'data2')\n        msg.write_eof()\n\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertEqual(\n            b'data1data2', content.split(b'\\r\\n\\r\\n', 1)[-1])\n\n    def test_write_payload_chunked(self):\n        write = self.transport.write = unittest.mock.Mock()\n\n        msg = protocol.Response(self.transport, 200)\n        msg.enable_chunked_encoding()\n        msg.send_headers()\n\n        msg.write(b'data')\n        msg.write_eof()\n\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertEqual(\n            b'4\\r\\ndata\\r\\n0\\r\\n\\r\\n',\n            content.split(b'\\r\\n\\r\\n', 1)[-1])\n\n    def test_write_payload_chunked_multiple(self):\n        write = self.transport.write = unittest.mock.Mock()\n\n        msg = protocol.Response(self.transport, 200)\n        msg.enable_chunked_encoding()\n        msg.send_headers()\n\n        msg.write(b'data1')\n        msg.write(b'data2')\n        msg.write_eof()\n\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertEqual(\n            b'5\\r\\ndata1\\r\\n5\\r\\ndata2\\r\\n0\\r\\n\\r\\n',\n            content.split(b'\\r\\n\\r\\n', 1)[-1])\n\n    def test_write_payload_length(self):\n        write = self.transport.write = unittest.mock.Mock()\n\n        msg = protocol.Response(self.transport, 200)\n        msg.add_headers(('content-length', '2'))\n        msg.send_headers()\n\n        msg.write(b'd')\n        msg.write(b'ata')\n        msg.write_eof()\n\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertEqual(\n            b'da', content.split(b'\\r\\n\\r\\n', 1)[-1])\n\n    def test_write_payload_chunked_filter(self):\n        write = self.transport.write = unittest.mock.Mock()\n\n        msg = protocol.Response(self.transport, 200)\n        msg.send_headers()\n\n        msg.add_chunking_filter(2)\n        msg.write(b'data')\n        msg.write_eof()\n\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertTrue(content.endswith(b'2\\r\\nda\\r\\n2\\r\\nta\\r\\n0\\r\\n\\r\\n'))\n\n    def test_write_payload_chunked_filter_mutiple_chunks(self):\n        write = self.transport.write = unittest.mock.Mock()\n        msg = protocol.Response(self.transport, 200)\n        msg.send_headers()\n\n        msg.add_chunking_filter(2)\n        msg.write(b'data1')\n        msg.write(b'data2')\n        msg.write_eof()\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertTrue(content.endswith(\n            b'2\\r\\nda\\r\\n2\\r\\nta\\r\\n2\\r\\n1d\\r\\n2\\r\\nat\\r\\n'\n            b'2\\r\\na2\\r\\n0\\r\\n\\r\\n'))\n\n    def test_write_payload_chunked_large_chunk(self):\n        write = self.transport.write = unittest.mock.Mock()\n        msg = protocol.Response(self.transport, 200)\n        msg.send_headers()\n\n        msg.add_chunking_filter(1024)\n        msg.write(b'data')\n        msg.write_eof()\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertTrue(content.endswith(b'4\\r\\ndata\\r\\n0\\r\\n\\r\\n'))\n\n    _comp = zlib.compressobj(wbits=-zlib.MAX_WBITS)\n    _COMPRESSED = b''.join([_comp.compress(b'data'), _comp.flush()])\n\n    def test_write_payload_deflate_filter(self):\n        write = self.transport.write = unittest.mock.Mock()\n        msg = protocol.Response(self.transport, 200)\n        msg.add_headers(('content-length', '{}'.format(len(self._COMPRESSED))))\n        msg.send_headers()\n\n        msg.add_compression_filter('deflate')\n        msg.write(b'data')\n        msg.write_eof()\n\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertEqual(\n            self._COMPRESSED, content.split(b'\\r\\n\\r\\n', 1)[-1])\n\n    def test_write_payload_deflate_and_chunked(self):\n        write = self.transport.write = unittest.mock.Mock()\n        msg = protocol.Response(self.transport, 200)\n        msg.send_headers()\n\n        msg.add_compression_filter('deflate')\n        msg.add_chunking_filter(2)\n\n        msg.write(b'data')\n        msg.write_eof()\n\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertEqual(\n            b'2\\r\\nKI\\r\\n2\\r\\n,I\\r\\n2\\r\\n\\x04\\x00\\r\\n0\\r\\n\\r\\n',\n            content.split(b'\\r\\n\\r\\n', 1)[-1])\n\n    def test_write_payload_chunked_and_deflate(self):\n        write = self.transport.write = unittest.mock.Mock()\n        msg = protocol.Response(self.transport, 200)\n        msg.add_headers(('content-length', '{}'.format(len(self._COMPRESSED))))\n\n        msg.add_chunking_filter(2)\n        msg.add_compression_filter('deflate')\n        msg.send_headers()\n\n        msg.write(b'data')\n        msg.write_eof()\n\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertEqual(\n            self._COMPRESSED, content.split(b'\\r\\n\\r\\n', 1)[-1])\n\n    def test_write_drain(self):\n        msg = protocol.Response(self.transport, 200, http_version=(1, 0))\n        msg._send_headers = True\n\n        msg.write(b'1' * (64 * 1024 * 2))\n        self.assertFalse(self.transport.drain.called)\n\n        msg.write(b'1', drain=True)\n        self.assertTrue(self.transport.drain.called)\n        self.assertEqual(msg._output_size, 0)\n\n    def test_dont_override_request_headers_with_default_values(self):\n        msg = protocol.Request(\n            self.transport, 'GET', '/index.html', close=True)\n        msg.add_header('USER-AGENT', 'custom')\n        msg._add_default_headers()\n        self.assertEqual('custom', msg.headers['USER-AGENT'])\n\n    def test_dont_override_response_headers_with_default_values(self):\n        msg = protocol.Response(self.transport, 200, http_version=(1, 0))\n        msg.add_header('DATE', 'now')\n        msg.add_header('SERVER', 'custom')\n        msg._add_default_headers()\n        self.assertEqual('custom', msg.headers['SERVER'])\n        self.assertEqual('now', msg.headers['DATE'])",
                                "ast_type_str": "ClassDef",
                                "start_lineno": 11,
                                "end_lineno": 497,
                                "parent": null
                            }
                        },
                        {
                            "file_name": "tests/test_http_protocol.py",
                            "type": "class",
                            "name": "TestHttpMessage",
                            "content": "class TestHttpMessage(unittest.TestCase):\n\n    def setUp(self):\n        self.transport = unittest.mock.Mock()\n        asyncio.set_event_loop(None)\n\n    def test_start_request(self):\n        msg = protocol.Request(\n            self.transport, 'GET', '/index.html', close=True)\n\n        self.assertIs(msg.transport, self.transport)\n        self.assertIsNone(msg.status)\n        self.assertTrue(msg.closing)\n        self.assertEqual(msg.status_line, 'GET /index.html HTTP/1.1\\r\\n')\n\n    def test_start_response(self):\n        msg = protocol.Response(self.transport, 200, close=True)\n\n        self.assertIs(msg.transport, self.transport)\n        self.assertEqual(msg.status, 200)\n        self.assertEqual(msg.reason, \"OK\")\n        self.assertTrue(msg.closing)\n        self.assertEqual(msg.status_line, 'HTTP/1.1 200 OK\\r\\n')\n\n    def test_start_response_with_reason(self):\n        msg = protocol.Response(self.transport, 333, close=True,\n                                reason=\"My Reason\")\n\n        self.assertEqual(msg.status, 333)\n        self.assertEqual(msg.reason, \"My Reason\")\n        self.assertEqual(msg.status_line, 'HTTP/1.1 333 My Reason\\r\\n')\n\n    def test_start_response_with_unknown_reason(self):\n        msg = protocol.Response(self.transport, 777, close=True)\n\n        self.assertEqual(msg.status, 777)\n        self.assertEqual(msg.reason, \"777\")\n        self.assertEqual(msg.status_line, 'HTTP/1.1 777 777\\r\\n')\n\n    def test_force_close(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertFalse(msg.closing)\n        msg.force_close()\n        self.assertTrue(msg.closing)\n\n    def test_force_chunked(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertFalse(msg.chunked)\n        msg.enable_chunked_encoding()\n        self.assertTrue(msg.chunked)\n\n    def test_keep_alive(self):\n        msg = protocol.Response(self.transport, 200, close=True)\n        self.assertFalse(msg.keep_alive())\n        msg.keepalive = True\n        self.assertTrue(msg.keep_alive())\n\n        msg.force_close()\n        self.assertFalse(msg.keep_alive())\n\n    def test_keep_alive_http10(self):\n        msg = protocol.Response(self.transport, 200, http_version=(1, 0))\n        self.assertFalse(msg.keepalive)\n        self.assertFalse(msg.keep_alive())\n\n        msg = protocol.Response(self.transport, 200, http_version=(1, 1))\n        self.assertIsNone(msg.keepalive)\n\n    def test_add_header(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertEqual([], list(msg.headers))\n\n        msg.add_header('content-type', 'plain/html')\n        self.assertEqual(\n            [('CONTENT-TYPE', 'plain/html')], list(msg.headers.items()))\n\n    def test_add_header_with_spaces(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertEqual([], list(msg.headers))\n\n        msg.add_header('content-type', '  plain/html  ')\n        self.assertEqual(\n            [('CONTENT-TYPE', 'plain/html')], list(msg.headers.items()))\n\n    def test_add_header_non_ascii(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertEqual([], list(msg.headers))\n\n        with self.assertRaises(AssertionError):\n            msg.add_header('тип-контента', 'текст/плейн')\n\n    def test_add_header_invalid_value_type(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertEqual([], list(msg.headers))\n\n        with self.assertRaises(AssertionError):\n            msg.add_header('content-type', {'test': 'plain'})\n\n        with self.assertRaises(AssertionError):\n            msg.add_header(list('content-type'), 'text/plain')\n\n    def test_add_headers(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertEqual([], list(msg.headers))\n\n        msg.add_headers(('content-type', 'plain/html'))\n        self.assertEqual(\n            [('CONTENT-TYPE', 'plain/html')], list(msg.headers.items()))\n\n    def test_add_headers_length(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertIsNone(msg.length)\n\n        msg.add_headers(('content-length', '42'))\n        self.assertEqual(42, msg.length)\n\n    def test_add_headers_upgrade(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertFalse(msg.upgrade)\n\n        msg.add_headers(('connection', 'upgrade'))\n        self.assertTrue(msg.upgrade)\n\n    def test_add_headers_upgrade_websocket(self):\n        msg = protocol.Response(self.transport, 200)\n\n        msg.add_headers(('upgrade', 'test'))\n        self.assertEqual([], list(msg.headers))\n\n        msg.add_headers(('upgrade', 'websocket'))\n        self.assertEqual(\n            [('UPGRADE', 'websocket')], list(msg.headers.items()))\n\n    def test_add_headers_connection_keepalive(self):\n        msg = protocol.Response(self.transport, 200)\n\n        msg.add_headers(('connection', 'keep-alive'))\n        self.assertEqual([], list(msg.headers))\n        self.assertTrue(msg.keepalive)\n\n        msg.add_headers(('connection', 'close'))\n        self.assertFalse(msg.keepalive)\n\n    def test_add_headers_hop_headers(self):\n        msg = protocol.Response(self.transport, 200)\n        msg.HOP_HEADERS = (hdrs.TRANSFER_ENCODING,)\n\n        msg.add_headers(('connection', 'test'), ('transfer-encoding', 't'))\n        self.assertEqual([], list(msg.headers))\n\n    def test_default_headers(self):\n        msg = protocol.Response(self.transport, 200)\n        msg._add_default_headers()\n\n        headers = [r for r, _ in msg.headers.items()]\n        self.assertIn('DATE', headers)\n        self.assertIn('CONNECTION', headers)\n\n    def test_default_headers_server(self):\n        msg = protocol.Response(self.transport, 200)\n        msg._add_default_headers()\n\n        self.assertIn('SERVER', msg.headers)\n\n    def test_default_headers_useragent(self):\n        msg = protocol.Request(self.transport, 'GET', '/')\n        msg._add_default_headers()\n\n        self.assertNotIn('SERVER', msg.headers)\n        self.assertIn('USER-AGENT', msg.headers)\n\n    def test_default_headers_useragent_custom(self):\n        msg = protocol.Request(self.transport, 'GET', '/')\n        msg.add_headers(('user-agent', 'my custom agent'))\n        msg._add_default_headers()\n\n        headers = [r for r, _ in msg.headers.items()\n                   if r.lower() == 'user-agent']\n        self.assertEqual(len(headers), 1)\n\n    def test_default_headers_chunked(self):\n        msg = protocol.Response(self.transport, 200)\n        msg._add_default_headers()\n\n        headers = [r for r, _ in msg.headers.items()]\n        self.assertNotIn('TRANSFER-ENCODING', headers)\n\n        msg = protocol.Response(self.transport, 200)\n        msg.enable_chunked_encoding()\n        msg.send_headers()\n\n        headers = [r for r, _ in msg.headers.items()]\n        self.assertIn('TRANSFER-ENCODING', headers)\n\n    def test_default_headers_connection_upgrade(self):\n        msg = protocol.Response(self.transport, 200)\n        msg.upgrade = True\n        msg._add_default_headers()\n\n        headers = [r for r in msg.headers.items() if r[0] == 'CONNECTION']\n        self.assertEqual([('CONNECTION', 'upgrade')], headers)\n\n    def test_default_headers_connection_close(self):\n        msg = protocol.Response(self.transport, 200)\n        msg.force_close()\n        msg._add_default_headers()\n\n        headers = [r for r in msg.headers.items() if r[0] == 'CONNECTION']\n        self.assertEqual([('CONNECTION', 'close')], headers)\n\n    def test_default_headers_connection_keep_alive(self):\n        msg = protocol.Response(self.transport, 200)\n        msg.keepalive = True\n        msg._add_default_headers()\n\n        headers = [r for r in msg.headers.items() if r[0] == 'CONNECTION']\n        self.assertEqual([('CONNECTION', 'keep-alive')], headers)\n\n    def test_send_headers(self):\n        write = self.transport.write = unittest.mock.Mock()\n\n        msg = protocol.Response(self.transport, 200)\n        msg.add_headers(('content-type', 'plain/html'))\n        self.assertFalse(msg.is_headers_sent())\n\n        msg.send_headers()\n\n        content = b''.join([arg[1][0] for arg in list(write.mock_calls)])\n\n        self.assertTrue(content.startswith(b'HTTP/1.1 200 OK\\r\\n'))\n        self.assertIn(b'CONTENT-TYPE: plain/html', content)\n        self.assertTrue(msg.headers_sent)\n        self.assertTrue(msg.is_headers_sent())\n        # cleanup\n        msg.writer.close()\n\n    def test_send_headers_non_ascii(self):\n        write = self.transport.write = unittest.mock.Mock()\n\n        msg = protocol.Response(self.transport, 200)\n        msg.add_headers(('x-header', 'текст'))\n        self.assertFalse(msg.is_headers_sent())\n\n        msg.send_headers()\n\n        content = b''.join([arg[1][0] for arg in list(write.mock_calls)])\n\n        self.assertTrue(content.startswith(b'HTTP/1.1 200 OK\\r\\n'))\n        self.assertIn(b'X-HEADER: \\xd1\\x82\\xd0\\xb5\\xd0\\xba\\xd1\\x81\\xd1\\x82',\n                      content)\n        self.assertTrue(msg.headers_sent)\n        self.assertTrue(msg.is_headers_sent())\n        # cleanup\n        msg.writer.close()\n\n    def test_send_headers_nomore_add(self):\n        msg = protocol.Response(self.transport, 200)\n        msg.add_headers(('content-type', 'plain/html'))\n        msg.send_headers()\n\n        self.assertRaises(AssertionError,\n                          msg.add_header, 'content-type', 'plain/html')\n        # cleanup\n        msg.writer.close()\n\n    def test_prepare_length(self):\n        msg = protocol.Response(self.transport, 200)\n        w_l_p = msg._write_length_payload = unittest.mock.Mock()\n        w_l_p.return_value = iter([1, 2, 3])\n\n        msg.add_headers(('content-length', '42'))\n        msg.send_headers()\n\n        self.assertTrue(w_l_p.called)\n        self.assertEqual((42,), w_l_p.call_args[0])\n\n    def test_prepare_chunked_force(self):\n        msg = protocol.Response(self.transport, 200)\n        msg.enable_chunked_encoding()\n\n        chunked = msg._write_chunked_payload = unittest.mock.Mock()\n        chunked.return_value = iter([1, 2, 3])\n\n        msg.add_headers(('content-length', '42'))\n        msg.send_headers()\n        self.assertTrue(chunked.called)\n\n    def test_prepare_chunked_no_length(self):\n        msg = protocol.Response(self.transport, 200)\n\n        chunked = msg._write_chunked_payload = unittest.mock.Mock()\n        chunked.return_value = iter([1, 2, 3])\n\n        msg.send_headers()\n        self.assertTrue(chunked.called)\n\n    def test_prepare_eof(self):\n        msg = protocol.Response(self.transport, 200, http_version=(1, 0))\n\n        eof = msg._write_eof_payload = unittest.mock.Mock()\n        eof.return_value = iter([1, 2, 3])\n\n        msg.send_headers()\n        self.assertTrue(eof.called)\n\n    def test_write_auto_send_headers(self):\n        msg = protocol.Response(self.transport, 200, http_version=(1, 0))\n        msg._send_headers = True\n\n        msg.write(b'data1')\n        self.assertTrue(msg.headers_sent)\n        # cleanup\n        msg.writer.close()\n\n    def test_write_payload_eof(self):\n        write = self.transport.write = unittest.mock.Mock()\n        msg = protocol.Response(self.transport, 200, http_version=(1, 0))\n        msg.send_headers()\n\n        msg.write(b'data1')\n        self.assertTrue(msg.headers_sent)\n\n        msg.write(b'data2')\n        msg.write_eof()\n\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertEqual(\n            b'data1data2', content.split(b'\\r\\n\\r\\n', 1)[-1])\n\n    def test_write_payload_chunked(self):\n        write = self.transport.write = unittest.mock.Mock()\n\n        msg = protocol.Response(self.transport, 200)\n        msg.enable_chunked_encoding()\n        msg.send_headers()\n\n        msg.write(b'data')\n        msg.write_eof()\n\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertEqual(\n            b'4\\r\\ndata\\r\\n0\\r\\n\\r\\n',\n            content.split(b'\\r\\n\\r\\n', 1)[-1])\n\n    def test_write_payload_chunked_multiple(self):\n        write = self.transport.write = unittest.mock.Mock()\n\n        msg = protocol.Response(self.transport, 200)\n        msg.enable_chunked_encoding()\n        msg.send_headers()\n\n        msg.write(b'data1')\n        msg.write(b'data2')\n        msg.write_eof()\n\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertEqual(\n            b'5\\r\\ndata1\\r\\n5\\r\\ndata2\\r\\n0\\r\\n\\r\\n',\n            content.split(b'\\r\\n\\r\\n', 1)[-1])\n\n    def test_write_payload_length(self):\n        write = self.transport.write = unittest.mock.Mock()\n\n        msg = protocol.Response(self.transport, 200)\n        msg.add_headers(('content-length', '2'))\n        msg.send_headers()\n\n        msg.write(b'd')\n        msg.write(b'ata')\n        msg.write_eof()\n\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertEqual(\n            b'da', content.split(b'\\r\\n\\r\\n', 1)[-1])\n\n    def test_write_payload_chunked_filter(self):\n        write = self.transport.write = unittest.mock.Mock()\n\n        msg = protocol.Response(self.transport, 200)\n        msg.send_headers()\n\n        msg.add_chunking_filter(2)\n        msg.write(b'data')\n        msg.write_eof()\n\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertTrue(content.endswith(b'2\\r\\nda\\r\\n2\\r\\nta\\r\\n0\\r\\n\\r\\n'))\n\n    def test_write_payload_chunked_filter_mutiple_chunks(self):\n        write = self.transport.write = unittest.mock.Mock()\n        msg = protocol.Response(self.transport, 200)\n        msg.send_headers()\n\n        msg.add_chunking_filter(2)\n        msg.write(b'data1')\n        msg.write(b'data2')\n        msg.write_eof()\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertTrue(content.endswith(\n            b'2\\r\\nda\\r\\n2\\r\\nta\\r\\n2\\r\\n1d\\r\\n2\\r\\nat\\r\\n'\n            b'2\\r\\na2\\r\\n0\\r\\n\\r\\n'))\n\n    def test_write_payload_chunked_large_chunk(self):\n        write = self.transport.write = unittest.mock.Mock()\n        msg = protocol.Response(self.transport, 200)\n        msg.send_headers()\n\n        msg.add_chunking_filter(1024)\n        msg.write(b'data')\n        msg.write_eof()\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertTrue(content.endswith(b'4\\r\\ndata\\r\\n0\\r\\n\\r\\n'))\n\n    _comp = zlib.compressobj(wbits=-zlib.MAX_WBITS)\n    _COMPRESSED = b''.join([_comp.compress(b'data'), _comp.flush()])\n\n    def test_write_payload_deflate_filter(self):\n        write = self.transport.write = unittest.mock.Mock()\n        msg = protocol.Response(self.transport, 200)\n        msg.add_headers(('content-length', '{}'.format(len(self._COMPRESSED))))\n        msg.send_headers()\n\n        msg.add_compression_filter('deflate')\n        msg.write(b'data')\n        msg.write_eof()\n\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertEqual(\n            self._COMPRESSED, content.split(b'\\r\\n\\r\\n', 1)[-1])\n\n    def test_write_payload_deflate_and_chunked(self):\n        write = self.transport.write = unittest.mock.Mock()\n        msg = protocol.Response(self.transport, 200)\n        msg.send_headers()\n\n        msg.add_compression_filter('deflate')\n        msg.add_chunking_filter(2)\n\n        msg.write(b'data')\n        msg.write_eof()\n\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertEqual(\n            b'2\\r\\nKI\\r\\n2\\r\\n,I\\r\\n2\\r\\n\\x04\\x00\\r\\n0\\r\\n\\r\\n',\n            content.split(b'\\r\\n\\r\\n', 1)[-1])\n\n    def test_write_payload_chunked_and_deflate(self):\n        write = self.transport.write = unittest.mock.Mock()\n        msg = protocol.Response(self.transport, 200)\n        msg.add_headers(('content-length', '{}'.format(len(self._COMPRESSED))))\n\n        msg.add_chunking_filter(2)\n        msg.add_compression_filter('deflate')\n        msg.send_headers()\n\n        msg.write(b'data')\n        msg.write_eof()\n\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertEqual(\n            self._COMPRESSED, content.split(b'\\r\\n\\r\\n', 1)[-1])\n\n    def test_write_drain(self):\n        msg = protocol.Response(self.transport, 200, http_version=(1, 0))\n        msg._send_headers = True\n\n        msg.write(b'1' * (64 * 1024 * 2))\n        self.assertFalse(self.transport.drain.called)\n\n        msg.write(b'1', drain=True)\n        self.assertTrue(self.transport.drain.called)\n        self.assertEqual(msg._output_size, 0)\n\n    def test_dont_override_request_headers_with_default_values(self):\n        msg = protocol.Request(\n            self.transport, 'GET', '/index.html', close=True)\n        msg.add_header('USER-AGENT', 'custom')\n        msg._add_default_headers()\n        self.assertEqual('custom', msg.headers['USER-AGENT'])\n\n    def test_dont_override_response_headers_with_default_values(self):\n        msg = protocol.Response(self.transport, 200, http_version=(1, 0))\n        msg.add_header('DATE', 'now')\n        msg.add_header('SERVER', 'custom')\n        msg._add_default_headers()\n        self.assertEqual('custom', msg.headers['SERVER'])\n        self.assertEqual('now', msg.headers['DATE'])",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 11,
                            "end_lineno": 497,
                            "parent": null
                        }
                    ],
                    "added_entities": [],
                    "deleted_entities": []
                },
                {
                    "descriptor": {
                        "old_range": {
                            "start": 466,
                            "length": 7
                        },
                        "new_range": {
                            "start": 470,
                            "length": 9
                        },
                        "section": "class TestHttpMessage(unittest.TestCase):"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "        msg.write(b'data')",
                                "type": "context"
                            },
                            {
                                "content": "        msg.write_eof()",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "        content = b''.join([c[1][0] for c in list(write.mock_calls)])",
                                "type": "deleted"
                            },
                            {
                                "content": "        chunks = [c[1][0] for c in list(write.mock_calls)]",
                                "type": "added"
                            },
                            {
                                "content": "        self.assertTrue(all(chunks))",
                                "type": "added"
                            },
                            {
                                "content": "        content = b''.join(chunks)",
                                "type": "added"
                            },
                            {
                                "content": "        self.assertEqual(",
                                "type": "context"
                            },
                            {
                                "content": "            self._COMPRESSED, content.split(b'\\r\\n\\r\\n', 1)[-1])",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [
                        {
                            "file_name": "tests/test_http_protocol.py",
                            "type": "method",
                            "name": "TestHttpMessage.test_write_payload_chunked_and_deflate",
                            "content": "class TestHttpMessage(unittest.TestCase):\n\n    def setUp(self):\n        self.transport = unittest.mock.Mock()\n        asyncio.set_event_loop(None)\n\n    def test_start_request(self):\n        msg = protocol.Request(\n            self.transport, 'GET', '/index.html', close=True)\n\n        self.assertIs(msg.transport, self.transport)\n        self.assertIsNone(msg.status)\n        self.assertTrue(msg.closing)\n        self.assertEqual(msg.status_line, 'GET /index.html HTTP/1.1\\r\\n')\n\n    def test_start_response(self):\n        msg = protocol.Response(self.transport, 200, close=True)\n\n        self.assertIs(msg.transport, self.transport)\n        self.assertEqual(msg.status, 200)\n        self.assertEqual(msg.reason, \"OK\")\n        self.assertTrue(msg.closing)\n        self.assertEqual(msg.status_line, 'HTTP/1.1 200 OK\\r\\n')\n\n    def test_start_response_with_reason(self):\n        msg = protocol.Response(self.transport, 333, close=True,\n                                reason=\"My Reason\")\n\n        self.assertEqual(msg.status, 333)\n        self.assertEqual(msg.reason, \"My Reason\")\n        self.assertEqual(msg.status_line, 'HTTP/1.1 333 My Reason\\r\\n')\n\n    def test_start_response_with_unknown_reason(self):\n        msg = protocol.Response(self.transport, 777, close=True)\n\n        self.assertEqual(msg.status, 777)\n        self.assertEqual(msg.reason, \"777\")\n        self.assertEqual(msg.status_line, 'HTTP/1.1 777 777\\r\\n')\n\n    def test_force_close(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertFalse(msg.closing)\n        msg.force_close()\n        self.assertTrue(msg.closing)\n\n    def test_force_chunked(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertFalse(msg.chunked)\n        msg.enable_chunked_encoding()\n        self.assertTrue(msg.chunked)\n\n    def test_keep_alive(self):\n        msg = protocol.Response(self.transport, 200, close=True)\n        self.assertFalse(msg.keep_alive())\n        msg.keepalive = True\n        self.assertTrue(msg.keep_alive())\n\n        msg.force_close()\n        self.assertFalse(msg.keep_alive())\n\n    def test_keep_alive_http10(self):\n        msg = protocol.Response(self.transport, 200, http_version=(1, 0))\n        self.assertFalse(msg.keepalive)\n        self.assertFalse(msg.keep_alive())\n\n        msg = protocol.Response(self.transport, 200, http_version=(1, 1))\n        self.assertIsNone(msg.keepalive)\n\n    def test_add_header(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertEqual([], list(msg.headers))\n\n        msg.add_header('content-type', 'plain/html')\n        self.assertEqual(\n            [('CONTENT-TYPE', 'plain/html')], list(msg.headers.items()))\n\n    def test_add_header_with_spaces(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertEqual([], list(msg.headers))\n\n        msg.add_header('content-type', '  plain/html  ')\n        self.assertEqual(\n            [('CONTENT-TYPE', 'plain/html')], list(msg.headers.items()))\n\n    def test_add_header_non_ascii(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertEqual([], list(msg.headers))\n\n        with self.assertRaises(AssertionError):\n            msg.add_header('тип-контента', 'текст/плейн')\n\n    def test_add_header_invalid_value_type(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertEqual([], list(msg.headers))\n\n        with self.assertRaises(AssertionError):\n            msg.add_header('content-type', {'test': 'plain'})\n\n        with self.assertRaises(AssertionError):\n            msg.add_header(list('content-type'), 'text/plain')\n\n    def test_add_headers(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertEqual([], list(msg.headers))\n\n        msg.add_headers(('content-type', 'plain/html'))\n        self.assertEqual(\n            [('CONTENT-TYPE', 'plain/html')], list(msg.headers.items()))\n\n    def test_add_headers_length(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertIsNone(msg.length)\n\n        msg.add_headers(('content-length', '42'))\n        self.assertEqual(42, msg.length)\n\n    def test_add_headers_upgrade(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertFalse(msg.upgrade)\n\n        msg.add_headers(('connection', 'upgrade'))\n        self.assertTrue(msg.upgrade)\n\n    def test_add_headers_upgrade_websocket(self):\n        msg = protocol.Response(self.transport, 200)\n\n        msg.add_headers(('upgrade', 'test'))\n        self.assertEqual([], list(msg.headers))\n\n        msg.add_headers(('upgrade', 'websocket'))\n        self.assertEqual(\n            [('UPGRADE', 'websocket')], list(msg.headers.items()))\n\n    def test_add_headers_connection_keepalive(self):\n        msg = protocol.Response(self.transport, 200)\n\n        msg.add_headers(('connection', 'keep-alive'))\n        self.assertEqual([], list(msg.headers))\n        self.assertTrue(msg.keepalive)\n\n        msg.add_headers(('connection', 'close'))\n        self.assertFalse(msg.keepalive)\n\n    def test_add_headers_hop_headers(self):\n        msg = protocol.Response(self.transport, 200)\n        msg.HOP_HEADERS = (hdrs.TRANSFER_ENCODING,)\n\n        msg.add_headers(('connection', 'test'), ('transfer-encoding', 't'))\n        self.assertEqual([], list(msg.headers))\n\n    def test_default_headers(self):\n        msg = protocol.Response(self.transport, 200)\n        msg._add_default_headers()\n\n        headers = [r for r, _ in msg.headers.items()]\n        self.assertIn('DATE', headers)\n        self.assertIn('CONNECTION', headers)\n\n    def test_default_headers_server(self):\n        msg = protocol.Response(self.transport, 200)\n        msg._add_default_headers()\n\n        self.assertIn('SERVER', msg.headers)\n\n    def test_default_headers_useragent(self):\n        msg = protocol.Request(self.transport, 'GET', '/')\n        msg._add_default_headers()\n\n        self.assertNotIn('SERVER', msg.headers)\n        self.assertIn('USER-AGENT', msg.headers)\n\n    def test_default_headers_useragent_custom(self):\n        msg = protocol.Request(self.transport, 'GET', '/')\n        msg.add_headers(('user-agent', 'my custom agent'))\n        msg._add_default_headers()\n\n        headers = [r for r, _ in msg.headers.items()\n                   if r.lower() == 'user-agent']\n        self.assertEqual(len(headers), 1)\n\n    def test_default_headers_chunked(self):\n        msg = protocol.Response(self.transport, 200)\n        msg._add_default_headers()\n\n        headers = [r for r, _ in msg.headers.items()]\n        self.assertNotIn('TRANSFER-ENCODING', headers)\n\n        msg = protocol.Response(self.transport, 200)\n        msg.enable_chunked_encoding()\n        msg.send_headers()\n\n        headers = [r for r, _ in msg.headers.items()]\n        self.assertIn('TRANSFER-ENCODING', headers)\n\n    def test_default_headers_connection_upgrade(self):\n        msg = protocol.Response(self.transport, 200)\n        msg.upgrade = True\n        msg._add_default_headers()\n\n        headers = [r for r in msg.headers.items() if r[0] == 'CONNECTION']\n        self.assertEqual([('CONNECTION', 'upgrade')], headers)\n\n    def test_default_headers_connection_close(self):\n        msg = protocol.Response(self.transport, 200)\n        msg.force_close()\n        msg._add_default_headers()\n\n        headers = [r for r in msg.headers.items() if r[0] == 'CONNECTION']\n        self.assertEqual([('CONNECTION', 'close')], headers)\n\n    def test_default_headers_connection_keep_alive(self):\n        msg = protocol.Response(self.transport, 200)\n        msg.keepalive = True\n        msg._add_default_headers()\n\n        headers = [r for r in msg.headers.items() if r[0] == 'CONNECTION']\n        self.assertEqual([('CONNECTION', 'keep-alive')], headers)\n\n    def test_send_headers(self):\n        write = self.transport.write = unittest.mock.Mock()\n\n        msg = protocol.Response(self.transport, 200)\n        msg.add_headers(('content-type', 'plain/html'))\n        self.assertFalse(msg.is_headers_sent())\n\n        msg.send_headers()\n\n        content = b''.join([arg[1][0] for arg in list(write.mock_calls)])\n\n        self.assertTrue(content.startswith(b'HTTP/1.1 200 OK\\r\\n'))\n        self.assertIn(b'CONTENT-TYPE: plain/html', content)\n        self.assertTrue(msg.headers_sent)\n        self.assertTrue(msg.is_headers_sent())\n        # cleanup\n        msg.writer.close()\n\n    def test_send_headers_non_ascii(self):\n        write = self.transport.write = unittest.mock.Mock()\n\n        msg = protocol.Response(self.transport, 200)\n        msg.add_headers(('x-header', 'текст'))\n        self.assertFalse(msg.is_headers_sent())\n\n        msg.send_headers()\n\n        content = b''.join([arg[1][0] for arg in list(write.mock_calls)])\n\n        self.assertTrue(content.startswith(b'HTTP/1.1 200 OK\\r\\n'))\n        self.assertIn(b'X-HEADER: \\xd1\\x82\\xd0\\xb5\\xd0\\xba\\xd1\\x81\\xd1\\x82',\n                      content)\n        self.assertTrue(msg.headers_sent)\n        self.assertTrue(msg.is_headers_sent())\n        # cleanup\n        msg.writer.close()\n\n    def test_send_headers_nomore_add(self):\n        msg = protocol.Response(self.transport, 200)\n        msg.add_headers(('content-type', 'plain/html'))\n        msg.send_headers()\n\n        self.assertRaises(AssertionError,\n                          msg.add_header, 'content-type', 'plain/html')\n        # cleanup\n        msg.writer.close()\n\n    def test_prepare_length(self):\n        msg = protocol.Response(self.transport, 200)\n        w_l_p = msg._write_length_payload = unittest.mock.Mock()\n        w_l_p.return_value = iter([1, 2, 3])\n\n        msg.add_headers(('content-length', '42'))\n        msg.send_headers()\n\n        self.assertTrue(w_l_p.called)\n        self.assertEqual((42,), w_l_p.call_args[0])\n\n    def test_prepare_chunked_force(self):\n        msg = protocol.Response(self.transport, 200)\n        msg.enable_chunked_encoding()\n\n        chunked = msg._write_chunked_payload = unittest.mock.Mock()\n        chunked.return_value = iter([1, 2, 3])\n\n        msg.add_headers(('content-length', '42'))\n        msg.send_headers()\n        self.assertTrue(chunked.called)\n\n    def test_prepare_chunked_no_length(self):\n        msg = protocol.Response(self.transport, 200)\n\n        chunked = msg._write_chunked_payload = unittest.mock.Mock()\n        chunked.return_value = iter([1, 2, 3])\n\n        msg.send_headers()\n        self.assertTrue(chunked.called)\n\n    def test_prepare_eof(self):\n        msg = protocol.Response(self.transport, 200, http_version=(1, 0))\n\n        eof = msg._write_eof_payload = unittest.mock.Mock()\n        eof.return_value = iter([1, 2, 3])\n\n        msg.send_headers()\n        self.assertTrue(eof.called)\n\n    def test_write_auto_send_headers(self):\n        msg = protocol.Response(self.transport, 200, http_version=(1, 0))\n        msg._send_headers = True\n\n        msg.write(b'data1')\n        self.assertTrue(msg.headers_sent)\n        # cleanup\n        msg.writer.close()\n\n    def test_write_payload_eof(self):\n        write = self.transport.write = unittest.mock.Mock()\n        msg = protocol.Response(self.transport, 200, http_version=(1, 0))\n        msg.send_headers()\n\n        msg.write(b'data1')\n        self.assertTrue(msg.headers_sent)\n\n        msg.write(b'data2')\n        msg.write_eof()\n\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertEqual(\n            b'data1data2', content.split(b'\\r\\n\\r\\n', 1)[-1])\n\n    def test_write_payload_chunked(self):\n        write = self.transport.write = unittest.mock.Mock()\n\n        msg = protocol.Response(self.transport, 200)\n        msg.enable_chunked_encoding()\n        msg.send_headers()\n\n        msg.write(b'data')\n        msg.write_eof()\n\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertEqual(\n            b'4\\r\\ndata\\r\\n0\\r\\n\\r\\n',\n            content.split(b'\\r\\n\\r\\n', 1)[-1])\n\n    def test_write_payload_chunked_multiple(self):\n        write = self.transport.write = unittest.mock.Mock()\n\n        msg = protocol.Response(self.transport, 200)\n        msg.enable_chunked_encoding()\n        msg.send_headers()\n\n        msg.write(b'data1')\n        msg.write(b'data2')\n        msg.write_eof()\n\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertEqual(\n            b'5\\r\\ndata1\\r\\n5\\r\\ndata2\\r\\n0\\r\\n\\r\\n',\n            content.split(b'\\r\\n\\r\\n', 1)[-1])\n\n    def test_write_payload_length(self):\n        write = self.transport.write = unittest.mock.Mock()\n\n        msg = protocol.Response(self.transport, 200)\n        msg.add_headers(('content-length', '2'))\n        msg.send_headers()\n\n        msg.write(b'd')\n        msg.write(b'ata')\n        msg.write_eof()\n\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertEqual(\n            b'da', content.split(b'\\r\\n\\r\\n', 1)[-1])\n\n    def test_write_payload_chunked_filter(self):\n        write = self.transport.write = unittest.mock.Mock()\n\n        msg = protocol.Response(self.transport, 200)\n        msg.send_headers()\n\n        msg.add_chunking_filter(2)\n        msg.write(b'data')\n        msg.write_eof()\n\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertTrue(content.endswith(b'2\\r\\nda\\r\\n2\\r\\nta\\r\\n0\\r\\n\\r\\n'))\n\n    def test_write_payload_chunked_filter_mutiple_chunks(self):\n        write = self.transport.write = unittest.mock.Mock()\n        msg = protocol.Response(self.transport, 200)\n        msg.send_headers()\n\n        msg.add_chunking_filter(2)\n        msg.write(b'data1')\n        msg.write(b'data2')\n        msg.write_eof()\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertTrue(content.endswith(\n            b'2\\r\\nda\\r\\n2\\r\\nta\\r\\n2\\r\\n1d\\r\\n2\\r\\nat\\r\\n'\n            b'2\\r\\na2\\r\\n0\\r\\n\\r\\n'))\n\n    def test_write_payload_chunked_large_chunk(self):\n        write = self.transport.write = unittest.mock.Mock()\n        msg = protocol.Response(self.transport, 200)\n        msg.send_headers()\n\n        msg.add_chunking_filter(1024)\n        msg.write(b'data')\n        msg.write_eof()\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertTrue(content.endswith(b'4\\r\\ndata\\r\\n0\\r\\n\\r\\n'))\n\n    _comp = zlib.compressobj(wbits=-zlib.MAX_WBITS)\n    _COMPRESSED = b''.join([_comp.compress(b'data'), _comp.flush()])\n\n    def test_write_payload_deflate_filter(self):\n        write = self.transport.write = unittest.mock.Mock()\n        msg = protocol.Response(self.transport, 200)\n        msg.add_headers(('content-length', '{}'.format(len(self._COMPRESSED))))\n        msg.send_headers()\n\n        msg.add_compression_filter('deflate')\n        msg.write(b'data')\n        msg.write_eof()\n\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertEqual(\n            self._COMPRESSED, content.split(b'\\r\\n\\r\\n', 1)[-1])\n\n    def test_write_payload_deflate_and_chunked(self):\n        write = self.transport.write = unittest.mock.Mock()\n        msg = protocol.Response(self.transport, 200)\n        msg.send_headers()\n\n        msg.add_compression_filter('deflate')\n        msg.add_chunking_filter(2)\n\n        msg.write(b'data')\n        msg.write_eof()\n\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertEqual(\n            b'2\\r\\nKI\\r\\n2\\r\\n,I\\r\\n2\\r\\n\\x04\\x00\\r\\n0\\r\\n\\r\\n',\n            content.split(b'\\r\\n\\r\\n', 1)[-1])\n\n    def test_write_payload_chunked_and_deflate(self):\n        write = self.transport.write = unittest.mock.Mock()\n        msg = protocol.Response(self.transport, 200)\n        msg.add_headers(('content-length', '{}'.format(len(self._COMPRESSED))))\n\n        msg.add_chunking_filter(2)\n        msg.add_compression_filter('deflate')\n        msg.send_headers()\n\n        msg.write(b'data')\n        msg.write_eof()\n\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertEqual(\n            self._COMPRESSED, content.split(b'\\r\\n\\r\\n', 1)[-1])\n\n    def test_write_drain(self):\n        msg = protocol.Response(self.transport, 200, http_version=(1, 0))\n        msg._send_headers = True\n\n        msg.write(b'1' * (64 * 1024 * 2))\n        self.assertFalse(self.transport.drain.called)\n\n        msg.write(b'1', drain=True)\n        self.assertTrue(self.transport.drain.called)\n        self.assertEqual(msg._output_size, 0)\n\n    def test_dont_override_request_headers_with_default_values(self):\n        msg = protocol.Request(\n            self.transport, 'GET', '/index.html', close=True)\n        msg.add_header('USER-AGENT', 'custom')\n        msg._add_default_headers()\n        self.assertEqual('custom', msg.headers['USER-AGENT'])\n\n    def test_dont_override_response_headers_with_default_values(self):\n        msg = protocol.Response(self.transport, 200, http_version=(1, 0))\n        msg.add_header('DATE', 'now')\n        msg.add_header('SERVER', 'custom')\n        msg._add_default_headers()\n        self.assertEqual('custom', msg.headers['SERVER'])\n        self.assertEqual('now', msg.headers['DATE'])",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 457,
                            "end_lineno": 471,
                            "parent": {
                                "file_name": "tests/test_http_protocol.py",
                                "type": "class",
                                "name": "TestHttpMessage",
                                "content": "class TestHttpMessage(unittest.TestCase):\n\n    def setUp(self):\n        self.transport = unittest.mock.Mock()\n        asyncio.set_event_loop(None)\n\n    def test_start_request(self):\n        msg = protocol.Request(\n            self.transport, 'GET', '/index.html', close=True)\n\n        self.assertIs(msg.transport, self.transport)\n        self.assertIsNone(msg.status)\n        self.assertTrue(msg.closing)\n        self.assertEqual(msg.status_line, 'GET /index.html HTTP/1.1\\r\\n')\n\n    def test_start_response(self):\n        msg = protocol.Response(self.transport, 200, close=True)\n\n        self.assertIs(msg.transport, self.transport)\n        self.assertEqual(msg.status, 200)\n        self.assertEqual(msg.reason, \"OK\")\n        self.assertTrue(msg.closing)\n        self.assertEqual(msg.status_line, 'HTTP/1.1 200 OK\\r\\n')\n\n    def test_start_response_with_reason(self):\n        msg = protocol.Response(self.transport, 333, close=True,\n                                reason=\"My Reason\")\n\n        self.assertEqual(msg.status, 333)\n        self.assertEqual(msg.reason, \"My Reason\")\n        self.assertEqual(msg.status_line, 'HTTP/1.1 333 My Reason\\r\\n')\n\n    def test_start_response_with_unknown_reason(self):\n        msg = protocol.Response(self.transport, 777, close=True)\n\n        self.assertEqual(msg.status, 777)\n        self.assertEqual(msg.reason, \"777\")\n        self.assertEqual(msg.status_line, 'HTTP/1.1 777 777\\r\\n')\n\n    def test_force_close(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertFalse(msg.closing)\n        msg.force_close()\n        self.assertTrue(msg.closing)\n\n    def test_force_chunked(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertFalse(msg.chunked)\n        msg.enable_chunked_encoding()\n        self.assertTrue(msg.chunked)\n\n    def test_keep_alive(self):\n        msg = protocol.Response(self.transport, 200, close=True)\n        self.assertFalse(msg.keep_alive())\n        msg.keepalive = True\n        self.assertTrue(msg.keep_alive())\n\n        msg.force_close()\n        self.assertFalse(msg.keep_alive())\n\n    def test_keep_alive_http10(self):\n        msg = protocol.Response(self.transport, 200, http_version=(1, 0))\n        self.assertFalse(msg.keepalive)\n        self.assertFalse(msg.keep_alive())\n\n        msg = protocol.Response(self.transport, 200, http_version=(1, 1))\n        self.assertIsNone(msg.keepalive)\n\n    def test_add_header(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertEqual([], list(msg.headers))\n\n        msg.add_header('content-type', 'plain/html')\n        self.assertEqual(\n            [('CONTENT-TYPE', 'plain/html')], list(msg.headers.items()))\n\n    def test_add_header_with_spaces(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertEqual([], list(msg.headers))\n\n        msg.add_header('content-type', '  plain/html  ')\n        self.assertEqual(\n            [('CONTENT-TYPE', 'plain/html')], list(msg.headers.items()))\n\n    def test_add_header_non_ascii(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertEqual([], list(msg.headers))\n\n        with self.assertRaises(AssertionError):\n            msg.add_header('тип-контента', 'текст/плейн')\n\n    def test_add_header_invalid_value_type(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertEqual([], list(msg.headers))\n\n        with self.assertRaises(AssertionError):\n            msg.add_header('content-type', {'test': 'plain'})\n\n        with self.assertRaises(AssertionError):\n            msg.add_header(list('content-type'), 'text/plain')\n\n    def test_add_headers(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertEqual([], list(msg.headers))\n\n        msg.add_headers(('content-type', 'plain/html'))\n        self.assertEqual(\n            [('CONTENT-TYPE', 'plain/html')], list(msg.headers.items()))\n\n    def test_add_headers_length(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertIsNone(msg.length)\n\n        msg.add_headers(('content-length', '42'))\n        self.assertEqual(42, msg.length)\n\n    def test_add_headers_upgrade(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertFalse(msg.upgrade)\n\n        msg.add_headers(('connection', 'upgrade'))\n        self.assertTrue(msg.upgrade)\n\n    def test_add_headers_upgrade_websocket(self):\n        msg = protocol.Response(self.transport, 200)\n\n        msg.add_headers(('upgrade', 'test'))\n        self.assertEqual([], list(msg.headers))\n\n        msg.add_headers(('upgrade', 'websocket'))\n        self.assertEqual(\n            [('UPGRADE', 'websocket')], list(msg.headers.items()))\n\n    def test_add_headers_connection_keepalive(self):\n        msg = protocol.Response(self.transport, 200)\n\n        msg.add_headers(('connection', 'keep-alive'))\n        self.assertEqual([], list(msg.headers))\n        self.assertTrue(msg.keepalive)\n\n        msg.add_headers(('connection', 'close'))\n        self.assertFalse(msg.keepalive)\n\n    def test_add_headers_hop_headers(self):\n        msg = protocol.Response(self.transport, 200)\n        msg.HOP_HEADERS = (hdrs.TRANSFER_ENCODING,)\n\n        msg.add_headers(('connection', 'test'), ('transfer-encoding', 't'))\n        self.assertEqual([], list(msg.headers))\n\n    def test_default_headers(self):\n        msg = protocol.Response(self.transport, 200)\n        msg._add_default_headers()\n\n        headers = [r for r, _ in msg.headers.items()]\n        self.assertIn('DATE', headers)\n        self.assertIn('CONNECTION', headers)\n\n    def test_default_headers_server(self):\n        msg = protocol.Response(self.transport, 200)\n        msg._add_default_headers()\n\n        self.assertIn('SERVER', msg.headers)\n\n    def test_default_headers_useragent(self):\n        msg = protocol.Request(self.transport, 'GET', '/')\n        msg._add_default_headers()\n\n        self.assertNotIn('SERVER', msg.headers)\n        self.assertIn('USER-AGENT', msg.headers)\n\n    def test_default_headers_useragent_custom(self):\n        msg = protocol.Request(self.transport, 'GET', '/')\n        msg.add_headers(('user-agent', 'my custom agent'))\n        msg._add_default_headers()\n\n        headers = [r for r, _ in msg.headers.items()\n                   if r.lower() == 'user-agent']\n        self.assertEqual(len(headers), 1)\n\n    def test_default_headers_chunked(self):\n        msg = protocol.Response(self.transport, 200)\n        msg._add_default_headers()\n\n        headers = [r for r, _ in msg.headers.items()]\n        self.assertNotIn('TRANSFER-ENCODING', headers)\n\n        msg = protocol.Response(self.transport, 200)\n        msg.enable_chunked_encoding()\n        msg.send_headers()\n\n        headers = [r for r, _ in msg.headers.items()]\n        self.assertIn('TRANSFER-ENCODING', headers)\n\n    def test_default_headers_connection_upgrade(self):\n        msg = protocol.Response(self.transport, 200)\n        msg.upgrade = True\n        msg._add_default_headers()\n\n        headers = [r for r in msg.headers.items() if r[0] == 'CONNECTION']\n        self.assertEqual([('CONNECTION', 'upgrade')], headers)\n\n    def test_default_headers_connection_close(self):\n        msg = protocol.Response(self.transport, 200)\n        msg.force_close()\n        msg._add_default_headers()\n\n        headers = [r for r in msg.headers.items() if r[0] == 'CONNECTION']\n        self.assertEqual([('CONNECTION', 'close')], headers)\n\n    def test_default_headers_connection_keep_alive(self):\n        msg = protocol.Response(self.transport, 200)\n        msg.keepalive = True\n        msg._add_default_headers()\n\n        headers = [r for r in msg.headers.items() if r[0] == 'CONNECTION']\n        self.assertEqual([('CONNECTION', 'keep-alive')], headers)\n\n    def test_send_headers(self):\n        write = self.transport.write = unittest.mock.Mock()\n\n        msg = protocol.Response(self.transport, 200)\n        msg.add_headers(('content-type', 'plain/html'))\n        self.assertFalse(msg.is_headers_sent())\n\n        msg.send_headers()\n\n        content = b''.join([arg[1][0] for arg in list(write.mock_calls)])\n\n        self.assertTrue(content.startswith(b'HTTP/1.1 200 OK\\r\\n'))\n        self.assertIn(b'CONTENT-TYPE: plain/html', content)\n        self.assertTrue(msg.headers_sent)\n        self.assertTrue(msg.is_headers_sent())\n        # cleanup\n        msg.writer.close()\n\n    def test_send_headers_non_ascii(self):\n        write = self.transport.write = unittest.mock.Mock()\n\n        msg = protocol.Response(self.transport, 200)\n        msg.add_headers(('x-header', 'текст'))\n        self.assertFalse(msg.is_headers_sent())\n\n        msg.send_headers()\n\n        content = b''.join([arg[1][0] for arg in list(write.mock_calls)])\n\n        self.assertTrue(content.startswith(b'HTTP/1.1 200 OK\\r\\n'))\n        self.assertIn(b'X-HEADER: \\xd1\\x82\\xd0\\xb5\\xd0\\xba\\xd1\\x81\\xd1\\x82',\n                      content)\n        self.assertTrue(msg.headers_sent)\n        self.assertTrue(msg.is_headers_sent())\n        # cleanup\n        msg.writer.close()\n\n    def test_send_headers_nomore_add(self):\n        msg = protocol.Response(self.transport, 200)\n        msg.add_headers(('content-type', 'plain/html'))\n        msg.send_headers()\n\n        self.assertRaises(AssertionError,\n                          msg.add_header, 'content-type', 'plain/html')\n        # cleanup\n        msg.writer.close()\n\n    def test_prepare_length(self):\n        msg = protocol.Response(self.transport, 200)\n        w_l_p = msg._write_length_payload = unittest.mock.Mock()\n        w_l_p.return_value = iter([1, 2, 3])\n\n        msg.add_headers(('content-length', '42'))\n        msg.send_headers()\n\n        self.assertTrue(w_l_p.called)\n        self.assertEqual((42,), w_l_p.call_args[0])\n\n    def test_prepare_chunked_force(self):\n        msg = protocol.Response(self.transport, 200)\n        msg.enable_chunked_encoding()\n\n        chunked = msg._write_chunked_payload = unittest.mock.Mock()\n        chunked.return_value = iter([1, 2, 3])\n\n        msg.add_headers(('content-length', '42'))\n        msg.send_headers()\n        self.assertTrue(chunked.called)\n\n    def test_prepare_chunked_no_length(self):\n        msg = protocol.Response(self.transport, 200)\n\n        chunked = msg._write_chunked_payload = unittest.mock.Mock()\n        chunked.return_value = iter([1, 2, 3])\n\n        msg.send_headers()\n        self.assertTrue(chunked.called)\n\n    def test_prepare_eof(self):\n        msg = protocol.Response(self.transport, 200, http_version=(1, 0))\n\n        eof = msg._write_eof_payload = unittest.mock.Mock()\n        eof.return_value = iter([1, 2, 3])\n\n        msg.send_headers()\n        self.assertTrue(eof.called)\n\n    def test_write_auto_send_headers(self):\n        msg = protocol.Response(self.transport, 200, http_version=(1, 0))\n        msg._send_headers = True\n\n        msg.write(b'data1')\n        self.assertTrue(msg.headers_sent)\n        # cleanup\n        msg.writer.close()\n\n    def test_write_payload_eof(self):\n        write = self.transport.write = unittest.mock.Mock()\n        msg = protocol.Response(self.transport, 200, http_version=(1, 0))\n        msg.send_headers()\n\n        msg.write(b'data1')\n        self.assertTrue(msg.headers_sent)\n\n        msg.write(b'data2')\n        msg.write_eof()\n\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertEqual(\n            b'data1data2', content.split(b'\\r\\n\\r\\n', 1)[-1])\n\n    def test_write_payload_chunked(self):\n        write = self.transport.write = unittest.mock.Mock()\n\n        msg = protocol.Response(self.transport, 200)\n        msg.enable_chunked_encoding()\n        msg.send_headers()\n\n        msg.write(b'data')\n        msg.write_eof()\n\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertEqual(\n            b'4\\r\\ndata\\r\\n0\\r\\n\\r\\n',\n            content.split(b'\\r\\n\\r\\n', 1)[-1])\n\n    def test_write_payload_chunked_multiple(self):\n        write = self.transport.write = unittest.mock.Mock()\n\n        msg = protocol.Response(self.transport, 200)\n        msg.enable_chunked_encoding()\n        msg.send_headers()\n\n        msg.write(b'data1')\n        msg.write(b'data2')\n        msg.write_eof()\n\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertEqual(\n            b'5\\r\\ndata1\\r\\n5\\r\\ndata2\\r\\n0\\r\\n\\r\\n',\n            content.split(b'\\r\\n\\r\\n', 1)[-1])\n\n    def test_write_payload_length(self):\n        write = self.transport.write = unittest.mock.Mock()\n\n        msg = protocol.Response(self.transport, 200)\n        msg.add_headers(('content-length', '2'))\n        msg.send_headers()\n\n        msg.write(b'd')\n        msg.write(b'ata')\n        msg.write_eof()\n\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertEqual(\n            b'da', content.split(b'\\r\\n\\r\\n', 1)[-1])\n\n    def test_write_payload_chunked_filter(self):\n        write = self.transport.write = unittest.mock.Mock()\n\n        msg = protocol.Response(self.transport, 200)\n        msg.send_headers()\n\n        msg.add_chunking_filter(2)\n        msg.write(b'data')\n        msg.write_eof()\n\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertTrue(content.endswith(b'2\\r\\nda\\r\\n2\\r\\nta\\r\\n0\\r\\n\\r\\n'))\n\n    def test_write_payload_chunked_filter_mutiple_chunks(self):\n        write = self.transport.write = unittest.mock.Mock()\n        msg = protocol.Response(self.transport, 200)\n        msg.send_headers()\n\n        msg.add_chunking_filter(2)\n        msg.write(b'data1')\n        msg.write(b'data2')\n        msg.write_eof()\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertTrue(content.endswith(\n            b'2\\r\\nda\\r\\n2\\r\\nta\\r\\n2\\r\\n1d\\r\\n2\\r\\nat\\r\\n'\n            b'2\\r\\na2\\r\\n0\\r\\n\\r\\n'))\n\n    def test_write_payload_chunked_large_chunk(self):\n        write = self.transport.write = unittest.mock.Mock()\n        msg = protocol.Response(self.transport, 200)\n        msg.send_headers()\n\n        msg.add_chunking_filter(1024)\n        msg.write(b'data')\n        msg.write_eof()\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertTrue(content.endswith(b'4\\r\\ndata\\r\\n0\\r\\n\\r\\n'))\n\n    _comp = zlib.compressobj(wbits=-zlib.MAX_WBITS)\n    _COMPRESSED = b''.join([_comp.compress(b'data'), _comp.flush()])\n\n    def test_write_payload_deflate_filter(self):\n        write = self.transport.write = unittest.mock.Mock()\n        msg = protocol.Response(self.transport, 200)\n        msg.add_headers(('content-length', '{}'.format(len(self._COMPRESSED))))\n        msg.send_headers()\n\n        msg.add_compression_filter('deflate')\n        msg.write(b'data')\n        msg.write_eof()\n\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertEqual(\n            self._COMPRESSED, content.split(b'\\r\\n\\r\\n', 1)[-1])\n\n    def test_write_payload_deflate_and_chunked(self):\n        write = self.transport.write = unittest.mock.Mock()\n        msg = protocol.Response(self.transport, 200)\n        msg.send_headers()\n\n        msg.add_compression_filter('deflate')\n        msg.add_chunking_filter(2)\n\n        msg.write(b'data')\n        msg.write_eof()\n\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertEqual(\n            b'2\\r\\nKI\\r\\n2\\r\\n,I\\r\\n2\\r\\n\\x04\\x00\\r\\n0\\r\\n\\r\\n',\n            content.split(b'\\r\\n\\r\\n', 1)[-1])\n\n    def test_write_payload_chunked_and_deflate(self):\n        write = self.transport.write = unittest.mock.Mock()\n        msg = protocol.Response(self.transport, 200)\n        msg.add_headers(('content-length', '{}'.format(len(self._COMPRESSED))))\n\n        msg.add_chunking_filter(2)\n        msg.add_compression_filter('deflate')\n        msg.send_headers()\n\n        msg.write(b'data')\n        msg.write_eof()\n\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertEqual(\n            self._COMPRESSED, content.split(b'\\r\\n\\r\\n', 1)[-1])\n\n    def test_write_drain(self):\n        msg = protocol.Response(self.transport, 200, http_version=(1, 0))\n        msg._send_headers = True\n\n        msg.write(b'1' * (64 * 1024 * 2))\n        self.assertFalse(self.transport.drain.called)\n\n        msg.write(b'1', drain=True)\n        self.assertTrue(self.transport.drain.called)\n        self.assertEqual(msg._output_size, 0)\n\n    def test_dont_override_request_headers_with_default_values(self):\n        msg = protocol.Request(\n            self.transport, 'GET', '/index.html', close=True)\n        msg.add_header('USER-AGENT', 'custom')\n        msg._add_default_headers()\n        self.assertEqual('custom', msg.headers['USER-AGENT'])\n\n    def test_dont_override_response_headers_with_default_values(self):\n        msg = protocol.Response(self.transport, 200, http_version=(1, 0))\n        msg.add_header('DATE', 'now')\n        msg.add_header('SERVER', 'custom')\n        msg._add_default_headers()\n        self.assertEqual('custom', msg.headers['SERVER'])\n        self.assertEqual('now', msg.headers['DATE'])",
                                "ast_type_str": "ClassDef",
                                "start_lineno": 11,
                                "end_lineno": 497,
                                "parent": null
                            }
                        },
                        {
                            "file_name": "tests/test_http_protocol.py",
                            "type": "class",
                            "name": "TestHttpMessage",
                            "content": "class TestHttpMessage(unittest.TestCase):\n\n    def setUp(self):\n        self.transport = unittest.mock.Mock()\n        asyncio.set_event_loop(None)\n\n    def test_start_request(self):\n        msg = protocol.Request(\n            self.transport, 'GET', '/index.html', close=True)\n\n        self.assertIs(msg.transport, self.transport)\n        self.assertIsNone(msg.status)\n        self.assertTrue(msg.closing)\n        self.assertEqual(msg.status_line, 'GET /index.html HTTP/1.1\\r\\n')\n\n    def test_start_response(self):\n        msg = protocol.Response(self.transport, 200, close=True)\n\n        self.assertIs(msg.transport, self.transport)\n        self.assertEqual(msg.status, 200)\n        self.assertEqual(msg.reason, \"OK\")\n        self.assertTrue(msg.closing)\n        self.assertEqual(msg.status_line, 'HTTP/1.1 200 OK\\r\\n')\n\n    def test_start_response_with_reason(self):\n        msg = protocol.Response(self.transport, 333, close=True,\n                                reason=\"My Reason\")\n\n        self.assertEqual(msg.status, 333)\n        self.assertEqual(msg.reason, \"My Reason\")\n        self.assertEqual(msg.status_line, 'HTTP/1.1 333 My Reason\\r\\n')\n\n    def test_start_response_with_unknown_reason(self):\n        msg = protocol.Response(self.transport, 777, close=True)\n\n        self.assertEqual(msg.status, 777)\n        self.assertEqual(msg.reason, \"777\")\n        self.assertEqual(msg.status_line, 'HTTP/1.1 777 777\\r\\n')\n\n    def test_force_close(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertFalse(msg.closing)\n        msg.force_close()\n        self.assertTrue(msg.closing)\n\n    def test_force_chunked(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertFalse(msg.chunked)\n        msg.enable_chunked_encoding()\n        self.assertTrue(msg.chunked)\n\n    def test_keep_alive(self):\n        msg = protocol.Response(self.transport, 200, close=True)\n        self.assertFalse(msg.keep_alive())\n        msg.keepalive = True\n        self.assertTrue(msg.keep_alive())\n\n        msg.force_close()\n        self.assertFalse(msg.keep_alive())\n\n    def test_keep_alive_http10(self):\n        msg = protocol.Response(self.transport, 200, http_version=(1, 0))\n        self.assertFalse(msg.keepalive)\n        self.assertFalse(msg.keep_alive())\n\n        msg = protocol.Response(self.transport, 200, http_version=(1, 1))\n        self.assertIsNone(msg.keepalive)\n\n    def test_add_header(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertEqual([], list(msg.headers))\n\n        msg.add_header('content-type', 'plain/html')\n        self.assertEqual(\n            [('CONTENT-TYPE', 'plain/html')], list(msg.headers.items()))\n\n    def test_add_header_with_spaces(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertEqual([], list(msg.headers))\n\n        msg.add_header('content-type', '  plain/html  ')\n        self.assertEqual(\n            [('CONTENT-TYPE', 'plain/html')], list(msg.headers.items()))\n\n    def test_add_header_non_ascii(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertEqual([], list(msg.headers))\n\n        with self.assertRaises(AssertionError):\n            msg.add_header('тип-контента', 'текст/плейн')\n\n    def test_add_header_invalid_value_type(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertEqual([], list(msg.headers))\n\n        with self.assertRaises(AssertionError):\n            msg.add_header('content-type', {'test': 'plain'})\n\n        with self.assertRaises(AssertionError):\n            msg.add_header(list('content-type'), 'text/plain')\n\n    def test_add_headers(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertEqual([], list(msg.headers))\n\n        msg.add_headers(('content-type', 'plain/html'))\n        self.assertEqual(\n            [('CONTENT-TYPE', 'plain/html')], list(msg.headers.items()))\n\n    def test_add_headers_length(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertIsNone(msg.length)\n\n        msg.add_headers(('content-length', '42'))\n        self.assertEqual(42, msg.length)\n\n    def test_add_headers_upgrade(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertFalse(msg.upgrade)\n\n        msg.add_headers(('connection', 'upgrade'))\n        self.assertTrue(msg.upgrade)\n\n    def test_add_headers_upgrade_websocket(self):\n        msg = protocol.Response(self.transport, 200)\n\n        msg.add_headers(('upgrade', 'test'))\n        self.assertEqual([], list(msg.headers))\n\n        msg.add_headers(('upgrade', 'websocket'))\n        self.assertEqual(\n            [('UPGRADE', 'websocket')], list(msg.headers.items()))\n\n    def test_add_headers_connection_keepalive(self):\n        msg = protocol.Response(self.transport, 200)\n\n        msg.add_headers(('connection', 'keep-alive'))\n        self.assertEqual([], list(msg.headers))\n        self.assertTrue(msg.keepalive)\n\n        msg.add_headers(('connection', 'close'))\n        self.assertFalse(msg.keepalive)\n\n    def test_add_headers_hop_headers(self):\n        msg = protocol.Response(self.transport, 200)\n        msg.HOP_HEADERS = (hdrs.TRANSFER_ENCODING,)\n\n        msg.add_headers(('connection', 'test'), ('transfer-encoding', 't'))\n        self.assertEqual([], list(msg.headers))\n\n    def test_default_headers(self):\n        msg = protocol.Response(self.transport, 200)\n        msg._add_default_headers()\n\n        headers = [r for r, _ in msg.headers.items()]\n        self.assertIn('DATE', headers)\n        self.assertIn('CONNECTION', headers)\n\n    def test_default_headers_server(self):\n        msg = protocol.Response(self.transport, 200)\n        msg._add_default_headers()\n\n        self.assertIn('SERVER', msg.headers)\n\n    def test_default_headers_useragent(self):\n        msg = protocol.Request(self.transport, 'GET', '/')\n        msg._add_default_headers()\n\n        self.assertNotIn('SERVER', msg.headers)\n        self.assertIn('USER-AGENT', msg.headers)\n\n    def test_default_headers_useragent_custom(self):\n        msg = protocol.Request(self.transport, 'GET', '/')\n        msg.add_headers(('user-agent', 'my custom agent'))\n        msg._add_default_headers()\n\n        headers = [r for r, _ in msg.headers.items()\n                   if r.lower() == 'user-agent']\n        self.assertEqual(len(headers), 1)\n\n    def test_default_headers_chunked(self):\n        msg = protocol.Response(self.transport, 200)\n        msg._add_default_headers()\n\n        headers = [r for r, _ in msg.headers.items()]\n        self.assertNotIn('TRANSFER-ENCODING', headers)\n\n        msg = protocol.Response(self.transport, 200)\n        msg.enable_chunked_encoding()\n        msg.send_headers()\n\n        headers = [r for r, _ in msg.headers.items()]\n        self.assertIn('TRANSFER-ENCODING', headers)\n\n    def test_default_headers_connection_upgrade(self):\n        msg = protocol.Response(self.transport, 200)\n        msg.upgrade = True\n        msg._add_default_headers()\n\n        headers = [r for r in msg.headers.items() if r[0] == 'CONNECTION']\n        self.assertEqual([('CONNECTION', 'upgrade')], headers)\n\n    def test_default_headers_connection_close(self):\n        msg = protocol.Response(self.transport, 200)\n        msg.force_close()\n        msg._add_default_headers()\n\n        headers = [r for r in msg.headers.items() if r[0] == 'CONNECTION']\n        self.assertEqual([('CONNECTION', 'close')], headers)\n\n    def test_default_headers_connection_keep_alive(self):\n        msg = protocol.Response(self.transport, 200)\n        msg.keepalive = True\n        msg._add_default_headers()\n\n        headers = [r for r in msg.headers.items() if r[0] == 'CONNECTION']\n        self.assertEqual([('CONNECTION', 'keep-alive')], headers)\n\n    def test_send_headers(self):\n        write = self.transport.write = unittest.mock.Mock()\n\n        msg = protocol.Response(self.transport, 200)\n        msg.add_headers(('content-type', 'plain/html'))\n        self.assertFalse(msg.is_headers_sent())\n\n        msg.send_headers()\n\n        content = b''.join([arg[1][0] for arg in list(write.mock_calls)])\n\n        self.assertTrue(content.startswith(b'HTTP/1.1 200 OK\\r\\n'))\n        self.assertIn(b'CONTENT-TYPE: plain/html', content)\n        self.assertTrue(msg.headers_sent)\n        self.assertTrue(msg.is_headers_sent())\n        # cleanup\n        msg.writer.close()\n\n    def test_send_headers_non_ascii(self):\n        write = self.transport.write = unittest.mock.Mock()\n\n        msg = protocol.Response(self.transport, 200)\n        msg.add_headers(('x-header', 'текст'))\n        self.assertFalse(msg.is_headers_sent())\n\n        msg.send_headers()\n\n        content = b''.join([arg[1][0] for arg in list(write.mock_calls)])\n\n        self.assertTrue(content.startswith(b'HTTP/1.1 200 OK\\r\\n'))\n        self.assertIn(b'X-HEADER: \\xd1\\x82\\xd0\\xb5\\xd0\\xba\\xd1\\x81\\xd1\\x82',\n                      content)\n        self.assertTrue(msg.headers_sent)\n        self.assertTrue(msg.is_headers_sent())\n        # cleanup\n        msg.writer.close()\n\n    def test_send_headers_nomore_add(self):\n        msg = protocol.Response(self.transport, 200)\n        msg.add_headers(('content-type', 'plain/html'))\n        msg.send_headers()\n\n        self.assertRaises(AssertionError,\n                          msg.add_header, 'content-type', 'plain/html')\n        # cleanup\n        msg.writer.close()\n\n    def test_prepare_length(self):\n        msg = protocol.Response(self.transport, 200)\n        w_l_p = msg._write_length_payload = unittest.mock.Mock()\n        w_l_p.return_value = iter([1, 2, 3])\n\n        msg.add_headers(('content-length', '42'))\n        msg.send_headers()\n\n        self.assertTrue(w_l_p.called)\n        self.assertEqual((42,), w_l_p.call_args[0])\n\n    def test_prepare_chunked_force(self):\n        msg = protocol.Response(self.transport, 200)\n        msg.enable_chunked_encoding()\n\n        chunked = msg._write_chunked_payload = unittest.mock.Mock()\n        chunked.return_value = iter([1, 2, 3])\n\n        msg.add_headers(('content-length', '42'))\n        msg.send_headers()\n        self.assertTrue(chunked.called)\n\n    def test_prepare_chunked_no_length(self):\n        msg = protocol.Response(self.transport, 200)\n\n        chunked = msg._write_chunked_payload = unittest.mock.Mock()\n        chunked.return_value = iter([1, 2, 3])\n\n        msg.send_headers()\n        self.assertTrue(chunked.called)\n\n    def test_prepare_eof(self):\n        msg = protocol.Response(self.transport, 200, http_version=(1, 0))\n\n        eof = msg._write_eof_payload = unittest.mock.Mock()\n        eof.return_value = iter([1, 2, 3])\n\n        msg.send_headers()\n        self.assertTrue(eof.called)\n\n    def test_write_auto_send_headers(self):\n        msg = protocol.Response(self.transport, 200, http_version=(1, 0))\n        msg._send_headers = True\n\n        msg.write(b'data1')\n        self.assertTrue(msg.headers_sent)\n        # cleanup\n        msg.writer.close()\n\n    def test_write_payload_eof(self):\n        write = self.transport.write = unittest.mock.Mock()\n        msg = protocol.Response(self.transport, 200, http_version=(1, 0))\n        msg.send_headers()\n\n        msg.write(b'data1')\n        self.assertTrue(msg.headers_sent)\n\n        msg.write(b'data2')\n        msg.write_eof()\n\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertEqual(\n            b'data1data2', content.split(b'\\r\\n\\r\\n', 1)[-1])\n\n    def test_write_payload_chunked(self):\n        write = self.transport.write = unittest.mock.Mock()\n\n        msg = protocol.Response(self.transport, 200)\n        msg.enable_chunked_encoding()\n        msg.send_headers()\n\n        msg.write(b'data')\n        msg.write_eof()\n\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertEqual(\n            b'4\\r\\ndata\\r\\n0\\r\\n\\r\\n',\n            content.split(b'\\r\\n\\r\\n', 1)[-1])\n\n    def test_write_payload_chunked_multiple(self):\n        write = self.transport.write = unittest.mock.Mock()\n\n        msg = protocol.Response(self.transport, 200)\n        msg.enable_chunked_encoding()\n        msg.send_headers()\n\n        msg.write(b'data1')\n        msg.write(b'data2')\n        msg.write_eof()\n\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertEqual(\n            b'5\\r\\ndata1\\r\\n5\\r\\ndata2\\r\\n0\\r\\n\\r\\n',\n            content.split(b'\\r\\n\\r\\n', 1)[-1])\n\n    def test_write_payload_length(self):\n        write = self.transport.write = unittest.mock.Mock()\n\n        msg = protocol.Response(self.transport, 200)\n        msg.add_headers(('content-length', '2'))\n        msg.send_headers()\n\n        msg.write(b'd')\n        msg.write(b'ata')\n        msg.write_eof()\n\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertEqual(\n            b'da', content.split(b'\\r\\n\\r\\n', 1)[-1])\n\n    def test_write_payload_chunked_filter(self):\n        write = self.transport.write = unittest.mock.Mock()\n\n        msg = protocol.Response(self.transport, 200)\n        msg.send_headers()\n\n        msg.add_chunking_filter(2)\n        msg.write(b'data')\n        msg.write_eof()\n\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertTrue(content.endswith(b'2\\r\\nda\\r\\n2\\r\\nta\\r\\n0\\r\\n\\r\\n'))\n\n    def test_write_payload_chunked_filter_mutiple_chunks(self):\n        write = self.transport.write = unittest.mock.Mock()\n        msg = protocol.Response(self.transport, 200)\n        msg.send_headers()\n\n        msg.add_chunking_filter(2)\n        msg.write(b'data1')\n        msg.write(b'data2')\n        msg.write_eof()\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertTrue(content.endswith(\n            b'2\\r\\nda\\r\\n2\\r\\nta\\r\\n2\\r\\n1d\\r\\n2\\r\\nat\\r\\n'\n            b'2\\r\\na2\\r\\n0\\r\\n\\r\\n'))\n\n    def test_write_payload_chunked_large_chunk(self):\n        write = self.transport.write = unittest.mock.Mock()\n        msg = protocol.Response(self.transport, 200)\n        msg.send_headers()\n\n        msg.add_chunking_filter(1024)\n        msg.write(b'data')\n        msg.write_eof()\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertTrue(content.endswith(b'4\\r\\ndata\\r\\n0\\r\\n\\r\\n'))\n\n    _comp = zlib.compressobj(wbits=-zlib.MAX_WBITS)\n    _COMPRESSED = b''.join([_comp.compress(b'data'), _comp.flush()])\n\n    def test_write_payload_deflate_filter(self):\n        write = self.transport.write = unittest.mock.Mock()\n        msg = protocol.Response(self.transport, 200)\n        msg.add_headers(('content-length', '{}'.format(len(self._COMPRESSED))))\n        msg.send_headers()\n\n        msg.add_compression_filter('deflate')\n        msg.write(b'data')\n        msg.write_eof()\n\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertEqual(\n            self._COMPRESSED, content.split(b'\\r\\n\\r\\n', 1)[-1])\n\n    def test_write_payload_deflate_and_chunked(self):\n        write = self.transport.write = unittest.mock.Mock()\n        msg = protocol.Response(self.transport, 200)\n        msg.send_headers()\n\n        msg.add_compression_filter('deflate')\n        msg.add_chunking_filter(2)\n\n        msg.write(b'data')\n        msg.write_eof()\n\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertEqual(\n            b'2\\r\\nKI\\r\\n2\\r\\n,I\\r\\n2\\r\\n\\x04\\x00\\r\\n0\\r\\n\\r\\n',\n            content.split(b'\\r\\n\\r\\n', 1)[-1])\n\n    def test_write_payload_chunked_and_deflate(self):\n        write = self.transport.write = unittest.mock.Mock()\n        msg = protocol.Response(self.transport, 200)\n        msg.add_headers(('content-length', '{}'.format(len(self._COMPRESSED))))\n\n        msg.add_chunking_filter(2)\n        msg.add_compression_filter('deflate')\n        msg.send_headers()\n\n        msg.write(b'data')\n        msg.write_eof()\n\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertEqual(\n            self._COMPRESSED, content.split(b'\\r\\n\\r\\n', 1)[-1])\n\n    def test_write_drain(self):\n        msg = protocol.Response(self.transport, 200, http_version=(1, 0))\n        msg._send_headers = True\n\n        msg.write(b'1' * (64 * 1024 * 2))\n        self.assertFalse(self.transport.drain.called)\n\n        msg.write(b'1', drain=True)\n        self.assertTrue(self.transport.drain.called)\n        self.assertEqual(msg._output_size, 0)\n\n    def test_dont_override_request_headers_with_default_values(self):\n        msg = protocol.Request(\n            self.transport, 'GET', '/index.html', close=True)\n        msg.add_header('USER-AGENT', 'custom')\n        msg._add_default_headers()\n        self.assertEqual('custom', msg.headers['USER-AGENT'])\n\n    def test_dont_override_response_headers_with_default_values(self):\n        msg = protocol.Response(self.transport, 200, http_version=(1, 0))\n        msg.add_header('DATE', 'now')\n        msg.add_header('SERVER', 'custom')\n        msg._add_default_headers()\n        self.assertEqual('custom', msg.headers['SERVER'])\n        self.assertEqual('now', msg.headers['DATE'])",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 11,
                            "end_lineno": 497,
                            "parent": null
                        }
                    ],
                    "added_entities": [],
                    "deleted_entities": []
                }
            ]
        }
    ],
    "old_commit_hash": "618335186f22834c0d8daabcf53ccf44d42488a2^",
    "new_commit_hash": "618335186f22834c0d8daabcf53ccf44d42488a2",
    "commit_message": "Fix deflate compression when writing a chunked response\n\nEnsure all chunks have a size greater than 0, to avoid indicating end of\nfile prematurely.",
    "commit_date": "2015-06-04T17:13:25-07:00",
    "metadata": {}
}
{
    "repo_name": "aiohttp",
    "new_commit_hash": "618335186f22834c0d8daabcf53ccf44d42488a2",
    "test_file_codes": [
        "\"\"\"Tests for aiohttp/protocol.py\"\"\"\n\nimport unittest\nimport unittest.mock\nimport asyncio\nimport zlib\n\nfrom aiohttp import hdrs, protocol\n\n\nclass TestHttpMessage(unittest.TestCase):\n\n    def setUp(self):\n        self.transport = unittest.mock.Mock()\n        asyncio.set_event_loop(None)\n\n    def test_start_request(self):\n        msg = protocol.Request(\n            self.transport, 'GET', '/index.html', close=True)\n\n        self.assertIs(msg.transport, self.transport)\n        self.assertIsNone(msg.status)\n        self.assertTrue(msg.closing)\n        self.assertEqual(msg.status_line, 'GET /index.html HTTP/1.1\\r\\n')\n\n    def test_start_response(self):\n        msg = protocol.Response(self.transport, 200, close=True)\n\n        self.assertIs(msg.transport, self.transport)\n        self.assertEqual(msg.status, 200)\n        self.assertEqual(msg.reason, \"OK\")\n        self.assertTrue(msg.closing)\n        self.assertEqual(msg.status_line, 'HTTP/1.1 200 OK\\r\\n')\n\n    def test_start_response_with_reason(self):\n        msg = protocol.Response(self.transport, 333, close=True,\n                                reason=\"My Reason\")\n\n        self.assertEqual(msg.status, 333)\n        self.assertEqual(msg.reason, \"My Reason\")\n        self.assertEqual(msg.status_line, 'HTTP/1.1 333 My Reason\\r\\n')\n\n    def test_start_response_with_unknown_reason(self):\n        msg = protocol.Response(self.transport, 777, close=True)\n\n        self.assertEqual(msg.status, 777)\n        self.assertEqual(msg.reason, \"777\")\n        self.assertEqual(msg.status_line, 'HTTP/1.1 777 777\\r\\n')\n\n    def test_force_close(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertFalse(msg.closing)\n        msg.force_close()\n        self.assertTrue(msg.closing)\n\n    def test_force_chunked(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertFalse(msg.chunked)\n        msg.enable_chunked_encoding()\n        self.assertTrue(msg.chunked)\n\n    def test_keep_alive(self):\n        msg = protocol.Response(self.transport, 200, close=True)\n        self.assertFalse(msg.keep_alive())\n        msg.keepalive = True\n        self.assertTrue(msg.keep_alive())\n\n        msg.force_close()\n        self.assertFalse(msg.keep_alive())\n\n    def test_keep_alive_http10(self):\n        msg = protocol.Response(self.transport, 200, http_version=(1, 0))\n        self.assertFalse(msg.keepalive)\n        self.assertFalse(msg.keep_alive())\n\n        msg = protocol.Response(self.transport, 200, http_version=(1, 1))\n        self.assertIsNone(msg.keepalive)\n\n    def test_add_header(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertEqual([], list(msg.headers))\n\n        msg.add_header('content-type', 'plain/html')\n        self.assertEqual(\n            [('CONTENT-TYPE', 'plain/html')], list(msg.headers.items()))\n\n    def test_add_header_with_spaces(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertEqual([], list(msg.headers))\n\n        msg.add_header('content-type', '  plain/html  ')\n        self.assertEqual(\n            [('CONTENT-TYPE', 'plain/html')], list(msg.headers.items()))\n\n    def test_add_header_non_ascii(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertEqual([], list(msg.headers))\n\n        with self.assertRaises(AssertionError):\n            msg.add_header('тип-контента', 'текст/плейн')\n\n    def test_add_header_invalid_value_type(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertEqual([], list(msg.headers))\n\n        with self.assertRaises(AssertionError):\n            msg.add_header('content-type', {'test': 'plain'})\n\n        with self.assertRaises(AssertionError):\n            msg.add_header(list('content-type'), 'text/plain')\n\n    def test_add_headers(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertEqual([], list(msg.headers))\n\n        msg.add_headers(('content-type', 'plain/html'))\n        self.assertEqual(\n            [('CONTENT-TYPE', 'plain/html')], list(msg.headers.items()))\n\n    def test_add_headers_length(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertIsNone(msg.length)\n\n        msg.add_headers(('content-length', '42'))\n        self.assertEqual(42, msg.length)\n\n    def test_add_headers_upgrade(self):\n        msg = protocol.Response(self.transport, 200)\n        self.assertFalse(msg.upgrade)\n\n        msg.add_headers(('connection', 'upgrade'))\n        self.assertTrue(msg.upgrade)\n\n    def test_add_headers_upgrade_websocket(self):\n        msg = protocol.Response(self.transport, 200)\n\n        msg.add_headers(('upgrade', 'test'))\n        self.assertEqual([], list(msg.headers))\n\n        msg.add_headers(('upgrade', 'websocket'))\n        self.assertEqual(\n            [('UPGRADE', 'websocket')], list(msg.headers.items()))\n\n    def test_add_headers_connection_keepalive(self):\n        msg = protocol.Response(self.transport, 200)\n\n        msg.add_headers(('connection', 'keep-alive'))\n        self.assertEqual([], list(msg.headers))\n        self.assertTrue(msg.keepalive)\n\n        msg.add_headers(('connection', 'close'))\n        self.assertFalse(msg.keepalive)\n\n    def test_add_headers_hop_headers(self):\n        msg = protocol.Response(self.transport, 200)\n        msg.HOP_HEADERS = (hdrs.TRANSFER_ENCODING,)\n\n        msg.add_headers(('connection', 'test'), ('transfer-encoding', 't'))\n        self.assertEqual([], list(msg.headers))\n\n    def test_default_headers(self):\n        msg = protocol.Response(self.transport, 200)\n        msg._add_default_headers()\n\n        headers = [r for r, _ in msg.headers.items()]\n        self.assertIn('DATE', headers)\n        self.assertIn('CONNECTION', headers)\n\n    def test_default_headers_server(self):\n        msg = protocol.Response(self.transport, 200)\n        msg._add_default_headers()\n\n        self.assertIn('SERVER', msg.headers)\n\n    def test_default_headers_useragent(self):\n        msg = protocol.Request(self.transport, 'GET', '/')\n        msg._add_default_headers()\n\n        self.assertNotIn('SERVER', msg.headers)\n        self.assertIn('USER-AGENT', msg.headers)\n\n    def test_default_headers_useragent_custom(self):\n        msg = protocol.Request(self.transport, 'GET', '/')\n        msg.add_headers(('user-agent', 'my custom agent'))\n        msg._add_default_headers()\n\n        headers = [r for r, _ in msg.headers.items()\n                   if r.lower() == 'user-agent']\n        self.assertEqual(len(headers), 1)\n\n    def test_default_headers_chunked(self):\n        msg = protocol.Response(self.transport, 200)\n        msg._add_default_headers()\n\n        headers = [r for r, _ in msg.headers.items()]\n        self.assertNotIn('TRANSFER-ENCODING', headers)\n\n        msg = protocol.Response(self.transport, 200)\n        msg.enable_chunked_encoding()\n        msg.send_headers()\n\n        headers = [r for r, _ in msg.headers.items()]\n        self.assertIn('TRANSFER-ENCODING', headers)\n\n    def test_default_headers_connection_upgrade(self):\n        msg = protocol.Response(self.transport, 200)\n        msg.upgrade = True\n        msg._add_default_headers()\n\n        headers = [r for r in msg.headers.items() if r[0] == 'CONNECTION']\n        self.assertEqual([('CONNECTION', 'upgrade')], headers)\n\n    def test_default_headers_connection_close(self):\n        msg = protocol.Response(self.transport, 200)\n        msg.force_close()\n        msg._add_default_headers()\n\n        headers = [r for r in msg.headers.items() if r[0] == 'CONNECTION']\n        self.assertEqual([('CONNECTION', 'close')], headers)\n\n    def test_default_headers_connection_keep_alive(self):\n        msg = protocol.Response(self.transport, 200)\n        msg.keepalive = True\n        msg._add_default_headers()\n\n        headers = [r for r in msg.headers.items() if r[0] == 'CONNECTION']\n        self.assertEqual([('CONNECTION', 'keep-alive')], headers)\n\n    def test_send_headers(self):\n        write = self.transport.write = unittest.mock.Mock()\n\n        msg = protocol.Response(self.transport, 200)\n        msg.add_headers(('content-type', 'plain/html'))\n        self.assertFalse(msg.is_headers_sent())\n\n        msg.send_headers()\n\n        content = b''.join([arg[1][0] for arg in list(write.mock_calls)])\n\n        self.assertTrue(content.startswith(b'HTTP/1.1 200 OK\\r\\n'))\n        self.assertIn(b'CONTENT-TYPE: plain/html', content)\n        self.assertTrue(msg.headers_sent)\n        self.assertTrue(msg.is_headers_sent())\n        # cleanup\n        msg.writer.close()\n\n    def test_send_headers_non_ascii(self):\n        write = self.transport.write = unittest.mock.Mock()\n\n        msg = protocol.Response(self.transport, 200)\n        msg.add_headers(('x-header', 'текст'))\n        self.assertFalse(msg.is_headers_sent())\n\n        msg.send_headers()\n\n        content = b''.join([arg[1][0] for arg in list(write.mock_calls)])\n\n        self.assertTrue(content.startswith(b'HTTP/1.1 200 OK\\r\\n'))\n        self.assertIn(b'X-HEADER: \\xd1\\x82\\xd0\\xb5\\xd0\\xba\\xd1\\x81\\xd1\\x82',\n                      content)\n        self.assertTrue(msg.headers_sent)\n        self.assertTrue(msg.is_headers_sent())\n        # cleanup\n        msg.writer.close()\n\n    def test_send_headers_nomore_add(self):\n        msg = protocol.Response(self.transport, 200)\n        msg.add_headers(('content-type', 'plain/html'))\n        msg.send_headers()\n\n        self.assertRaises(AssertionError,\n                          msg.add_header, 'content-type', 'plain/html')\n        # cleanup\n        msg.writer.close()\n\n    def test_prepare_length(self):\n        msg = protocol.Response(self.transport, 200)\n        w_l_p = msg._write_length_payload = unittest.mock.Mock()\n        w_l_p.return_value = iter([1, 2, 3])\n\n        msg.add_headers(('content-length', '42'))\n        msg.send_headers()\n\n        self.assertTrue(w_l_p.called)\n        self.assertEqual((42,), w_l_p.call_args[0])\n\n    def test_prepare_chunked_force(self):\n        msg = protocol.Response(self.transport, 200)\n        msg.enable_chunked_encoding()\n\n        chunked = msg._write_chunked_payload = unittest.mock.Mock()\n        chunked.return_value = iter([1, 2, 3])\n\n        msg.add_headers(('content-length', '42'))\n        msg.send_headers()\n        self.assertTrue(chunked.called)\n\n    def test_prepare_chunked_no_length(self):\n        msg = protocol.Response(self.transport, 200)\n\n        chunked = msg._write_chunked_payload = unittest.mock.Mock()\n        chunked.return_value = iter([1, 2, 3])\n\n        msg.send_headers()\n        self.assertTrue(chunked.called)\n\n    def test_prepare_eof(self):\n        msg = protocol.Response(self.transport, 200, http_version=(1, 0))\n\n        eof = msg._write_eof_payload = unittest.mock.Mock()\n        eof.return_value = iter([1, 2, 3])\n\n        msg.send_headers()\n        self.assertTrue(eof.called)\n\n    def test_write_auto_send_headers(self):\n        msg = protocol.Response(self.transport, 200, http_version=(1, 0))\n        msg._send_headers = True\n\n        msg.write(b'data1')\n        self.assertTrue(msg.headers_sent)\n        # cleanup\n        msg.writer.close()\n\n    def test_write_payload_eof(self):\n        write = self.transport.write = unittest.mock.Mock()\n        msg = protocol.Response(self.transport, 200, http_version=(1, 0))\n        msg.send_headers()\n\n        msg.write(b'data1')\n        self.assertTrue(msg.headers_sent)\n\n        msg.write(b'data2')\n        msg.write_eof()\n\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertEqual(\n            b'data1data2', content.split(b'\\r\\n\\r\\n', 1)[-1])\n\n    def test_write_payload_chunked(self):\n        write = self.transport.write = unittest.mock.Mock()\n\n        msg = protocol.Response(self.transport, 200)\n        msg.enable_chunked_encoding()\n        msg.send_headers()\n\n        msg.write(b'data')\n        msg.write_eof()\n\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertEqual(\n            b'4\\r\\ndata\\r\\n0\\r\\n\\r\\n',\n            content.split(b'\\r\\n\\r\\n', 1)[-1])\n\n    def test_write_payload_chunked_multiple(self):\n        write = self.transport.write = unittest.mock.Mock()\n\n        msg = protocol.Response(self.transport, 200)\n        msg.enable_chunked_encoding()\n        msg.send_headers()\n\n        msg.write(b'data1')\n        msg.write(b'data2')\n        msg.write_eof()\n\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertEqual(\n            b'5\\r\\ndata1\\r\\n5\\r\\ndata2\\r\\n0\\r\\n\\r\\n',\n            content.split(b'\\r\\n\\r\\n', 1)[-1])\n\n    def test_write_payload_length(self):\n        write = self.transport.write = unittest.mock.Mock()\n\n        msg = protocol.Response(self.transport, 200)\n        msg.add_headers(('content-length', '2'))\n        msg.send_headers()\n\n        msg.write(b'd')\n        msg.write(b'ata')\n        msg.write_eof()\n\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertEqual(\n            b'da', content.split(b'\\r\\n\\r\\n', 1)[-1])\n\n    def test_write_payload_chunked_filter(self):\n        write = self.transport.write = unittest.mock.Mock()\n\n        msg = protocol.Response(self.transport, 200)\n        msg.send_headers()\n\n        msg.add_chunking_filter(2)\n        msg.write(b'data')\n        msg.write_eof()\n\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertTrue(content.endswith(b'2\\r\\nda\\r\\n2\\r\\nta\\r\\n0\\r\\n\\r\\n'))\n\n    def test_write_payload_chunked_filter_mutiple_chunks(self):\n        write = self.transport.write = unittest.mock.Mock()\n        msg = protocol.Response(self.transport, 200)\n        msg.send_headers()\n\n        msg.add_chunking_filter(2)\n        msg.write(b'data1')\n        msg.write(b'data2')\n        msg.write_eof()\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertTrue(content.endswith(\n            b'2\\r\\nda\\r\\n2\\r\\nta\\r\\n2\\r\\n1d\\r\\n2\\r\\nat\\r\\n'\n            b'2\\r\\na2\\r\\n0\\r\\n\\r\\n'))\n\n    def test_write_payload_chunked_large_chunk(self):\n        write = self.transport.write = unittest.mock.Mock()\n        msg = protocol.Response(self.transport, 200)\n        msg.send_headers()\n\n        msg.add_chunking_filter(1024)\n        msg.write(b'data')\n        msg.write_eof()\n        content = b''.join([c[1][0] for c in list(write.mock_calls)])\n        self.assertTrue(content.endswith(b'4\\r\\ndata\\r\\n0\\r\\n\\r\\n'))\n\n    _comp = zlib.compressobj(wbits=-zlib.MAX_WBITS)\n    _COMPRESSED = b''.join([_comp.compress(b'data'), _comp.flush()])\n\n    def test_write_payload_deflate_filter(self):\n        write = self.transport.write = unittest.mock.Mock()\n        msg = protocol.Response(self.transport, 200)\n        msg.add_headers(('content-length', '{}'.format(len(self._COMPRESSED))))\n        msg.send_headers()\n\n        msg.add_compression_filter('deflate')\n        msg.write(b'data')\n        msg.write_eof()\n\n        chunks = [c[1][0] for c in list(write.mock_calls)]\n        self.assertTrue(all(chunks))\n        content = b''.join(chunks)\n        self.assertEqual(\n            self._COMPRESSED, content.split(b'\\r\\n\\r\\n', 1)[-1])\n\n    def test_write_payload_deflate_and_chunked(self):\n        write = self.transport.write = unittest.mock.Mock()\n        msg = protocol.Response(self.transport, 200)\n        msg.send_headers()\n\n        msg.add_compression_filter('deflate')\n        msg.add_chunking_filter(2)\n\n        msg.write(b'data')\n        msg.write_eof()\n\n        chunks = [c[1][0] for c in list(write.mock_calls)]\n        self.assertTrue(all(chunks))\n        content = b''.join(chunks)\n        self.assertEqual(\n            b'2\\r\\nKI\\r\\n2\\r\\n,I\\r\\n2\\r\\n\\x04\\x00\\r\\n0\\r\\n\\r\\n',\n            content.split(b'\\r\\n\\r\\n', 1)[-1])\n\n    def test_write_payload_chunked_and_deflate(self):\n        write = self.transport.write = unittest.mock.Mock()\n        msg = protocol.Response(self.transport, 200)\n        msg.add_headers(('content-length', '{}'.format(len(self._COMPRESSED))))\n\n        msg.add_chunking_filter(2)\n        msg.add_compression_filter('deflate')\n        msg.send_headers()\n\n        msg.write(b'data')\n        msg.write_eof()\n\n        chunks = [c[1][0] for c in list(write.mock_calls)]\n        self.assertTrue(all(chunks))\n        content = b''.join(chunks)\n        self.assertEqual(\n            self._COMPRESSED, content.split(b'\\r\\n\\r\\n', 1)[-1])\n\n    def test_write_drain(self):\n        msg = protocol.Response(self.transport, 200, http_version=(1, 0))\n        msg._send_headers = True\n\n        msg.write(b'1' * (64 * 1024 * 2))\n        self.assertFalse(self.transport.drain.called)\n\n        msg.write(b'1', drain=True)\n        self.assertTrue(self.transport.drain.called)\n        self.assertEqual(msg._output_size, 0)\n\n    def test_dont_override_request_headers_with_default_values(self):\n        msg = protocol.Request(\n            self.transport, 'GET', '/index.html', close=True)\n        msg.add_header('USER-AGENT', 'custom')\n        msg._add_default_headers()\n        self.assertEqual('custom', msg.headers['USER-AGENT'])\n\n    def test_dont_override_response_headers_with_default_values(self):\n        msg = protocol.Response(self.transport, 200, http_version=(1, 0))\n        msg.add_header('DATE', 'now')\n        msg.add_header('SERVER', 'custom')\n        msg._add_default_headers()\n        self.assertEqual('custom', msg.headers['SERVER'])\n        self.assertEqual('now', msg.headers['DATE'])\n"
    ],
    "test_file_names": [
        "test_1.py"
    ],
    "setup_res_code": 0,
    "setup_res_stdout": "Transforming aiohttp/worker.py\nTransforming aiohttp/client_reqrep.py\nTransforming aiohttp/server.py\nTransforming aiohttp/client.py\n",
    "setup_res_stderr": "Using CPython 3.9.21\nCreating virtual environment at: .venv\nActivate with: source .venv/bin/activate\nmake: *** No rule to make target '.develop'.  Stop.\nResolved 26 packages in 43ms\nInstalled 26 packages in 32ms\n + async-generator==1.10\n + async-timeout==5.0.1\n + brotlipy==0.7.0\n + cffi==1.17.1\n + chardet==5.2.0\n + coverage==7.6.10\n + cryptography==44.0.0\n + cython==3.0.11\n + exceptiongroup==1.2.2\n + gunicorn==23.0.0\n + idna==3.10\n + iniconfig==2.0.0\n + multdict==0.0.5\n + multidict==6.1.0\n + packaging==24.2\n + pluggy==1.5.0\n + propcache==0.2.1\n + pycparser==2.22\n + pytest==8.3.4\n + pytest-asyncio==0.25.0\n + pytest-cov==6.0.0\n + pytest-mock==3.14.0\n + tomli==2.2.1\n + trustme==1.2.1\n + typing-extensions==4.12.2\n + yarl==1.18.3\n",
    "new_commit_res_code": 0,
    "new_commit_res_stdout": "============================= test session starts ==============================\nplatform linux -- Python 3.9.21, pytest-8.3.4, pluggy-1.5.0\nrootdir: /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_618335186f22834c0d8daabcf53ccf44d42488a2\nplugins: asyncio-0.25.0, mock-3.14.0, cov-6.0.0\nasyncio: mode=strict, asyncio_default_fixture_loop_scope=None\ncollected 47 items\n\nr2e_tests/test_1.py ...............................................      [100%]\n\n==================================== PASSES ====================================\n=========================== short test summary info ============================\nPASSED r2e_tests/test_1.py::TestHttpMessage::test_add_header\nPASSED r2e_tests/test_1.py::TestHttpMessage::test_add_header_invalid_value_type\nPASSED r2e_tests/test_1.py::TestHttpMessage::test_add_header_non_ascii\nPASSED r2e_tests/test_1.py::TestHttpMessage::test_add_header_with_spaces\nPASSED r2e_tests/test_1.py::TestHttpMessage::test_add_headers\nPASSED r2e_tests/test_1.py::TestHttpMessage::test_add_headers_connection_keepalive\nPASSED r2e_tests/test_1.py::TestHttpMessage::test_add_headers_hop_headers\nPASSED r2e_tests/test_1.py::TestHttpMessage::test_add_headers_length\nPASSED r2e_tests/test_1.py::TestHttpMessage::test_add_headers_upgrade\nPASSED r2e_tests/test_1.py::TestHttpMessage::test_add_headers_upgrade_websocket\nPASSED r2e_tests/test_1.py::TestHttpMessage::test_default_headers\nPASSED r2e_tests/test_1.py::TestHttpMessage::test_default_headers_chunked\nPASSED r2e_tests/test_1.py::TestHttpMessage::test_default_headers_connection_close\nPASSED r2e_tests/test_1.py::TestHttpMessage::test_default_headers_connection_keep_alive\nPASSED r2e_tests/test_1.py::TestHttpMessage::test_default_headers_connection_upgrade\nPASSED r2e_tests/test_1.py::TestHttpMessage::test_default_headers_server\nPASSED r2e_tests/test_1.py::TestHttpMessage::test_default_headers_useragent\nPASSED r2e_tests/test_1.py::TestHttpMessage::test_default_headers_useragent_custom\nPASSED r2e_tests/test_1.py::TestHttpMessage::test_dont_override_request_headers_with_default_values\nPASSED r2e_tests/test_1.py::TestHttpMessage::test_dont_override_response_headers_with_default_values\nPASSED r2e_tests/test_1.py::TestHttpMessage::test_force_chunked\nPASSED r2e_tests/test_1.py::TestHttpMessage::test_force_close\nPASSED r2e_tests/test_1.py::TestHttpMessage::test_keep_alive\nPASSED r2e_tests/test_1.py::TestHttpMessage::test_keep_alive_http10\nPASSED r2e_tests/test_1.py::TestHttpMessage::test_prepare_chunked_force\nPASSED r2e_tests/test_1.py::TestHttpMessage::test_prepare_chunked_no_length\nPASSED r2e_tests/test_1.py::TestHttpMessage::test_prepare_eof\nPASSED r2e_tests/test_1.py::TestHttpMessage::test_prepare_length\nPASSED r2e_tests/test_1.py::TestHttpMessage::test_send_headers\nPASSED r2e_tests/test_1.py::TestHttpMessage::test_send_headers_nomore_add\nPASSED r2e_tests/test_1.py::TestHttpMessage::test_send_headers_non_ascii\nPASSED r2e_tests/test_1.py::TestHttpMessage::test_start_request\nPASSED r2e_tests/test_1.py::TestHttpMessage::test_start_response\nPASSED r2e_tests/test_1.py::TestHttpMessage::test_start_response_with_reason\nPASSED r2e_tests/test_1.py::TestHttpMessage::test_start_response_with_unknown_reason\nPASSED r2e_tests/test_1.py::TestHttpMessage::test_write_auto_send_headers\nPASSED r2e_tests/test_1.py::TestHttpMessage::test_write_drain\nPASSED r2e_tests/test_1.py::TestHttpMessage::test_write_payload_chunked\nPASSED r2e_tests/test_1.py::TestHttpMessage::test_write_payload_chunked_and_deflate\nPASSED r2e_tests/test_1.py::TestHttpMessage::test_write_payload_chunked_filter\nPASSED r2e_tests/test_1.py::TestHttpMessage::test_write_payload_chunked_filter_mutiple_chunks\nPASSED r2e_tests/test_1.py::TestHttpMessage::test_write_payload_chunked_large_chunk\nPASSED r2e_tests/test_1.py::TestHttpMessage::test_write_payload_chunked_multiple\nPASSED r2e_tests/test_1.py::TestHttpMessage::test_write_payload_deflate_and_chunked\nPASSED r2e_tests/test_1.py::TestHttpMessage::test_write_payload_deflate_filter\nPASSED r2e_tests/test_1.py::TestHttpMessage::test_write_payload_eof\nPASSED r2e_tests/test_1.py::TestHttpMessage::test_write_payload_length\n============================== 47 passed in 0.45s ==============================\n",
    "new_commit_res_stderr": "/home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_618335186f22834c0d8daabcf53ccf44d42488a2/.venv/lib/python3.9/site-packages/pytest_asyncio/plugin.py:207: PytestDeprecationWarning: The configuration option \"asyncio_default_fixture_loop_scope\" is unset.\nThe event loop scope for asynchronous fixtures will default to the fixture caching scope. Future versions of pytest-asyncio will default the loop scope for asynchronous fixtures to function scope. Set the default fixture loop scope explicitly in order to avoid unexpected behavior in the future. Valid fixture loop scopes are: \"function\", \"class\", \"module\", \"package\", \"session\"\n\n  warnings.warn(PytestDeprecationWarning(_DEFAULT_FIXTURE_LOOP_SCOPE_UNSET))\n",
    "old_commit_res_code": 1,
    "old_commit_res_stdout": "============================= test session starts ==============================\nplatform linux -- Python 3.9.21, pytest-8.3.4, pluggy-1.5.0\nrootdir: /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_618335186f22834c0d8daabcf53ccf44d42488a2\nplugins: asyncio-0.25.0, mock-3.14.0, cov-6.0.0\nasyncio: mode=strict, asyncio_default_fixture_loop_scope=None\ncollected 47 items\n\nr2e_tests/test_1.py ......................................F.....F..      [100%]\n\n=================================== FAILURES ===================================\n____________ TestHttpMessage.test_write_payload_chunked_and_deflate ____________\n\nself = <r2e_tests.test_1.TestHttpMessage testMethod=test_write_payload_chunked_and_deflate>\n\n    def test_write_payload_chunked_and_deflate(self):\n        write = self.transport.write = unittest.mock.Mock()\n        msg = protocol.Response(self.transport, 200)\n        msg.add_headers(('content-length', '{}'.format(len(self._COMPRESSED))))\n    \n        msg.add_chunking_filter(2)\n        msg.add_compression_filter('deflate')\n        msg.send_headers()\n    \n        msg.write(b'data')\n        msg.write_eof()\n    \n        chunks = [c[1][0] for c in list(write.mock_calls)]\n>       self.assertTrue(all(chunks))\nE       AssertionError: False is not true\n\nr2e_tests/test_1.py:474: AssertionError\n______________ TestHttpMessage.test_write_payload_deflate_filter _______________\n\nself = <r2e_tests.test_1.TestHttpMessage testMethod=test_write_payload_deflate_filter>\n\n    def test_write_payload_deflate_filter(self):\n        write = self.transport.write = unittest.mock.Mock()\n        msg = protocol.Response(self.transport, 200)\n        msg.add_headers(('content-length', '{}'.format(len(self._COMPRESSED))))\n        msg.send_headers()\n    \n        msg.add_compression_filter('deflate')\n        msg.write(b'data')\n        msg.write_eof()\n    \n        chunks = [c[1][0] for c in list(write.mock_calls)]\n>       self.assertTrue(all(chunks))\nE       AssertionError: False is not true\n\nr2e_tests/test_1.py:438: AssertionError\n==================================== PASSES ====================================\n=========================== short test summary info ============================\nPASSED r2e_tests/test_1.py::TestHttpMessage::test_add_header\nPASSED r2e_tests/test_1.py::TestHttpMessage::test_add_header_invalid_value_type\nPASSED r2e_tests/test_1.py::TestHttpMessage::test_add_header_non_ascii\nPASSED r2e_tests/test_1.py::TestHttpMessage::test_add_header_with_spaces\nPASSED r2e_tests/test_1.py::TestHttpMessage::test_add_headers\nPASSED r2e_tests/test_1.py::TestHttpMessage::test_add_headers_connection_keepalive\nPASSED r2e_tests/test_1.py::TestHttpMessage::test_add_headers_hop_headers\nPASSED r2e_tests/test_1.py::TestHttpMessage::test_add_headers_length\nPASSED r2e_tests/test_1.py::TestHttpMessage::test_add_headers_upgrade\nPASSED r2e_tests/test_1.py::TestHttpMessage::test_add_headers_upgrade_websocket\nPASSED r2e_tests/test_1.py::TestHttpMessage::test_default_headers\nPASSED r2e_tests/test_1.py::TestHttpMessage::test_default_headers_chunked\nPASSED r2e_tests/test_1.py::TestHttpMessage::test_default_headers_connection_close\nPASSED r2e_tests/test_1.py::TestHttpMessage::test_default_headers_connection_keep_alive\nPASSED r2e_tests/test_1.py::TestHttpMessage::test_default_headers_connection_upgrade\nPASSED r2e_tests/test_1.py::TestHttpMessage::test_default_headers_server\nPASSED r2e_tests/test_1.py::TestHttpMessage::test_default_headers_useragent\nPASSED r2e_tests/test_1.py::TestHttpMessage::test_default_headers_useragent_custom\nPASSED r2e_tests/test_1.py::TestHttpMessage::test_dont_override_request_headers_with_default_values\nPASSED r2e_tests/test_1.py::TestHttpMessage::test_dont_override_response_headers_with_default_values\nPASSED r2e_tests/test_1.py::TestHttpMessage::test_force_chunked\nPASSED r2e_tests/test_1.py::TestHttpMessage::test_force_close\nPASSED r2e_tests/test_1.py::TestHttpMessage::test_keep_alive\nPASSED r2e_tests/test_1.py::TestHttpMessage::test_keep_alive_http10\nPASSED r2e_tests/test_1.py::TestHttpMessage::test_prepare_chunked_force\nPASSED r2e_tests/test_1.py::TestHttpMessage::test_prepare_chunked_no_length\nPASSED r2e_tests/test_1.py::TestHttpMessage::test_prepare_eof\nPASSED r2e_tests/test_1.py::TestHttpMessage::test_prepare_length\nPASSED r2e_tests/test_1.py::TestHttpMessage::test_send_headers\nPASSED r2e_tests/test_1.py::TestHttpMessage::test_send_headers_nomore_add\nPASSED r2e_tests/test_1.py::TestHttpMessage::test_send_headers_non_ascii\nPASSED r2e_tests/test_1.py::TestHttpMessage::test_start_request\nPASSED r2e_tests/test_1.py::TestHttpMessage::test_start_response\nPASSED r2e_tests/test_1.py::TestHttpMessage::test_start_response_with_reason\nPASSED r2e_tests/test_1.py::TestHttpMessage::test_start_response_with_unknown_reason\nPASSED r2e_tests/test_1.py::TestHttpMessage::test_write_auto_send_headers\nPASSED r2e_tests/test_1.py::TestHttpMessage::test_write_drain\nPASSED r2e_tests/test_1.py::TestHttpMessage::test_write_payload_chunked\nPASSED r2e_tests/test_1.py::TestHttpMessage::test_write_payload_chunked_filter\nPASSED r2e_tests/test_1.py::TestHttpMessage::test_write_payload_chunked_filter_mutiple_chunks\nPASSED r2e_tests/test_1.py::TestHttpMessage::test_write_payload_chunked_large_chunk\nPASSED r2e_tests/test_1.py::TestHttpMessage::test_write_payload_chunked_multiple\nPASSED r2e_tests/test_1.py::TestHttpMessage::test_write_payload_deflate_and_chunked\nPASSED r2e_tests/test_1.py::TestHttpMessage::test_write_payload_eof\nPASSED r2e_tests/test_1.py::TestHttpMessage::test_write_payload_length\nFAILED r2e_tests/test_1.py::TestHttpMessage::test_write_payload_chunked_and_deflate\nFAILED r2e_tests/test_1.py::TestHttpMessage::test_write_payload_deflate_filter\n========================= 2 failed, 45 passed in 0.17s =========================\n",
    "old_commit_res_stderr": "/home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_618335186f22834c0d8daabcf53ccf44d42488a2/.venv/lib/python3.9/site-packages/pytest_asyncio/plugin.py:207: PytestDeprecationWarning: The configuration option \"asyncio_default_fixture_loop_scope\" is unset.\nThe event loop scope for asynchronous fixtures will default to the fixture caching scope. Future versions of pytest-asyncio will default the loop scope for asynchronous fixtures to function scope. Set the default fixture loop scope explicitly in order to avoid unexpected behavior in the future. Valid fixture loop scopes are: \"function\", \"class\", \"module\", \"package\", \"session\"\n\n  warnings.warn(PytestDeprecationWarning(_DEFAULT_FIXTURE_LOOP_SCOPE_UNSET))\n"
}
aiohttp/protocol.py tests/test_http_protocol.py
We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
[ISSUE]
**Title:** Deflate Compression Sends Empty Chunks in Chunked Responses, Causing Premature EOF

**Description:**
When sending a chunked HTTP response with deflate compression, some data chunks are being sent with a size of zero. This results in the response indicating the end of the file prematurely, potentially truncating the actual data.

**Example Code:**
```python
msg = protocol.Response(transport, 200)
msg.add_headers(('content-length', str(len(compressed_data))))
msg.add_chunking_filter(2)
msg.add_compression_filter('deflate')
msg.send_headers()
msg.write(b'data')
msg.write_eof()

chunks = [chunk for chunk in write.mock_calls]
assert all(chunks)  # This assertion fails because some chunks are empty
```

**Expected Behavior:**
All chunks sent in the compressed, chunked response should have a size greater than zero to ensure the entire payload is transmitted without prematurely signaling the end of the response.

**Actual Behavior:**
Some chunks are empty (`size = 0`), leading to an early EOF signal. This causes the response to end before all data is properly sent, resulting in incomplete data transmission.

[/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/protocol.py
"""Http related parsers and protocol."""

import collections
import functools
import http.server
import itertools
import re
import string
import sys
import zlib
from wsgiref.handlers import format_date_time

import aiohttp
from . import errors, hdrs
from .multidict import CIMultiDict
from .log import internal_logger

__all__ = ('HttpMessage', 'Request', 'Response',
           'HttpVersion', 'HttpVersion10', 'HttpVersion11',
           'RawRequestMessage', 'RawResponseMessage',
           'HttpPrefixParser', 'HttpRequestParser', 'HttpResponseParser',
           'HttpPayloadParser')

ASCIISET = set(string.printable)
METHRE = re.compile('[A-Z0-9$-_.]+')
VERSRE = re.compile('HTTP/(\d+).(\d+)')
HDRRE = re.compile('[\x00-\x1F\x7F()<>@,;:\[\]={} \t\\\\\"]')
CONTINUATION = (' ', '\t')
EOF_MARKER = object()
EOL_MARKER = object()
STATUS_LINE_READY = object()

RESPONSES = http.server.BaseHTTPRequestHandler.responses

HttpVersion = collections.namedtuple(
    'HttpVersion', ['major', 'minor'])
HttpVersion10 = HttpVersion(1, 0)
HttpVersion11 = HttpVersion(1, 1)

RawStatusLineMessage = collections.namedtuple(
    'RawStatusLineMessage', ['method', 'path', 'version'])

RawRequestMessage = collections.namedtuple(
    'RawRequestMessage',
    ['method', 'path', 'version', 'headers', 'should_close', 'compression'])


RawResponseMessage = collections.namedtuple(
    'RawResponseMessage',
    ['version', 'code', 'reason', 'headers', 'should_close', 'compression'])


class HttpParser:

    def __init__(self, max_line_size=8190, max_headers=32768,
                 max_field_size=8190):
        self.max_line_size = max_line_size
        self.max_headers = max_headers
        self.max_field_size = max_field_size

    def parse_headers(self, lines):
        """Parses RFC2822 headers from a stream.

        Line continuations are supported. Returns list of header name
        and value pairs. Header name is in upper case.
        """
        close_conn = None
        encoding = None
        headers = CIMultiDict()

        lines_idx = 1
        line = lines[1]

        while line:
            header_length = len(line)

            # Parse initial header name : value pair.
            try:
                name, value = line.split(':', 1)
            except ValueError:
                raise errors.InvalidHeader(line) from None

            name = name.strip(' \t').upper()
            if HDRRE.search(name):
                raise errors.InvalidHeader(name)

            # next line
            lines_idx += 1
            line = lines[lines_idx]

            # consume continuation lines
            continuation = line and line[0] in CONTINUATION

            if continuation:
                value = [value]
                while continuation:
                    header_length += len(line)
                    if header_length > self.max_field_size:
                        raise errors.LineTooLong(
                            'limit request headers fields size')
                    value.append(line)

                    # next line
                    lines_idx += 1
                    line = lines[lines_idx]
                    continuation = line[0] in CONTINUATION
                value = '\r\n'.join(value)
            else:
                if header_length > self.max_field_size:
                    raise errors.LineTooLong(
                        'limit request headers fields size')

            value = value.strip()

            # keep-alive and encoding
            if name == hdrs.CONNECTION:
                v = value.lower()
                if v == 'close':
                    close_conn = True
                elif v == 'keep-alive':
                    close_conn = False
            elif name == hdrs.CONTENT_ENCODING:
                enc = value.lower()
                if enc in ('gzip', 'deflate'):
                    encoding = enc

            headers.add(name, value)

        return headers, close_conn, encoding


class HttpPrefixParser:
    """Waits for 'HTTP' prefix (non destructive)"""

    def __init__(self, allowed_methods=()):
        self.allowed_methods = [m.upper() for m in allowed_methods]

    def __call__(self, out, buf):
        raw_data = yield from buf.waituntil(b' ', 12)
        method = raw_data.decode('ascii', 'surrogateescape').strip()

        # method
        method = method.upper()
        if not METHRE.match(method):
            raise errors.BadStatusLine(method)

        # allowed method
        if self.allowed_methods and method not in self.allowed_methods:
            raise errors.HttpMethodNotAllowed(message=method)

        out.feed_data(method, len(method))
        out.feed_eof()


class HttpRequestParser(HttpParser):
    """Read request status line. Exception errors.BadStatusLine
    could be raised in case of any errors in status line.
    Returns RawRequestMessage.
    """

    def __call__(self, out, buf):
        # read http message (request line + headers)
        try:
            raw_data = yield from buf.readuntil(
                b'\r\n\r\n', self.max_headers)
        except errors.LineLimitExceededParserError as exc:
            raise errors.LineTooLong(exc.limit) from None

        lines = raw_data.decode(
            'utf-8', 'surrogateescape').split('\r\n')

        # request line
        line = lines[0]
        try:
            method, path, version = line.split(None, 2)
        except ValueError:
            raise errors.BadStatusLine(line) from None

        # method
        method = method.upper()
        if not METHRE.match(method):
            raise errors.BadStatusLine(method)

        # version
        try:
            if version.startswith('HTTP/'):
                n1, n2 = version[5:].split('.', 1)
                version = HttpVersion(int(n1), int(n2))
            else:
                raise errors.BadStatusLine(version)
        except:
            raise errors.BadStatusLine(version)

        # read headers
        headers, close, compression = self.parse_headers(lines)
        if close is None:  # then the headers weren't set in the request
            if version <= HttpVersion10:  # HTTP 1.0 must asks to not close
                close = True
            else:  # HTTP 1.1 must ask to close.
                close = False

        out.feed_data(
            RawRequestMessage(
                method, path, version, headers, close, compression),
            len(raw_data))
        out.feed_eof()


class HttpResponseParser(HttpParser):
    """Read response status line and headers.

    BadStatusLine could be raised in case of any errors in status line.
    Returns RawResponseMessage"""

    def __call__(self, out, buf):
        # read http message (response line + headers)
        try:
            raw_data = yield from buf.readuntil(
                b'\r\n\r\n', self.max_line_size + self.max_headers)
        except errors.LineLimitExceededParserError as exc:
            raise errors.LineTooLong(exc.limit) from None

        lines = raw_data.decode(
            'utf-8', 'surrogateescape').split('\r\n')

        line = lines[0]
        try:
            version, status = line.split(None, 1)
        except ValueError:
            raise errors.BadStatusLine(line) from None
        else:
            try:
                status, reason = status.split(None, 1)
            except ValueError:
                reason = ''

        # version
        match = VERSRE.match(version)
        if match is None:
            raise errors.BadStatusLine(line)
        version = HttpVersion(int(match.group(1)), int(match.group(2)))

        # The status code is a three-digit number
        try:
            status = int(status)
        except ValueError:
            raise errors.BadStatusLine(line) from None

        if status < 100 or status > 999:
            raise errors.BadStatusLine(line)

        # read headers
        headers, close, compression = self.parse_headers(lines)

        if close is None:
            close = version <= HttpVersion10

        out.feed_data(
            RawResponseMessage(
                version, status, reason.strip(),
                headers, close, compression),
            len(raw_data))
        out.feed_eof()


class HttpPayloadParser:

    def __init__(self, message, length=None, compression=True,
                 readall=False, response_with_body=True):
        self.message = message
        self.length = length
        self.compression = compression
        self.readall = readall
        self.response_with_body = response_with_body

    def __call__(self, out, buf):
        # payload params
        length = self.message.headers.get(hdrs.CONTENT_LENGTH, self.length)
        if hdrs.SEC_WEBSOCKET_KEY1 in self.message.headers:
            length = 8

        # payload decompression wrapper
        if self.compression and self.message.compression:
            out = DeflateBuffer(out, self.message.compression)

        # payload parser
        if not self.response_with_body:
            # don't parse payload if it's not expected to be received
            pass

        elif 'chunked' in self.message.headers.get(
                hdrs.TRANSFER_ENCODING, ''):
            yield from self.parse_chunked_payload(out, buf)

        elif length is not None:
            try:
                length = int(length)
            except ValueError:
                raise errors.InvalidHeader(hdrs.CONTENT_LENGTH) from None

            if length < 0:
                raise errors.InvalidHeader(hdrs.CONTENT_LENGTH)
            elif length > 0:
                yield from self.parse_length_payload(out, buf, length)
        else:
            if self.readall and getattr(self.message, 'code', 0) != 204:
                yield from self.parse_eof_payload(out, buf)
            elif getattr(self.message, 'method', None) in ('PUT', 'POST'):
                internal_logger.warning(  # pragma: no cover
                    'Content-Length or Transfer-Encoding header is required')

        out.feed_eof()

    def parse_chunked_payload(self, out, buf):
        """Chunked transfer encoding parser."""
        while True:
            # read next chunk size
            line = yield from buf.readuntil(b'\r\n', 8192)

            i = line.find(b';')
            if i >= 0:
                line = line[:i]  # strip chunk-extensions
            else:
                line = line.strip()
            try:
                size = int(line, 16)
            except ValueError:
                raise errors.TransferEncodingError(line) from None

            if size == 0:  # eof marker
                break

            # read chunk and feed buffer
            while size:
                chunk = yield from buf.readsome(size)
                out.feed_data(chunk, len(chunk))
                size = size - len(chunk)

            # toss the CRLF at the end of the chunk
            yield from buf.skip(2)

        # read and discard trailer up to the CRLF terminator
        yield from buf.skipuntil(b'\r\n')

    def parse_length_payload(self, out, buf, length=0):
        """Read specified amount of bytes."""
        required = length
        while required:
            chunk = yield from buf.readsome(required)
            out.feed_data(chunk, len(chunk))
            required -= len(chunk)

    def parse_eof_payload(self, out, buf):
        """Read all bytes until eof."""
        try:
            while True:
                chunk = yield from buf.readsome()
                out.feed_data(chunk, len(chunk))
        except aiohttp.EofStream:
            pass


class DeflateBuffer:
    """DeflateStream decompress stream and feed data into specified stream."""

    def __init__(self, out, encoding):
        self.out = out
        zlib_mode = (16 + zlib.MAX_WBITS
                     if encoding == 'gzip' else -zlib.MAX_WBITS)

        self.zlib = zlib.decompressobj(wbits=zlib_mode)

    def feed_data(self, chunk, size):
        try:
            chunk = self.zlib.decompress(chunk)
        except Exception:
            raise errors.ContentEncodingError('deflate')

        if chunk:
            self.out.feed_data(chunk, len(chunk))

    def feed_eof(self):
        chunk = self.zlib.flush()
        self.out.feed_data(chunk, len(chunk))
        if not self.zlib.eof:
            raise errors.ContentEncodingError('deflate')

        self.out.feed_eof()


def wrap_payload_filter(func):
    """Wraps payload filter and piped filters.

    Filter is a generator that accepts arbitrary chunks of data,
    modify data and emit new stream of data.

    For example we have stream of chunks: ['1', '2', '3', '4', '5'],
    we can apply chunking filter to this stream:

    ['1', '2', '3', '4', '5']
      |
    response.add_chunking_filter(2)
      |
    ['12', '34', '5']

    It is possible to use different filters at the same time.

    For a example to compress incoming stream with 'deflate' encoding
    and then split data and emit chunks of 8192 bytes size chunks:

      >>> response.add_compression_filter('deflate')
      >>> response.add_chunking_filter(8192)

    Filters do not alter transfer encoding.

    Filter can receive types types of data, bytes object or EOF_MARKER.

      1. If filter receives bytes object, it should process data
         and yield processed data then yield EOL_MARKER object.
      2. If Filter received EOF_MARKER, it should yield remaining
         data (buffered) and then yield EOF_MARKER.
    """
    @functools.wraps(func)
    def wrapper(self, *args, **kw):
        new_filter = func(self, *args, **kw)

        filter = self.filter
        if filter is not None:
            next(new_filter)
            self.filter = filter_pipe(filter, new_filter)
        else:
            self.filter = new_filter

        next(self.filter)

    return wrapper


def filter_pipe(filter, filter2, *,
                EOF_MARKER=EOF_MARKER, EOL_MARKER=EOL_MARKER):
    """Creates pipe between two filters.

    filter_pipe() feeds first filter with incoming data and then
    send yielded from first filter data into filter2, results of
    filter2 are being emitted.

      1. If filter_pipe receives bytes object, it sends it to the first filter.
      2. Reads yielded values from the first filter until it receives
         EOF_MARKER or EOL_MARKER.
      3. Each of this values is being send to second filter.
      4. Reads yielded values from second filter until it receives EOF_MARKER
         or EOL_MARKER. Each of this values yields to writer.
    """
    chunk = yield

    while True:
        eof = chunk is EOF_MARKER
        chunk = filter.send(chunk)

        while chunk is not EOL_MARKER:
            chunk = filter2.send(chunk)

            while chunk not in (EOF_MARKER, EOL_MARKER):
                yield chunk
                chunk = next(filter2)

            if chunk is not EOF_MARKER:
                if eof:
                    chunk = EOF_MARKER
                else:
                    chunk = next(filter)
            else:
                break

        chunk = yield EOL_MARKER


class HttpMessage:
    """HttpMessage allows to write headers and payload to a stream.

    For example, lets say we want to read file then compress it with deflate
    compression and then send it with chunked transfer encoding, code may look
    like this:

       >>> response = aiohttp.Response(transport, 200)

    We have to use deflate compression first:

      >>> response.add_compression_filter('deflate')

    Then we want to split output stream into chunks of 1024 bytes size:

      >>> response.add_chunking_filter(1024)

    We can add headers to response with add_headers() method. add_headers()
    does not send data to transport, send_headers() sends request/response
    line and then sends headers:

      >>> response.add_headers(
      ...     ('Content-Disposition', 'attachment; filename="..."'))
      >>> response.send_headers()

    Now we can use chunked writer to write stream to a network stream.
    First call to write() method sends response status line and headers,
    add_header() and add_headers() method unavailable at this stage:

    >>> with open('...', 'rb') as f:
    ...     chunk = fp.read(8192)
    ...     while chunk:
    ...         response.write(chunk)
    ...         chunk = fp.read(8192)

    >>> response.write_eof()

    """

    writer = None

    # 'filter' is being used for altering write() behaviour,
    # add_chunking_filter adds deflate/gzip compression and
    # add_compression_filter splits incoming data into a chunks.
    filter = None

    HOP_HEADERS = None  # Must be set by subclass.

    SERVER_SOFTWARE = 'Python/{0[0]}.{0[1]} aiohttp/{1}'.format(
        sys.version_info, aiohttp.__version__)

    status = None
    status_line = b''
    upgrade = False  # Connection: UPGRADE
    websocket = False  # Upgrade: WEBSOCKET
    has_chunked_hdr = False  # Transfer-encoding: chunked

    # subclass can enable auto sending headers with write() call,
    # this is useful for wsgi's start_response implementation.
    _send_headers = False

    def __init__(self, transport, version, close):
        self.transport = transport
        self.version = version
        self.closing = close
        self.keepalive = None
        self.chunked = False
        self.length = None
        self.headers = CIMultiDict()
        self.headers_sent = False
        self.output_length = 0
        self._output_size = 0

    def force_close(self):
        self.closing = True
        self.keepalive = False

    def enable_chunked_encoding(self):
        self.chunked = True

    def keep_alive(self):
        if self.keepalive is None:
            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
            else:
                return not self.closing
        else:
            return self.keepalive

    def is_headers_sent(self):
        return self.headers_sent

    def add_header(self, name, value):
        """Analyze headers. Calculate content length,
        removes hop headers, etc."""
        assert not self.headers_sent, 'headers have been sent already'
        assert isinstance(name, str), \
            'Header name should be a string, got {!r}'.format(name)
        assert set(name).issubset(ASCIISET), \
            'Header name should contain ASCII chars, got {!r}'.format(name)
        assert isinstance(value, str), \
            'Header {!r} should have string value, got {!r}'.format(
                name, value)

        name = name.strip().upper()
        value = value.strip()

        if name == hdrs.CONTENT_LENGTH:
            self.length = int(value)

        if name == hdrs.TRANSFER_ENCODING:
            self.has_chunked_hdr = value.lower().strip() == 'chunked'

        if name == hdrs.CONNECTION:
            val = value.lower()
            # handle websocket
            if 'upgrade' in val:
                self.upgrade = True
            # connection keep-alive
            elif 'close' in val:
                self.keepalive = False
            elif 'keep-alive' in val:
                self.keepalive = True

        elif name == hdrs.UPGRADE:
            if 'websocket' in value.lower():
                self.websocket = True
                self.headers[name] = value

        elif name not in self.HOP_HEADERS:
            # ignore hop-by-hop headers
            self.headers.add(name, value)

    def add_headers(self, *headers):
        """Adds headers to a http message."""
        for name, value in headers:
            self.add_header(name, value)

    def send_headers(self, _sep=': ', _end='\r\n'):
        """Writes headers to a stream. Constructs payload writer."""
        # Chunked response is only for HTTP/1.1 clients or newer
        # and there is no Content-Length header is set.
        # Do not use chunked responses when the response is guaranteed to
        # not have a response body (304, 204).
        assert not self.headers_sent, 'headers have been sent already'
        self.headers_sent = True

        if self.chunked or (self.length is None and
                            self.version >= HttpVersion11 and
                            self.status not in (304, 204)):
            self.writer = self._write_chunked_payload()
            self.headers[hdrs.TRANSFER_ENCODING] = 'chunked'

        elif self.length is not None:
            self.writer = self._write_length_payload(self.length)

        else:
            self.writer = self._write_eof_payload()

        next(self.writer)

        self._add_default_headers()

        # status + headers
        headers = ''.join(itertools.chain(
            (self.status_line,),
            *((k, _sep, v, _end) for k, v in self.headers.items())))
        headers = headers.encode('utf-8') + b'\r\n'

        self.output_length += len(headers)
        self.transport.write(headers)

    def _add_default_headers(self):
        # set the connection header
        if self.upgrade:
            connection = 'upgrade'
        elif not self.closing if self.keepalive is None else self.keepalive:
            connection = 'keep-alive'
        else:
            connection = 'close'

        self.headers[hdrs.CONNECTION] = connection

    def write(self, chunk, *,
              drain=False, EOF_MARKER=EOF_MARKER, EOL_MARKER=EOL_MARKER):
        """Writes chunk of data to a stream by using different writers.

        writer uses filter to modify chunk of data.
        write_eof() indicates end of stream.
        writer can't be used after write_eof() method being called.
        write() return drain future.
        """
        assert (isinstance(chunk, (bytes, bytearray)) or
                chunk is EOF_MARKER), chunk

        size = self.output_length

        if self._send_headers and not self.headers_sent:
            self.send_headers()

        assert self.writer is not None, 'send_headers() is not called.'

        if self.filter:
            chunk = self.filter.send(chunk)
            while chunk not in (EOF_MARKER, EOL_MARKER):
                self.writer.send(chunk)
                chunk = next(self.filter)
        else:
            if chunk is not EOF_MARKER:
                self.writer.send(chunk)

        self._output_size += self.output_length - size

        if self._output_size > 64 * 1024:
            if drain:
                self._output_size = 0
                return self.transport.drain()

        return ()

    def write_eof(self):
        self.write(EOF_MARKER)
        try:
            self.writer.throw(aiohttp.EofStream())
        except StopIteration:
            pass

        return self.transport.drain()

    def _write_chunked_payload(self):
        """Write data in chunked transfer encoding."""
        while True:
            try:
                chunk = yield
            except aiohttp.EofStream:
                self.transport.write(b'0\r\n\r\n')
                self.output_length += 5
                break

            chunk = bytes(chunk)
            chunk_len = '{:x}\r\n'.format(len(chunk)).encode('ascii')
            self.transport.write(chunk_len)
            self.transport.write(chunk)
            self.transport.write(b'\r\n')
            self.output_length += len(chunk_len) + len(chunk) + 2

    def _write_length_payload(self, length):
        """Write specified number of bytes to a stream."""
        while True:
            try:
                chunk = yield
            except aiohttp.EofStream:
                break

            if length:
                l = len(chunk)
                if length >= l:
                    self.transport.write(chunk)
                    self.output_length += l
                    length = length-l
                else:
                    self.transport.write(chunk[:length])
                    self.output_length += length
                    length = 0

    def _write_eof_payload(self):
        while True:
            try:
                chunk = yield
            except aiohttp.EofStream:
                break

            self.transport.write(chunk)
            self.output_length += len(chunk)

    @wrap_payload_filter
    def add_chunking_filter(self, chunk_size=16*1024, *,
                            EOF_MARKER=EOF_MARKER, EOL_MARKER=EOL_MARKER):
        """Split incoming stream into chunks."""
        buf = bytearray()
        chunk = yield

        while True:
            if chunk is EOF_MARKER:
                if buf:
                    yield buf

                yield EOF_MARKER

            else:
                buf.extend(chunk)

                while len(buf) >= chunk_size:
                    chunk = bytes(buf[:chunk_size])
                    del buf[:chunk_size]
                    yield chunk

                chunk = yield EOL_MARKER

    @wrap_payload_filter
    def add_compression_filter(self, encoding='deflate', *,
                               EOF_MARKER=EOF_MARKER, EOL_MARKER=EOL_MARKER):
        """Compress incoming stream with deflate or gzip encoding."""
        zlib_mode = (16 + zlib.MAX_WBITS
                     if encoding == 'gzip' else -zlib.MAX_WBITS)
        zcomp = zlib.compressobj(wbits=zlib_mode)

        chunk = yield
        while True:
            if chunk is EOF_MARKER:
                yield zcomp.flush()
                chunk = yield EOF_MARKER

            else:
                yield zcomp.compress(chunk)
                chunk = yield EOL_MARKER


class Response(HttpMessage):
    """Create http response message.

    Transport is a socket stream transport. status is a response status code,
    status has to be integer value. http_version is a tuple that represents
    http version, (1, 0) stands for HTTP/1.0 and (1, 1) is for HTTP/1.1
    """

    HOP_HEADERS = ()

    @staticmethod
    def calc_reason(status):
        record = RESPONSES.get(status)
        if record is not None:
            reason = record[0]
        else:
            reason = str(status)
        return reason

    def __init__(self, transport, status,
                 http_version=HttpVersion11, close=False, reason=None):
        super().__init__(transport, http_version, close)

        self.status = status
        if reason is None:
            reason = self.calc_reason(status)

        self.reason = reason
        self.status_line = 'HTTP/{}.{} {} {}\r\n'.format(
            http_version[0], http_version[1], status, reason)

    def _add_default_headers(self):
        super()._add_default_headers()

        if hdrs.DATE not in self.headers:
            # format_date_time(None) is quite expensive
            self.headers.setdefault(hdrs.DATE, format_date_time(None))
        self.headers.setdefault(hdrs.SERVER, self.SERVER_SOFTWARE)


class Request(HttpMessage):

    HOP_HEADERS = ()

    def __init__(self, transport, method, path,
                 http_version=HttpVersion11, close=False):
        # set the default for HTTP 1.0 to be different
        # will only be overwritten with keep-alive header
        if http_version < HttpVersion11:
            close = True

        super().__init__(transport, http_version, close)

        self.method = method
        self.path = path
        self.status_line = '{0} {1} HTTP/{2[0]}.{2[1]}\r\n'.format(
            method, path, http_version)

    def _add_default_headers(self):
        super()._add_default_headers()

        self.headers.setdefault(hdrs.USER_AGENT, self.SERVER_SOFTWARE)

```
--- 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:** Deflate Compression Sends Empty Chunks in Chunked Responses, Causing Premature EOF

**Description:**
When sending a chunked HTTP response with deflate compression, some data chunks are being sent with a size of zero. This results in the response indicating the end of the file prematurely, potentially truncating the actual data.

**Example Code:**
```python
msg = protocol.Response(transport, 200)
msg.add_headers(('content-length', str(len(compressed_data))))
msg.add_chunking_filter(2)
msg.add_compression_filter('deflate')
msg.send_headers()
msg.write(b'data')
msg.write_eof()

chunks = [chunk for chunk in write.mock_calls]
assert all(chunks)  # This assertion fails because some chunks are empty
```

**Expected Behavior:**
All chunks sent in the compressed, chunked response should have a size greater than zero to ensure the entire payload is transmitted without prematurely signaling the end of the response.

**Actual Behavior:**
Some chunks are empty (`size = 0`), leading to an early EOF signal. This causes the response to end before all data is properly sent, resulting in incomplete data transmission.

[/ISSUE]
{
    "TestHttpMessage.test_add_header": "PASSED",
    "TestHttpMessage.test_add_header_invalid_value_type": "PASSED",
    "TestHttpMessage.test_add_header_non_ascii": "PASSED",
    "TestHttpMessage.test_add_header_with_spaces": "PASSED",
    "TestHttpMessage.test_add_headers": "PASSED",
    "TestHttpMessage.test_add_headers_connection_keepalive": "PASSED",
    "TestHttpMessage.test_add_headers_hop_headers": "PASSED",
    "TestHttpMessage.test_add_headers_length": "PASSED",
    "TestHttpMessage.test_add_headers_upgrade": "PASSED",
    "TestHttpMessage.test_add_headers_upgrade_websocket": "PASSED",
    "TestHttpMessage.test_default_headers": "PASSED",
    "TestHttpMessage.test_default_headers_chunked": "PASSED",
    "TestHttpMessage.test_default_headers_connection_close": "PASSED",
    "TestHttpMessage.test_default_headers_connection_keep_alive": "PASSED",
    "TestHttpMessage.test_default_headers_connection_upgrade": "PASSED",
    "TestHttpMessage.test_default_headers_server": "PASSED",
    "TestHttpMessage.test_default_headers_useragent": "PASSED",
    "TestHttpMessage.test_default_headers_useragent_custom": "PASSED",
    "TestHttpMessage.test_dont_override_request_headers_with_default_values": "PASSED",
    "TestHttpMessage.test_dont_override_response_headers_with_default_values": "PASSED",
    "TestHttpMessage.test_force_chunked": "PASSED",
    "TestHttpMessage.test_force_close": "PASSED",
    "TestHttpMessage.test_keep_alive": "PASSED",
    "TestHttpMessage.test_keep_alive_http10": "PASSED",
    "TestHttpMessage.test_prepare_chunked_force": "PASSED",
    "TestHttpMessage.test_prepare_chunked_no_length": "PASSED",
    "TestHttpMessage.test_prepare_eof": "PASSED",
    "TestHttpMessage.test_prepare_length": "PASSED",
    "TestHttpMessage.test_send_headers": "PASSED",
    "TestHttpMessage.test_send_headers_nomore_add": "PASSED",
    "TestHttpMessage.test_send_headers_non_ascii": "PASSED",
    "TestHttpMessage.test_start_request": "PASSED",
    "TestHttpMessage.test_start_response": "PASSED",
    "TestHttpMessage.test_start_response_with_reason": "PASSED",
    "TestHttpMessage.test_start_response_with_unknown_reason": "PASSED",
    "TestHttpMessage.test_write_auto_send_headers": "PASSED",
    "TestHttpMessage.test_write_drain": "PASSED",
    "TestHttpMessage.test_write_payload_chunked": "PASSED",
    "TestHttpMessage.test_write_payload_chunked_and_deflate": "PASSED",
    "TestHttpMessage.test_write_payload_chunked_filter": "PASSED",
    "TestHttpMessage.test_write_payload_chunked_filter_mutiple_chunks": "PASSED",
    "TestHttpMessage.test_write_payload_chunked_large_chunk": "PASSED",
    "TestHttpMessage.test_write_payload_chunked_multiple": "PASSED",
    "TestHttpMessage.test_write_payload_deflate_and_chunked": "PASSED",
    "TestHttpMessage.test_write_payload_deflate_filter": "PASSED",
    "TestHttpMessage.test_write_payload_eof": "PASSED",
    "TestHttpMessage.test_write_payload_length": "PASSED"
}
diff --git a/aiohttp/protocol.py b/aiohttp/protocol.py
index 43094961..e8c4e4d3 100644
--- a/aiohttp/protocol.py
+++ b/aiohttp/protocol.py
@@ -686,7 +686,8 @@ class HttpMessage:
         if self.filter:
             chunk = self.filter.send(chunk)
             while chunk not in (EOF_MARKER, EOL_MARKER):
-                self.writer.send(chunk)
+                if chunk:
+                    self.writer.send(chunk)
                 chunk = next(self.filter)
         else:
             if chunk is not EOF_MARKER:

{"aiohttp/protocol.py": "\"\"\"Http related parsers and protocol.\"\"\"\n\nimport collections\nimport functools\nimport http.server\nimport itertools\nimport re\nimport string\nimport sys\nimport zlib\nfrom wsgiref.handlers import format_date_time\n\nimport aiohttp\nfrom . import errors, hdrs\nfrom .multidict import CIMultiDict\nfrom .log import internal_logger\n\n__all__ = ('HttpMessage', 'Request', 'Response',\n           'HttpVersion', 'HttpVersion10', 'HttpVersion11',\n           'RawRequestMessage', 'RawResponseMessage',\n           'HttpPrefixParser', 'HttpRequestParser', 'HttpResponseParser',\n           'HttpPayloadParser')\n\nASCIISET = set(string.printable)\nMETHRE = re.compile('[A-Z0-9$-_.]+')\nVERSRE = re.compile('HTTP/(\\d+).(\\d+)')\nHDRRE = re.compile('[\\x00-\\x1F\\x7F()<>@,;:\\[\\]={} \\t\\\\\\\\\\\"]')\nCONTINUATION = (' ', '\\t')\nEOF_MARKER = object()\nEOL_MARKER = object()\nSTATUS_LINE_READY = object()\n\nRESPONSES = http.server.BaseHTTPRequestHandler.responses\n\nHttpVersion = collections.namedtuple(\n    'HttpVersion', ['major', 'minor'])\nHttpVersion10 = HttpVersion(1, 0)\nHttpVersion11 = HttpVersion(1, 1)\n\nRawStatusLineMessage = collections.namedtuple(\n    'RawStatusLineMessage', ['method', 'path', 'version'])\n\nRawRequestMessage = collections.namedtuple(\n    'RawRequestMessage',\n    ['method', 'path', 'version', 'headers', 'should_close', 'compression'])\n\n\nRawResponseMessage = collections.namedtuple(\n    'RawResponseMessage',\n    ['version', 'code', 'reason', 'headers', 'should_close', 'compression'])\n\n\nclass HttpParser:\n\n    def __init__(self, max_line_size=8190, max_headers=32768,\n                 max_field_size=8190):\n        self.max_line_size = max_line_size\n        self.max_headers = max_headers\n        self.max_field_size = max_field_size\n\n    def parse_headers(self, lines):\n        \"\"\"Parses RFC2822 headers from a stream.\n\n        Line continuations are supported. Returns list of header name\n        and value pairs. Header name is in upper case.\n        \"\"\"\n        close_conn = None\n        encoding = None\n        headers = CIMultiDict()\n\n        lines_idx = 1\n        line = lines[1]\n\n        while line:\n            header_length = len(line)\n\n            # Parse initial header name : value pair.\n            try:\n                name, value = line.split(':', 1)\n            except ValueError:\n                raise errors.InvalidHeader(line) from None\n\n            name = name.strip(' \\t').upper()\n            if HDRRE.search(name):\n                raise errors.InvalidHeader(name)\n\n            # next line\n            lines_idx += 1\n            line = lines[lines_idx]\n\n            # consume continuation lines\n            continuation = line and line[0] in CONTINUATION\n\n            if continuation:\n                value = [value]\n                while continuation:\n                    header_length += len(line)\n                    if header_length > self.max_field_size:\n                        raise errors.LineTooLong(\n                            'limit request headers fields size')\n                    value.append(line)\n\n                    # next line\n                    lines_idx += 1\n                    line = lines[lines_idx]\n                    continuation = line[0] in CONTINUATION\n                value = '\\r\\n'.join(value)\n            else:\n                if header_length > self.max_field_size:\n                    raise errors.LineTooLong(\n                        'limit request headers fields size')\n\n            value = value.strip()\n\n            # keep-alive and encoding\n            if name == hdrs.CONNECTION:\n                v = value.lower()\n                if v == 'close':\n                    close_conn = True\n                elif v == 'keep-alive':\n                    close_conn = False\n            elif name == hdrs.CONTENT_ENCODING:\n                enc = value.lower()\n                if enc in ('gzip', 'deflate'):\n                    encoding = enc\n\n            headers.add(name, value)\n\n        return headers, close_conn, encoding\n\n\nclass HttpPrefixParser:\n    \"\"\"Waits for 'HTTP' prefix (non destructive)\"\"\"\n\n    def __init__(self, allowed_methods=()):\n        self.allowed_methods = [m.upper() for m in allowed_methods]\n\n    def __call__(self, out, buf):\n        raw_data = yield from buf.waituntil(b' ', 12)\n        method = raw_data.decode('ascii', 'surrogateescape').strip()\n\n        # method\n        method = method.upper()\n        if not METHRE.match(method):\n            raise errors.BadStatusLine(method)\n\n        # allowed method\n        if self.allowed_methods and method not in self.allowed_methods:\n            raise errors.HttpMethodNotAllowed(message=method)\n\n        out.feed_data(method, len(method))\n        out.feed_eof()\n\n\nclass HttpRequestParser(HttpParser):\n    \"\"\"Read request status line. Exception errors.BadStatusLine\n    could be raised in case of any errors in status line.\n    Returns RawRequestMessage.\n    \"\"\"\n\n    def __call__(self, out, buf):\n        # read http message (request line + headers)\n        try:\n            raw_data = yield from buf.readuntil(\n                b'\\r\\n\\r\\n', self.max_headers)\n        except errors.LineLimitExceededParserError as exc:\n            raise errors.LineTooLong(exc.limit) from None\n\n        lines = raw_data.decode(\n            'utf-8', 'surrogateescape').split('\\r\\n')\n\n        # request line\n        line = lines[0]\n        try:\n            method, path, version = line.split(None, 2)\n        except ValueError:\n            raise errors.BadStatusLine(line) from None\n\n        # method\n        method = method.upper()\n        if not METHRE.match(method):\n            raise errors.BadStatusLine(method)\n\n        # version\n        try:\n            if version.startswith('HTTP/'):\n                n1, n2 = version[5:].split('.', 1)\n                version = HttpVersion(int(n1), int(n2))\n            else:\n                raise errors.BadStatusLine(version)\n        except:\n            raise errors.BadStatusLine(version)\n\n        # read headers\n        headers, close, compression = self.parse_headers(lines)\n        if close is None:  # then the headers weren't set in the request\n            if version <= HttpVersion10:  # HTTP 1.0 must asks to not close\n                close = True\n            else:  # HTTP 1.1 must ask to close.\n                close = False\n\n        out.feed_data(\n            RawRequestMessage(\n                method, path, version, headers, close, compression),\n            len(raw_data))\n        out.feed_eof()\n\n\nclass HttpResponseParser(HttpParser):\n    \"\"\"Read response status line and headers.\n\n    BadStatusLine could be raised in case of any errors in status line.\n    Returns RawResponseMessage\"\"\"\n\n    def __call__(self, out, buf):\n        # read http message (response line + headers)\n        try:\n            raw_data = yield from buf.readuntil(\n                b'\\r\\n\\r\\n', self.max_line_size + self.max_headers)\n        except errors.LineLimitExceededParserError as exc:\n            raise errors.LineTooLong(exc.limit) from None\n\n        lines = raw_data.decode(\n            'utf-8', 'surrogateescape').split('\\r\\n')\n\n        line = lines[0]\n        try:\n            version, status = line.split(None, 1)\n        except ValueError:\n            raise errors.BadStatusLine(line) from None\n        else:\n            try:\n                status, reason = status.split(None, 1)\n            except ValueError:\n                reason = ''\n\n        # version\n        match = VERSRE.match(version)\n        if match is None:\n            raise errors.BadStatusLine(line)\n        version = HttpVersion(int(match.group(1)), int(match.group(2)))\n\n        # The status code is a three-digit number\n        try:\n            status = int(status)\n        except ValueError:\n            raise errors.BadStatusLine(line) from None\n\n        if status < 100 or status > 999:\n            raise errors.BadStatusLine(line)\n\n        # read headers\n        headers, close, compression = self.parse_headers(lines)\n\n        if close is None:\n            close = version <= HttpVersion10\n\n        out.feed_data(\n            RawResponseMessage(\n                version, status, reason.strip(),\n                headers, close, compression),\n            len(raw_data))\n        out.feed_eof()\n\n\nclass HttpPayloadParser:\n\n    def __init__(self, message, length=None, compression=True,\n                 readall=False, response_with_body=True):\n        self.message = message\n        self.length = length\n        self.compression = compression\n        self.readall = readall\n        self.response_with_body = response_with_body\n\n    def __call__(self, out, buf):\n        # payload params\n        length = self.message.headers.get(hdrs.CONTENT_LENGTH, self.length)\n        if hdrs.SEC_WEBSOCKET_KEY1 in self.message.headers:\n            length = 8\n\n        # payload decompression wrapper\n        if self.compression and self.message.compression:\n            out = DeflateBuffer(out, self.message.compression)\n\n        # payload parser\n        if not self.response_with_body:\n            # don't parse payload if it's not expected to be received\n            pass\n\n        elif 'chunked' in self.message.headers.get(\n                hdrs.TRANSFER_ENCODING, ''):\n            yield from self.parse_chunked_payload(out, buf)\n\n        elif length is not None:\n            try:\n                length = int(length)\n            except ValueError:\n                raise errors.InvalidHeader(hdrs.CONTENT_LENGTH) from None\n\n            if length < 0:\n                raise errors.InvalidHeader(hdrs.CONTENT_LENGTH)\n            elif length > 0:\n                yield from self.parse_length_payload(out, buf, length)\n        else:\n            if self.readall and getattr(self.message, 'code', 0) != 204:\n                yield from self.parse_eof_payload(out, buf)\n            elif getattr(self.message, 'method', None) in ('PUT', 'POST'):\n                internal_logger.warning(  # pragma: no cover\n                    'Content-Length or Transfer-Encoding header is required')\n\n        out.feed_eof()\n\n    def parse_chunked_payload(self, out, buf):\n        \"\"\"Chunked transfer encoding parser.\"\"\"\n        while True:\n            # read next chunk size\n            line = yield from buf.readuntil(b'\\r\\n', 8192)\n\n            i = line.find(b';')\n            if i >= 0:\n                line = line[:i]  # strip chunk-extensions\n            else:\n                line = line.strip()\n            try:\n                size = int(line, 16)\n            except ValueError:\n                raise errors.TransferEncodingError(line) from None\n\n            if size == 0:  # eof marker\n                break\n\n            # read chunk and feed buffer\n            while size:\n                chunk = yield from buf.readsome(size)\n                out.feed_data(chunk, len(chunk))\n                size = size - len(chunk)\n\n            # toss the CRLF at the end of the chunk\n            yield from buf.skip(2)\n\n        # read and discard trailer up to the CRLF terminator\n        yield from buf.skipuntil(b'\\r\\n')\n\n    def parse_length_payload(self, out, buf, length=0):\n        \"\"\"Read specified amount of bytes.\"\"\"\n        required = length\n        while required:\n            chunk = yield from buf.readsome(required)\n            out.feed_data(chunk, len(chunk))\n            required -= len(chunk)\n\n    def parse_eof_payload(self, out, buf):\n        \"\"\"Read all bytes until eof.\"\"\"\n        try:\n            while True:\n                chunk = yield from buf.readsome()\n                out.feed_data(chunk, len(chunk))\n        except aiohttp.EofStream:\n            pass\n\n\nclass DeflateBuffer:\n    \"\"\"DeflateStream decompress stream and feed data into specified stream.\"\"\"\n\n    def __init__(self, out, encoding):\n        self.out = out\n        zlib_mode = (16 + zlib.MAX_WBITS\n                     if encoding == 'gzip' else -zlib.MAX_WBITS)\n\n        self.zlib = zlib.decompressobj(wbits=zlib_mode)\n\n    def feed_data(self, chunk, size):\n        try:\n            chunk = self.zlib.decompress(chunk)\n        except Exception:\n            raise errors.ContentEncodingError('deflate')\n\n        if chunk:\n            self.out.feed_data(chunk, len(chunk))\n\n    def feed_eof(self):\n        chunk = self.zlib.flush()\n        self.out.feed_data(chunk, len(chunk))\n        if not self.zlib.eof:\n            raise errors.ContentEncodingError('deflate')\n\n        self.out.feed_eof()\n\n\ndef wrap_payload_filter(func):\n    \"\"\"Wraps payload filter and piped filters.\n\n    Filter is a generator that accepts arbitrary chunks of data,\n    modify data and emit new stream of data.\n\n    For example we have stream of chunks: ['1', '2', '3', '4', '5'],\n    we can apply chunking filter to this stream:\n\n    ['1', '2', '3', '4', '5']\n      |\n    response.add_chunking_filter(2)\n      |\n    ['12', '34', '5']\n\n    It is possible to use different filters at the same time.\n\n    For a example to compress incoming stream with 'deflate' encoding\n    and then split data and emit chunks of 8192 bytes size chunks:\n\n      >>> response.add_compression_filter('deflate')\n      >>> response.add_chunking_filter(8192)\n\n    Filters do not alter transfer encoding.\n\n    Filter can receive types types of data, bytes object or EOF_MARKER.\n\n      1. If filter receives bytes object, it should process data\n         and yield processed data then yield EOL_MARKER object.\n      2. If Filter received EOF_MARKER, it should yield remaining\n         data (buffered) and then yield EOF_MARKER.\n    \"\"\"\n    @functools.wraps(func)\n    def wrapper(self, *args, **kw):\n        new_filter = func(self, *args, **kw)\n\n        filter = self.filter\n        if filter is not None:\n            next(new_filter)\n            self.filter = filter_pipe(filter, new_filter)\n        else:\n            self.filter = new_filter\n\n        next(self.filter)\n\n    return wrapper\n\n\ndef filter_pipe(filter, filter2, *,\n                EOF_MARKER=EOF_MARKER, EOL_MARKER=EOL_MARKER):\n    \"\"\"Creates pipe between two filters.\n\n    filter_pipe() feeds first filter with incoming data and then\n    send yielded from first filter data into filter2, results of\n    filter2 are being emitted.\n\n      1. If filter_pipe receives bytes object, it sends it to the first filter.\n      2. Reads yielded values from the first filter until it receives\n         EOF_MARKER or EOL_MARKER.\n      3. Each of this values is being send to second filter.\n      4. Reads yielded values from second filter until it receives EOF_MARKER\n         or EOL_MARKER. Each of this values yields to writer.\n    \"\"\"\n    chunk = yield\n\n    while True:\n        eof = chunk is EOF_MARKER\n        chunk = filter.send(chunk)\n\n        while chunk is not EOL_MARKER:\n            chunk = filter2.send(chunk)\n\n            while chunk not in (EOF_MARKER, EOL_MARKER):\n                yield chunk\n                chunk = next(filter2)\n\n            if chunk is not EOF_MARKER:\n                if eof:\n                    chunk = EOF_MARKER\n                else:\n                    chunk = next(filter)\n            else:\n                break\n\n        chunk = yield EOL_MARKER\n\n\nclass HttpMessage:\n    \"\"\"HttpMessage allows to write headers and payload to a stream.\n\n    For example, lets say we want to read file then compress it with deflate\n    compression and then send it with chunked transfer encoding, code may look\n    like this:\n\n       >>> response = aiohttp.Response(transport, 200)\n\n    We have to use deflate compression first:\n\n      >>> response.add_compression_filter('deflate')\n\n    Then we want to split output stream into chunks of 1024 bytes size:\n\n      >>> response.add_chunking_filter(1024)\n\n    We can add headers to response with add_headers() method. add_headers()\n    does not send data to transport, send_headers() sends request/response\n    line and then sends headers:\n\n      >>> response.add_headers(\n      ...     ('Content-Disposition', 'attachment; filename=\"...\"'))\n      >>> response.send_headers()\n\n    Now we can use chunked writer to write stream to a network stream.\n    First call to write() method sends response status line and headers,\n    add_header() and add_headers() method unavailable at this stage:\n\n    >>> with open('...', 'rb') as f:\n    ...     chunk = fp.read(8192)\n    ...     while chunk:\n    ...         response.write(chunk)\n    ...         chunk = fp.read(8192)\n\n    >>> response.write_eof()\n\n    \"\"\"\n\n    writer = None\n\n    # 'filter' is being used for altering write() behaviour,\n    # add_chunking_filter adds deflate/gzip compression and\n    # add_compression_filter splits incoming data into a chunks.\n    filter = None\n\n    HOP_HEADERS = None  # Must be set by subclass.\n\n    SERVER_SOFTWARE = 'Python/{0[0]}.{0[1]} aiohttp/{1}'.format(\n        sys.version_info, aiohttp.__version__)\n\n    status = None\n    status_line = b''\n    upgrade = False  # Connection: UPGRADE\n    websocket = False  # Upgrade: WEBSOCKET\n    has_chunked_hdr = False  # Transfer-encoding: chunked\n\n    # subclass can enable auto sending headers with write() call,\n    # this is useful for wsgi's start_response implementation.\n    _send_headers = False\n\n    def __init__(self, transport, version, close):\n        self.transport = transport\n        self.version = version\n        self.closing = close\n        self.keepalive = None\n        self.chunked = False\n        self.length = None\n        self.headers = CIMultiDict()\n        self.headers_sent = False\n        self.output_length = 0\n        self._output_size = 0\n\n    def force_close(self):\n        self.closing = True\n        self.keepalive = False\n\n    def enable_chunked_encoding(self):\n        self.chunked = True\n\n    def keep_alive(self):\n        if self.keepalive is None:\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            else:\n                return not self.closing\n        else:\n            return self.keepalive\n\n    def is_headers_sent(self):\n        return self.headers_sent\n\n    def add_header(self, name, value):\n        \"\"\"Analyze headers. Calculate content length,\n        removes hop headers, etc.\"\"\"\n        assert not self.headers_sent, 'headers have been sent already'\n        assert isinstance(name, str), \\\n            'Header name should be a string, got {!r}'.format(name)\n        assert set(name).issubset(ASCIISET), \\\n            'Header name should contain ASCII chars, got {!r}'.format(name)\n        assert isinstance(value, str), \\\n            'Header {!r} should have string value, got {!r}'.format(\n                name, value)\n\n        name = name.strip().upper()\n        value = value.strip()\n\n        if name == hdrs.CONTENT_LENGTH:\n            self.length = int(value)\n\n        if name == hdrs.TRANSFER_ENCODING:\n            self.has_chunked_hdr = value.lower().strip() == 'chunked'\n\n        if name == hdrs.CONNECTION:\n            val = value.lower()\n            # handle websocket\n            if 'upgrade' in val:\n                self.upgrade = True\n            # connection keep-alive\n            elif 'close' in val:\n                self.keepalive = False\n            elif 'keep-alive' in val:\n                self.keepalive = True\n\n        elif name == hdrs.UPGRADE:\n            if 'websocket' in value.lower():\n                self.websocket = True\n                self.headers[name] = value\n\n        elif name not in self.HOP_HEADERS:\n            # ignore hop-by-hop headers\n            self.headers.add(name, value)\n\n    def add_headers(self, *headers):\n        \"\"\"Adds headers to a http message.\"\"\"\n        for name, value in headers:\n            self.add_header(name, value)\n\n    def send_headers(self, _sep=': ', _end='\\r\\n'):\n        \"\"\"Writes headers to a stream. Constructs payload writer.\"\"\"\n        # Chunked response is only for HTTP/1.1 clients or newer\n        # and there is no Content-Length header is set.\n        # Do not use chunked responses when the response is guaranteed to\n        # not have a response body (304, 204).\n        assert not self.headers_sent, 'headers have been sent already'\n        self.headers_sent = True\n\n        if self.chunked or (self.length is None and\n                            self.version >= HttpVersion11 and\n                            self.status not in (304, 204)):\n            self.writer = self._write_chunked_payload()\n            self.headers[hdrs.TRANSFER_ENCODING] = 'chunked'\n\n        elif self.length is not None:\n            self.writer = self._write_length_payload(self.length)\n\n        else:\n            self.writer = self._write_eof_payload()\n\n        next(self.writer)\n\n        self._add_default_headers()\n\n        # status + headers\n        headers = ''.join(itertools.chain(\n            (self.status_line,),\n            *((k, _sep, v, _end) for k, v in self.headers.items())))\n        headers = headers.encode('utf-8') + b'\\r\\n'\n\n        self.output_length += len(headers)\n        self.transport.write(headers)\n\n    def _add_default_headers(self):\n        # set the connection header\n        if self.upgrade:\n            connection = 'upgrade'\n        elif not self.closing if self.keepalive is None else self.keepalive:\n            connection = 'keep-alive'\n        else:\n            connection = 'close'\n\n        self.headers[hdrs.CONNECTION] = connection\n\n    def write(self, chunk, *,\n              drain=False, EOF_MARKER=EOF_MARKER, EOL_MARKER=EOL_MARKER):\n        \"\"\"Writes chunk of data to a stream by using different writers.\n\n        writer uses filter to modify chunk of data.\n        write_eof() indicates end of stream.\n        writer can't be used after write_eof() method being called.\n        write() return drain future.\n        \"\"\"\n        assert (isinstance(chunk, (bytes, bytearray)) or\n                chunk is EOF_MARKER), chunk\n\n        size = self.output_length\n\n        if self._send_headers and not self.headers_sent:\n            self.send_headers()\n\n        assert self.writer is not None, 'send_headers() is not called.'\n\n        if self.filter:\n            chunk = self.filter.send(chunk)\n            while chunk not in (EOF_MARKER, EOL_MARKER):\n                self.writer.send(chunk)\n                chunk = next(self.filter)\n        else:\n            if chunk is not EOF_MARKER:\n                self.writer.send(chunk)\n\n        self._output_size += self.output_length - size\n\n        if self._output_size > 64 * 1024:\n            if drain:\n                self._output_size = 0\n                return self.transport.drain()\n\n        return ()\n\n    def write_eof(self):\n        self.write(EOF_MARKER)\n        try:\n            self.writer.throw(aiohttp.EofStream())\n        except StopIteration:\n            pass\n\n        return self.transport.drain()\n\n    def _write_chunked_payload(self):\n        \"\"\"Write data in chunked transfer encoding.\"\"\"\n        while True:\n            try:\n                chunk = yield\n            except aiohttp.EofStream:\n                self.transport.write(b'0\\r\\n\\r\\n')\n                self.output_length += 5\n                break\n\n            chunk = bytes(chunk)\n            chunk_len = '{:x}\\r\\n'.format(len(chunk)).encode('ascii')\n            self.transport.write(chunk_len)\n            self.transport.write(chunk)\n            self.transport.write(b'\\r\\n')\n            self.output_length += len(chunk_len) + len(chunk) + 2\n\n    def _write_length_payload(self, length):\n        \"\"\"Write specified number of bytes to a stream.\"\"\"\n        while True:\n            try:\n                chunk = yield\n            except aiohttp.EofStream:\n                break\n\n            if length:\n                l = len(chunk)\n                if length >= l:\n                    self.transport.write(chunk)\n                    self.output_length += l\n                    length = length-l\n                else:\n                    self.transport.write(chunk[:length])\n                    self.output_length += length\n                    length = 0\n\n    def _write_eof_payload(self):\n        while True:\n            try:\n                chunk = yield\n            except aiohttp.EofStream:\n                break\n\n            self.transport.write(chunk)\n            self.output_length += len(chunk)\n\n    @wrap_payload_filter\n    def add_chunking_filter(self, chunk_size=16*1024, *,\n                            EOF_MARKER=EOF_MARKER, EOL_MARKER=EOL_MARKER):\n        \"\"\"Split incoming stream into chunks.\"\"\"\n        buf = bytearray()\n        chunk = yield\n\n        while True:\n            if chunk is EOF_MARKER:\n                if buf:\n                    yield buf\n\n                yield EOF_MARKER\n\n            else:\n                buf.extend(chunk)\n\n                while len(buf) >= chunk_size:\n                    chunk = bytes(buf[:chunk_size])\n                    del buf[:chunk_size]\n                    yield chunk\n\n                chunk = yield EOL_MARKER\n\n    @wrap_payload_filter\n    def add_compression_filter(self, encoding='deflate', *,\n                               EOF_MARKER=EOF_MARKER, EOL_MARKER=EOL_MARKER):\n        \"\"\"Compress incoming stream with deflate or gzip encoding.\"\"\"\n        zlib_mode = (16 + zlib.MAX_WBITS\n                     if encoding == 'gzip' else -zlib.MAX_WBITS)\n        zcomp = zlib.compressobj(wbits=zlib_mode)\n\n        chunk = yield\n        while True:\n            if chunk is EOF_MARKER:\n                yield zcomp.flush()\n                chunk = yield EOF_MARKER\n\n            else:\n                yield zcomp.compress(chunk)\n                chunk = yield EOL_MARKER\n\n\nclass Response(HttpMessage):\n    \"\"\"Create http response message.\n\n    Transport is a socket stream transport. status is a response status code,\n    status has to be integer value. http_version is a tuple that represents\n    http version, (1, 0) stands for HTTP/1.0 and (1, 1) is for HTTP/1.1\n    \"\"\"\n\n    HOP_HEADERS = ()\n\n    @staticmethod\n    def calc_reason(status):\n        record = RESPONSES.get(status)\n        if record is not None:\n            reason = record[0]\n        else:\n            reason = str(status)\n        return reason\n\n    def __init__(self, transport, status,\n                 http_version=HttpVersion11, close=False, reason=None):\n        super().__init__(transport, http_version, close)\n\n        self.status = status\n        if reason is None:\n            reason = self.calc_reason(status)\n\n        self.reason = reason\n        self.status_line = 'HTTP/{}.{} {} {}\\r\\n'.format(\n            http_version[0], http_version[1], status, reason)\n\n    def _add_default_headers(self):\n        super()._add_default_headers()\n\n        if hdrs.DATE not in self.headers:\n            # format_date_time(None) is quite expensive\n            self.headers.setdefault(hdrs.DATE, format_date_time(None))\n        self.headers.setdefault(hdrs.SERVER, self.SERVER_SOFTWARE)\n\n\nclass Request(HttpMessage):\n\n    HOP_HEADERS = ()\n\n    def __init__(self, transport, method, path,\n                 http_version=HttpVersion11, close=False):\n        # set the default for HTTP 1.0 to be different\n        # will only be overwritten with keep-alive header\n        if http_version < HttpVersion11:\n            close = True\n\n        super().__init__(transport, http_version, close)\n\n        self.method = method\n        self.path = path\n        self.status_line = '{0} {1} HTTP/{2[0]}.{2[1]}\\r\\n'.format(\n            method, path, http_version)\n\n    def _add_default_headers(self):\n        super()._add_default_headers()\n\n        self.headers.setdefault(hdrs.USER_AGENT, self.SERVER_SOFTWARE)\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:** Deflate Compression Sends Empty Chunks in Chunked Responses, Causing Premature EOF

**Description:**
When sending a chunked HTTP response with deflate compression, some data chunks are being sent with a size of zero. This results in the response indicating the end of the file prematurely, potentially truncating the actual data.

**Example Code:**
```python
msg = protocol.Response(transport, 200)
msg.add_headers(('content-length', str(len(compressed_data))))
msg.add_chunking_filter(2)
msg.add_compression_filter('deflate')
msg.send_headers()
msg.write(b'data')
msg.write_eof()

chunks = [chunk for chunk in write.mock_calls]
assert all(chunks)  # This assertion fails because some chunks are empty
```

**Expected Behavior:**
All chunks sent in the compressed, chunked response should have a size greater than zero to ensure the entire payload is transmitted without prematurely signaling the end of the response.

**Actual Behavior:**
Some chunks are empty (`size = 0`), leading to an early EOF signal. This causes the response to end before all data is properly sent, resulting in incomplete data transmission.

[/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/protocol.py
"""Http related parsers and protocol."""

import collections
import functools
import http.server
import itertools
import re
import string
import sys
import zlib
from wsgiref.handlers import format_date_time

import aiohttp
from . import errors, hdrs
from .multidict import CIMultiDict
from .log import internal_logger

__all__ = ('HttpMessage', 'Request', 'Response',
           'HttpVersion', 'HttpVersion10', 'HttpVersion11',
           'RawRequestMessage', 'RawResponseMessage',
           'HttpPrefixParser', 'HttpRequestParser', 'HttpResponseParser',
           'HttpPayloadParser')

ASCIISET = set(string.printable)
METHRE = re.compile('[A-Z0-9$-_.]+')
VERSRE = re.compile('HTTP/(\d+).(\d+)')
HDRRE = re.compile('[\x00-\x1F\x7F()<>@,;:\[\]={} \t\\\\\"]')
CONTINUATION = (' ', '\t')
EOF_MARKER = object()
EOL_MARKER = object()
STATUS_LINE_READY = object()

RESPONSES = http.server.BaseHTTPRequestHandler.responses

HttpVersion = collections.namedtuple(
    'HttpVersion', ['major', 'minor'])
HttpVersion10 = HttpVersion(1, 0)
HttpVersion11 = HttpVersion(1, 1)

RawStatusLineMessage = collections.namedtuple(
    'RawStatusLineMessage', ['method', 'path', 'version'])

RawRequestMessage = collections.namedtuple(
    'RawRequestMessage',
    ['method', 'path', 'version', 'headers', 'should_close', 'compression'])


RawResponseMessage = collections.namedtuple(
    'RawResponseMessage',
    ['version', 'code', 'reason', 'headers', 'should_close', 'compression'])


class HttpParser:

    def __init__(self, max_line_size=8190, max_headers=32768,
                 max_field_size=8190):
        self.max_line_size = max_line_size
        self.max_headers = max_headers
        self.max_field_size = max_field_size

    def parse_headers(self, lines):
        """Parses RFC2822 headers from a stream.

        Line continuations are supported. Returns list of header name
        and value pairs. Header name is in upper case.
        """
        close_conn = None
        encoding = None
        headers = CIMultiDict()

        lines_idx = 1
        line = lines[1]

        while line:
            header_length = len(line)

            # Parse initial header name : value pair.
            try:
                name, value = line.split(':', 1)
            except ValueError:
                raise errors.InvalidHeader(line) from None

            name = name.strip(' \t').upper()
            if HDRRE.search(name):
                raise errors.InvalidHeader(name)

            # next line
            lines_idx += 1
            line = lines[lines_idx]

            # consume continuation lines
            continuation = line and line[0] in CONTINUATION

            if continuation:
                value = [value]
                while continuation:
                    header_length += len(line)
                    if header_length > self.max_field_size:
                        raise errors.LineTooLong(
                            'limit request headers fields size')
                    value.append(line)

                    # next line
                    lines_idx += 1
                    line = lines[lines_idx]
                    continuation = line[0] in CONTINUATION
                value = '\r\n'.join(value)
            else:
                if header_length > self.max_field_size:
                    raise errors.LineTooLong(
                        'limit request headers fields size')

            value = value.strip()

            # keep-alive and encoding
            if name == hdrs.CONNECTION:
                v = value.lower()
                if v == 'close':
                    close_conn = True
                elif v == 'keep-alive':
                    close_conn = False
            elif name == hdrs.CONTENT_ENCODING:
                enc = value.lower()
                if enc in ('gzip', 'deflate'):
                    encoding = enc

            headers.add(name, value)

        return headers, close_conn, encoding


class HttpPrefixParser:
    """Waits for 'HTTP' prefix (non destructive)"""

    def __init__(self, allowed_methods=()):
        self.allowed_methods = [m.upper() for m in allowed_methods]

    def __call__(self, out, buf):
        raw_data = yield from buf.waituntil(b' ', 12)
        method = raw_data.decode('ascii', 'surrogateescape').strip()

        # method
        method = method.upper()
        if not METHRE.match(method):
            raise errors.BadStatusLine(method)

        # allowed method
        if self.allowed_methods and method not in self.allowed_methods:
            raise errors.HttpMethodNotAllowed(message=method)

        out.feed_data(method, len(method))
        out.feed_eof()


class HttpRequestParser(HttpParser):
    """Read request status line. Exception errors.BadStatusLine
    could be raised in case of any errors in status line.
    Returns RawRequestMessage.
    """

    def __call__(self, out, buf):
        # read http message (request line + headers)
        try:
            raw_data = yield from buf.readuntil(
                b'\r\n\r\n', self.max_headers)
        except errors.LineLimitExceededParserError as exc:
            raise errors.LineTooLong(exc.limit) from None

        lines = raw_data.decode(
            'utf-8', 'surrogateescape').split('\r\n')

        # request line
        line = lines[0]
        try:
            method, path, version = line.split(None, 2)
        except ValueError:
            raise errors.BadStatusLine(line) from None

        # method
        method = method.upper()
        if not METHRE.match(method):
            raise errors.BadStatusLine(method)

        # version
        try:
            if version.startswith('HTTP/'):
                n1, n2 = version[5:].split('.', 1)
                version = HttpVersion(int(n1), int(n2))
            else:
                raise errors.BadStatusLine(version)
        except:
            raise errors.BadStatusLine(version)

        # read headers
        headers, close, compression = self.parse_headers(lines)
        if close is None:  # then the headers weren't set in the request
            if version <= HttpVersion10:  # HTTP 1.0 must asks to not close
                close = True
            else:  # HTTP 1.1 must ask to close.
                close = False

        out.feed_data(
            RawRequestMessage(
                method, path, version, headers, close, compression),
            len(raw_data))
        out.feed_eof()


class HttpResponseParser(HttpParser):
    """Read response status line and headers.

    BadStatusLine could be raised in case of any errors in status line.
    Returns RawResponseMessage"""

    def __call__(self, out, buf):
        # read http message (response line + headers)
        try:
            raw_data = yield from buf.readuntil(
                b'\r\n\r\n', self.max_line_size + self.max_headers)
        except errors.LineLimitExceededParserError as exc:
            raise errors.LineTooLong(exc.limit) from None

        lines = raw_data.decode(
            'utf-8', 'surrogateescape').split('\r\n')

        line = lines[0]
        try:
            version, status = line.split(None, 1)
        except ValueError:
            raise errors.BadStatusLine(line) from None
        else:
            try:
                status, reason = status.split(None, 1)
            except ValueError:
                reason = ''

        # version
        match = VERSRE.match(version)
        if match is None:
            raise errors.BadStatusLine(line)
        version = HttpVersion(int(match.group(1)), int(match.group(2)))

        # The status code is a three-digit number
        try:
            status = int(status)
        except ValueError:
            raise errors.BadStatusLine(line) from None

        if status < 100 or status > 999:
            raise errors.BadStatusLine(line)

        # read headers
        headers, close, compression = self.parse_headers(lines)

        if close is None:
            close = version <= HttpVersion10

        out.feed_data(
            RawResponseMessage(
                version, status, reason.strip(),
                headers, close, compression),
            len(raw_data))
        out.feed_eof()


class HttpPayloadParser:

    def __init__(self, message, length=None, compression=True,
                 readall=False, response_with_body=True):
        self.message = message
        self.length = length
        self.compression = compression
        self.readall = readall
        self.response_with_body = response_with_body

    def __call__(self, out, buf):
        # payload params
        length = self.message.headers.get(hdrs.CONTENT_LENGTH, self.length)
        if hdrs.SEC_WEBSOCKET_KEY1 in self.message.headers:
            length = 8

        # payload decompression wrapper
        if self.compression and self.message.compression:
            out = DeflateBuffer(out, self.message.compression)

        # payload parser
        if not self.response_with_body:
            # don't parse payload if it's not expected to be received
            pass

        elif 'chunked' in self.message.headers.get(
                hdrs.TRANSFER_ENCODING, ''):
            yield from self.parse_chunked_payload(out, buf)

        elif length is not None:
            try:
                length = int(length)
            except ValueError:
                raise errors.InvalidHeader(hdrs.CONTENT_LENGTH) from None

            if length < 0:
                raise errors.InvalidHeader(hdrs.CONTENT_LENGTH)
            elif length > 0:
                yield from self.parse_length_payload(out, buf, length)
        else:
            if self.readall and getattr(self.message, 'code', 0) != 204:
                yield from self.parse_eof_payload(out, buf)
            elif getattr(self.message, 'method', None) in ('PUT', 'POST'):
                internal_logger.warning(  # pragma: no cover
                    'Content-Length or Transfer-Encoding header is required')

        out.feed_eof()

    def parse_chunked_payload(self, out, buf):
        """Chunked transfer encoding parser."""
        while True:
            # read next chunk size
            line = yield from buf.readuntil(b'\r\n', 8192)

            i = line.find(b';')
            if i >= 0:
                line = line[:i]  # strip chunk-extensions
            else:
                line = line.strip()
            try:
                size = int(line, 16)
            except ValueError:
                raise errors.TransferEncodingError(line) from None

            if size == 0:  # eof marker
                break

            # read chunk and feed buffer
            while size:
                chunk = yield from buf.readsome(size)
                out.feed_data(chunk, len(chunk))
                size = size - len(chunk)

            # toss the CRLF at the end of the chunk
            yield from buf.skip(2)

        # read and discard trailer up to the CRLF terminator
        yield from buf.skipuntil(b'\r\n')

    def parse_length_payload(self, out, buf, length=0):
        """Read specified amount of bytes."""
        required = length
        while required:
            chunk = yield from buf.readsome(required)
            out.feed_data(chunk, len(chunk))
            required -= len(chunk)

    def parse_eof_payload(self, out, buf):
        """Read all bytes until eof."""
        try:
            while True:
                chunk = yield from buf.readsome()
                out.feed_data(chunk, len(chunk))
        except aiohttp.EofStream:
            pass


class DeflateBuffer:
    """DeflateStream decompress stream and feed data into specified stream."""

    def __init__(self, out, encoding):
        self.out = out
        zlib_mode = (16 + zlib.MAX_WBITS
                     if encoding == 'gzip' else -zlib.MAX_WBITS)

        self.zlib = zlib.decompressobj(wbits=zlib_mode)

    def feed_data(self, chunk, size):
        try:
            chunk = self.zlib.decompress(chunk)
        except Exception:
            raise errors.ContentEncodingError('deflate')

        if chunk:
            self.out.feed_data(chunk, len(chunk))

    def feed_eof(self):
        chunk = self.zlib.flush()
        self.out.feed_data(chunk, len(chunk))
        if not self.zlib.eof:
            raise errors.ContentEncodingError('deflate')

        self.out.feed_eof()


def wrap_payload_filter(func):
    """Wraps payload filter and piped filters.

    Filter is a generator that accepts arbitrary chunks of data,
    modify data and emit new stream of data.

    For example we have stream of chunks: ['1', '2', '3', '4', '5'],
    we can apply chunking filter to this stream:

    ['1', '2', '3', '4', '5']
      |
    response.add_chunking_filter(2)
      |
    ['12', '34', '5']

    It is possible to use different filters at the same time.

    For a example to compress incoming stream with 'deflate' encoding
    and then split data and emit chunks of 8192 bytes size chunks:

      >>> response.add_compression_filter('deflate')
      >>> response.add_chunking_filter(8192)

    Filters do not alter transfer encoding.

    Filter can receive types types of data, bytes object or EOF_MARKER.

      1. If filter receives bytes object, it should process data
         and yield processed data then yield EOL_MARKER object.
      2. If Filter received EOF_MARKER, it should yield remaining
         data (buffered) and then yield EOF_MARKER.
    """
    @functools.wraps(func)
    def wrapper(self, *args, **kw):
        new_filter = func(self, *args, **kw)

        filter = self.filter
        if filter is not None:
            next(new_filter)
            self.filter = filter_pipe(filter, new_filter)
        else:
            self.filter = new_filter

        next(self.filter)

    return wrapper


def filter_pipe(filter, filter2, *,
                EOF_MARKER=EOF_MARKER, EOL_MARKER=EOL_MARKER):
    """Creates pipe between two filters.

    filter_pipe() feeds first filter with incoming data and then
    send yielded from first filter data into filter2, results of
    filter2 are being emitted.

      1. If filter_pipe receives bytes object, it sends it to the first filter.
      2. Reads yielded values from the first filter until it receives
         EOF_MARKER or EOL_MARKER.
      3. Each of this values is being send to second filter.
      4. Reads yielded values from second filter until it receives EOF_MARKER
         or EOL_MARKER. Each of this values yields to writer.
    """
    chunk = yield

    while True:
        eof = chunk is EOF_MARKER
        chunk = filter.send(chunk)

        while chunk is not EOL_MARKER:
            chunk = filter2.send(chunk)

            while chunk not in (EOF_MARKER, EOL_MARKER):
                yield chunk
                chunk = next(filter2)

            if chunk is not EOF_MARKER:
                if eof:
                    chunk = EOF_MARKER
                else:
                    chunk = next(filter)
            else:
                break

        chunk = yield EOL_MARKER


class HttpMessage:
    """HttpMessage allows to write headers and payload to a stream.

    For example, lets say we want to read file then compress it with deflate
    compression and then send it with chunked transfer encoding, code may look
    like this:

       >>> response = aiohttp.Response(transport, 200)

    We have to use deflate compression first:

      >>> response.add_compression_filter('deflate')

    Then we want to split output stream into chunks of 1024 bytes size:

      >>> response.add_chunking_filter(1024)

    We can add headers to response with add_headers() method. add_headers()
    does not send data to transport, send_headers() sends request/response
    line and then sends headers:

      >>> response.add_headers(
      ...     ('Content-Disposition', 'attachment; filename="..."'))
      >>> response.send_headers()

    Now we can use chunked writer to write stream to a network stream.
    First call to write() method sends response status line and headers,
    add_header() and add_headers() method unavailable at this stage:

    >>> with open('...', 'rb') as f:
    ...     chunk = fp.read(8192)
    ...     while chunk:
    ...         response.write(chunk)
    ...         chunk = fp.read(8192)

    >>> response.write_eof()

    """

    writer = None

    # 'filter' is being used for altering write() behaviour,
    # add_chunking_filter adds deflate/gzip compression and
    # add_compression_filter splits incoming data into a chunks.
    filter = None

    HOP_HEADERS = None  # Must be set by subclass.

    SERVER_SOFTWARE = 'Python/{0[0]}.{0[1]} aiohttp/{1}'.format(
        sys.version_info, aiohttp.__version__)

    status = None
    status_line = b''
    upgrade = False  # Connection: UPGRADE
    websocket = False  # Upgrade: WEBSOCKET
    has_chunked_hdr = False  # Transfer-encoding: chunked

    # subclass can enable auto sending headers with write() call,
    # this is useful for wsgi's start_response implementation.
    _send_headers = False

    def __init__(self, transport, version, close):
        self.transport = transport
        self.version = version
        self.closing = close
        self.keepalive = None
        self.chunked = False
        self.length = None
        self.headers = CIMultiDict()
        self.headers_sent = False
        self.output_length = 0
        self._output_size = 0

    def force_close(self):
        self.closing = True
        self.keepalive = False

    def enable_chunked_encoding(self):
        self.chunked = True

    def keep_alive(self):
        if self.keepalive is None:
            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
            else:
                return not self.closing
        else:
            return self.keepalive

    def is_headers_sent(self):
        return self.headers_sent

    def add_header(self, name, value):
        """Analyze headers. Calculate content length,
        removes hop headers, etc."""
        assert not self.headers_sent, 'headers have been sent already'
        assert isinstance(name, str), \
            'Header name should be a string, got {!r}'.format(name)
        assert set(name).issubset(ASCIISET), \
            'Header name should contain ASCII chars, got {!r}'.format(name)
        assert isinstance(value, str), \
            'Header {!r} should have string value, got {!r}'.format(
                name, value)

        name = name.strip().upper()
        value = value.strip()

        if name == hdrs.CONTENT_LENGTH:
            self.length = int(value)

        if name == hdrs.TRANSFER_ENCODING:
            self.has_chunked_hdr = value.lower().strip() == 'chunked'

        if name == hdrs.CONNECTION:
            val = value.lower()
            # handle websocket
            if 'upgrade' in val:
                self.upgrade = True
            # connection keep-alive
            elif 'close' in val:
                self.keepalive = False
            elif 'keep-alive' in val:
                self.keepalive = True

        elif name == hdrs.UPGRADE:
            if 'websocket' in value.lower():
                self.websocket = True
                self.headers[name] = value

        elif name not in self.HOP_HEADERS:
            # ignore hop-by-hop headers
            self.headers.add(name, value)

    def add_headers(self, *headers):
        """Adds headers to a http message."""
        for name, value in headers:
            self.add_header(name, value)

    def send_headers(self, _sep=': ', _end='\r\n'):
        """Writes headers to a stream. Constructs payload writer."""
        # Chunked response is only for HTTP/1.1 clients or newer
        # and there is no Content-Length header is set.
        # Do not use chunked responses when the response is guaranteed to
        # not have a response body (304, 204).
        assert not self.headers_sent, 'headers have been sent already'
        self.headers_sent = True

        if self.chunked or (self.length is None and
                            self.version >= HttpVersion11 and
                            self.status not in (304, 204)):
            self.writer = self._write_chunked_payload()
            self.headers[hdrs.TRANSFER_ENCODING] = 'chunked'

        elif self.length is not None:
            self.writer = self._write_length_payload(self.length)

        else:
            self.writer = self._write_eof_payload()

        next(self.writer)

        self._add_default_headers()

        # status + headers
        headers = ''.join(itertools.chain(
            (self.status_line,),
            *((k, _sep, v, _end) for k, v in self.headers.items())))
        headers = headers.encode('utf-8') + b'\r\n'

        self.output_length += len(headers)
        self.transport.write(headers)

    def _add_default_headers(self):
        # set the connection header
        if self.upgrade:
            connection = 'upgrade'
        elif not self.closing if self.keepalive is None else self.keepalive:
            connection = 'keep-alive'
        else:
            connection = 'close'

        self.headers[hdrs.CONNECTION] = connection

    def write(self, chunk, *,
              drain=False, EOF_MARKER=EOF_MARKER, EOL_MARKER=EOL_MARKER):
        """Writes chunk of data to a stream by using different writers.

        writer uses filter to modify chunk of data.
        write_eof() indicates end of stream.
        writer can't be used after write_eof() method being called.
        write() return drain future.
        """
        assert (isinstance(chunk, (bytes, bytearray)) or
                chunk is EOF_MARKER), chunk

        size = self.output_length

        if self._send_headers and not self.headers_sent:
            self.send_headers()

        assert self.writer is not None, 'send_headers() is not called.'

        if self.filter:
            chunk = self.filter.send(chunk)
            while chunk not in (EOF_MARKER, EOL_MARKER):
                self.writer.send(chunk)
                chunk = next(self.filter)
        else:
            if chunk is not EOF_MARKER:
                self.writer.send(chunk)

        self._output_size += self.output_length - size

        if self._output_size > 64 * 1024:
            if drain:
                self._output_size = 0
                return self.transport.drain()

        return ()

    def write_eof(self):
        self.write(EOF_MARKER)
        try:
            self.writer.throw(aiohttp.EofStream())
        except StopIteration:
            pass

        return self.transport.drain()

    def _write_chunked_payload(self):
        """Write data in chunked transfer encoding."""
        while True:
            try:
                chunk = yield
            except aiohttp.EofStream:
                self.transport.write(b'0\r\n\r\n')
                self.output_length += 5
                break

            chunk = bytes(chunk)
            chunk_len = '{:x}\r\n'.format(len(chunk)).encode('ascii')
            self.transport.write(chunk_len)
            self.transport.write(chunk)
            self.transport.write(b'\r\n')
            self.output_length += len(chunk_len) + len(chunk) + 2

    def _write_length_payload(self, length):
        """Write specified number of bytes to a stream."""
        while True:
            try:
                chunk = yield
            except aiohttp.EofStream:
                break

            if length:
                l = len(chunk)
                if length >= l:
                    self.transport.write(chunk)
                    self.output_length += l
                    length = length-l
                else:
                    self.transport.write(chunk[:length])
                    self.output_length += length
                    length = 0

    def _write_eof_payload(self):
        while True:
            try:
                chunk = yield
            except aiohttp.EofStream:
                break

            self.transport.write(chunk)
            self.output_length += len(chunk)

    @wrap_payload_filter
    def add_chunking_filter(self, chunk_size=16*1024, *,
                            EOF_MARKER=EOF_MARKER, EOL_MARKER=EOL_MARKER):
        """Split incoming stream into chunks."""
        buf = bytearray()
        chunk = yield

        while True:
            if chunk is EOF_MARKER:
                if buf:
                    yield buf

                yield EOF_MARKER

            else:
                buf.extend(chunk)

                while len(buf) >= chunk_size:
                    chunk = bytes(buf[:chunk_size])
                    del buf[:chunk_size]
                    yield chunk

                chunk = yield EOL_MARKER

    @wrap_payload_filter
    def add_compression_filter(self, encoding='deflate', *,
                               EOF_MARKER=EOF_MARKER, EOL_MARKER=EOL_MARKER):
        """Compress incoming stream with deflate or gzip encoding."""
        zlib_mode = (16 + zlib.MAX_WBITS
                     if encoding == 'gzip' else -zlib.MAX_WBITS)
        zcomp = zlib.compressobj(wbits=zlib_mode)

        chunk = yield
        while True:
            if chunk is EOF_MARKER:
                yield zcomp.flush()
                chunk = yield EOF_MARKER

            else:
                yield zcomp.compress(chunk)
                chunk = yield EOL_MARKER


class Response(HttpMessage):
    """Create http response message.

    Transport is a socket stream transport. status is a response status code,
    status has to be integer value. http_version is a tuple that represents
    http version, (1, 0) stands for HTTP/1.0 and (1, 1) is for HTTP/1.1
    """

    HOP_HEADERS = ()

    @staticmethod
    def calc_reason(status):
        record = RESPONSES.get(status)
        if record is not None:
            reason = record[0]
        else:
            reason = str(status)
        return reason

    def __init__(self, transport, status,
                 http_version=HttpVersion11, close=False, reason=None):
        super().__init__(transport, http_version, close)

        self.status = status
        if reason is None:
            reason = self.calc_reason(status)

        self.reason = reason
        self.status_line = 'HTTP/{}.{} {} {}\r\n'.format(
            http_version[0], http_version[1], status, reason)

    def _add_default_headers(self):
        super()._add_default_headers()

        if hdrs.DATE not in self.headers:
            # format_date_time(None) is quite expensive
            self.headers.setdefault(hdrs.DATE, format_date_time(None))
        self.headers.setdefault(hdrs.SERVER, self.SERVER_SOFTWARE)


class Request(HttpMessage):

    HOP_HEADERS = ()

    def __init__(self, transport, method, path,
                 http_version=HttpVersion11, close=False):
        # set the default for HTTP 1.0 to be different
        # will only be overwritten with keep-alive header
        if http_version < HttpVersion11:
            close = True

        super().__init__(transport, http_version, close)

        self.method = method
        self.path = path
        self.status_line = '{0} {1} HTTP/{2[0]}.{2[1]}\r\n'.format(
            method, path, http_version)

    def _add_default_headers(self):
        super()._add_default_headers()

        self.headers.setdefault(hdrs.USER_AGENT, self.SERVER_SOFTWARE)

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