{
    "file_diffs": [
        {
            "old_file_content": "import asyncio\nimport binascii\nimport collections\nimport cgi\nimport http.cookies\nimport io\nimport json\nimport re\nimport weakref\n\nfrom urllib.parse import urlsplit, parse_qsl, unquote\n\nfrom .abc import AbstractRouter, AbstractMatchInfo\nfrom .errors import HttpErrorException\nfrom .helpers import parse_mimetype\nfrom .multidict import MultiDict, MutableMultiDict\nfrom .protocol import Response as ResponseImpl, HttpVersion\nfrom .server import ServerHttpProtocol\nfrom .streams import EOF_MARKER\n\n\n__all__ = [\n    'Application',\n    'HttpVersion',\n    'Request',\n    'StreamResponse',\n    'Response',\n    'UrlDispatch',\n    'UrlMappingMatchInfo',\n    ]\n\n\nclass HeadersMixin:\n\n    _content_type = None\n    _content_dict = None\n\n    @property\n    def content_type(self):\n        if self._content_type is not None:\n            return self._content_type\n        raw = self.headers.get('Content-Type')\n        if raw is None:\n            # default value according to RFC 2616\n            self._content_type = 'application/octet-stream'\n            self._content_dict = {}\n        else:\n            self._content_type, self._content_dict = cgi.parse_header(raw)\n        return self._content_type\n\n    @property\n    def charset(self):\n        # Assumes that charset is UTF8 if not specified\n        if self._content_type is None:\n            self.content_type  # calculates _content_dict also\n        return self._content_dict.get('charset', 'utf-8')\n\n\nclass StreamResponse(HeadersMixin):\n\n    def __init__(self, request):\n        self._request = request\n        self.headers = MutableMultiDict()\n        self._status_code = 200\n        self._cookies = http.cookies.SimpleCookie()\n        self._deleted_cookies = set()\n        self._keep_alive = True\n        self._version = request.version\n\n        self._resp_impl = None\n        self._eof_sent = False\n\n    def _copy_cookies(self):\n        for cookie in self._cookies.values():\n            value = cookie.output(header='')[1:]\n            self.headers.add('Set-Cookie', value)\n\n    def _check_sending_started(self):\n        resp = self._request._response\n        if resp is not None:\n            resp = resp()  # dereference weakref\n        if resp is not None:\n            raise RuntimeError((\"Response {!r} already started to send\"\n                                \" data\").format(resp))\n\n    @property\n    def cookies(self):\n        return self._cookies\n\n    def set_cookie(self, name, value, *, expires=None,\n                   domain=None, max_age=None, path=None,\n                   secure=None, httponly=None, version=None):\n        \"\"\"Set or update response cookie.\n\n        Sets new cookie or updates existent with new value.\n        Also updates only those params which are not None.\n        \"\"\"\n\n        self._check_sending_started()\n        if name in self._deleted_cookies:\n            self._deleted_cookies.remove(name)\n            self._cookies.pop(name, None)\n\n        self._cookies[name] = value\n        c = self._cookies[name]\n        if expires is not None:\n            c['expires'] = expires\n        if domain is not None:\n            c['domain'] = domain\n        if max_age is not None:\n            c['max-age'] = max_age\n        if path is not None:\n            c['path'] = path\n        if secure is not None:\n            c['secure'] = secure\n        if httponly is not None:\n            c['httponly'] = httponly\n        if version is not None:\n            c['version'] = version\n\n    def del_cookie(self, name, *, domain=None, path=None):\n        \"\"\"Delete cookie.\n\n        Creates new empty expired cookie.\n        \"\"\"\n        # TODO: do we need domain/path here?\n        self._check_sending_started()\n        self._cookies.pop(name, None)\n        self.set_cookie(name, '', max_age=0, domain=domain, path=path)\n        self._deleted_cookies.add(name)\n\n    @property\n    def status_code(self):\n        return self._status_code\n\n    @status_code.setter\n    def status_code(self, value):\n        self._check_sending_started()\n        if not isinstance(value, int):\n            raise TypeError(\"Status code must be int\")\n        self._status_code = value\n\n    @property\n    def version(self):\n        return self._version\n\n    @version.setter\n    def version(self, value):\n        self._check_sending_started()\n        if not isinstance(value, HttpVersion):\n            raise TypeError(\"HTTP version must be HttpVersion instance\")\n        self._version = value\n\n    @property\n    def keep_alive(self):\n        return self._keep_alive\n\n    @keep_alive.setter\n    def keep_alive(self, value):\n        self._check_sending_started()\n        self._keep_alive = bool(value)\n\n    @property\n    def content_length(self):\n        l = self.headers.get('Content-Length')\n        if l is None:\n            return None\n        else:\n            return int(l)\n\n    @content_length.setter\n    def content_length(self, value):\n        self._check_sending_started()\n        value = int(value)\n        # TODO: raise error if chunked enabled\n        self.headers['Content-Length'] = str(value)\n\n    def set_chunked(self, chunk_size, buffered=True):\n        if self.content_length is not None:\n            raise RuntimeError(\n                \"Cannot use chunked encoding with Content-Length set up\")\n\n    def send_headers(self):\n        if self._resp_impl is not None:\n            raise RuntimeError(\"HTTP headers are already sent\")\n        if self._eof_sent:\n            raise RuntimeError(\"Cannot call send_header() after write_eof()\")\n\n        self._check_sending_started()\n        self._request._response = weakref.ref(self)\n\n        resp_impl = self._resp_impl = ResponseImpl(\n            self._request._server_http_protocol.writer,\n            self._status_code,\n            self._request.version)\n\n        self._copy_cookies()\n\n        headers = self.headers.items(getall=True)\n        for key, val in headers:\n            resp_impl.add_header(key, val)\n\n        resp_impl.send_headers()\n\n    def write(self, data):\n        if not isinstance(data, (bytes, bytearray, memoryview)):\n            raise TypeError('data argument must be byte-ish (%r)',\n                            type(data))\n\n        if self._eof_sent:\n            raise RuntimeError(\"Cannot call write() after send_eof()\")\n        if self._resp_impl is None:\n            self.send_headers()\n\n        if data:\n            self._resp_impl.write(data)\n\n    @asyncio.coroutine\n    def write_eof(self):\n        if self._resp_impl is None:\n            raise RuntimeError(\"No data has been sent\")\n        if self._eof_sent:\n            return\n\n        yield from self._resp_impl.write_eof()\n        if self._resp_impl.keep_alive():\n            self._request._server_http_protocol.keep_alive(self._keep_alive)\n        self._eof_sent = True\n\n\nclass Response(StreamResponse):\n\n    def __init__(self, request, body=b'', *, status_code=200, headers=None):\n        super().__init__(request)\n        self.status_code = status_code\n        self.body = body\n        if headers is not None:\n            self.headers.extend(headers)\n\n    @property\n    def body(self):\n        return self._body\n\n    @body.setter\n    def body(self, body):\n        if not isinstance(body, (bytes, bytearray, memoryview)):\n            raise TypeError('body argument must be byte-ish (%r)',\n                            type(body))\n        self._check_sending_started()\n        self._body = body\n\n    @asyncio.coroutine\n    def render(self):\n        body = self._body\n        self.content_length = len(body)\n        self.write(body)\n\n\nclass Request(HeadersMixin):\n\n    def __init__(self, app, message, payload, protocol):\n        path = unquote(message.path)\n        res = urlsplit(path)\n        self._app = app\n        self._version = message.version\n        self._server_http_protocol = protocol\n        self._method = message.method.upper()\n        self._host = message.headers.get('HOST')\n        self._path_qs = path\n        self._path = res.path\n        self._query_string = res.query\n        self._get = MultiDict(parse_qsl(res.query))\n        self._post = None\n        self._headers = message.headers\n\n        # matchdict, route_name, handler\n        # or information about traversal lookup\n        self._match_info = None  # initialized after route resolving\n\n        self._payload = payload\n        self._response = None\n        self._cookies = None\n\n    @property\n    def method(self):\n        return self._method\n\n    @property\n    def version(self):\n        return self._version\n\n    @property\n    def host(self):\n        return self._host\n\n    @property\n    def path_qs(self):\n        return self._path_qs\n\n    @property\n    def path(self):\n        return self._path\n\n    @property\n    def query_string(self):\n        return self._query_string\n\n    @property\n    def GET(self):\n        return self._get\n\n    @property\n    def headers(self):\n        return self._headers\n\n    @property\n    def match_info(self):\n        return self._match_info\n\n    @property\n    def app(self):\n        \"\"\"Application instance.\"\"\"\n        return self._app\n\n    @property\n    def cookies(self):\n        \"\"\"Return request cookies.\n\n        A read-only dictionary-like object.\n        \"\"\"\n        if self._cookies is None:\n            raw = self.headers.get('COOKIE', '')\n            parsed = http.cookies.SimpleCookie(raw)\n            self._cookies = MultiDict({key: val.value\n                                       for key, val in parsed.items()})\n        return self._cookies\n\n    @property\n    def payload(self):\n        \"\"\"Return raw paiload stream.\"\"\"\n        return self._payload\n\n    @asyncio.coroutine\n    def release(self):\n        \"\"\"Release request.\n\n        Eat unread part of HTTP BODY if present.\n        \"\"\"\n        chunk = yield from self._payload.readany()\n        while chunk is not EOF_MARKER or chunk:\n            chunk = yield from self._payload.readany()\n\n    def terminate(self):\n        # TODO: the method should close connection after sending response\n        # the main reason is to don't read request body as release() does\n        pass\n\n    @asyncio.coroutine\n    def read(self):\n        \"\"\"Read request body if present.\n\n        Returns bytes object with full request content or None if\n        request has no BODY.\n        \"\"\"\n\n        if self._payload is None:\n            return None\n        body = bytearray()\n        while True:\n            chunk = yield from self._payload.readany()\n            body.extend(chunk)\n            if chunk is EOF_MARKER:\n                break\n        return bytes(body)\n\n    @asyncio.coroutine\n    def text(self):\n        bytes_body = yield from self.read()\n        if bytes_body is None:\n            return None\n        encoding = self.charset\n        return bytes_body.decode(encoding)\n\n    @asyncio.coroutine\n    def json(self, *, loader=json.loads):\n        body = yield from self.text()\n        if body is None:\n            return None\n        return loader(body)\n\n    @asyncio.coroutine\n    def POST(self):\n        if self._post is not None:\n            return self._post\n        if self.method not in ('POST', 'PUT', 'PATCH'):\n            self._post = MultiDict()\n            return\n        content_type = self.content_type\n        if (content_type not in ('',\n                                 'application/x-www-form-urlencoded',\n                                 'multipart/form-data')):\n            self._post = MultiDict()\n            return\n\n        body = yield from self.text()\n        fs = cgi.FieldStorage(fp=io.StringIO(body),\n                              environ={'CONTENT_LENGTH': '0',\n                                       'QUERY_STRING': '',\n                                       'REQUEST_METHOD': self.method,\n                                       'CONTENT_TYPE': content_type},\n                              keep_blank_values=True,\n                              encoding='utf-8')\n\n        out = MutableMultiDict()\n        for field in fs.list or ():\n            charset = field.type_options.get('charset', 'utf-8')\n            transfer_encoding = field.headers.get('Content-Transfer-Encoding',\n                                                  None)\n            supported_tranfer_encoding = {\n                'base64': binascii.a2b_base64,\n                'quoted-printable': binascii.a2b_qp\n                }\n            if charset == 'utf-8':\n                decode = lambda b: b\n            else:\n                decode = lambda b: b.encode('utf-8').decode(charset)\n            if field.filename:\n                field.filename = decode(field.filename)\n                out.add(field.name, field)\n            else:\n                value = field.value\n                if transfer_encoding in supported_tranfer_encoding:\n                    # binascii accepts bytes\n                    value = value.encode('utf-8')\n                    value = supported_tranfer_encoding[\n                        transfer_encoding](value)\n                    # binascii returns bytes\n                    value = value.decode('utf-8')\n                out.add(field.name, decode(value))\n        self._post = MultiDict(out)\n        return self._post\n\n    @asyncio.coroutine\n    def start_websocket(self):\n        \"\"\"Upgrade connection to websocket.\n\n        Returns (reader, writer) pair.\n        \"\"\"\n\n\nclass UrlMappingMatchInfo(AbstractMatchInfo):\n\n    def __init__(self, matchdict, entry):\n        self._matchdict = matchdict\n        self._entry = entry\n\n    @property\n    def handler(self):\n        return self._entry.handler\n\n    @property\n    def matchdict(self):\n        return self._matchdict\n\n    @property\n    def route_name(self):\n        return self._entry.name\n\n\nEntry = collections.namedtuple('Entry', 'regex method handler')\n\n\nclass UrlDispatch(AbstractRouter):\n\n    DYN = re.compile(r'^\\{[_a-zA-Z][_a-zA-Z0-9]*\\}$')\n    GOOD = r'[^{}/]+'\n    PLAIN = re.compile('^'+GOOD+'$')\n\n    METHODS = {'POST', 'GET', 'PUT', 'DELETE', 'PATCH', 'HEAD', 'OPTIONS'}\n\n    def __init__(self, *, loop=None):\n        if loop is None:\n            loop = asyncio.get_event_loop()\n        self._loop = loop\n        super().__init__()\n        self._urls = []\n\n    @asyncio.coroutine\n    def resolve(self, request):\n        path = request.path\n        method = request.method\n        allowed_methods = set()\n        for entry in self._urls:\n            match = entry.regex.match(path)\n            if match is None:\n                continue\n            if entry.method != method:\n                allowed_methods.add(entry.method)\n            else:\n                break\n        else:\n            if allowed_methods:\n                allow = ', '.join(sorted(allowed_methods))\n                # add log\n                raise HttpErrorException(405, \"Method Not Allowed\",\n                                         headers=(('Allow', allow),))\n            else:\n                # add log\n                raise HttpErrorException(404, \"Not Found\")\n\n        matchdict = match.groupdict()\n        return UrlMappingMatchInfo(matchdict, entry)\n\n    def add_route(self, method, path, handler):\n        assert callable(handler), handler\n\n        assert path.startswith('/')\n        assert callable(handler), handler\n        method = method.upper()\n        assert method in self.METHODS, method\n        regexp = []\n        for part in path.split('/'):\n            if not part:\n                continue\n            if self.DYN.match(part):\n                regexp.append('(?P<'+part[1:-1]+'>'+self.GOOD+')')\n            elif self.PLAIN.match(part):\n                regexp.append(part)\n            else:\n                raise ValueError(\"Invalid path '{}'['{}']\".format(path, part))\n        pattern = '/' + '/'.join(regexp)\n        if path.endswith('/') and pattern != '/':\n            pattern += '/'\n        try:\n            compiled = re.compile('^' + pattern + '$')\n        except re.error:\n            raise ValueError(\"Invalid path '{}'\".format(path))\n        self._urls.append(Entry(compiled, method, handler))\n\n\nclass RequestHandler(ServerHttpProtocol):\n\n    def __init__(self, app, **kwargs):\n        super().__init__(**kwargs)\n        self._app = app\n\n    @asyncio.coroutine\n    def handle_request(self, message, payload):\n        request = Request(self._app, message, payload, self)\n        match_info = yield from self._app.router.resolve(request)\n        if match_info is not None:\n            request._match_info = match_info\n            handler = match_info.handler\n\n            if asyncio.iscoroutinefunction(handler):\n                resp = yield from handler(request)\n            else:\n                resp = handler(request)\n            yield from request.release()\n\n            if isinstance(resp, Response):\n                yield from resp.render()\n            else:\n                raise RuntimeError((\"Handler should return Response \"\n                                    \"instance, got {!r}\")\n                                   .format(type(resp)))\n            yield from resp.write_eof()\n        else:\n            raise HttpErrorException(404, \"Not Found\")\n\n\nclass Application(dict, asyncio.AbstractServer):\n\n    def __init__(self, *, loop=None, router=None, **kwargs):\n        # TODO: explicitly accept *debug* param\n        self._kwargs = kwargs\n        if loop is None:\n            loop = asyncio.get_event_loop()\n        if router is None:\n            router = UrlDispatch(loop=loop)\n        self._router = router\n        self._loop = loop\n\n    @property\n    def router(self):\n        return self._router\n\n    def make_handler(self):\n        return RequestHandler(self, loop=self._loop, **self._kwargs)\n\n    def close(self):\n        pass\n\n    def register_on_close(self, cb):\n        pass\n\n    @asyncio.coroutine\n    def wait_closed(self):\n        pass\n",
            "new_file_content": "import asyncio\nimport binascii\nimport collections\nimport cgi\nimport http.cookies\nimport io\nimport json\nimport re\nimport weakref\n\nfrom urllib.parse import urlsplit, parse_qsl, unquote\n\nfrom .abc import AbstractRouter, AbstractMatchInfo\nfrom .errors import HttpErrorException\nfrom .helpers import parse_mimetype\nfrom .multidict import MultiDict, MutableMultiDict\nfrom .protocol import Response as ResponseImpl, HttpVersion\nfrom .server import ServerHttpProtocol\nfrom .streams import EOF_MARKER\n\n\n__all__ = [\n    'Application',\n    'HttpVersion',\n    'Request',\n    'StreamResponse',\n    'Response',\n    'UrlDispatch',\n    'UrlMappingMatchInfo',\n    ]\n\n\nclass HeadersMixin:\n\n    _content_type = None\n    _content_dict = None\n\n    @property\n    def content_type(self):\n        if self._content_type is not None:\n            return self._content_type\n        raw = self.headers.get('Content-Type')\n        if raw is None:\n            # default value according to RFC 2616\n            self._content_type = 'application/octet-stream'\n            self._content_dict = {}\n        else:\n            self._content_type, self._content_dict = cgi.parse_header(raw)\n        return self._content_type\n\n    @property\n    def charset(self):\n        # Assumes that charset is UTF8 if not specified\n        if self._content_type is None:\n            self.content_type  # calculates _content_dict also\n        return self._content_dict.get('charset', 'utf-8')\n\n    @property\n    def content_length(self):\n        l = self.headers.get('Content-Length')\n        if l is None:\n            return None\n        else:\n            return int(l)\n\n\nclass StreamResponse(HeadersMixin):\n\n    def __init__(self, request):\n        self._request = request\n        self.headers = MutableMultiDict()\n        self._status_code = 200\n        self._cookies = http.cookies.SimpleCookie()\n        self._deleted_cookies = set()\n        self._keep_alive = True\n        self._version = request.version\n\n        self._resp_impl = None\n        self._eof_sent = False\n\n    def _copy_cookies(self):\n        for cookie in self._cookies.values():\n            value = cookie.output(header='')[1:]\n            self.headers.add('Set-Cookie', value)\n\n    def _check_sending_started(self):\n        resp = self._request._response\n        if resp is not None:\n            resp = resp()  # dereference weakref\n        if resp is not None:\n            raise RuntimeError((\"Response {!r} already started to send\"\n                                \" data\").format(resp))\n\n    @property\n    def cookies(self):\n        return self._cookies\n\n    def set_cookie(self, name, value, *, expires=None,\n                   domain=None, max_age=None, path=None,\n                   secure=None, httponly=None, version=None):\n        \"\"\"Set or update response cookie.\n\n        Sets new cookie or updates existent with new value.\n        Also updates only those params which are not None.\n        \"\"\"\n\n        self._check_sending_started()\n        if name in self._deleted_cookies:\n            self._deleted_cookies.remove(name)\n            self._cookies.pop(name, None)\n\n        self._cookies[name] = value\n        c = self._cookies[name]\n        if expires is not None:\n            c['expires'] = expires\n        if domain is not None:\n            c['domain'] = domain\n        if max_age is not None:\n            c['max-age'] = max_age\n        if path is not None:\n            c['path'] = path\n        if secure is not None:\n            c['secure'] = secure\n        if httponly is not None:\n            c['httponly'] = httponly\n        if version is not None:\n            c['version'] = version\n\n    def del_cookie(self, name, *, domain=None, path=None):\n        \"\"\"Delete cookie.\n\n        Creates new empty expired cookie.\n        \"\"\"\n        # TODO: do we need domain/path here?\n        self._check_sending_started()\n        self._cookies.pop(name, None)\n        self.set_cookie(name, '', max_age=0, domain=domain, path=path)\n        self._deleted_cookies.add(name)\n\n    @property\n    def status_code(self):\n        return self._status_code\n\n    @status_code.setter\n    def status_code(self, value):\n        self._check_sending_started()\n        if not isinstance(value, int):\n            raise TypeError(\"Status code must be int\")\n        self._status_code = value\n\n    @property\n    def version(self):\n        return self._version\n\n    @version.setter\n    def version(self, value):\n        self._check_sending_started()\n        if not isinstance(value, HttpVersion):\n            raise TypeError(\"HTTP version must be HttpVersion instance\")\n        self._version = value\n\n    @property\n    def keep_alive(self):\n        return self._keep_alive\n\n    @keep_alive.setter\n    def keep_alive(self, value):\n        self._check_sending_started()\n        self._keep_alive = bool(value)\n\n    @property\n    def content_length(self):\n        # Just a placeholder for adding setter\n        return super().content_length\n\n    @content_length.setter\n    def content_length(self, value):\n        self._check_sending_started()\n        value = int(value)\n        # TODO: raise error if chunked enabled\n        self.headers['Content-Length'] = str(value)\n\n    def set_chunked(self, chunk_size, buffered=True):\n        if self.content_length is not None:\n            raise RuntimeError(\n                \"Cannot use chunked encoding with Content-Length set up\")\n\n    def send_headers(self):\n        if self._resp_impl is not None:\n            raise RuntimeError(\"HTTP headers are already sent\")\n        if self._eof_sent:\n            raise RuntimeError(\"Cannot call send_header() after write_eof()\")\n\n        self._check_sending_started()\n        self._request._response = weakref.ref(self)\n\n        resp_impl = self._resp_impl = ResponseImpl(\n            self._request._server_http_protocol.writer,\n            self._status_code,\n            self._request.version)\n\n        self._copy_cookies()\n\n        headers = self.headers.items(getall=True)\n        for key, val in headers:\n            resp_impl.add_header(key, val)\n\n        resp_impl.send_headers()\n\n    def write(self, data):\n        if not isinstance(data, (bytes, bytearray, memoryview)):\n            raise TypeError('data argument must be byte-ish (%r)',\n                            type(data))\n\n        if self._eof_sent:\n            raise RuntimeError(\"Cannot call write() after send_eof()\")\n        if self._resp_impl is None:\n            self.send_headers()\n\n        if data:\n            self._resp_impl.write(data)\n\n    @asyncio.coroutine\n    def write_eof(self):\n        if self._resp_impl is None:\n            raise RuntimeError(\"No data has been sent\")\n        if self._eof_sent:\n            return\n\n        yield from self._resp_impl.write_eof()\n        if self._resp_impl.keep_alive():\n            self._request._server_http_protocol.keep_alive(self._keep_alive)\n        self._eof_sent = True\n\n\nclass Response(StreamResponse):\n\n    def __init__(self, request, body=b'', *, status_code=200, headers=None):\n        super().__init__(request)\n        self.status_code = status_code\n        self.body = body\n        if headers is not None:\n            self.headers.extend(headers)\n\n    @property\n    def body(self):\n        return self._body\n\n    @body.setter\n    def body(self, body):\n        if not isinstance(body, (bytes, bytearray, memoryview)):\n            raise TypeError('body argument must be byte-ish (%r)',\n                            type(body))\n        self._check_sending_started()\n        self._body = body\n\n    @asyncio.coroutine\n    def render(self):\n        body = self._body\n        self.content_length = len(body)\n        self.write(body)\n\n\nclass Request(HeadersMixin):\n\n    def __init__(self, app, message, payload, protocol):\n        path = unquote(message.path)\n        res = urlsplit(path)\n        self._app = app\n        self._version = message.version\n        self._server_http_protocol = protocol\n        self._method = message.method.upper()\n        self._host = message.headers.get('HOST')\n        self._path_qs = path\n        self._path = res.path\n        self._query_string = res.query\n        self._get = MultiDict(parse_qsl(res.query))\n        self._post = None\n        self._headers = message.headers\n\n        # matchdict, route_name, handler\n        # or information about traversal lookup\n        self._match_info = None  # initialized after route resolving\n\n        self._payload = payload\n        self._response = None\n        self._cookies = None\n\n    @property\n    def method(self):\n        return self._method\n\n    @property\n    def version(self):\n        return self._version\n\n    @property\n    def host(self):\n        return self._host\n\n    @property\n    def path_qs(self):\n        return self._path_qs\n\n    @property\n    def path(self):\n        return self._path\n\n    @property\n    def query_string(self):\n        return self._query_string\n\n    @property\n    def GET(self):\n        return self._get\n\n    @property\n    def headers(self):\n        return self._headers\n\n    @property\n    def match_info(self):\n        return self._match_info\n\n    @property\n    def app(self):\n        \"\"\"Application instance.\"\"\"\n        return self._app\n\n    @property\n    def cookies(self):\n        \"\"\"Return request cookies.\n\n        A read-only dictionary-like object.\n        \"\"\"\n        if self._cookies is None:\n            raw = self.headers.get('COOKIE', '')\n            parsed = http.cookies.SimpleCookie(raw)\n            self._cookies = MultiDict({key: val.value\n                                       for key, val in parsed.items()})\n        return self._cookies\n\n    @property\n    def payload(self):\n        \"\"\"Return raw paiload stream.\"\"\"\n        return self._payload\n\n    @asyncio.coroutine\n    def release(self):\n        \"\"\"Release request.\n\n        Eat unread part of HTTP BODY if present.\n        \"\"\"\n        chunk = yield from self._payload.readany()\n        while chunk is not EOF_MARKER or chunk:\n            chunk = yield from self._payload.readany()\n\n    def terminate(self):\n        # TODO: the method should close connection after sending response\n        # the main reason is to don't read request body as release() does\n        pass\n\n    @asyncio.coroutine\n    def read(self):\n        \"\"\"Read request body if present.\n\n        Returns bytes object with full request content or None if\n        request has no BODY.\n        \"\"\"\n\n        if self._payload is None:\n            return None\n        body = bytearray()\n        while True:\n            chunk = yield from self._payload.readany()\n            body.extend(chunk)\n            if chunk is EOF_MARKER:\n                break\n        return bytes(body)\n\n    @asyncio.coroutine\n    def text(self):\n        bytes_body = yield from self.read()\n        if bytes_body is None:\n            return None\n        encoding = self.charset\n        return bytes_body.decode(encoding)\n\n    @asyncio.coroutine\n    def json(self, *, loader=json.loads):\n        body = yield from self.text()\n        if body is None:\n            return None\n        return loader(body)\n\n    @asyncio.coroutine\n    def POST(self):\n        if self._post is not None:\n            return self._post\n        if self.method not in ('POST', 'PUT', 'PATCH'):\n            self._post = MultiDict()\n            return\n        content_type = self.content_type\n        if (content_type not in ('',\n                                 'application/x-www-form-urlencoded',\n                                 'multipart/form-data')):\n            self._post = MultiDict()\n            return\n\n        body = yield from self.text()\n        fs = cgi.FieldStorage(fp=io.StringIO(body),\n                              environ={'CONTENT_LENGTH': '0',\n                                       'QUERY_STRING': '',\n                                       'REQUEST_METHOD': self.method,\n                                       'CONTENT_TYPE': content_type},\n                              keep_blank_values=True,\n                              encoding='utf-8')\n\n        out = MutableMultiDict()\n        for field in fs.list or ():\n            charset = field.type_options.get('charset', 'utf-8')\n            transfer_encoding = field.headers.get('Content-Transfer-Encoding',\n                                                  None)\n            supported_tranfer_encoding = {\n                'base64': binascii.a2b_base64,\n                'quoted-printable': binascii.a2b_qp\n                }\n            if charset == 'utf-8':\n                decode = lambda b: b\n            else:\n                decode = lambda b: b.encode('utf-8').decode(charset)\n            if field.filename:\n                field.filename = decode(field.filename)\n                out.add(field.name, field)\n            else:\n                value = field.value\n                if transfer_encoding in supported_tranfer_encoding:\n                    # binascii accepts bytes\n                    value = value.encode('utf-8')\n                    value = supported_tranfer_encoding[\n                        transfer_encoding](value)\n                    # binascii returns bytes\n                    value = value.decode('utf-8')\n                out.add(field.name, decode(value))\n        self._post = MultiDict(out)\n        return self._post\n\n    @asyncio.coroutine\n    def start_websocket(self):\n        \"\"\"Upgrade connection to websocket.\n\n        Returns (reader, writer) pair.\n        \"\"\"\n\n\nclass UrlMappingMatchInfo(AbstractMatchInfo):\n\n    def __init__(self, matchdict, entry):\n        self._matchdict = matchdict\n        self._entry = entry\n\n    @property\n    def handler(self):\n        return self._entry.handler\n\n    @property\n    def matchdict(self):\n        return self._matchdict\n\n    @property\n    def route_name(self):\n        return self._entry.name\n\n\nEntry = collections.namedtuple('Entry', 'regex method handler')\n\n\nclass UrlDispatch(AbstractRouter):\n\n    DYN = re.compile(r'^\\{[_a-zA-Z][_a-zA-Z0-9]*\\}$')\n    GOOD = r'[^{}/]+'\n    PLAIN = re.compile('^'+GOOD+'$')\n\n    METHODS = {'POST', 'GET', 'PUT', 'DELETE', 'PATCH', 'HEAD', 'OPTIONS'}\n\n    def __init__(self, *, loop=None):\n        if loop is None:\n            loop = asyncio.get_event_loop()\n        self._loop = loop\n        super().__init__()\n        self._urls = []\n\n    @asyncio.coroutine\n    def resolve(self, request):\n        path = request.path\n        method = request.method\n        allowed_methods = set()\n        for entry in self._urls:\n            match = entry.regex.match(path)\n            if match is None:\n                continue\n            if entry.method != method:\n                allowed_methods.add(entry.method)\n            else:\n                break\n        else:\n            if allowed_methods:\n                allow = ', '.join(sorted(allowed_methods))\n                # add log\n                raise HttpErrorException(405, \"Method Not Allowed\",\n                                         headers=(('Allow', allow),))\n            else:\n                # add log\n                raise HttpErrorException(404, \"Not Found\")\n\n        matchdict = match.groupdict()\n        return UrlMappingMatchInfo(matchdict, entry)\n\n    def add_route(self, method, path, handler):\n        assert callable(handler), handler\n\n        assert path.startswith('/')\n        assert callable(handler), handler\n        method = method.upper()\n        assert method in self.METHODS, method\n        regexp = []\n        for part in path.split('/'):\n            if not part:\n                continue\n            if self.DYN.match(part):\n                regexp.append('(?P<'+part[1:-1]+'>'+self.GOOD+')')\n            elif self.PLAIN.match(part):\n                regexp.append(part)\n            else:\n                raise ValueError(\"Invalid path '{}'['{}']\".format(path, part))\n        pattern = '/' + '/'.join(regexp)\n        if path.endswith('/') and pattern != '/':\n            pattern += '/'\n        try:\n            compiled = re.compile('^' + pattern + '$')\n        except re.error:\n            raise ValueError(\"Invalid path '{}'\".format(path))\n        self._urls.append(Entry(compiled, method, handler))\n\n\nclass RequestHandler(ServerHttpProtocol):\n\n    def __init__(self, app, **kwargs):\n        super().__init__(**kwargs)\n        self._app = app\n\n    @asyncio.coroutine\n    def handle_request(self, message, payload):\n        request = Request(self._app, message, payload, self)\n        match_info = yield from self._app.router.resolve(request)\n        if match_info is not None:\n            request._match_info = match_info\n            handler = match_info.handler\n\n            if asyncio.iscoroutinefunction(handler):\n                resp = yield from handler(request)\n            else:\n                resp = handler(request)\n            yield from request.release()\n\n            if isinstance(resp, Response):\n                yield from resp.render()\n            else:\n                raise RuntimeError((\"Handler should return Response \"\n                                    \"instance, got {!r}\")\n                                   .format(type(resp)))\n            yield from resp.write_eof()\n        else:\n            raise HttpErrorException(404, \"Not Found\")\n\n\nclass Application(dict, asyncio.AbstractServer):\n\n    def __init__(self, *, loop=None, router=None, **kwargs):\n        # TODO: explicitly accept *debug* param\n        self._kwargs = kwargs\n        if loop is None:\n            loop = asyncio.get_event_loop()\n        if router is None:\n            router = UrlDispatch(loop=loop)\n        self._router = router\n        self._loop = loop\n\n    @property\n    def router(self):\n        return self._router\n\n    def make_handler(self):\n        return RequestHandler(self, loop=self._loop, **self._kwargs)\n\n    def close(self):\n        pass\n\n    def register_on_close(self, cb):\n        pass\n\n    @asyncio.coroutine\n    def wait_closed(self):\n        pass\n",
            "header": {
                "file": {
                    "path": "aiohttp/web.py"
                },
                "misc_line": null
            },
            "index_line": {
                "old_commit_hash": "3d55eb21",
                "new_commit_hash": "d750026b",
                "mode": "100644"
            },
            "is_binary_file": false,
            "binary_line": null,
            "minus_file": {
                "path": "a/aiohttp/web.py"
            },
            "plus_file": {
                "path": "b/aiohttp/web.py"
            },
            "hunks": [
                {
                    "descriptor": {
                        "old_range": {
                            "start": 55,
                            "length": 6
                        },
                        "new_range": {
                            "start": 55,
                            "length": 14
                        },
                        "section": "class HeadersMixin:"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "            self.content_type  # calculates _content_dict also",
                                "type": "context"
                            },
                            {
                                "content": "        return self._content_dict.get('charset', 'utf-8')",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "    @property",
                                "type": "added"
                            },
                            {
                                "content": "    def content_length(self):",
                                "type": "added"
                            },
                            {
                                "content": "        l = self.headers.get('Content-Length')",
                                "type": "added"
                            },
                            {
                                "content": "        if l is None:",
                                "type": "added"
                            },
                            {
                                "content": "            return None",
                                "type": "added"
                            },
                            {
                                "content": "        else:",
                                "type": "added"
                            },
                            {
                                "content": "            return int(l)",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "class StreamResponse(HeadersMixin):",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [
                        {
                            "file_name": "aiohttp/web.py",
                            "type": "class",
                            "name": "HeadersMixin",
                            "content": "class HeadersMixin:\n\n    _content_type = None\n    _content_dict = None\n\n    @property\n    def content_type(self):\n        if self._content_type is not None:\n            return self._content_type\n        raw = self.headers.get('Content-Type')\n        if raw is None:\n            # default value according to RFC 2616\n            self._content_type = 'application/octet-stream'\n            self._content_dict = {}\n        else:\n            self._content_type, self._content_dict = cgi.parse_header(raw)\n        return self._content_type\n\n    @property\n    def charset(self):\n        # Assumes that charset is UTF8 if not specified\n        if self._content_type is None:\n            self.content_type  # calculates _content_dict also\n        return self._content_dict.get('charset', 'utf-8')\n\n    @property\n    def content_length(self):\n        l = self.headers.get('Content-Length')\n        if l is None:\n            return None\n        else:\n            return int(l)",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 33,
                            "end_lineno": 64,
                            "parent": null
                        }
                    ],
                    "added_entities": [
                        {
                            "file_name": "aiohttp/web.py",
                            "type": "method",
                            "name": "HeadersMixin.content_length",
                            "content": "class HeadersMixin:\n\n    _content_type = None\n    _content_dict = None\n\n    @property\n    def content_type(self):\n        if self._content_type is not None:\n            return self._content_type\n        raw = self.headers.get('Content-Type')\n        if raw is None:\n            # default value according to RFC 2616\n            self._content_type = 'application/octet-stream'\n            self._content_dict = {}\n        else:\n            self._content_type, self._content_dict = cgi.parse_header(raw)\n        return self._content_type\n\n    @property\n    def charset(self):\n        # Assumes that charset is UTF8 if not specified\n        if self._content_type is None:\n            self.content_type  # calculates _content_dict also\n        return self._content_dict.get('charset', 'utf-8')\n\n    @property\n    def content_length(self):\n        l = self.headers.get('Content-Length')\n        if l is None:\n            return None\n        else:\n            return int(l)",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 59,
                            "end_lineno": 64,
                            "parent": {
                                "file_name": "aiohttp/web.py",
                                "type": "class",
                                "name": "HeadersMixin",
                                "content": "class HeadersMixin:\n\n    _content_type = None\n    _content_dict = None\n\n    @property\n    def content_type(self):\n        if self._content_type is not None:\n            return self._content_type\n        raw = self.headers.get('Content-Type')\n        if raw is None:\n            # default value according to RFC 2616\n            self._content_type = 'application/octet-stream'\n            self._content_dict = {}\n        else:\n            self._content_type, self._content_dict = cgi.parse_header(raw)\n        return self._content_type\n\n    @property\n    def charset(self):\n        # Assumes that charset is UTF8 if not specified\n        if self._content_type is None:\n            self.content_type  # calculates _content_dict also\n        return self._content_dict.get('charset', 'utf-8')\n\n    @property\n    def content_length(self):\n        l = self.headers.get('Content-Length')\n        if l is None:\n            return None\n        else:\n            return int(l)",
                                "ast_type_str": "ClassDef",
                                "start_lineno": 33,
                                "end_lineno": 64,
                                "parent": null
                            }
                        }
                    ],
                    "deleted_entities": []
                },
                {
                    "descriptor": {
                        "old_range": {
                            "start": 162,
                            "length": 11
                        },
                        "new_range": {
                            "start": 170,
                            "length": 8
                        },
                        "section": "class StreamResponse(HeadersMixin):"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "    @property",
                                "type": "context"
                            },
                            {
                                "content": "    def content_length(self):",
                                "type": "context"
                            },
                            {
                                "content": "        l = self.headers.get('Content-Length')",
                                "type": "deleted"
                            },
                            {
                                "content": "        if l is None:",
                                "type": "deleted"
                            },
                            {
                                "content": "            return None",
                                "type": "deleted"
                            },
                            {
                                "content": "        else:",
                                "type": "deleted"
                            },
                            {
                                "content": "            return int(l)",
                                "type": "deleted"
                            },
                            {
                                "content": "        # Just a placeholder for adding setter",
                                "type": "added"
                            },
                            {
                                "content": "        return super().content_length",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "    @content_length.setter",
                                "type": "context"
                            },
                            {
                                "content": "    def content_length(self, value):",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [
                        {
                            "file_name": "aiohttp/web.py",
                            "type": "method",
                            "name": "StreamResponse.content_length",
                            "content": "class StreamResponse(HeadersMixin):\n\n    def __init__(self, request):\n        self._request = request\n        self.headers = MutableMultiDict()\n        self._status_code = 200\n        self._cookies = http.cookies.SimpleCookie()\n        self._deleted_cookies = set()\n        self._keep_alive = True\n        self._version = request.version\n\n        self._resp_impl = None\n        self._eof_sent = False\n\n    def _copy_cookies(self):\n        for cookie in self._cookies.values():\n            value = cookie.output(header='')[1:]\n            self.headers.add('Set-Cookie', value)\n\n    def _check_sending_started(self):\n        resp = self._request._response\n        if resp is not None:\n            resp = resp()  # dereference weakref\n        if resp is not None:\n            raise RuntimeError((\"Response {!r} already started to send\"\n                                \" data\").format(resp))\n\n    @property\n    def cookies(self):\n        return self._cookies\n\n    def set_cookie(self, name, value, *, expires=None,\n                   domain=None, max_age=None, path=None,\n                   secure=None, httponly=None, version=None):\n        \"\"\"Set or update response cookie.\n\n        Sets new cookie or updates existent with new value.\n        Also updates only those params which are not None.\n        \"\"\"\n\n        self._check_sending_started()\n        if name in self._deleted_cookies:\n            self._deleted_cookies.remove(name)\n            self._cookies.pop(name, None)\n\n        self._cookies[name] = value\n        c = self._cookies[name]\n        if expires is not None:\n            c['expires'] = expires\n        if domain is not None:\n            c['domain'] = domain\n        if max_age is not None:\n            c['max-age'] = max_age\n        if path is not None:\n            c['path'] = path\n        if secure is not None:\n            c['secure'] = secure\n        if httponly is not None:\n            c['httponly'] = httponly\n        if version is not None:\n            c['version'] = version\n\n    def del_cookie(self, name, *, domain=None, path=None):\n        \"\"\"Delete cookie.\n\n        Creates new empty expired cookie.\n        \"\"\"\n        # TODO: do we need domain/path here?\n        self._check_sending_started()\n        self._cookies.pop(name, None)\n        self.set_cookie(name, '', max_age=0, domain=domain, path=path)\n        self._deleted_cookies.add(name)\n\n    @property\n    def status_code(self):\n        return self._status_code\n\n    @status_code.setter\n    def status_code(self, value):\n        self._check_sending_started()\n        if not isinstance(value, int):\n            raise TypeError(\"Status code must be int\")\n        self._status_code = value\n\n    @property\n    def version(self):\n        return self._version\n\n    @version.setter\n    def version(self, value):\n        self._check_sending_started()\n        if not isinstance(value, HttpVersion):\n            raise TypeError(\"HTTP version must be HttpVersion instance\")\n        self._version = value\n\n    @property\n    def keep_alive(self):\n        return self._keep_alive\n\n    @keep_alive.setter\n    def keep_alive(self, value):\n        self._check_sending_started()\n        self._keep_alive = bool(value)\n\n    @property\n    def content_length(self):\n        l = self.headers.get('Content-Length')\n        if l is None:\n            return None\n        else:\n            return int(l)\n\n    @content_length.setter\n    def content_length(self, value):\n        self._check_sending_started()\n        value = int(value)\n        # TODO: raise error if chunked enabled\n        self.headers['Content-Length'] = str(value)\n\n    def set_chunked(self, chunk_size, buffered=True):\n        if self.content_length is not None:\n            raise RuntimeError(\n                \"Cannot use chunked encoding with Content-Length set up\")\n\n    def send_headers(self):\n        if self._resp_impl is not None:\n            raise RuntimeError(\"HTTP headers are already sent\")\n        if self._eof_sent:\n            raise RuntimeError(\"Cannot call send_header() after write_eof()\")\n\n        self._check_sending_started()\n        self._request._response = weakref.ref(self)\n\n        resp_impl = self._resp_impl = ResponseImpl(\n            self._request._server_http_protocol.writer,\n            self._status_code,\n            self._request.version)\n\n        self._copy_cookies()\n\n        headers = self.headers.items(getall=True)\n        for key, val in headers:\n            resp_impl.add_header(key, val)\n\n        resp_impl.send_headers()\n\n    def write(self, data):\n        if not isinstance(data, (bytes, bytearray, memoryview)):\n            raise TypeError('data argument must be byte-ish (%r)',\n                            type(data))\n\n        if self._eof_sent:\n            raise RuntimeError(\"Cannot call write() after send_eof()\")\n        if self._resp_impl is None:\n            self.send_headers()\n\n        if data:\n            self._resp_impl.write(data)\n\n    @asyncio.coroutine\n    def write_eof(self):\n        if self._resp_impl is None:\n            raise RuntimeError(\"No data has been sent\")\n        if self._eof_sent:\n            return\n\n        yield from self._resp_impl.write_eof()\n        if self._resp_impl.keep_alive():\n            self._request._server_http_protocol.keep_alive(self._keep_alive)\n        self._eof_sent = True",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 164,
                            "end_lineno": 169,
                            "parent": {
                                "file_name": "aiohttp/web.py",
                                "type": "class",
                                "name": "StreamResponse",
                                "content": "class StreamResponse(HeadersMixin):\n\n    def __init__(self, request):\n        self._request = request\n        self.headers = MutableMultiDict()\n        self._status_code = 200\n        self._cookies = http.cookies.SimpleCookie()\n        self._deleted_cookies = set()\n        self._keep_alive = True\n        self._version = request.version\n\n        self._resp_impl = None\n        self._eof_sent = False\n\n    def _copy_cookies(self):\n        for cookie in self._cookies.values():\n            value = cookie.output(header='')[1:]\n            self.headers.add('Set-Cookie', value)\n\n    def _check_sending_started(self):\n        resp = self._request._response\n        if resp is not None:\n            resp = resp()  # dereference weakref\n        if resp is not None:\n            raise RuntimeError((\"Response {!r} already started to send\"\n                                \" data\").format(resp))\n\n    @property\n    def cookies(self):\n        return self._cookies\n\n    def set_cookie(self, name, value, *, expires=None,\n                   domain=None, max_age=None, path=None,\n                   secure=None, httponly=None, version=None):\n        \"\"\"Set or update response cookie.\n\n        Sets new cookie or updates existent with new value.\n        Also updates only those params which are not None.\n        \"\"\"\n\n        self._check_sending_started()\n        if name in self._deleted_cookies:\n            self._deleted_cookies.remove(name)\n            self._cookies.pop(name, None)\n\n        self._cookies[name] = value\n        c = self._cookies[name]\n        if expires is not None:\n            c['expires'] = expires\n        if domain is not None:\n            c['domain'] = domain\n        if max_age is not None:\n            c['max-age'] = max_age\n        if path is not None:\n            c['path'] = path\n        if secure is not None:\n            c['secure'] = secure\n        if httponly is not None:\n            c['httponly'] = httponly\n        if version is not None:\n            c['version'] = version\n\n    def del_cookie(self, name, *, domain=None, path=None):\n        \"\"\"Delete cookie.\n\n        Creates new empty expired cookie.\n        \"\"\"\n        # TODO: do we need domain/path here?\n        self._check_sending_started()\n        self._cookies.pop(name, None)\n        self.set_cookie(name, '', max_age=0, domain=domain, path=path)\n        self._deleted_cookies.add(name)\n\n    @property\n    def status_code(self):\n        return self._status_code\n\n    @status_code.setter\n    def status_code(self, value):\n        self._check_sending_started()\n        if not isinstance(value, int):\n            raise TypeError(\"Status code must be int\")\n        self._status_code = value\n\n    @property\n    def version(self):\n        return self._version\n\n    @version.setter\n    def version(self, value):\n        self._check_sending_started()\n        if not isinstance(value, HttpVersion):\n            raise TypeError(\"HTTP version must be HttpVersion instance\")\n        self._version = value\n\n    @property\n    def keep_alive(self):\n        return self._keep_alive\n\n    @keep_alive.setter\n    def keep_alive(self, value):\n        self._check_sending_started()\n        self._keep_alive = bool(value)\n\n    @property\n    def content_length(self):\n        l = self.headers.get('Content-Length')\n        if l is None:\n            return None\n        else:\n            return int(l)\n\n    @content_length.setter\n    def content_length(self, value):\n        self._check_sending_started()\n        value = int(value)\n        # TODO: raise error if chunked enabled\n        self.headers['Content-Length'] = str(value)\n\n    def set_chunked(self, chunk_size, buffered=True):\n        if self.content_length is not None:\n            raise RuntimeError(\n                \"Cannot use chunked encoding with Content-Length set up\")\n\n    def send_headers(self):\n        if self._resp_impl is not None:\n            raise RuntimeError(\"HTTP headers are already sent\")\n        if self._eof_sent:\n            raise RuntimeError(\"Cannot call send_header() after write_eof()\")\n\n        self._check_sending_started()\n        self._request._response = weakref.ref(self)\n\n        resp_impl = self._resp_impl = ResponseImpl(\n            self._request._server_http_protocol.writer,\n            self._status_code,\n            self._request.version)\n\n        self._copy_cookies()\n\n        headers = self.headers.items(getall=True)\n        for key, val in headers:\n            resp_impl.add_header(key, val)\n\n        resp_impl.send_headers()\n\n    def write(self, data):\n        if not isinstance(data, (bytes, bytearray, memoryview)):\n            raise TypeError('data argument must be byte-ish (%r)',\n                            type(data))\n\n        if self._eof_sent:\n            raise RuntimeError(\"Cannot call write() after send_eof()\")\n        if self._resp_impl is None:\n            self.send_headers()\n\n        if data:\n            self._resp_impl.write(data)\n\n    @asyncio.coroutine\n    def write_eof(self):\n        if self._resp_impl is None:\n            raise RuntimeError(\"No data has been sent\")\n        if self._eof_sent:\n            return\n\n        yield from self._resp_impl.write_eof()\n        if self._resp_impl.keep_alive():\n            self._request._server_http_protocol.keep_alive(self._keep_alive)\n        self._eof_sent = True",
                                "ast_type_str": "ClassDef",
                                "start_lineno": 59,
                                "end_lineno": 228,
                                "parent": null
                            }
                        },
                        {
                            "file_name": "aiohttp/web.py",
                            "type": "class",
                            "name": "StreamResponse",
                            "content": "class StreamResponse(HeadersMixin):\n\n    def __init__(self, request):\n        self._request = request\n        self.headers = MutableMultiDict()\n        self._status_code = 200\n        self._cookies = http.cookies.SimpleCookie()\n        self._deleted_cookies = set()\n        self._keep_alive = True\n        self._version = request.version\n\n        self._resp_impl = None\n        self._eof_sent = False\n\n    def _copy_cookies(self):\n        for cookie in self._cookies.values():\n            value = cookie.output(header='')[1:]\n            self.headers.add('Set-Cookie', value)\n\n    def _check_sending_started(self):\n        resp = self._request._response\n        if resp is not None:\n            resp = resp()  # dereference weakref\n        if resp is not None:\n            raise RuntimeError((\"Response {!r} already started to send\"\n                                \" data\").format(resp))\n\n    @property\n    def cookies(self):\n        return self._cookies\n\n    def set_cookie(self, name, value, *, expires=None,\n                   domain=None, max_age=None, path=None,\n                   secure=None, httponly=None, version=None):\n        \"\"\"Set or update response cookie.\n\n        Sets new cookie or updates existent with new value.\n        Also updates only those params which are not None.\n        \"\"\"\n\n        self._check_sending_started()\n        if name in self._deleted_cookies:\n            self._deleted_cookies.remove(name)\n            self._cookies.pop(name, None)\n\n        self._cookies[name] = value\n        c = self._cookies[name]\n        if expires is not None:\n            c['expires'] = expires\n        if domain is not None:\n            c['domain'] = domain\n        if max_age is not None:\n            c['max-age'] = max_age\n        if path is not None:\n            c['path'] = path\n        if secure is not None:\n            c['secure'] = secure\n        if httponly is not None:\n            c['httponly'] = httponly\n        if version is not None:\n            c['version'] = version\n\n    def del_cookie(self, name, *, domain=None, path=None):\n        \"\"\"Delete cookie.\n\n        Creates new empty expired cookie.\n        \"\"\"\n        # TODO: do we need domain/path here?\n        self._check_sending_started()\n        self._cookies.pop(name, None)\n        self.set_cookie(name, '', max_age=0, domain=domain, path=path)\n        self._deleted_cookies.add(name)\n\n    @property\n    def status_code(self):\n        return self._status_code\n\n    @status_code.setter\n    def status_code(self, value):\n        self._check_sending_started()\n        if not isinstance(value, int):\n            raise TypeError(\"Status code must be int\")\n        self._status_code = value\n\n    @property\n    def version(self):\n        return self._version\n\n    @version.setter\n    def version(self, value):\n        self._check_sending_started()\n        if not isinstance(value, HttpVersion):\n            raise TypeError(\"HTTP version must be HttpVersion instance\")\n        self._version = value\n\n    @property\n    def keep_alive(self):\n        return self._keep_alive\n\n    @keep_alive.setter\n    def keep_alive(self, value):\n        self._check_sending_started()\n        self._keep_alive = bool(value)\n\n    @property\n    def content_length(self):\n        l = self.headers.get('Content-Length')\n        if l is None:\n            return None\n        else:\n            return int(l)\n\n    @content_length.setter\n    def content_length(self, value):\n        self._check_sending_started()\n        value = int(value)\n        # TODO: raise error if chunked enabled\n        self.headers['Content-Length'] = str(value)\n\n    def set_chunked(self, chunk_size, buffered=True):\n        if self.content_length is not None:\n            raise RuntimeError(\n                \"Cannot use chunked encoding with Content-Length set up\")\n\n    def send_headers(self):\n        if self._resp_impl is not None:\n            raise RuntimeError(\"HTTP headers are already sent\")\n        if self._eof_sent:\n            raise RuntimeError(\"Cannot call send_header() after write_eof()\")\n\n        self._check_sending_started()\n        self._request._response = weakref.ref(self)\n\n        resp_impl = self._resp_impl = ResponseImpl(\n            self._request._server_http_protocol.writer,\n            self._status_code,\n            self._request.version)\n\n        self._copy_cookies()\n\n        headers = self.headers.items(getall=True)\n        for key, val in headers:\n            resp_impl.add_header(key, val)\n\n        resp_impl.send_headers()\n\n    def write(self, data):\n        if not isinstance(data, (bytes, bytearray, memoryview)):\n            raise TypeError('data argument must be byte-ish (%r)',\n                            type(data))\n\n        if self._eof_sent:\n            raise RuntimeError(\"Cannot call write() after send_eof()\")\n        if self._resp_impl is None:\n            self.send_headers()\n\n        if data:\n            self._resp_impl.write(data)\n\n    @asyncio.coroutine\n    def write_eof(self):\n        if self._resp_impl is None:\n            raise RuntimeError(\"No data has been sent\")\n        if self._eof_sent:\n            return\n\n        yield from self._resp_impl.write_eof()\n        if self._resp_impl.keep_alive():\n            self._request._server_http_protocol.keep_alive(self._keep_alive)\n        self._eof_sent = True",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 59,
                            "end_lineno": 228,
                            "parent": null
                        }
                    ],
                    "added_entities": [],
                    "deleted_entities": []
                }
            ]
        },
        {
            "old_file_content": "import unittest\nfrom unittest import mock\nfrom aiohttp.web import Request\nfrom aiohttp.multidict import MultiDict\nfrom aiohttp.protocol import HttpVersion\nfrom aiohttp.protocol import Request as RequestImpl\n\n\nclass TestWebRequest(unittest.TestCase):\n\n    def make_request(self, method, path, headers=()):\n        self.app = mock.Mock()\n        self.transport = mock.Mock()\n        message = RequestImpl(self.transport, method, path)\n        message.headers.extend(headers)\n        self.payload = mock.Mock()\n        self.protocol = mock.Mock()\n        req = Request(self.app, message, self.payload, self.protocol)\n        return req\n\n    def test_ctor(self):\n        req = self.make_request('GeT', '/path/to?a=1&b=2')\n\n        self.assertIs(self.app, req.app)\n        self.assertEqual('GET', req.method)\n        self.assertEqual(HttpVersion(1, 1), req.version)\n        self.assertEqual(None, req.host)\n        self.assertEqual('/path/to?a=1&b=2', req.path_qs)\n        self.assertEqual('/path/to', req.path)\n        self.assertEqual('a=1&b=2', req.query_string)\n        self.assertEqual(MultiDict([('a', '1'), ('b', '2')]), req.GET)\n        self.assertIs(self.payload, req.payload)\n\n    def test_content_type_not_specified(self):\n        req = self.make_request('Get', '/')\n        self.assertEqual('application/octet-stream', req.content_type)\n\n    def test_content_type_from_spec(self):\n        req = self.make_request('Get', '/',\n                                {'content-type': 'application/json'})\n        self.assertEqual('application/json', req.content_type)\n\n    def test_content_type_from_spec_with_charset(self):\n        req = self.make_request('Get', '/',\n                                {'content-type': 'text/html; charset=UTF-8'})\n        self.assertEqual('text/html', req.content_type)\n        self.assertEqual('UTF-8', req.charset)\n\n    def test_calc_content_type_on_getting_charset(self):\n        req = self.make_request('Get', '/',\n                                {'content-type': 'text/html; charset=UTF-8'})\n        self.assertEqual('UTF-8', req.charset)\n        self.assertEqual('text/html', req.content_type)\n\n    def test_urlencoded_querystring(self):\n        req = self.make_request(\n            'GET',\n            '/yandsearch?text=%D1%82%D0%B5%D0%BA%D1%81%D1%82')\n        self.assertEqual({'text': 'текст'}, req.GET)\n\n    def test_non_ascii_path(self):\n        req = self.make_request('GET', '/путь')\n        self.assertEqual('/путь', req.path)\n",
            "new_file_content": "import unittest\nfrom unittest import mock\nfrom aiohttp.web import Request\nfrom aiohttp.multidict import MultiDict\nfrom aiohttp.protocol import HttpVersion\nfrom aiohttp.protocol import Request as RequestImpl\n\n\nclass TestWebRequest(unittest.TestCase):\n\n    def make_request(self, method, path, headers=()):\n        self.app = mock.Mock()\n        self.transport = mock.Mock()\n        message = RequestImpl(self.transport, method, path)\n        message.headers.extend(headers)\n        self.payload = mock.Mock()\n        self.protocol = mock.Mock()\n        req = Request(self.app, message, self.payload, self.protocol)\n        return req\n\n    def test_ctor(self):\n        req = self.make_request('GeT', '/path/to?a=1&b=2')\n\n        self.assertIs(self.app, req.app)\n        self.assertEqual('GET', req.method)\n        self.assertEqual(HttpVersion(1, 1), req.version)\n        self.assertEqual(None, req.host)\n        self.assertEqual('/path/to?a=1&b=2', req.path_qs)\n        self.assertEqual('/path/to', req.path)\n        self.assertEqual('a=1&b=2', req.query_string)\n        self.assertEqual(MultiDict([('a', '1'), ('b', '2')]), req.GET)\n        self.assertIs(self.payload, req.payload)\n\n    def test_content_type_not_specified(self):\n        req = self.make_request('Get', '/')\n        self.assertEqual('application/octet-stream', req.content_type)\n\n    def test_content_type_from_spec(self):\n        req = self.make_request('Get', '/',\n                                {'content-type': 'application/json'})\n        self.assertEqual('application/json', req.content_type)\n\n    def test_content_type_from_spec_with_charset(self):\n        req = self.make_request('Get', '/',\n                                {'content-type': 'text/html; charset=UTF-8'})\n        self.assertEqual('text/html', req.content_type)\n        self.assertEqual('UTF-8', req.charset)\n\n    def test_calc_content_type_on_getting_charset(self):\n        req = self.make_request('Get', '/',\n                                {'content-type': 'text/html; charset=UTF-8'})\n        self.assertEqual('UTF-8', req.charset)\n        self.assertEqual('text/html', req.content_type)\n\n    def test_urlencoded_querystring(self):\n        req = self.make_request(\n            'GET',\n            '/yandsearch?text=%D1%82%D0%B5%D0%BA%D1%81%D1%82')\n        self.assertEqual({'text': 'текст'}, req.GET)\n\n    def test_non_ascii_path(self):\n        req = self.make_request('GET', '/путь')\n        self.assertEqual('/путь', req.path)\n\n    def test_content_length(self):\n        req = self.make_request('Get', '/', {'Content-Length': '123'})\n\n        self.assertEqual(123, req.content_length)\n",
            "header": {
                "file": {
                    "path": "tests/test_web_request.py"
                },
                "misc_line": null
            },
            "index_line": {
                "old_commit_hash": "3e8d6def",
                "new_commit_hash": "590467a6",
                "mode": "100644"
            },
            "is_binary_file": false,
            "binary_line": null,
            "minus_file": {
                "path": "a/tests/test_web_request.py"
            },
            "plus_file": {
                "path": "b/tests/test_web_request.py"
            },
            "hunks": [
                {
                    "descriptor": {
                        "old_range": {
                            "start": 61,
                            "length": 3
                        },
                        "new_range": {
                            "start": 61,
                            "length": 8
                        },
                        "section": "class TestWebRequest(unittest.TestCase):"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "    def test_non_ascii_path(self):",
                                "type": "context"
                            },
                            {
                                "content": "        req = self.make_request('GET', '/путь')",
                                "type": "context"
                            },
                            {
                                "content": "        self.assertEqual('/путь', req.path)",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "    def test_content_length(self):",
                                "type": "added"
                            },
                            {
                                "content": "        req = self.make_request('Get', '/', {'Content-Length': '123'})",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "        self.assertEqual(123, req.content_length)",
                                "type": "added"
                            }
                        ]
                    },
                    "modified_entities": [
                        {
                            "file_name": "tests/test_web_request.py",
                            "type": "class",
                            "name": "TestWebRequest",
                            "content": "class TestWebRequest(unittest.TestCase):\n\n    def make_request(self, method, path, headers=()):\n        self.app = mock.Mock()\n        self.transport = mock.Mock()\n        message = RequestImpl(self.transport, method, path)\n        message.headers.extend(headers)\n        self.payload = mock.Mock()\n        self.protocol = mock.Mock()\n        req = Request(self.app, message, self.payload, self.protocol)\n        return req\n\n    def test_ctor(self):\n        req = self.make_request('GeT', '/path/to?a=1&b=2')\n\n        self.assertIs(self.app, req.app)\n        self.assertEqual('GET', req.method)\n        self.assertEqual(HttpVersion(1, 1), req.version)\n        self.assertEqual(None, req.host)\n        self.assertEqual('/path/to?a=1&b=2', req.path_qs)\n        self.assertEqual('/path/to', req.path)\n        self.assertEqual('a=1&b=2', req.query_string)\n        self.assertEqual(MultiDict([('a', '1'), ('b', '2')]), req.GET)\n        self.assertIs(self.payload, req.payload)\n\n    def test_content_type_not_specified(self):\n        req = self.make_request('Get', '/')\n        self.assertEqual('application/octet-stream', req.content_type)\n\n    def test_content_type_from_spec(self):\n        req = self.make_request('Get', '/',\n                                {'content-type': 'application/json'})\n        self.assertEqual('application/json', req.content_type)\n\n    def test_content_type_from_spec_with_charset(self):\n        req = self.make_request('Get', '/',\n                                {'content-type': 'text/html; charset=UTF-8'})\n        self.assertEqual('text/html', req.content_type)\n        self.assertEqual('UTF-8', req.charset)\n\n    def test_calc_content_type_on_getting_charset(self):\n        req = self.make_request('Get', '/',\n                                {'content-type': 'text/html; charset=UTF-8'})\n        self.assertEqual('UTF-8', req.charset)\n        self.assertEqual('text/html', req.content_type)\n\n    def test_urlencoded_querystring(self):\n        req = self.make_request(\n            'GET',\n            '/yandsearch?text=%D1%82%D0%B5%D0%BA%D1%81%D1%82')\n        self.assertEqual({'text': 'текст'}, req.GET)\n\n    def test_non_ascii_path(self):\n        req = self.make_request('GET', '/путь')\n        self.assertEqual('/путь', req.path)\n\n    def test_content_length(self):\n        req = self.make_request('Get', '/', {'Content-Length': '123'})\n\n        self.assertEqual(123, req.content_length)",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 9,
                            "end_lineno": 68,
                            "parent": null
                        }
                    ],
                    "added_entities": [
                        {
                            "file_name": "tests/test_web_request.py",
                            "type": "method",
                            "name": "TestWebRequest.test_content_length",
                            "content": "class TestWebRequest(unittest.TestCase):\n\n    def make_request(self, method, path, headers=()):\n        self.app = mock.Mock()\n        self.transport = mock.Mock()\n        message = RequestImpl(self.transport, method, path)\n        message.headers.extend(headers)\n        self.payload = mock.Mock()\n        self.protocol = mock.Mock()\n        req = Request(self.app, message, self.payload, self.protocol)\n        return req\n\n    def test_ctor(self):\n        req = self.make_request('GeT', '/path/to?a=1&b=2')\n\n        self.assertIs(self.app, req.app)\n        self.assertEqual('GET', req.method)\n        self.assertEqual(HttpVersion(1, 1), req.version)\n        self.assertEqual(None, req.host)\n        self.assertEqual('/path/to?a=1&b=2', req.path_qs)\n        self.assertEqual('/path/to', req.path)\n        self.assertEqual('a=1&b=2', req.query_string)\n        self.assertEqual(MultiDict([('a', '1'), ('b', '2')]), req.GET)\n        self.assertIs(self.payload, req.payload)\n\n    def test_content_type_not_specified(self):\n        req = self.make_request('Get', '/')\n        self.assertEqual('application/octet-stream', req.content_type)\n\n    def test_content_type_from_spec(self):\n        req = self.make_request('Get', '/',\n                                {'content-type': 'application/json'})\n        self.assertEqual('application/json', req.content_type)\n\n    def test_content_type_from_spec_with_charset(self):\n        req = self.make_request('Get', '/',\n                                {'content-type': 'text/html; charset=UTF-8'})\n        self.assertEqual('text/html', req.content_type)\n        self.assertEqual('UTF-8', req.charset)\n\n    def test_calc_content_type_on_getting_charset(self):\n        req = self.make_request('Get', '/',\n                                {'content-type': 'text/html; charset=UTF-8'})\n        self.assertEqual('UTF-8', req.charset)\n        self.assertEqual('text/html', req.content_type)\n\n    def test_urlencoded_querystring(self):\n        req = self.make_request(\n            'GET',\n            '/yandsearch?text=%D1%82%D0%B5%D0%BA%D1%81%D1%82')\n        self.assertEqual({'text': 'текст'}, req.GET)\n\n    def test_non_ascii_path(self):\n        req = self.make_request('GET', '/путь')\n        self.assertEqual('/путь', req.path)\n\n    def test_content_length(self):\n        req = self.make_request('Get', '/', {'Content-Length': '123'})\n\n        self.assertEqual(123, req.content_length)",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 65,
                            "end_lineno": 68,
                            "parent": {
                                "file_name": "tests/test_web_request.py",
                                "type": "class",
                                "name": "TestWebRequest",
                                "content": "class TestWebRequest(unittest.TestCase):\n\n    def make_request(self, method, path, headers=()):\n        self.app = mock.Mock()\n        self.transport = mock.Mock()\n        message = RequestImpl(self.transport, method, path)\n        message.headers.extend(headers)\n        self.payload = mock.Mock()\n        self.protocol = mock.Mock()\n        req = Request(self.app, message, self.payload, self.protocol)\n        return req\n\n    def test_ctor(self):\n        req = self.make_request('GeT', '/path/to?a=1&b=2')\n\n        self.assertIs(self.app, req.app)\n        self.assertEqual('GET', req.method)\n        self.assertEqual(HttpVersion(1, 1), req.version)\n        self.assertEqual(None, req.host)\n        self.assertEqual('/path/to?a=1&b=2', req.path_qs)\n        self.assertEqual('/path/to', req.path)\n        self.assertEqual('a=1&b=2', req.query_string)\n        self.assertEqual(MultiDict([('a', '1'), ('b', '2')]), req.GET)\n        self.assertIs(self.payload, req.payload)\n\n    def test_content_type_not_specified(self):\n        req = self.make_request('Get', '/')\n        self.assertEqual('application/octet-stream', req.content_type)\n\n    def test_content_type_from_spec(self):\n        req = self.make_request('Get', '/',\n                                {'content-type': 'application/json'})\n        self.assertEqual('application/json', req.content_type)\n\n    def test_content_type_from_spec_with_charset(self):\n        req = self.make_request('Get', '/',\n                                {'content-type': 'text/html; charset=UTF-8'})\n        self.assertEqual('text/html', req.content_type)\n        self.assertEqual('UTF-8', req.charset)\n\n    def test_calc_content_type_on_getting_charset(self):\n        req = self.make_request('Get', '/',\n                                {'content-type': 'text/html; charset=UTF-8'})\n        self.assertEqual('UTF-8', req.charset)\n        self.assertEqual('text/html', req.content_type)\n\n    def test_urlencoded_querystring(self):\n        req = self.make_request(\n            'GET',\n            '/yandsearch?text=%D1%82%D0%B5%D0%BA%D1%81%D1%82')\n        self.assertEqual({'text': 'текст'}, req.GET)\n\n    def test_non_ascii_path(self):\n        req = self.make_request('GET', '/путь')\n        self.assertEqual('/путь', req.path)\n\n    def test_content_length(self):\n        req = self.make_request('Get', '/', {'Content-Length': '123'})\n\n        self.assertEqual(123, req.content_length)",
                                "ast_type_str": "ClassDef",
                                "start_lineno": 9,
                                "end_lineno": 68,
                                "parent": null
                            }
                        }
                    ],
                    "deleted_entities": []
                }
            ]
        },
        {
            "old_file_content": "import unittest\nfrom unittest import mock\nfrom aiohttp.web import Request, StreamResponse\nfrom aiohttp.protocol import Request as RequestImpl, HttpVersion\n\n\nclass TestStreamResponse(unittest.TestCase):\n\n    def make_request(self, method, path, headers=()):\n        self.app = mock.Mock()\n        self.transport = mock.Mock()\n        message = RequestImpl(self.transport, method, path)\n        message.headers.extend(headers)\n        self.payload = mock.Mock()\n        self.protocol = mock.Mock()\n        req = Request(self.app, message, self.payload, self.protocol)\n        return req\n\n    def test_ctor(self):\n        req = self.make_request('GET', '/')\n        resp = StreamResponse(req)\n\n        self.assertEqual(req, resp._request)\n        self.assertIsNone(req._response)\n        self.assertEqual(200, resp.status_code)\n        self.assertTrue(resp.keep_alive)\n        self.assertEqual(HttpVersion(1, 1), resp.version)\n\n    def test_status_code_cannot_assign_nonint(self):\n        req = self.make_request('GET', '/')\n        resp = StreamResponse(req)\n\n        with self.assertRaises(TypeError):\n            resp.status_code = 'abc'\n        self.assertEqual(200, resp.status_code)\n\n    def test_status_code_setter(self):\n        req = self.make_request('GET', '/')\n        resp = StreamResponse(req)\n\n        resp.status_code = 300\n        self.assertEqual(300, resp.status_code)\n\n    def test_status_code_cannot_assing_after_sending_headers(self):\n        req = self.make_request('GET', '/')\n        resp = StreamResponse(req)\n\n        resp.send_headers()\n        with self.assertRaises(RuntimeError):\n            resp.status_code = 300\n        self.assertEqual(200, resp.status_code)\n\n    def test_change_version(self):\n        req = self.make_request('GET', '/')\n        resp = StreamResponse(req)\n\n        resp.version = HttpVersion(1, 0)\n        self.assertEqual(HttpVersion(1, 0), resp.version)\n\n    def test_change_version_bad_type(self):\n        req = self.make_request('GET', '/')\n        resp = StreamResponse(req)\n\n        with self.assertRaises(TypeError):\n            resp.version = 123\n        self.assertEqual(HttpVersion(1, 1), resp.version)\n\n    def test_cannot_change_version_after_sending_headers(self):\n        req = self.make_request('GET', '/')\n        resp = StreamResponse(req)\n\n        resp.send_headers()\n        with self.assertRaises(RuntimeError):\n            resp.version = HttpVersion(1, 0)\n        self.assertEqual(HttpVersion(1, 1), resp.version)\n",
            "new_file_content": "import unittest\nfrom unittest import mock\nfrom aiohttp.web import Request, StreamResponse\nfrom aiohttp.protocol import Request as RequestImpl, HttpVersion\n\n\nclass TestStreamResponse(unittest.TestCase):\n\n    def make_request(self, method, path, headers=()):\n        self.app = mock.Mock()\n        self.transport = mock.Mock()\n        message = RequestImpl(self.transport, method, path)\n        message.headers.extend(headers)\n        self.payload = mock.Mock()\n        self.protocol = mock.Mock()\n        req = Request(self.app, message, self.payload, self.protocol)\n        return req\n\n    def test_ctor(self):\n        req = self.make_request('GET', '/')\n        resp = StreamResponse(req)\n\n        self.assertEqual(req, resp._request)\n        self.assertIsNone(req._response)\n        self.assertEqual(200, resp.status_code)\n        self.assertTrue(resp.keep_alive)\n        self.assertEqual(HttpVersion(1, 1), resp.version)\n\n    def test_status_code_cannot_assign_nonint(self):\n        req = self.make_request('GET', '/')\n        resp = StreamResponse(req)\n\n        with self.assertRaises(TypeError):\n            resp.status_code = 'abc'\n        self.assertEqual(200, resp.status_code)\n\n    def test_status_code_setter(self):\n        req = self.make_request('GET', '/')\n        resp = StreamResponse(req)\n\n        resp.status_code = 300\n        self.assertEqual(300, resp.status_code)\n\n    def test_status_code_cannot_assing_after_sending_headers(self):\n        req = self.make_request('GET', '/')\n        resp = StreamResponse(req)\n\n        resp.send_headers()\n        with self.assertRaises(RuntimeError):\n            resp.status_code = 300\n        self.assertEqual(200, resp.status_code)\n\n    def test_change_version(self):\n        req = self.make_request('GET', '/')\n        resp = StreamResponse(req)\n\n        resp.version = HttpVersion(1, 0)\n        self.assertEqual(HttpVersion(1, 0), resp.version)\n\n    def test_change_version_bad_type(self):\n        req = self.make_request('GET', '/')\n        resp = StreamResponse(req)\n\n        with self.assertRaises(TypeError):\n            resp.version = 123\n        self.assertEqual(HttpVersion(1, 1), resp.version)\n\n    def test_cannot_change_version_after_sending_headers(self):\n        req = self.make_request('GET', '/')\n        resp = StreamResponse(req)\n\n        resp.send_headers()\n        with self.assertRaises(RuntimeError):\n            resp.version = HttpVersion(1, 0)\n        self.assertEqual(HttpVersion(1, 1), resp.version)\n\n    def test_content_length(self):\n        req = self.make_request('GET', '/')\n        resp = StreamResponse(req)\n\n        self.assertIsNone(resp.content_length)\n\n    def test_content_length_setter(self):\n        req = self.make_request('GET', '/')\n        resp = StreamResponse(req)\n\n        resp.content_length = 234\n        self.assertEqual(234, resp.content_length)\n\n    def test_cannot_change_content_length_after_sending_headers(self):\n        req = self.make_request('GET', '/')\n        resp = StreamResponse(req)\n\n        resp.send_headers()\n        with self.assertRaises(RuntimeError):\n            resp.content_length = 123\n        self.assertIsNone(resp.content_length)\n",
            "header": {
                "file": {
                    "path": "tests/test_web_response.py"
                },
                "misc_line": null
            },
            "index_line": {
                "old_commit_hash": "e06bef75",
                "new_commit_hash": "988df74e",
                "mode": "100644"
            },
            "is_binary_file": false,
            "binary_line": null,
            "minus_file": {
                "path": "a/tests/test_web_response.py"
            },
            "plus_file": {
                "path": "b/tests/test_web_response.py"
            },
            "hunks": [
                {
                    "descriptor": {
                        "old_range": {
                            "start": 73,
                            "length": 3
                        },
                        "new_range": {
                            "start": 73,
                            "length": 25
                        },
                        "section": "class TestStreamResponse(unittest.TestCase):"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "        with self.assertRaises(RuntimeError):",
                                "type": "context"
                            },
                            {
                                "content": "            resp.version = HttpVersion(1, 0)",
                                "type": "context"
                            },
                            {
                                "content": "        self.assertEqual(HttpVersion(1, 1), resp.version)",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "    def test_content_length(self):",
                                "type": "added"
                            },
                            {
                                "content": "        req = self.make_request('GET', '/')",
                                "type": "added"
                            },
                            {
                                "content": "        resp = StreamResponse(req)",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "        self.assertIsNone(resp.content_length)",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "    def test_content_length_setter(self):",
                                "type": "added"
                            },
                            {
                                "content": "        req = self.make_request('GET', '/')",
                                "type": "added"
                            },
                            {
                                "content": "        resp = StreamResponse(req)",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "        resp.content_length = 234",
                                "type": "added"
                            },
                            {
                                "content": "        self.assertEqual(234, resp.content_length)",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "    def test_cannot_change_content_length_after_sending_headers(self):",
                                "type": "added"
                            },
                            {
                                "content": "        req = self.make_request('GET', '/')",
                                "type": "added"
                            },
                            {
                                "content": "        resp = StreamResponse(req)",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "        resp.send_headers()",
                                "type": "added"
                            },
                            {
                                "content": "        with self.assertRaises(RuntimeError):",
                                "type": "added"
                            },
                            {
                                "content": "            resp.content_length = 123",
                                "type": "added"
                            },
                            {
                                "content": "        self.assertIsNone(resp.content_length)",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [
                        {
                            "file_name": "tests/test_web_response.py",
                            "type": "class",
                            "name": "TestStreamResponse",
                            "content": "class TestStreamResponse(unittest.TestCase):\n\n    def make_request(self, method, path, headers=()):\n        self.app = mock.Mock()\n        self.transport = mock.Mock()\n        message = RequestImpl(self.transport, method, path)\n        message.headers.extend(headers)\n        self.payload = mock.Mock()\n        self.protocol = mock.Mock()\n        req = Request(self.app, message, self.payload, self.protocol)\n        return req\n\n    def test_ctor(self):\n        req = self.make_request('GET', '/')\n        resp = StreamResponse(req)\n\n        self.assertEqual(req, resp._request)\n        self.assertIsNone(req._response)\n        self.assertEqual(200, resp.status_code)\n        self.assertTrue(resp.keep_alive)\n        self.assertEqual(HttpVersion(1, 1), resp.version)\n\n    def test_status_code_cannot_assign_nonint(self):\n        req = self.make_request('GET', '/')\n        resp = StreamResponse(req)\n\n        with self.assertRaises(TypeError):\n            resp.status_code = 'abc'\n        self.assertEqual(200, resp.status_code)\n\n    def test_status_code_setter(self):\n        req = self.make_request('GET', '/')\n        resp = StreamResponse(req)\n\n        resp.status_code = 300\n        self.assertEqual(300, resp.status_code)\n\n    def test_status_code_cannot_assing_after_sending_headers(self):\n        req = self.make_request('GET', '/')\n        resp = StreamResponse(req)\n\n        resp.send_headers()\n        with self.assertRaises(RuntimeError):\n            resp.status_code = 300\n        self.assertEqual(200, resp.status_code)\n\n    def test_change_version(self):\n        req = self.make_request('GET', '/')\n        resp = StreamResponse(req)\n\n        resp.version = HttpVersion(1, 0)\n        self.assertEqual(HttpVersion(1, 0), resp.version)\n\n    def test_change_version_bad_type(self):\n        req = self.make_request('GET', '/')\n        resp = StreamResponse(req)\n\n        with self.assertRaises(TypeError):\n            resp.version = 123\n        self.assertEqual(HttpVersion(1, 1), resp.version)\n\n    def test_cannot_change_version_after_sending_headers(self):\n        req = self.make_request('GET', '/')\n        resp = StreamResponse(req)\n\n        resp.send_headers()\n        with self.assertRaises(RuntimeError):\n            resp.version = HttpVersion(1, 0)\n        self.assertEqual(HttpVersion(1, 1), resp.version)\n\n    def test_content_length(self):\n        req = self.make_request('GET', '/')\n        resp = StreamResponse(req)\n\n        self.assertIsNone(resp.content_length)\n\n    def test_content_length_setter(self):\n        req = self.make_request('GET', '/')\n        resp = StreamResponse(req)\n\n        resp.content_length = 234\n        self.assertEqual(234, resp.content_length)\n\n    def test_cannot_change_content_length_after_sending_headers(self):\n        req = self.make_request('GET', '/')\n        resp = StreamResponse(req)\n\n        resp.send_headers()\n        with self.assertRaises(RuntimeError):\n            resp.content_length = 123\n        self.assertIsNone(resp.content_length)",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 7,
                            "end_lineno": 97,
                            "parent": null
                        }
                    ],
                    "added_entities": [
                        {
                            "file_name": "tests/test_web_response.py",
                            "type": "method",
                            "name": "TestStreamResponse.test_content_length",
                            "content": "class TestStreamResponse(unittest.TestCase):\n\n    def make_request(self, method, path, headers=()):\n        self.app = mock.Mock()\n        self.transport = mock.Mock()\n        message = RequestImpl(self.transport, method, path)\n        message.headers.extend(headers)\n        self.payload = mock.Mock()\n        self.protocol = mock.Mock()\n        req = Request(self.app, message, self.payload, self.protocol)\n        return req\n\n    def test_ctor(self):\n        req = self.make_request('GET', '/')\n        resp = StreamResponse(req)\n\n        self.assertEqual(req, resp._request)\n        self.assertIsNone(req._response)\n        self.assertEqual(200, resp.status_code)\n        self.assertTrue(resp.keep_alive)\n        self.assertEqual(HttpVersion(1, 1), resp.version)\n\n    def test_status_code_cannot_assign_nonint(self):\n        req = self.make_request('GET', '/')\n        resp = StreamResponse(req)\n\n        with self.assertRaises(TypeError):\n            resp.status_code = 'abc'\n        self.assertEqual(200, resp.status_code)\n\n    def test_status_code_setter(self):\n        req = self.make_request('GET', '/')\n        resp = StreamResponse(req)\n\n        resp.status_code = 300\n        self.assertEqual(300, resp.status_code)\n\n    def test_status_code_cannot_assing_after_sending_headers(self):\n        req = self.make_request('GET', '/')\n        resp = StreamResponse(req)\n\n        resp.send_headers()\n        with self.assertRaises(RuntimeError):\n            resp.status_code = 300\n        self.assertEqual(200, resp.status_code)\n\n    def test_change_version(self):\n        req = self.make_request('GET', '/')\n        resp = StreamResponse(req)\n\n        resp.version = HttpVersion(1, 0)\n        self.assertEqual(HttpVersion(1, 0), resp.version)\n\n    def test_change_version_bad_type(self):\n        req = self.make_request('GET', '/')\n        resp = StreamResponse(req)\n\n        with self.assertRaises(TypeError):\n            resp.version = 123\n        self.assertEqual(HttpVersion(1, 1), resp.version)\n\n    def test_cannot_change_version_after_sending_headers(self):\n        req = self.make_request('GET', '/')\n        resp = StreamResponse(req)\n\n        resp.send_headers()\n        with self.assertRaises(RuntimeError):\n            resp.version = HttpVersion(1, 0)\n        self.assertEqual(HttpVersion(1, 1), resp.version)\n\n    def test_content_length(self):\n        req = self.make_request('GET', '/')\n        resp = StreamResponse(req)\n\n        self.assertIsNone(resp.content_length)\n\n    def test_content_length_setter(self):\n        req = self.make_request('GET', '/')\n        resp = StreamResponse(req)\n\n        resp.content_length = 234\n        self.assertEqual(234, resp.content_length)\n\n    def test_cannot_change_content_length_after_sending_headers(self):\n        req = self.make_request('GET', '/')\n        resp = StreamResponse(req)\n\n        resp.send_headers()\n        with self.assertRaises(RuntimeError):\n            resp.content_length = 123\n        self.assertIsNone(resp.content_length)",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 77,
                            "end_lineno": 81,
                            "parent": {
                                "file_name": "tests/test_web_response.py",
                                "type": "class",
                                "name": "TestStreamResponse",
                                "content": "class TestStreamResponse(unittest.TestCase):\n\n    def make_request(self, method, path, headers=()):\n        self.app = mock.Mock()\n        self.transport = mock.Mock()\n        message = RequestImpl(self.transport, method, path)\n        message.headers.extend(headers)\n        self.payload = mock.Mock()\n        self.protocol = mock.Mock()\n        req = Request(self.app, message, self.payload, self.protocol)\n        return req\n\n    def test_ctor(self):\n        req = self.make_request('GET', '/')\n        resp = StreamResponse(req)\n\n        self.assertEqual(req, resp._request)\n        self.assertIsNone(req._response)\n        self.assertEqual(200, resp.status_code)\n        self.assertTrue(resp.keep_alive)\n        self.assertEqual(HttpVersion(1, 1), resp.version)\n\n    def test_status_code_cannot_assign_nonint(self):\n        req = self.make_request('GET', '/')\n        resp = StreamResponse(req)\n\n        with self.assertRaises(TypeError):\n            resp.status_code = 'abc'\n        self.assertEqual(200, resp.status_code)\n\n    def test_status_code_setter(self):\n        req = self.make_request('GET', '/')\n        resp = StreamResponse(req)\n\n        resp.status_code = 300\n        self.assertEqual(300, resp.status_code)\n\n    def test_status_code_cannot_assing_after_sending_headers(self):\n        req = self.make_request('GET', '/')\n        resp = StreamResponse(req)\n\n        resp.send_headers()\n        with self.assertRaises(RuntimeError):\n            resp.status_code = 300\n        self.assertEqual(200, resp.status_code)\n\n    def test_change_version(self):\n        req = self.make_request('GET', '/')\n        resp = StreamResponse(req)\n\n        resp.version = HttpVersion(1, 0)\n        self.assertEqual(HttpVersion(1, 0), resp.version)\n\n    def test_change_version_bad_type(self):\n        req = self.make_request('GET', '/')\n        resp = StreamResponse(req)\n\n        with self.assertRaises(TypeError):\n            resp.version = 123\n        self.assertEqual(HttpVersion(1, 1), resp.version)\n\n    def test_cannot_change_version_after_sending_headers(self):\n        req = self.make_request('GET', '/')\n        resp = StreamResponse(req)\n\n        resp.send_headers()\n        with self.assertRaises(RuntimeError):\n            resp.version = HttpVersion(1, 0)\n        self.assertEqual(HttpVersion(1, 1), resp.version)\n\n    def test_content_length(self):\n        req = self.make_request('GET', '/')\n        resp = StreamResponse(req)\n\n        self.assertIsNone(resp.content_length)\n\n    def test_content_length_setter(self):\n        req = self.make_request('GET', '/')\n        resp = StreamResponse(req)\n\n        resp.content_length = 234\n        self.assertEqual(234, resp.content_length)\n\n    def test_cannot_change_content_length_after_sending_headers(self):\n        req = self.make_request('GET', '/')\n        resp = StreamResponse(req)\n\n        resp.send_headers()\n        with self.assertRaises(RuntimeError):\n            resp.content_length = 123\n        self.assertIsNone(resp.content_length)",
                                "ast_type_str": "ClassDef",
                                "start_lineno": 7,
                                "end_lineno": 97,
                                "parent": null
                            }
                        },
                        {
                            "file_name": "tests/test_web_response.py",
                            "type": "method",
                            "name": "TestStreamResponse.test_content_length_setter",
                            "content": "class TestStreamResponse(unittest.TestCase):\n\n    def make_request(self, method, path, headers=()):\n        self.app = mock.Mock()\n        self.transport = mock.Mock()\n        message = RequestImpl(self.transport, method, path)\n        message.headers.extend(headers)\n        self.payload = mock.Mock()\n        self.protocol = mock.Mock()\n        req = Request(self.app, message, self.payload, self.protocol)\n        return req\n\n    def test_ctor(self):\n        req = self.make_request('GET', '/')\n        resp = StreamResponse(req)\n\n        self.assertEqual(req, resp._request)\n        self.assertIsNone(req._response)\n        self.assertEqual(200, resp.status_code)\n        self.assertTrue(resp.keep_alive)\n        self.assertEqual(HttpVersion(1, 1), resp.version)\n\n    def test_status_code_cannot_assign_nonint(self):\n        req = self.make_request('GET', '/')\n        resp = StreamResponse(req)\n\n        with self.assertRaises(TypeError):\n            resp.status_code = 'abc'\n        self.assertEqual(200, resp.status_code)\n\n    def test_status_code_setter(self):\n        req = self.make_request('GET', '/')\n        resp = StreamResponse(req)\n\n        resp.status_code = 300\n        self.assertEqual(300, resp.status_code)\n\n    def test_status_code_cannot_assing_after_sending_headers(self):\n        req = self.make_request('GET', '/')\n        resp = StreamResponse(req)\n\n        resp.send_headers()\n        with self.assertRaises(RuntimeError):\n            resp.status_code = 300\n        self.assertEqual(200, resp.status_code)\n\n    def test_change_version(self):\n        req = self.make_request('GET', '/')\n        resp = StreamResponse(req)\n\n        resp.version = HttpVersion(1, 0)\n        self.assertEqual(HttpVersion(1, 0), resp.version)\n\n    def test_change_version_bad_type(self):\n        req = self.make_request('GET', '/')\n        resp = StreamResponse(req)\n\n        with self.assertRaises(TypeError):\n            resp.version = 123\n        self.assertEqual(HttpVersion(1, 1), resp.version)\n\n    def test_cannot_change_version_after_sending_headers(self):\n        req = self.make_request('GET', '/')\n        resp = StreamResponse(req)\n\n        resp.send_headers()\n        with self.assertRaises(RuntimeError):\n            resp.version = HttpVersion(1, 0)\n        self.assertEqual(HttpVersion(1, 1), resp.version)\n\n    def test_content_length(self):\n        req = self.make_request('GET', '/')\n        resp = StreamResponse(req)\n\n        self.assertIsNone(resp.content_length)\n\n    def test_content_length_setter(self):\n        req = self.make_request('GET', '/')\n        resp = StreamResponse(req)\n\n        resp.content_length = 234\n        self.assertEqual(234, resp.content_length)\n\n    def test_cannot_change_content_length_after_sending_headers(self):\n        req = self.make_request('GET', '/')\n        resp = StreamResponse(req)\n\n        resp.send_headers()\n        with self.assertRaises(RuntimeError):\n            resp.content_length = 123\n        self.assertIsNone(resp.content_length)",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 83,
                            "end_lineno": 88,
                            "parent": {
                                "file_name": "tests/test_web_response.py",
                                "type": "class",
                                "name": "TestStreamResponse",
                                "content": "class TestStreamResponse(unittest.TestCase):\n\n    def make_request(self, method, path, headers=()):\n        self.app = mock.Mock()\n        self.transport = mock.Mock()\n        message = RequestImpl(self.transport, method, path)\n        message.headers.extend(headers)\n        self.payload = mock.Mock()\n        self.protocol = mock.Mock()\n        req = Request(self.app, message, self.payload, self.protocol)\n        return req\n\n    def test_ctor(self):\n        req = self.make_request('GET', '/')\n        resp = StreamResponse(req)\n\n        self.assertEqual(req, resp._request)\n        self.assertIsNone(req._response)\n        self.assertEqual(200, resp.status_code)\n        self.assertTrue(resp.keep_alive)\n        self.assertEqual(HttpVersion(1, 1), resp.version)\n\n    def test_status_code_cannot_assign_nonint(self):\n        req = self.make_request('GET', '/')\n        resp = StreamResponse(req)\n\n        with self.assertRaises(TypeError):\n            resp.status_code = 'abc'\n        self.assertEqual(200, resp.status_code)\n\n    def test_status_code_setter(self):\n        req = self.make_request('GET', '/')\n        resp = StreamResponse(req)\n\n        resp.status_code = 300\n        self.assertEqual(300, resp.status_code)\n\n    def test_status_code_cannot_assing_after_sending_headers(self):\n        req = self.make_request('GET', '/')\n        resp = StreamResponse(req)\n\n        resp.send_headers()\n        with self.assertRaises(RuntimeError):\n            resp.status_code = 300\n        self.assertEqual(200, resp.status_code)\n\n    def test_change_version(self):\n        req = self.make_request('GET', '/')\n        resp = StreamResponse(req)\n\n        resp.version = HttpVersion(1, 0)\n        self.assertEqual(HttpVersion(1, 0), resp.version)\n\n    def test_change_version_bad_type(self):\n        req = self.make_request('GET', '/')\n        resp = StreamResponse(req)\n\n        with self.assertRaises(TypeError):\n            resp.version = 123\n        self.assertEqual(HttpVersion(1, 1), resp.version)\n\n    def test_cannot_change_version_after_sending_headers(self):\n        req = self.make_request('GET', '/')\n        resp = StreamResponse(req)\n\n        resp.send_headers()\n        with self.assertRaises(RuntimeError):\n            resp.version = HttpVersion(1, 0)\n        self.assertEqual(HttpVersion(1, 1), resp.version)\n\n    def test_content_length(self):\n        req = self.make_request('GET', '/')\n        resp = StreamResponse(req)\n\n        self.assertIsNone(resp.content_length)\n\n    def test_content_length_setter(self):\n        req = self.make_request('GET', '/')\n        resp = StreamResponse(req)\n\n        resp.content_length = 234\n        self.assertEqual(234, resp.content_length)\n\n    def test_cannot_change_content_length_after_sending_headers(self):\n        req = self.make_request('GET', '/')\n        resp = StreamResponse(req)\n\n        resp.send_headers()\n        with self.assertRaises(RuntimeError):\n            resp.content_length = 123\n        self.assertIsNone(resp.content_length)",
                                "ast_type_str": "ClassDef",
                                "start_lineno": 7,
                                "end_lineno": 97,
                                "parent": null
                            }
                        },
                        {
                            "file_name": "tests/test_web_response.py",
                            "type": "method",
                            "name": "TestStreamResponse.test_cannot_change_content_length_after_sending_headers",
                            "content": "class TestStreamResponse(unittest.TestCase):\n\n    def make_request(self, method, path, headers=()):\n        self.app = mock.Mock()\n        self.transport = mock.Mock()\n        message = RequestImpl(self.transport, method, path)\n        message.headers.extend(headers)\n        self.payload = mock.Mock()\n        self.protocol = mock.Mock()\n        req = Request(self.app, message, self.payload, self.protocol)\n        return req\n\n    def test_ctor(self):\n        req = self.make_request('GET', '/')\n        resp = StreamResponse(req)\n\n        self.assertEqual(req, resp._request)\n        self.assertIsNone(req._response)\n        self.assertEqual(200, resp.status_code)\n        self.assertTrue(resp.keep_alive)\n        self.assertEqual(HttpVersion(1, 1), resp.version)\n\n    def test_status_code_cannot_assign_nonint(self):\n        req = self.make_request('GET', '/')\n        resp = StreamResponse(req)\n\n        with self.assertRaises(TypeError):\n            resp.status_code = 'abc'\n        self.assertEqual(200, resp.status_code)\n\n    def test_status_code_setter(self):\n        req = self.make_request('GET', '/')\n        resp = StreamResponse(req)\n\n        resp.status_code = 300\n        self.assertEqual(300, resp.status_code)\n\n    def test_status_code_cannot_assing_after_sending_headers(self):\n        req = self.make_request('GET', '/')\n        resp = StreamResponse(req)\n\n        resp.send_headers()\n        with self.assertRaises(RuntimeError):\n            resp.status_code = 300\n        self.assertEqual(200, resp.status_code)\n\n    def test_change_version(self):\n        req = self.make_request('GET', '/')\n        resp = StreamResponse(req)\n\n        resp.version = HttpVersion(1, 0)\n        self.assertEqual(HttpVersion(1, 0), resp.version)\n\n    def test_change_version_bad_type(self):\n        req = self.make_request('GET', '/')\n        resp = StreamResponse(req)\n\n        with self.assertRaises(TypeError):\n            resp.version = 123\n        self.assertEqual(HttpVersion(1, 1), resp.version)\n\n    def test_cannot_change_version_after_sending_headers(self):\n        req = self.make_request('GET', '/')\n        resp = StreamResponse(req)\n\n        resp.send_headers()\n        with self.assertRaises(RuntimeError):\n            resp.version = HttpVersion(1, 0)\n        self.assertEqual(HttpVersion(1, 1), resp.version)\n\n    def test_content_length(self):\n        req = self.make_request('GET', '/')\n        resp = StreamResponse(req)\n\n        self.assertIsNone(resp.content_length)\n\n    def test_content_length_setter(self):\n        req = self.make_request('GET', '/')\n        resp = StreamResponse(req)\n\n        resp.content_length = 234\n        self.assertEqual(234, resp.content_length)\n\n    def test_cannot_change_content_length_after_sending_headers(self):\n        req = self.make_request('GET', '/')\n        resp = StreamResponse(req)\n\n        resp.send_headers()\n        with self.assertRaises(RuntimeError):\n            resp.content_length = 123\n        self.assertIsNone(resp.content_length)",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 90,
                            "end_lineno": 97,
                            "parent": {
                                "file_name": "tests/test_web_response.py",
                                "type": "class",
                                "name": "TestStreamResponse",
                                "content": "class TestStreamResponse(unittest.TestCase):\n\n    def make_request(self, method, path, headers=()):\n        self.app = mock.Mock()\n        self.transport = mock.Mock()\n        message = RequestImpl(self.transport, method, path)\n        message.headers.extend(headers)\n        self.payload = mock.Mock()\n        self.protocol = mock.Mock()\n        req = Request(self.app, message, self.payload, self.protocol)\n        return req\n\n    def test_ctor(self):\n        req = self.make_request('GET', '/')\n        resp = StreamResponse(req)\n\n        self.assertEqual(req, resp._request)\n        self.assertIsNone(req._response)\n        self.assertEqual(200, resp.status_code)\n        self.assertTrue(resp.keep_alive)\n        self.assertEqual(HttpVersion(1, 1), resp.version)\n\n    def test_status_code_cannot_assign_nonint(self):\n        req = self.make_request('GET', '/')\n        resp = StreamResponse(req)\n\n        with self.assertRaises(TypeError):\n            resp.status_code = 'abc'\n        self.assertEqual(200, resp.status_code)\n\n    def test_status_code_setter(self):\n        req = self.make_request('GET', '/')\n        resp = StreamResponse(req)\n\n        resp.status_code = 300\n        self.assertEqual(300, resp.status_code)\n\n    def test_status_code_cannot_assing_after_sending_headers(self):\n        req = self.make_request('GET', '/')\n        resp = StreamResponse(req)\n\n        resp.send_headers()\n        with self.assertRaises(RuntimeError):\n            resp.status_code = 300\n        self.assertEqual(200, resp.status_code)\n\n    def test_change_version(self):\n        req = self.make_request('GET', '/')\n        resp = StreamResponse(req)\n\n        resp.version = HttpVersion(1, 0)\n        self.assertEqual(HttpVersion(1, 0), resp.version)\n\n    def test_change_version_bad_type(self):\n        req = self.make_request('GET', '/')\n        resp = StreamResponse(req)\n\n        with self.assertRaises(TypeError):\n            resp.version = 123\n        self.assertEqual(HttpVersion(1, 1), resp.version)\n\n    def test_cannot_change_version_after_sending_headers(self):\n        req = self.make_request('GET', '/')\n        resp = StreamResponse(req)\n\n        resp.send_headers()\n        with self.assertRaises(RuntimeError):\n            resp.version = HttpVersion(1, 0)\n        self.assertEqual(HttpVersion(1, 1), resp.version)\n\n    def test_content_length(self):\n        req = self.make_request('GET', '/')\n        resp = StreamResponse(req)\n\n        self.assertIsNone(resp.content_length)\n\n    def test_content_length_setter(self):\n        req = self.make_request('GET', '/')\n        resp = StreamResponse(req)\n\n        resp.content_length = 234\n        self.assertEqual(234, resp.content_length)\n\n    def test_cannot_change_content_length_after_sending_headers(self):\n        req = self.make_request('GET', '/')\n        resp = StreamResponse(req)\n\n        resp.send_headers()\n        with self.assertRaises(RuntimeError):\n            resp.content_length = 123\n        self.assertIsNone(resp.content_length)",
                                "ast_type_str": "ClassDef",
                                "start_lineno": 7,
                                "end_lineno": 97,
                                "parent": null
                            }
                        }
                    ],
                    "deleted_entities": []
                }
            ]
        }
    ],
    "old_commit_hash": "aaa889312e9ba8ec7a812adc31e3d61c8cad4a49^",
    "new_commit_hash": "aaa889312e9ba8ec7a812adc31e3d61c8cad4a49",
    "commit_message": "Add test for content-length",
    "commit_date": "2014-10-16T16:31:21-07:00",
    "metadata": {}
}
{
    "repo_name": "aiohttp",
    "new_commit_hash": "aaa889312e9ba8ec7a812adc31e3d61c8cad4a49",
    "test_file_codes": [
        "import unittest\nfrom unittest import mock\nfrom aiohttp.web import Request, StreamResponse\nfrom aiohttp.protocol import Request as RequestImpl, HttpVersion\n\n\nclass TestStreamResponse(unittest.TestCase):\n\n    def make_request(self, method, path, headers=()):\n        self.app = mock.Mock()\n        self.transport = mock.Mock()\n        message = RequestImpl(self.transport, method, path)\n        message.headers.extend(headers)\n        self.payload = mock.Mock()\n        self.protocol = mock.Mock()\n        req = Request(self.app, message, self.payload, self.protocol)\n        return req\n\n    def test_ctor(self):\n        req = self.make_request('GET', '/')\n        resp = StreamResponse(req)\n\n        self.assertEqual(req, resp._request)\n        self.assertIsNone(req._response)\n        self.assertEqual(200, resp.status_code)\n        self.assertTrue(resp.keep_alive)\n        self.assertEqual(HttpVersion(1, 1), resp.version)\n\n    def test_status_code_cannot_assign_nonint(self):\n        req = self.make_request('GET', '/')\n        resp = StreamResponse(req)\n\n        with self.assertRaises(TypeError):\n            resp.status_code = 'abc'\n        self.assertEqual(200, resp.status_code)\n\n    def test_status_code_setter(self):\n        req = self.make_request('GET', '/')\n        resp = StreamResponse(req)\n\n        resp.status_code = 300\n        self.assertEqual(300, resp.status_code)\n\n    def test_status_code_cannot_assing_after_sending_headers(self):\n        req = self.make_request('GET', '/')\n        resp = StreamResponse(req)\n\n        resp.send_headers()\n        with self.assertRaises(RuntimeError):\n            resp.status_code = 300\n        self.assertEqual(200, resp.status_code)\n\n    def test_change_version(self):\n        req = self.make_request('GET', '/')\n        resp = StreamResponse(req)\n\n        resp.version = HttpVersion(1, 0)\n        self.assertEqual(HttpVersion(1, 0), resp.version)\n\n    def test_change_version_bad_type(self):\n        req = self.make_request('GET', '/')\n        resp = StreamResponse(req)\n\n        with self.assertRaises(TypeError):\n            resp.version = 123\n        self.assertEqual(HttpVersion(1, 1), resp.version)\n\n    def test_cannot_change_version_after_sending_headers(self):\n        req = self.make_request('GET', '/')\n        resp = StreamResponse(req)\n\n        resp.send_headers()\n        with self.assertRaises(RuntimeError):\n            resp.version = HttpVersion(1, 0)\n        self.assertEqual(HttpVersion(1, 1), resp.version)\n\n    def test_content_length(self):\n        req = self.make_request('GET', '/')\n        resp = StreamResponse(req)\n\n        self.assertIsNone(resp.content_length)\n\n    def test_content_length_setter(self):\n        req = self.make_request('GET', '/')\n        resp = StreamResponse(req)\n\n        resp.content_length = 234\n        self.assertEqual(234, resp.content_length)\n\n    def test_cannot_change_content_length_after_sending_headers(self):\n        req = self.make_request('GET', '/')\n        resp = StreamResponse(req)\n\n        resp.send_headers()\n        with self.assertRaises(RuntimeError):\n            resp.content_length = 123\n        self.assertIsNone(resp.content_length)\n",
        "import unittest\nfrom unittest import mock\nfrom aiohttp.web import Request\nfrom aiohttp.multidict import MultiDict\nfrom aiohttp.protocol import HttpVersion\nfrom aiohttp.protocol import Request as RequestImpl\n\n\nclass TestWebRequest(unittest.TestCase):\n\n    def make_request(self, method, path, headers=()):\n        self.app = mock.Mock()\n        self.transport = mock.Mock()\n        message = RequestImpl(self.transport, method, path)\n        message.headers.extend(headers)\n        self.payload = mock.Mock()\n        self.protocol = mock.Mock()\n        req = Request(self.app, message, self.payload, self.protocol)\n        return req\n\n    def test_ctor(self):\n        req = self.make_request('GeT', '/path/to?a=1&b=2')\n\n        self.assertIs(self.app, req.app)\n        self.assertEqual('GET', req.method)\n        self.assertEqual(HttpVersion(1, 1), req.version)\n        self.assertEqual(None, req.host)\n        self.assertEqual('/path/to?a=1&b=2', req.path_qs)\n        self.assertEqual('/path/to', req.path)\n        self.assertEqual('a=1&b=2', req.query_string)\n        self.assertEqual(MultiDict([('a', '1'), ('b', '2')]), req.GET)\n        self.assertIs(self.payload, req.payload)\n\n    def test_content_type_not_specified(self):\n        req = self.make_request('Get', '/')\n        self.assertEqual('application/octet-stream', req.content_type)\n\n    def test_content_type_from_spec(self):\n        req = self.make_request('Get', '/',\n                                {'content-type': 'application/json'})\n        self.assertEqual('application/json', req.content_type)\n\n    def test_content_type_from_spec_with_charset(self):\n        req = self.make_request('Get', '/',\n                                {'content-type': 'text/html; charset=UTF-8'})\n        self.assertEqual('text/html', req.content_type)\n        self.assertEqual('UTF-8', req.charset)\n\n    def test_calc_content_type_on_getting_charset(self):\n        req = self.make_request('Get', '/',\n                                {'content-type': 'text/html; charset=UTF-8'})\n        self.assertEqual('UTF-8', req.charset)\n        self.assertEqual('text/html', req.content_type)\n\n    def test_urlencoded_querystring(self):\n        req = self.make_request(\n            'GET',\n            '/yandsearch?text=%D1%82%D0%B5%D0%BA%D1%81%D1%82')\n        self.assertEqual({'text': 'текст'}, req.GET)\n\n    def test_non_ascii_path(self):\n        req = self.make_request('GET', '/путь')\n        self.assertEqual('/путь', req.path)\n\n    def test_content_length(self):\n        req = self.make_request('Get', '/', {'Content-Length': '123'})\n\n        self.assertEqual(123, req.content_length)\n"
    ],
    "test_file_names": [
        "test_1.py",
        "test_2.py"
    ],
    "setup_res_code": 0,
    "setup_res_stdout": "Transforming aiohttp/worker.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 66ms\nInstalled 26 packages in 41ms\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_aaa889312e9ba8ec7a812adc31e3d61c8cad4a49\nplugins: asyncio-0.25.0, mock-3.14.0, cov-6.0.0\nasyncio: mode=strict, asyncio_default_fixture_loop_scope=None\ncollected 18 items\n\nr2e_tests/test_1.py ..........                                           [ 55%]\nr2e_tests/test_2.py ........                                             [100%]\n\n==================================== PASSES ====================================\n=========================== short test summary info ============================\nPASSED r2e_tests/test_1.py::TestStreamResponse::test_cannot_change_content_length_after_sending_headers\nPASSED r2e_tests/test_1.py::TestStreamResponse::test_cannot_change_version_after_sending_headers\nPASSED r2e_tests/test_1.py::TestStreamResponse::test_change_version\nPASSED r2e_tests/test_1.py::TestStreamResponse::test_change_version_bad_type\nPASSED r2e_tests/test_1.py::TestStreamResponse::test_content_length\nPASSED r2e_tests/test_1.py::TestStreamResponse::test_content_length_setter\nPASSED r2e_tests/test_1.py::TestStreamResponse::test_ctor\nPASSED r2e_tests/test_1.py::TestStreamResponse::test_status_code_cannot_assign_nonint\nPASSED r2e_tests/test_1.py::TestStreamResponse::test_status_code_cannot_assing_after_sending_headers\nPASSED r2e_tests/test_1.py::TestStreamResponse::test_status_code_setter\nPASSED r2e_tests/test_2.py::TestWebRequest::test_calc_content_type_on_getting_charset\nPASSED r2e_tests/test_2.py::TestWebRequest::test_content_length\nPASSED r2e_tests/test_2.py::TestWebRequest::test_content_type_from_spec\nPASSED r2e_tests/test_2.py::TestWebRequest::test_content_type_from_spec_with_charset\nPASSED r2e_tests/test_2.py::TestWebRequest::test_content_type_not_specified\nPASSED r2e_tests/test_2.py::TestWebRequest::test_ctor\nPASSED r2e_tests/test_2.py::TestWebRequest::test_non_ascii_path\nPASSED r2e_tests/test_2.py::TestWebRequest::test_urlencoded_querystring\n============================== 18 passed in 0.34s ==============================\n",
    "new_commit_res_stderr": "/home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_aaa889312e9ba8ec7a812adc31e3d61c8cad4a49/.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_aaa889312e9ba8ec7a812adc31e3d61c8cad4a49\nplugins: asyncio-0.25.0, mock-3.14.0, cov-6.0.0\nasyncio: mode=strict, asyncio_default_fixture_loop_scope=None\ncollected 18 items\n\nr2e_tests/test_1.py ..........                                           [ 55%]\nr2e_tests/test_2.py .F......                                             [100%]\n\n=================================== FAILURES ===================================\n______________________ TestWebRequest.test_content_length ______________________\n\nself = <r2e_tests.test_2.TestWebRequest testMethod=test_content_length>\n\n    def test_content_length(self):\n        req = self.make_request('Get', '/', {'Content-Length': '123'})\n    \n>       self.assertEqual(123, req.content_length)\nE       AttributeError: 'Request' object has no attribute 'content_length'\n\nr2e_tests/test_2.py:68: AttributeError\n==================================== PASSES ====================================\n=========================== short test summary info ============================\nPASSED r2e_tests/test_1.py::TestStreamResponse::test_cannot_change_content_length_after_sending_headers\nPASSED r2e_tests/test_1.py::TestStreamResponse::test_cannot_change_version_after_sending_headers\nPASSED r2e_tests/test_1.py::TestStreamResponse::test_change_version\nPASSED r2e_tests/test_1.py::TestStreamResponse::test_change_version_bad_type\nPASSED r2e_tests/test_1.py::TestStreamResponse::test_content_length\nPASSED r2e_tests/test_1.py::TestStreamResponse::test_content_length_setter\nPASSED r2e_tests/test_1.py::TestStreamResponse::test_ctor\nPASSED r2e_tests/test_1.py::TestStreamResponse::test_status_code_cannot_assign_nonint\nPASSED r2e_tests/test_1.py::TestStreamResponse::test_status_code_cannot_assing_after_sending_headers\nPASSED r2e_tests/test_1.py::TestStreamResponse::test_status_code_setter\nPASSED r2e_tests/test_2.py::TestWebRequest::test_calc_content_type_on_getting_charset\nPASSED r2e_tests/test_2.py::TestWebRequest::test_content_type_from_spec\nPASSED r2e_tests/test_2.py::TestWebRequest::test_content_type_from_spec_with_charset\nPASSED r2e_tests/test_2.py::TestWebRequest::test_content_type_not_specified\nPASSED r2e_tests/test_2.py::TestWebRequest::test_ctor\nPASSED r2e_tests/test_2.py::TestWebRequest::test_non_ascii_path\nPASSED r2e_tests/test_2.py::TestWebRequest::test_urlencoded_querystring\nFAILED r2e_tests/test_2.py::TestWebRequest::test_content_length - AttributeEr...\n========================= 1 failed, 17 passed in 0.14s =========================\n",
    "old_commit_res_stderr": "/home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_aaa889312e9ba8ec7a812adc31e3d61c8cad4a49/.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/web.py tests/test_web_request.py tests/test_web_response.py
We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
[ISSUE]
**Title:** Accessing `content_length` on Request object raises AttributeError

**Description:**
When creating a request with the `Content-Length` header and attempting to access the `content_length` property, an `AttributeError` is raised because the `Request` object does not have a `content_length` attribute.

**Example Buggy Code:**
```python
def test_content_length():
    req = self.make_request('Get', '/', {'Content-Length': '123'})
    length = req.content_length  # Raises AttributeError
```

**Expected Behavior:**
Accessing `req.content_length` should return the integer value of the `Content-Length` header (e.g., `123`) if it is present, or `None` if the header is absent.

**Actual Behavior:**
Attempting to access `req.content_length` results in the following error:
```
AttributeError: 'Request' object has no attribute 'content_length'
```
[/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/web.py
import asyncio
import binascii
import collections
import cgi
import http.cookies
import io
import json
import re
import weakref

from urllib.parse import urlsplit, parse_qsl, unquote

from .abc import AbstractRouter, AbstractMatchInfo
from .errors import HttpErrorException
from .helpers import parse_mimetype
from .multidict import MultiDict, MutableMultiDict
from .protocol import Response as ResponseImpl, HttpVersion
from .server import ServerHttpProtocol
from .streams import EOF_MARKER


__all__ = [
    'Application',
    'HttpVersion',
    'Request',
    'StreamResponse',
    'Response',
    'UrlDispatch',
    'UrlMappingMatchInfo',
    ]


class HeadersMixin:

    _content_type = None
    _content_dict = None

    @property
    def content_type(self):
        if self._content_type is not None:
            return self._content_type
        raw = self.headers.get('Content-Type')
        if raw is None:
            # default value according to RFC 2616
            self._content_type = 'application/octet-stream'
            self._content_dict = {}
        else:
            self._content_type, self._content_dict = cgi.parse_header(raw)
        return self._content_type

    @property
    def charset(self):
        # Assumes that charset is UTF8 if not specified
        if self._content_type is None:
            self.content_type  # calculates _content_dict also
        return self._content_dict.get('charset', 'utf-8')


class StreamResponse(HeadersMixin):

    def __init__(self, request):
        self._request = request
        self.headers = MutableMultiDict()
        self._status_code = 200
        self._cookies = http.cookies.SimpleCookie()
        self._deleted_cookies = set()
        self._keep_alive = True
        self._version = request.version

        self._resp_impl = None
        self._eof_sent = False

    def _copy_cookies(self):
        for cookie in self._cookies.values():
            value = cookie.output(header='')[1:]
            self.headers.add('Set-Cookie', value)

    def _check_sending_started(self):
        resp = self._request._response
        if resp is not None:
            resp = resp()  # dereference weakref
        if resp is not None:
            raise RuntimeError(("Response {!r} already started to send"
                                " data").format(resp))

    @property
    def cookies(self):
        return self._cookies

    def set_cookie(self, name, value, *, expires=None,
                   domain=None, max_age=None, path=None,
                   secure=None, httponly=None, version=None):
        """Set or update response cookie.

        Sets new cookie or updates existent with new value.
        Also updates only those params which are not None.
        """

        self._check_sending_started()
        if name in self._deleted_cookies:
            self._deleted_cookies.remove(name)
            self._cookies.pop(name, None)

        self._cookies[name] = value
        c = self._cookies[name]
        if expires is not None:
            c['expires'] = expires
        if domain is not None:
            c['domain'] = domain
        if max_age is not None:
            c['max-age'] = max_age
        if path is not None:
            c['path'] = path
        if secure is not None:
            c['secure'] = secure
        if httponly is not None:
            c['httponly'] = httponly
        if version is not None:
            c['version'] = version

    def del_cookie(self, name, *, domain=None, path=None):
        """Delete cookie.

        Creates new empty expired cookie.
        """
        # TODO: do we need domain/path here?
        self._check_sending_started()
        self._cookies.pop(name, None)
        self.set_cookie(name, '', max_age=0, domain=domain, path=path)
        self._deleted_cookies.add(name)

    @property
    def status_code(self):
        return self._status_code

    @status_code.setter
    def status_code(self, value):
        self._check_sending_started()
        if not isinstance(value, int):
            raise TypeError("Status code must be int")
        self._status_code = value

    @property
    def version(self):
        return self._version

    @version.setter
    def version(self, value):
        self._check_sending_started()
        if not isinstance(value, HttpVersion):
            raise TypeError("HTTP version must be HttpVersion instance")
        self._version = value

    @property
    def keep_alive(self):
        return self._keep_alive

    @keep_alive.setter
    def keep_alive(self, value):
        self._check_sending_started()
        self._keep_alive = bool(value)

    @property
    def content_length(self):
        l = self.headers.get('Content-Length')
        if l is None:
            return None
        else:
            return int(l)

    @content_length.setter
    def content_length(self, value):
        self._check_sending_started()
        value = int(value)
        # TODO: raise error if chunked enabled
        self.headers['Content-Length'] = str(value)

    def set_chunked(self, chunk_size, buffered=True):
        if self.content_length is not None:
            raise RuntimeError(
                "Cannot use chunked encoding with Content-Length set up")

    def send_headers(self):
        if self._resp_impl is not None:
            raise RuntimeError("HTTP headers are already sent")
        if self._eof_sent:
            raise RuntimeError("Cannot call send_header() after write_eof()")

        self._check_sending_started()
        self._request._response = weakref.ref(self)

        resp_impl = self._resp_impl = ResponseImpl(
            self._request._server_http_protocol.writer,
            self._status_code,
            self._request.version)

        self._copy_cookies()

        headers = self.headers.items(getall=True)
        for key, val in headers:
            resp_impl.add_header(key, val)

        resp_impl.send_headers()

    def write(self, data):
        if not isinstance(data, (bytes, bytearray, memoryview)):
            raise TypeError('data argument must be byte-ish (%r)',
                            type(data))

        if self._eof_sent:
            raise RuntimeError("Cannot call write() after send_eof()")
        if self._resp_impl is None:
            self.send_headers()

        if data:
            self._resp_impl.write(data)

    @asyncio.coroutine
    def write_eof(self):
        if self._resp_impl is None:
            raise RuntimeError("No data has been sent")
        if self._eof_sent:
            return

        yield from self._resp_impl.write_eof()
        if self._resp_impl.keep_alive():
            self._request._server_http_protocol.keep_alive(self._keep_alive)
        self._eof_sent = True


class Response(StreamResponse):

    def __init__(self, request, body=b'', *, status_code=200, headers=None):
        super().__init__(request)
        self.status_code = status_code
        self.body = body
        if headers is not None:
            self.headers.extend(headers)

    @property
    def body(self):
        return self._body

    @body.setter
    def body(self, body):
        if not isinstance(body, (bytes, bytearray, memoryview)):
            raise TypeError('body argument must be byte-ish (%r)',
                            type(body))
        self._check_sending_started()
        self._body = body

    @asyncio.coroutine
    def render(self):
        body = self._body
        self.content_length = len(body)
        self.write(body)


class Request(HeadersMixin):

    def __init__(self, app, message, payload, protocol):
        path = unquote(message.path)
        res = urlsplit(path)
        self._app = app
        self._version = message.version
        self._server_http_protocol = protocol
        self._method = message.method.upper()
        self._host = message.headers.get('HOST')
        self._path_qs = path
        self._path = res.path
        self._query_string = res.query
        self._get = MultiDict(parse_qsl(res.query))
        self._post = None
        self._headers = message.headers

        # matchdict, route_name, handler
        # or information about traversal lookup
        self._match_info = None  # initialized after route resolving

        self._payload = payload
        self._response = None
        self._cookies = None

    @property
    def method(self):
        return self._method

    @property
    def version(self):
        return self._version

    @property
    def host(self):
        return self._host

    @property
    def path_qs(self):
        return self._path_qs

    @property
    def path(self):
        return self._path

    @property
    def query_string(self):
        return self._query_string

    @property
    def GET(self):
        return self._get

    @property
    def headers(self):
        return self._headers

    @property
    def match_info(self):
        return self._match_info

    @property
    def app(self):
        """Application instance."""
        return self._app

    @property
    def cookies(self):
        """Return request cookies.

        A read-only dictionary-like object.
        """
        if self._cookies is None:
            raw = self.headers.get('COOKIE', '')
            parsed = http.cookies.SimpleCookie(raw)
            self._cookies = MultiDict({key: val.value
                                       for key, val in parsed.items()})
        return self._cookies

    @property
    def payload(self):
        """Return raw paiload stream."""
        return self._payload

    @asyncio.coroutine
    def release(self):
        """Release request.

        Eat unread part of HTTP BODY if present.
        """
        chunk = yield from self._payload.readany()
        while chunk is not EOF_MARKER or chunk:
            chunk = yield from self._payload.readany()

    def terminate(self):
        # TODO: the method should close connection after sending response
        # the main reason is to don't read request body as release() does
        pass

    @asyncio.coroutine
    def read(self):
        """Read request body if present.

        Returns bytes object with full request content or None if
        request has no BODY.
        """

        if self._payload is None:
            return None
        body = bytearray()
        while True:
            chunk = yield from self._payload.readany()
            body.extend(chunk)
            if chunk is EOF_MARKER:
                break
        return bytes(body)

    @asyncio.coroutine
    def text(self):
        bytes_body = yield from self.read()
        if bytes_body is None:
            return None
        encoding = self.charset
        return bytes_body.decode(encoding)

    @asyncio.coroutine
    def json(self, *, loader=json.loads):
        body = yield from self.text()
        if body is None:
            return None
        return loader(body)

    @asyncio.coroutine
    def POST(self):
        if self._post is not None:
            return self._post
        if self.method not in ('POST', 'PUT', 'PATCH'):
            self._post = MultiDict()
            return
        content_type = self.content_type
        if (content_type not in ('',
                                 'application/x-www-form-urlencoded',
                                 'multipart/form-data')):
            self._post = MultiDict()
            return

        body = yield from self.text()
        fs = cgi.FieldStorage(fp=io.StringIO(body),
                              environ={'CONTENT_LENGTH': '0',
                                       'QUERY_STRING': '',
                                       'REQUEST_METHOD': self.method,
                                       'CONTENT_TYPE': content_type},
                              keep_blank_values=True,
                              encoding='utf-8')

        out = MutableMultiDict()
        for field in fs.list or ():
            charset = field.type_options.get('charset', 'utf-8')
            transfer_encoding = field.headers.get('Content-Transfer-Encoding',
                                                  None)
            supported_tranfer_encoding = {
                'base64': binascii.a2b_base64,
                'quoted-printable': binascii.a2b_qp
                }
            if charset == 'utf-8':
                decode = lambda b: b
            else:
                decode = lambda b: b.encode('utf-8').decode(charset)
            if field.filename:
                field.filename = decode(field.filename)
                out.add(field.name, field)
            else:
                value = field.value
                if transfer_encoding in supported_tranfer_encoding:
                    # binascii accepts bytes
                    value = value.encode('utf-8')
                    value = supported_tranfer_encoding[
                        transfer_encoding](value)
                    # binascii returns bytes
                    value = value.decode('utf-8')
                out.add(field.name, decode(value))
        self._post = MultiDict(out)
        return self._post

    @asyncio.coroutine
    def start_websocket(self):
        """Upgrade connection to websocket.

        Returns (reader, writer) pair.
        """


class UrlMappingMatchInfo(AbstractMatchInfo):

    def __init__(self, matchdict, entry):
        self._matchdict = matchdict
        self._entry = entry

    @property
    def handler(self):
        return self._entry.handler

    @property
    def matchdict(self):
        return self._matchdict

    @property
    def route_name(self):
        return self._entry.name


Entry = collections.namedtuple('Entry', 'regex method handler')


class UrlDispatch(AbstractRouter):

    DYN = re.compile(r'^\{[_a-zA-Z][_a-zA-Z0-9]*\}$')
    GOOD = r'[^{}/]+'
    PLAIN = re.compile('^'+GOOD+'$')

    METHODS = {'POST', 'GET', 'PUT', 'DELETE', 'PATCH', 'HEAD', 'OPTIONS'}

    def __init__(self, *, loop=None):
        if loop is None:
            loop = asyncio.get_event_loop()
        self._loop = loop
        super().__init__()
        self._urls = []

    @asyncio.coroutine
    def resolve(self, request):
        path = request.path
        method = request.method
        allowed_methods = set()
        for entry in self._urls:
            match = entry.regex.match(path)
            if match is None:
                continue
            if entry.method != method:
                allowed_methods.add(entry.method)
            else:
                break
        else:
            if allowed_methods:
                allow = ', '.join(sorted(allowed_methods))
                # add log
                raise HttpErrorException(405, "Method Not Allowed",
                                         headers=(('Allow', allow),))
            else:
                # add log
                raise HttpErrorException(404, "Not Found")

        matchdict = match.groupdict()
        return UrlMappingMatchInfo(matchdict, entry)

    def add_route(self, method, path, handler):
        assert callable(handler), handler

        assert path.startswith('/')
        assert callable(handler), handler
        method = method.upper()
        assert method in self.METHODS, method
        regexp = []
        for part in path.split('/'):
            if not part:
                continue
            if self.DYN.match(part):
                regexp.append('(?P<'+part[1:-1]+'>'+self.GOOD+')')
            elif self.PLAIN.match(part):
                regexp.append(part)
            else:
                raise ValueError("Invalid path '{}'['{}']".format(path, part))
        pattern = '/' + '/'.join(regexp)
        if path.endswith('/') and pattern != '/':
            pattern += '/'
        try:
            compiled = re.compile('^' + pattern + '$')
        except re.error:
            raise ValueError("Invalid path '{}'".format(path))
        self._urls.append(Entry(compiled, method, handler))


class RequestHandler(ServerHttpProtocol):

    def __init__(self, app, **kwargs):
        super().__init__(**kwargs)
        self._app = app

    @asyncio.coroutine
    def handle_request(self, message, payload):
        request = Request(self._app, message, payload, self)
        match_info = yield from self._app.router.resolve(request)
        if match_info is not None:
            request._match_info = match_info
            handler = match_info.handler

            if asyncio.iscoroutinefunction(handler):
                resp = yield from handler(request)
            else:
                resp = handler(request)
            yield from request.release()

            if isinstance(resp, Response):
                yield from resp.render()
            else:
                raise RuntimeError(("Handler should return Response "
                                    "instance, got {!r}")
                                   .format(type(resp)))
            yield from resp.write_eof()
        else:
            raise HttpErrorException(404, "Not Found")


class Application(dict, asyncio.AbstractServer):

    def __init__(self, *, loop=None, router=None, **kwargs):
        # TODO: explicitly accept *debug* param
        self._kwargs = kwargs
        if loop is None:
            loop = asyncio.get_event_loop()
        if router is None:
            router = UrlDispatch(loop=loop)
        self._router = router
        self._loop = loop

    @property
    def router(self):
        return self._router

    def make_handler(self):
        return RequestHandler(self, loop=self._loop, **self._kwargs)

    def close(self):
        pass

    def register_on_close(self, cb):
        pass

    @asyncio.coroutine
    def wait_closed(self):
        pass

```
--- 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:** Accessing `content_length` on Request object raises AttributeError

**Description:**
When creating a request with the `Content-Length` header and attempting to access the `content_length` property, an `AttributeError` is raised because the `Request` object does not have a `content_length` attribute.

**Example Buggy Code:**
```python
def test_content_length():
    req = self.make_request('Get', '/', {'Content-Length': '123'})
    length = req.content_length  # Raises AttributeError
```

**Expected Behavior:**
Accessing `req.content_length` should return the integer value of the `Content-Length` header (e.g., `123`) if it is present, or `None` if the header is absent.

**Actual Behavior:**
Attempting to access `req.content_length` results in the following error:
```
AttributeError: 'Request' object has no attribute 'content_length'
```
[/ISSUE]
{
    "TestStreamResponse.test_cannot_change_content_length_after_sending_headers": "PASSED",
    "TestStreamResponse.test_cannot_change_version_after_sending_headers": "PASSED",
    "TestStreamResponse.test_change_version": "PASSED",
    "TestStreamResponse.test_change_version_bad_type": "PASSED",
    "TestStreamResponse.test_content_length": "PASSED",
    "TestStreamResponse.test_content_length_setter": "PASSED",
    "TestStreamResponse.test_ctor": "PASSED",
    "TestStreamResponse.test_status_code_cannot_assign_nonint": "PASSED",
    "TestStreamResponse.test_status_code_cannot_assing_after_sending_headers": "PASSED",
    "TestStreamResponse.test_status_code_setter": "PASSED",
    "TestWebRequest.test_calc_content_type_on_getting_charset": "PASSED",
    "TestWebRequest.test_content_length": "PASSED",
    "TestWebRequest.test_content_type_from_spec": "PASSED",
    "TestWebRequest.test_content_type_from_spec_with_charset": "PASSED",
    "TestWebRequest.test_content_type_not_specified": "PASSED",
    "TestWebRequest.test_ctor": "PASSED",
    "TestWebRequest.test_non_ascii_path": "PASSED",
    "TestWebRequest.test_urlencoded_querystring": "PASSED"
}
diff --git a/aiohttp/web.py b/aiohttp/web.py
index 3d55eb21..d750026b 100644
--- a/aiohttp/web.py
+++ b/aiohttp/web.py
@@ -55,6 +55,14 @@ class HeadersMixin:
             self.content_type  # calculates _content_dict also
         return self._content_dict.get('charset', 'utf-8')
 
+    @property
+    def content_length(self):
+        l = self.headers.get('Content-Length')
+        if l is None:
+            return None
+        else:
+            return int(l)
+
 
 class StreamResponse(HeadersMixin):
 
@@ -162,11 +170,8 @@ class StreamResponse(HeadersMixin):
 
     @property
     def content_length(self):
-        l = self.headers.get('Content-Length')
-        if l is None:
-            return None
-        else:
-            return int(l)
+        # Just a placeholder for adding setter
+        return super().content_length
 
     @content_length.setter
     def content_length(self, value):

{"aiohttp/web.py": "import asyncio\nimport binascii\nimport collections\nimport cgi\nimport http.cookies\nimport io\nimport json\nimport re\nimport weakref\n\nfrom urllib.parse import urlsplit, parse_qsl, unquote\n\nfrom .abc import AbstractRouter, AbstractMatchInfo\nfrom .errors import HttpErrorException\nfrom .helpers import parse_mimetype\nfrom .multidict import MultiDict, MutableMultiDict\nfrom .protocol import Response as ResponseImpl, HttpVersion\nfrom .server import ServerHttpProtocol\nfrom .streams import EOF_MARKER\n\n\n__all__ = [\n    'Application',\n    'HttpVersion',\n    'Request',\n    'StreamResponse',\n    'Response',\n    'UrlDispatch',\n    'UrlMappingMatchInfo',\n    ]\n\n\nclass HeadersMixin:\n\n    _content_type = None\n    _content_dict = None\n\n    @property\n    def content_type(self):\n        if self._content_type is not None:\n            return self._content_type\n        raw = self.headers.get('Content-Type')\n        if raw is None:\n            # default value according to RFC 2616\n            self._content_type = 'application/octet-stream'\n            self._content_dict = {}\n        else:\n            self._content_type, self._content_dict = cgi.parse_header(raw)\n        return self._content_type\n\n    @property\n    def charset(self):\n        # Assumes that charset is UTF8 if not specified\n        if self._content_type is None:\n            self.content_type  # calculates _content_dict also\n        return self._content_dict.get('charset', 'utf-8')\n\n\nclass StreamResponse(HeadersMixin):\n\n    def __init__(self, request):\n        self._request = request\n        self.headers = MutableMultiDict()\n        self._status_code = 200\n        self._cookies = http.cookies.SimpleCookie()\n        self._deleted_cookies = set()\n        self._keep_alive = True\n        self._version = request.version\n\n        self._resp_impl = None\n        self._eof_sent = False\n\n    def _copy_cookies(self):\n        for cookie in self._cookies.values():\n            value = cookie.output(header='')[1:]\n            self.headers.add('Set-Cookie', value)\n\n    def _check_sending_started(self):\n        resp = self._request._response\n        if resp is not None:\n            resp = resp()  # dereference weakref\n        if resp is not None:\n            raise RuntimeError((\"Response {!r} already started to send\"\n                                \" data\").format(resp))\n\n    @property\n    def cookies(self):\n        return self._cookies\n\n    def set_cookie(self, name, value, *, expires=None,\n                   domain=None, max_age=None, path=None,\n                   secure=None, httponly=None, version=None):\n        \"\"\"Set or update response cookie.\n\n        Sets new cookie or updates existent with new value.\n        Also updates only those params which are not None.\n        \"\"\"\n\n        self._check_sending_started()\n        if name in self._deleted_cookies:\n            self._deleted_cookies.remove(name)\n            self._cookies.pop(name, None)\n\n        self._cookies[name] = value\n        c = self._cookies[name]\n        if expires is not None:\n            c['expires'] = expires\n        if domain is not None:\n            c['domain'] = domain\n        if max_age is not None:\n            c['max-age'] = max_age\n        if path is not None:\n            c['path'] = path\n        if secure is not None:\n            c['secure'] = secure\n        if httponly is not None:\n            c['httponly'] = httponly\n        if version is not None:\n            c['version'] = version\n\n    def del_cookie(self, name, *, domain=None, path=None):\n        \"\"\"Delete cookie.\n\n        Creates new empty expired cookie.\n        \"\"\"\n        # TODO: do we need domain/path here?\n        self._check_sending_started()\n        self._cookies.pop(name, None)\n        self.set_cookie(name, '', max_age=0, domain=domain, path=path)\n        self._deleted_cookies.add(name)\n\n    @property\n    def status_code(self):\n        return self._status_code\n\n    @status_code.setter\n    def status_code(self, value):\n        self._check_sending_started()\n        if not isinstance(value, int):\n            raise TypeError(\"Status code must be int\")\n        self._status_code = value\n\n    @property\n    def version(self):\n        return self._version\n\n    @version.setter\n    def version(self, value):\n        self._check_sending_started()\n        if not isinstance(value, HttpVersion):\n            raise TypeError(\"HTTP version must be HttpVersion instance\")\n        self._version = value\n\n    @property\n    def keep_alive(self):\n        return self._keep_alive\n\n    @keep_alive.setter\n    def keep_alive(self, value):\n        self._check_sending_started()\n        self._keep_alive = bool(value)\n\n    @property\n    def content_length(self):\n        l = self.headers.get('Content-Length')\n        if l is None:\n            return None\n        else:\n            return int(l)\n\n    @content_length.setter\n    def content_length(self, value):\n        self._check_sending_started()\n        value = int(value)\n        # TODO: raise error if chunked enabled\n        self.headers['Content-Length'] = str(value)\n\n    def set_chunked(self, chunk_size, buffered=True):\n        if self.content_length is not None:\n            raise RuntimeError(\n                \"Cannot use chunked encoding with Content-Length set up\")\n\n    def send_headers(self):\n        if self._resp_impl is not None:\n            raise RuntimeError(\"HTTP headers are already sent\")\n        if self._eof_sent:\n            raise RuntimeError(\"Cannot call send_header() after write_eof()\")\n\n        self._check_sending_started()\n        self._request._response = weakref.ref(self)\n\n        resp_impl = self._resp_impl = ResponseImpl(\n            self._request._server_http_protocol.writer,\n            self._status_code,\n            self._request.version)\n\n        self._copy_cookies()\n\n        headers = self.headers.items(getall=True)\n        for key, val in headers:\n            resp_impl.add_header(key, val)\n\n        resp_impl.send_headers()\n\n    def write(self, data):\n        if not isinstance(data, (bytes, bytearray, memoryview)):\n            raise TypeError('data argument must be byte-ish (%r)',\n                            type(data))\n\n        if self._eof_sent:\n            raise RuntimeError(\"Cannot call write() after send_eof()\")\n        if self._resp_impl is None:\n            self.send_headers()\n\n        if data:\n            self._resp_impl.write(data)\n\n    @asyncio.coroutine\n    def write_eof(self):\n        if self._resp_impl is None:\n            raise RuntimeError(\"No data has been sent\")\n        if self._eof_sent:\n            return\n\n        yield from self._resp_impl.write_eof()\n        if self._resp_impl.keep_alive():\n            self._request._server_http_protocol.keep_alive(self._keep_alive)\n        self._eof_sent = True\n\n\nclass Response(StreamResponse):\n\n    def __init__(self, request, body=b'', *, status_code=200, headers=None):\n        super().__init__(request)\n        self.status_code = status_code\n        self.body = body\n        if headers is not None:\n            self.headers.extend(headers)\n\n    @property\n    def body(self):\n        return self._body\n\n    @body.setter\n    def body(self, body):\n        if not isinstance(body, (bytes, bytearray, memoryview)):\n            raise TypeError('body argument must be byte-ish (%r)',\n                            type(body))\n        self._check_sending_started()\n        self._body = body\n\n    @asyncio.coroutine\n    def render(self):\n        body = self._body\n        self.content_length = len(body)\n        self.write(body)\n\n\nclass Request(HeadersMixin):\n\n    def __init__(self, app, message, payload, protocol):\n        path = unquote(message.path)\n        res = urlsplit(path)\n        self._app = app\n        self._version = message.version\n        self._server_http_protocol = protocol\n        self._method = message.method.upper()\n        self._host = message.headers.get('HOST')\n        self._path_qs = path\n        self._path = res.path\n        self._query_string = res.query\n        self._get = MultiDict(parse_qsl(res.query))\n        self._post = None\n        self._headers = message.headers\n\n        # matchdict, route_name, handler\n        # or information about traversal lookup\n        self._match_info = None  # initialized after route resolving\n\n        self._payload = payload\n        self._response = None\n        self._cookies = None\n\n    @property\n    def method(self):\n        return self._method\n\n    @property\n    def version(self):\n        return self._version\n\n    @property\n    def host(self):\n        return self._host\n\n    @property\n    def path_qs(self):\n        return self._path_qs\n\n    @property\n    def path(self):\n        return self._path\n\n    @property\n    def query_string(self):\n        return self._query_string\n\n    @property\n    def GET(self):\n        return self._get\n\n    @property\n    def headers(self):\n        return self._headers\n\n    @property\n    def match_info(self):\n        return self._match_info\n\n    @property\n    def app(self):\n        \"\"\"Application instance.\"\"\"\n        return self._app\n\n    @property\n    def cookies(self):\n        \"\"\"Return request cookies.\n\n        A read-only dictionary-like object.\n        \"\"\"\n        if self._cookies is None:\n            raw = self.headers.get('COOKIE', '')\n            parsed = http.cookies.SimpleCookie(raw)\n            self._cookies = MultiDict({key: val.value\n                                       for key, val in parsed.items()})\n        return self._cookies\n\n    @property\n    def payload(self):\n        \"\"\"Return raw paiload stream.\"\"\"\n        return self._payload\n\n    @asyncio.coroutine\n    def release(self):\n        \"\"\"Release request.\n\n        Eat unread part of HTTP BODY if present.\n        \"\"\"\n        chunk = yield from self._payload.readany()\n        while chunk is not EOF_MARKER or chunk:\n            chunk = yield from self._payload.readany()\n\n    def terminate(self):\n        # TODO: the method should close connection after sending response\n        # the main reason is to don't read request body as release() does\n        pass\n\n    @asyncio.coroutine\n    def read(self):\n        \"\"\"Read request body if present.\n\n        Returns bytes object with full request content or None if\n        request has no BODY.\n        \"\"\"\n\n        if self._payload is None:\n            return None\n        body = bytearray()\n        while True:\n            chunk = yield from self._payload.readany()\n            body.extend(chunk)\n            if chunk is EOF_MARKER:\n                break\n        return bytes(body)\n\n    @asyncio.coroutine\n    def text(self):\n        bytes_body = yield from self.read()\n        if bytes_body is None:\n            return None\n        encoding = self.charset\n        return bytes_body.decode(encoding)\n\n    @asyncio.coroutine\n    def json(self, *, loader=json.loads):\n        body = yield from self.text()\n        if body is None:\n            return None\n        return loader(body)\n\n    @asyncio.coroutine\n    def POST(self):\n        if self._post is not None:\n            return self._post\n        if self.method not in ('POST', 'PUT', 'PATCH'):\n            self._post = MultiDict()\n            return\n        content_type = self.content_type\n        if (content_type not in ('',\n                                 'application/x-www-form-urlencoded',\n                                 'multipart/form-data')):\n            self._post = MultiDict()\n            return\n\n        body = yield from self.text()\n        fs = cgi.FieldStorage(fp=io.StringIO(body),\n                              environ={'CONTENT_LENGTH': '0',\n                                       'QUERY_STRING': '',\n                                       'REQUEST_METHOD': self.method,\n                                       'CONTENT_TYPE': content_type},\n                              keep_blank_values=True,\n                              encoding='utf-8')\n\n        out = MutableMultiDict()\n        for field in fs.list or ():\n            charset = field.type_options.get('charset', 'utf-8')\n            transfer_encoding = field.headers.get('Content-Transfer-Encoding',\n                                                  None)\n            supported_tranfer_encoding = {\n                'base64': binascii.a2b_base64,\n                'quoted-printable': binascii.a2b_qp\n                }\n            if charset == 'utf-8':\n                decode = lambda b: b\n            else:\n                decode = lambda b: b.encode('utf-8').decode(charset)\n            if field.filename:\n                field.filename = decode(field.filename)\n                out.add(field.name, field)\n            else:\n                value = field.value\n                if transfer_encoding in supported_tranfer_encoding:\n                    # binascii accepts bytes\n                    value = value.encode('utf-8')\n                    value = supported_tranfer_encoding[\n                        transfer_encoding](value)\n                    # binascii returns bytes\n                    value = value.decode('utf-8')\n                out.add(field.name, decode(value))\n        self._post = MultiDict(out)\n        return self._post\n\n    @asyncio.coroutine\n    def start_websocket(self):\n        \"\"\"Upgrade connection to websocket.\n\n        Returns (reader, writer) pair.\n        \"\"\"\n\n\nclass UrlMappingMatchInfo(AbstractMatchInfo):\n\n    def __init__(self, matchdict, entry):\n        self._matchdict = matchdict\n        self._entry = entry\n\n    @property\n    def handler(self):\n        return self._entry.handler\n\n    @property\n    def matchdict(self):\n        return self._matchdict\n\n    @property\n    def route_name(self):\n        return self._entry.name\n\n\nEntry = collections.namedtuple('Entry', 'regex method handler')\n\n\nclass UrlDispatch(AbstractRouter):\n\n    DYN = re.compile(r'^\\{[_a-zA-Z][_a-zA-Z0-9]*\\}$')\n    GOOD = r'[^{}/]+'\n    PLAIN = re.compile('^'+GOOD+'$')\n\n    METHODS = {'POST', 'GET', 'PUT', 'DELETE', 'PATCH', 'HEAD', 'OPTIONS'}\n\n    def __init__(self, *, loop=None):\n        if loop is None:\n            loop = asyncio.get_event_loop()\n        self._loop = loop\n        super().__init__()\n        self._urls = []\n\n    @asyncio.coroutine\n    def resolve(self, request):\n        path = request.path\n        method = request.method\n        allowed_methods = set()\n        for entry in self._urls:\n            match = entry.regex.match(path)\n            if match is None:\n                continue\n            if entry.method != method:\n                allowed_methods.add(entry.method)\n            else:\n                break\n        else:\n            if allowed_methods:\n                allow = ', '.join(sorted(allowed_methods))\n                # add log\n                raise HttpErrorException(405, \"Method Not Allowed\",\n                                         headers=(('Allow', allow),))\n            else:\n                # add log\n                raise HttpErrorException(404, \"Not Found\")\n\n        matchdict = match.groupdict()\n        return UrlMappingMatchInfo(matchdict, entry)\n\n    def add_route(self, method, path, handler):\n        assert callable(handler), handler\n\n        assert path.startswith('/')\n        assert callable(handler), handler\n        method = method.upper()\n        assert method in self.METHODS, method\n        regexp = []\n        for part in path.split('/'):\n            if not part:\n                continue\n            if self.DYN.match(part):\n                regexp.append('(?P<'+part[1:-1]+'>'+self.GOOD+')')\n            elif self.PLAIN.match(part):\n                regexp.append(part)\n            else:\n                raise ValueError(\"Invalid path '{}'['{}']\".format(path, part))\n        pattern = '/' + '/'.join(regexp)\n        if path.endswith('/') and pattern != '/':\n            pattern += '/'\n        try:\n            compiled = re.compile('^' + pattern + '$')\n        except re.error:\n            raise ValueError(\"Invalid path '{}'\".format(path))\n        self._urls.append(Entry(compiled, method, handler))\n\n\nclass RequestHandler(ServerHttpProtocol):\n\n    def __init__(self, app, **kwargs):\n        super().__init__(**kwargs)\n        self._app = app\n\n    @asyncio.coroutine\n    def handle_request(self, message, payload):\n        request = Request(self._app, message, payload, self)\n        match_info = yield from self._app.router.resolve(request)\n        if match_info is not None:\n            request._match_info = match_info\n            handler = match_info.handler\n\n            if asyncio.iscoroutinefunction(handler):\n                resp = yield from handler(request)\n            else:\n                resp = handler(request)\n            yield from request.release()\n\n            if isinstance(resp, Response):\n                yield from resp.render()\n            else:\n                raise RuntimeError((\"Handler should return Response \"\n                                    \"instance, got {!r}\")\n                                   .format(type(resp)))\n            yield from resp.write_eof()\n        else:\n            raise HttpErrorException(404, \"Not Found\")\n\n\nclass Application(dict, asyncio.AbstractServer):\n\n    def __init__(self, *, loop=None, router=None, **kwargs):\n        # TODO: explicitly accept *debug* param\n        self._kwargs = kwargs\n        if loop is None:\n            loop = asyncio.get_event_loop()\n        if router is None:\n            router = UrlDispatch(loop=loop)\n        self._router = router\n        self._loop = loop\n\n    @property\n    def router(self):\n        return self._router\n\n    def make_handler(self):\n        return RequestHandler(self, loop=self._loop, **self._kwargs)\n\n    def close(self):\n        pass\n\n    def register_on_close(self, cb):\n        pass\n\n    @asyncio.coroutine\n    def wait_closed(self):\n        pass\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:** Accessing `content_length` on Request object raises AttributeError

**Description:**
When creating a request with the `Content-Length` header and attempting to access the `content_length` property, an `AttributeError` is raised because the `Request` object does not have a `content_length` attribute.

**Example Buggy Code:**
```python
def test_content_length():
    req = self.make_request('Get', '/', {'Content-Length': '123'})
    length = req.content_length  # Raises AttributeError
```

**Expected Behavior:**
Accessing `req.content_length` should return the integer value of the `Content-Length` header (e.g., `123`) if it is present, or `None` if the header is absent.

**Actual Behavior:**
Attempting to access `req.content_length` results in the following error:
```
AttributeError: 'Request' object has no attribute 'content_length'
```
[/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/web.py
import asyncio
import binascii
import collections
import cgi
import http.cookies
import io
import json
import re
import weakref

from urllib.parse import urlsplit, parse_qsl, unquote

from .abc import AbstractRouter, AbstractMatchInfo
from .errors import HttpErrorException
from .helpers import parse_mimetype
from .multidict import MultiDict, MutableMultiDict
from .protocol import Response as ResponseImpl, HttpVersion
from .server import ServerHttpProtocol
from .streams import EOF_MARKER


__all__ = [
    'Application',
    'HttpVersion',
    'Request',
    'StreamResponse',
    'Response',
    'UrlDispatch',
    'UrlMappingMatchInfo',
    ]


class HeadersMixin:

    _content_type = None
    _content_dict = None

    @property
    def content_type(self):
        if self._content_type is not None:
            return self._content_type
        raw = self.headers.get('Content-Type')
        if raw is None:
            # default value according to RFC 2616
            self._content_type = 'application/octet-stream'
            self._content_dict = {}
        else:
            self._content_type, self._content_dict = cgi.parse_header(raw)
        return self._content_type

    @property
    def charset(self):
        # Assumes that charset is UTF8 if not specified
        if self._content_type is None:
            self.content_type  # calculates _content_dict also
        return self._content_dict.get('charset', 'utf-8')


class StreamResponse(HeadersMixin):

    def __init__(self, request):
        self._request = request
        self.headers = MutableMultiDict()
        self._status_code = 200
        self._cookies = http.cookies.SimpleCookie()
        self._deleted_cookies = set()
        self._keep_alive = True
        self._version = request.version

        self._resp_impl = None
        self._eof_sent = False

    def _copy_cookies(self):
        for cookie in self._cookies.values():
            value = cookie.output(header='')[1:]
            self.headers.add('Set-Cookie', value)

    def _check_sending_started(self):
        resp = self._request._response
        if resp is not None:
            resp = resp()  # dereference weakref
        if resp is not None:
            raise RuntimeError(("Response {!r} already started to send"
                                " data").format(resp))

    @property
    def cookies(self):
        return self._cookies

    def set_cookie(self, name, value, *, expires=None,
                   domain=None, max_age=None, path=None,
                   secure=None, httponly=None, version=None):
        """Set or update response cookie.

        Sets new cookie or updates existent with new value.
        Also updates only those params which are not None.
        """

        self._check_sending_started()
        if name in self._deleted_cookies:
            self._deleted_cookies.remove(name)
            self._cookies.pop(name, None)

        self._cookies[name] = value
        c = self._cookies[name]
        if expires is not None:
            c['expires'] = expires
        if domain is not None:
            c['domain'] = domain
        if max_age is not None:
            c['max-age'] = max_age
        if path is not None:
            c['path'] = path
        if secure is not None:
            c['secure'] = secure
        if httponly is not None:
            c['httponly'] = httponly
        if version is not None:
            c['version'] = version

    def del_cookie(self, name, *, domain=None, path=None):
        """Delete cookie.

        Creates new empty expired cookie.
        """
        # TODO: do we need domain/path here?
        self._check_sending_started()
        self._cookies.pop(name, None)
        self.set_cookie(name, '', max_age=0, domain=domain, path=path)
        self._deleted_cookies.add(name)

    @property
    def status_code(self):
        return self._status_code

    @status_code.setter
    def status_code(self, value):
        self._check_sending_started()
        if not isinstance(value, int):
            raise TypeError("Status code must be int")
        self._status_code = value

    @property
    def version(self):
        return self._version

    @version.setter
    def version(self, value):
        self._check_sending_started()
        if not isinstance(value, HttpVersion):
            raise TypeError("HTTP version must be HttpVersion instance")
        self._version = value

    @property
    def keep_alive(self):
        return self._keep_alive

    @keep_alive.setter
    def keep_alive(self, value):
        self._check_sending_started()
        self._keep_alive = bool(value)

    @property
    def content_length(self):
        l = self.headers.get('Content-Length')
        if l is None:
            return None
        else:
            return int(l)

    @content_length.setter
    def content_length(self, value):
        self._check_sending_started()
        value = int(value)
        # TODO: raise error if chunked enabled
        self.headers['Content-Length'] = str(value)

    def set_chunked(self, chunk_size, buffered=True):
        if self.content_length is not None:
            raise RuntimeError(
                "Cannot use chunked encoding with Content-Length set up")

    def send_headers(self):
        if self._resp_impl is not None:
            raise RuntimeError("HTTP headers are already sent")
        if self._eof_sent:
            raise RuntimeError("Cannot call send_header() after write_eof()")

        self._check_sending_started()
        self._request._response = weakref.ref(self)

        resp_impl = self._resp_impl = ResponseImpl(
            self._request._server_http_protocol.writer,
            self._status_code,
            self._request.version)

        self._copy_cookies()

        headers = self.headers.items(getall=True)
        for key, val in headers:
            resp_impl.add_header(key, val)

        resp_impl.send_headers()

    def write(self, data):
        if not isinstance(data, (bytes, bytearray, memoryview)):
            raise TypeError('data argument must be byte-ish (%r)',
                            type(data))

        if self._eof_sent:
            raise RuntimeError("Cannot call write() after send_eof()")
        if self._resp_impl is None:
            self.send_headers()

        if data:
            self._resp_impl.write(data)

    @asyncio.coroutine
    def write_eof(self):
        if self._resp_impl is None:
            raise RuntimeError("No data has been sent")
        if self._eof_sent:
            return

        yield from self._resp_impl.write_eof()
        if self._resp_impl.keep_alive():
            self._request._server_http_protocol.keep_alive(self._keep_alive)
        self._eof_sent = True


class Response(StreamResponse):

    def __init__(self, request, body=b'', *, status_code=200, headers=None):
        super().__init__(request)
        self.status_code = status_code
        self.body = body
        if headers is not None:
            self.headers.extend(headers)

    @property
    def body(self):
        return self._body

    @body.setter
    def body(self, body):
        if not isinstance(body, (bytes, bytearray, memoryview)):
            raise TypeError('body argument must be byte-ish (%r)',
                            type(body))
        self._check_sending_started()
        self._body = body

    @asyncio.coroutine
    def render(self):
        body = self._body
        self.content_length = len(body)
        self.write(body)


class Request(HeadersMixin):

    def __init__(self, app, message, payload, protocol):
        path = unquote(message.path)
        res = urlsplit(path)
        self._app = app
        self._version = message.version
        self._server_http_protocol = protocol
        self._method = message.method.upper()
        self._host = message.headers.get('HOST')
        self._path_qs = path
        self._path = res.path
        self._query_string = res.query
        self._get = MultiDict(parse_qsl(res.query))
        self._post = None
        self._headers = message.headers

        # matchdict, route_name, handler
        # or information about traversal lookup
        self._match_info = None  # initialized after route resolving

        self._payload = payload
        self._response = None
        self._cookies = None

    @property
    def method(self):
        return self._method

    @property
    def version(self):
        return self._version

    @property
    def host(self):
        return self._host

    @property
    def path_qs(self):
        return self._path_qs

    @property
    def path(self):
        return self._path

    @property
    def query_string(self):
        return self._query_string

    @property
    def GET(self):
        return self._get

    @property
    def headers(self):
        return self._headers

    @property
    def match_info(self):
        return self._match_info

    @property
    def app(self):
        """Application instance."""
        return self._app

    @property
    def cookies(self):
        """Return request cookies.

        A read-only dictionary-like object.
        """
        if self._cookies is None:
            raw = self.headers.get('COOKIE', '')
            parsed = http.cookies.SimpleCookie(raw)
            self._cookies = MultiDict({key: val.value
                                       for key, val in parsed.items()})
        return self._cookies

    @property
    def payload(self):
        """Return raw paiload stream."""
        return self._payload

    @asyncio.coroutine
    def release(self):
        """Release request.

        Eat unread part of HTTP BODY if present.
        """
        chunk = yield from self._payload.readany()
        while chunk is not EOF_MARKER or chunk:
            chunk = yield from self._payload.readany()

    def terminate(self):
        # TODO: the method should close connection after sending response
        # the main reason is to don't read request body as release() does
        pass

    @asyncio.coroutine
    def read(self):
        """Read request body if present.

        Returns bytes object with full request content or None if
        request has no BODY.
        """

        if self._payload is None:
            return None
        body = bytearray()
        while True:
            chunk = yield from self._payload.readany()
            body.extend(chunk)
            if chunk is EOF_MARKER:
                break
        return bytes(body)

    @asyncio.coroutine
    def text(self):
        bytes_body = yield from self.read()
        if bytes_body is None:
            return None
        encoding = self.charset
        return bytes_body.decode(encoding)

    @asyncio.coroutine
    def json(self, *, loader=json.loads):
        body = yield from self.text()
        if body is None:
            return None
        return loader(body)

    @asyncio.coroutine
    def POST(self):
        if self._post is not None:
            return self._post
        if self.method not in ('POST', 'PUT', 'PATCH'):
            self._post = MultiDict()
            return
        content_type = self.content_type
        if (content_type not in ('',
                                 'application/x-www-form-urlencoded',
                                 'multipart/form-data')):
            self._post = MultiDict()
            return

        body = yield from self.text()
        fs = cgi.FieldStorage(fp=io.StringIO(body),
                              environ={'CONTENT_LENGTH': '0',
                                       'QUERY_STRING': '',
                                       'REQUEST_METHOD': self.method,
                                       'CONTENT_TYPE': content_type},
                              keep_blank_values=True,
                              encoding='utf-8')

        out = MutableMultiDict()
        for field in fs.list or ():
            charset = field.type_options.get('charset', 'utf-8')
            transfer_encoding = field.headers.get('Content-Transfer-Encoding',
                                                  None)
            supported_tranfer_encoding = {
                'base64': binascii.a2b_base64,
                'quoted-printable': binascii.a2b_qp
                }
            if charset == 'utf-8':
                decode = lambda b: b
            else:
                decode = lambda b: b.encode('utf-8').decode(charset)
            if field.filename:
                field.filename = decode(field.filename)
                out.add(field.name, field)
            else:
                value = field.value
                if transfer_encoding in supported_tranfer_encoding:
                    # binascii accepts bytes
                    value = value.encode('utf-8')
                    value = supported_tranfer_encoding[
                        transfer_encoding](value)
                    # binascii returns bytes
                    value = value.decode('utf-8')
                out.add(field.name, decode(value))
        self._post = MultiDict(out)
        return self._post

    @asyncio.coroutine
    def start_websocket(self):
        """Upgrade connection to websocket.

        Returns (reader, writer) pair.
        """


class UrlMappingMatchInfo(AbstractMatchInfo):

    def __init__(self, matchdict, entry):
        self._matchdict = matchdict
        self._entry = entry

    @property
    def handler(self):
        return self._entry.handler

    @property
    def matchdict(self):
        return self._matchdict

    @property
    def route_name(self):
        return self._entry.name


Entry = collections.namedtuple('Entry', 'regex method handler')


class UrlDispatch(AbstractRouter):

    DYN = re.compile(r'^\{[_a-zA-Z][_a-zA-Z0-9]*\}$')
    GOOD = r'[^{}/]+'
    PLAIN = re.compile('^'+GOOD+'$')

    METHODS = {'POST', 'GET', 'PUT', 'DELETE', 'PATCH', 'HEAD', 'OPTIONS'}

    def __init__(self, *, loop=None):
        if loop is None:
            loop = asyncio.get_event_loop()
        self._loop = loop
        super().__init__()
        self._urls = []

    @asyncio.coroutine
    def resolve(self, request):
        path = request.path
        method = request.method
        allowed_methods = set()
        for entry in self._urls:
            match = entry.regex.match(path)
            if match is None:
                continue
            if entry.method != method:
                allowed_methods.add(entry.method)
            else:
                break
        else:
            if allowed_methods:
                allow = ', '.join(sorted(allowed_methods))
                # add log
                raise HttpErrorException(405, "Method Not Allowed",
                                         headers=(('Allow', allow),))
            else:
                # add log
                raise HttpErrorException(404, "Not Found")

        matchdict = match.groupdict()
        return UrlMappingMatchInfo(matchdict, entry)

    def add_route(self, method, path, handler):
        assert callable(handler), handler

        assert path.startswith('/')
        assert callable(handler), handler
        method = method.upper()
        assert method in self.METHODS, method
        regexp = []
        for part in path.split('/'):
            if not part:
                continue
            if self.DYN.match(part):
                regexp.append('(?P<'+part[1:-1]+'>'+self.GOOD+')')
            elif self.PLAIN.match(part):
                regexp.append(part)
            else:
                raise ValueError("Invalid path '{}'['{}']".format(path, part))
        pattern = '/' + '/'.join(regexp)
        if path.endswith('/') and pattern != '/':
            pattern += '/'
        try:
            compiled = re.compile('^' + pattern + '$')
        except re.error:
            raise ValueError("Invalid path '{}'".format(path))
        self._urls.append(Entry(compiled, method, handler))


class RequestHandler(ServerHttpProtocol):

    def __init__(self, app, **kwargs):
        super().__init__(**kwargs)
        self._app = app

    @asyncio.coroutine
    def handle_request(self, message, payload):
        request = Request(self._app, message, payload, self)
        match_info = yield from self._app.router.resolve(request)
        if match_info is not None:
            request._match_info = match_info
            handler = match_info.handler

            if asyncio.iscoroutinefunction(handler):
                resp = yield from handler(request)
            else:
                resp = handler(request)
            yield from request.release()

            if isinstance(resp, Response):
                yield from resp.render()
            else:
                raise RuntimeError(("Handler should return Response "
                                    "instance, got {!r}")
                                   .format(type(resp)))
            yield from resp.write_eof()
        else:
            raise HttpErrorException(404, "Not Found")


class Application(dict, asyncio.AbstractServer):

    def __init__(self, *, loop=None, router=None, **kwargs):
        # TODO: explicitly accept *debug* param
        self._kwargs = kwargs
        if loop is None:
            loop = asyncio.get_event_loop()
        if router is None:
            router = UrlDispatch(loop=loop)
        self._router = router
        self._loop = loop

    @property
    def router(self):
        return self._router

    def make_handler(self):
        return RequestHandler(self, loop=self._loop, **self._kwargs)

    def close(self):
        pass

    def register_on_close(self, cb):
        pass

    @asyncio.coroutine
    def wait_closed(self):
        pass

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