{
    "file_diffs": [
        {
            "old_file_content": "CHANGES\n=======\n\n0.10.1 (11-17-2014)\n-------------------\n\n- aiohttp.web.HTTPException and descendants now files response body\n  with string like `400: NotFound`\n\n- Fix multidict __iter__, the method should iterate over keys, not (key, value) pairs.\n\n0.10.0 (11-13-2014)\n-------------------\n\n- Add aiohttp.web subpackage for highlevel http server support.\n\n- Add *reason* optional parameter to aiohttp.protocol.Response ctor.\n\n- Fix aiohttp.client bug for sending file without content-type.\n\n- Change error text for connection closed between server responses\n  from 'Can not read status line' to explicit 'Connection closed by\n  server'\n\n- Drop closed connections from connector #173\n\n- Set server.transport to None on .closing() #172\n\n0.9.3 (10-30-2014)\n------------------\n\n- Fix compatibility with asyncio 3.4.1+ #170\n\n0.9.2 (10-16-2014)\n------------------\n\n- Improve redirect handling #157\n\n- Send raw files as is #153\n\n- Better websocket support #150\n\n\n0.9.1 (08-30-2014)\n------------------\n\n- Added MultiDict support for client request params and data #114.\n\n- Fixed parameter type for IncompleteRead exception #118.\n\n- Strictly require ASCII headers names and values #137\n\n- Keep port in ProxyConnector #128.\n\n- Python 3.4.1 compatibility #131.\n\n\n0.9.0 (07-08-2014)\n------------------\n\n- Better client basic authentication support #112.\n\n- Fixed incorrect line splitting in HttpRequestParser #97.\n\n- Support StreamReader and DataQueue as request data.\n\n- Client files handling refactoring #20.\n\n- Backward incompatible: Replace DataQueue with StreamReader for request payload #87.\n\n\n0.8.4 (07-04-2014)\n------------------\n\n- Change ProxyConnector authorization parameters.\n\n\n0.8.3 (07-03-2014)\n------------------\n\n- Publish TCPConnector properties: verify_ssl, family, resolve, resolved_hosts.\n\n- Don't parse message body for HEAD responses.\n\n- Refactor client response decoding.\n\n\n0.8.2 (06-22-2014)\n------------------\n\n- Make ProxyConnector.proxy immutable property.\n\n- Make UnixConnector.path immutable property.\n\n- Fix resource leak for aiohttp.request() with implicit connector.\n\n- Rename Connector's reuse_timeout to keepalive_timeout.\n\n\n0.8.1 (06-18-2014)\n------------------\n\n- Use case insensitive multidict for server request/response headers.\n\n- MultiDict.getall() accepts default value.\n\n- Catch server ConnectionError.\n\n- Accept MultiDict (and derived) instances in aiohttp.request header argument.\n\n- Proxy 'CONNECT' support.\n\n\n0.8.0 (06-06-2014)\n------------------\n\n- Add support for utf-8 values in HTTP headers\n\n- Allow to use custom response class instead of HttpResponse\n\n- Use MultiDict for client request headers\n\n- Use MultiDict for server request/response headers\n\n- Store response headers in ClientResponse.headers attribute\n\n- Get rid of timeout parameter in aiohttp.client API\n\n- Exceptions refactoring\n\n\n0.7.3 (05-20-2014)\n------------------\n\n- Simple HTTP proxy support.\n\n\n0.7.2 (05-14-2014)\n------------------\n\n- Get rid of __del__ methods\n\n- Use ResourceWarning instead of logging warning record.\n\n\n0.7.1 (04-28-2014)\n------------------\n\n- Do not unquote client request urls.\n\n- Allow multple waiters on transport drain.\n\n- Do not return client connection to pool in case of exceptions.\n\n- Rename SocketConnector to TCPConnector and UnixSocketConnector to UnixConnector.\n\n\n0.7.0 (04-16-2014)\n------------------\n\n- Connection flow control.\n\n- Http client session/connection pool refactoring.\n\n- Better handling for bad server requests.\n\n\n0.6.5 (03-29-2014)\n------------------\n\n- Added client session reuse timeout.\n\n- Better client request cancellation support.\n\n- Better handling responses without content length.\n\n- Added HttpClient verify_ssl parameter support.\n\n\n0.6.4 (02-27-2014)\n------------------\n\n- Log content-length missing warning only for put and post requests.\n\n\n0.6.3 (02-27-2014)\n------------------\n\n- Better support for server exit.\n\n- Read response body until eof if content-length is not defined #14\n\n\n0.6.2 (02-18-2014)\n------------------\n\n- Fix trailing char in allowed_methods.\n\n- Start slow request timer for first request.\n\n\n0.6.1 (02-17-2014)\n------------------\n\n- Added utility method HttpResponse.read_and_close()\n\n- Added slow request timeout.\n\n- Enable socket SO_KEEPALIVE if available. (@polymorphm)\n\n\n0.6.0 (02-12-2014)\n------------------\n\n- Better handling for process exit.\n\n\n0.5.0 (01-29-2014)\n------------------\n\n- Allow to use custom HttpRequest client class.\n\n- Use gunicorn keepalive setting for async worker.\n\n- Log leaking responses.\n\n- python 3.4 compatibility\n\n\n0.4.4 (11-15-2013)\n------------------\n\n- Resolve only AF_INET family, because it is not clear how to pass extra info to asyncio.\n\n\n0.4.3 (11-15-2013)\n------------------\n\n- Allow to wait completion of request with `HttpResponse.wait_for_close()`\n\n\n0.4.2 (11-14-2013)\n------------------\n\n- Handle exception in client request stream.\n\n- Prevent host resolving for each client request.\n\n\n0.4.1 (11-12-2013)\n------------------\n\n- Added client support for `expect: 100-continue` header.\n\n\n0.4 (11-06-2013)\n----------------\n\n- Added custom wsgi application close procedure\n\n- Fixed concurrent host failure in HttpClient\n\n\n0.3 (11-04-2013)\n----------------\n\n- Added PortMapperWorker\n\n- Added HttpClient\n\n- Added tcp connection timeout to http client\n\n- Better client connection errors handling\n\n- Gracefully handle process exit\n\n\n0.2\n---\n\n- Fix packaging\n",
            "new_file_content": "CHANGES\n=======\n\n0.10.2 (11-19-2014)\n-------------------\n\n- Don't unquote `environ['PATH_INFO']` in wsgi.py #177\n\n0.10.1 (11-17-2014)\n-------------------\n\n- aiohttp.web.HTTPException and descendants now files response body\n  with string like `400: NotFound`\n\n- Fix multidict __iter__, the method should iterate over keys, not (key, value) pairs.\n\n0.10.0 (11-13-2014)\n-------------------\n\n- Add aiohttp.web subpackage for highlevel http server support.\n\n- Add *reason* optional parameter to aiohttp.protocol.Response ctor.\n\n- Fix aiohttp.client bug for sending file without content-type.\n\n- Change error text for connection closed between server responses\n  from 'Can not read status line' to explicit 'Connection closed by\n  server'\n\n- Drop closed connections from connector #173\n\n- Set server.transport to None on .closing() #172\n\n0.9.3 (10-30-2014)\n------------------\n\n- Fix compatibility with asyncio 3.4.1+ #170\n\n0.9.2 (10-16-2014)\n------------------\n\n- Improve redirect handling #157\n\n- Send raw files as is #153\n\n- Better websocket support #150\n\n\n0.9.1 (08-30-2014)\n------------------\n\n- Added MultiDict support for client request params and data #114.\n\n- Fixed parameter type for IncompleteRead exception #118.\n\n- Strictly require ASCII headers names and values #137\n\n- Keep port in ProxyConnector #128.\n\n- Python 3.4.1 compatibility #131.\n\n\n0.9.0 (07-08-2014)\n------------------\n\n- Better client basic authentication support #112.\n\n- Fixed incorrect line splitting in HttpRequestParser #97.\n\n- Support StreamReader and DataQueue as request data.\n\n- Client files handling refactoring #20.\n\n- Backward incompatible: Replace DataQueue with StreamReader for request payload #87.\n\n\n0.8.4 (07-04-2014)\n------------------\n\n- Change ProxyConnector authorization parameters.\n\n\n0.8.3 (07-03-2014)\n------------------\n\n- Publish TCPConnector properties: verify_ssl, family, resolve, resolved_hosts.\n\n- Don't parse message body for HEAD responses.\n\n- Refactor client response decoding.\n\n\n0.8.2 (06-22-2014)\n------------------\n\n- Make ProxyConnector.proxy immutable property.\n\n- Make UnixConnector.path immutable property.\n\n- Fix resource leak for aiohttp.request() with implicit connector.\n\n- Rename Connector's reuse_timeout to keepalive_timeout.\n\n\n0.8.1 (06-18-2014)\n------------------\n\n- Use case insensitive multidict for server request/response headers.\n\n- MultiDict.getall() accepts default value.\n\n- Catch server ConnectionError.\n\n- Accept MultiDict (and derived) instances in aiohttp.request header argument.\n\n- Proxy 'CONNECT' support.\n\n\n0.8.0 (06-06-2014)\n------------------\n\n- Add support for utf-8 values in HTTP headers\n\n- Allow to use custom response class instead of HttpResponse\n\n- Use MultiDict for client request headers\n\n- Use MultiDict for server request/response headers\n\n- Store response headers in ClientResponse.headers attribute\n\n- Get rid of timeout parameter in aiohttp.client API\n\n- Exceptions refactoring\n\n\n0.7.3 (05-20-2014)\n------------------\n\n- Simple HTTP proxy support.\n\n\n0.7.2 (05-14-2014)\n------------------\n\n- Get rid of __del__ methods\n\n- Use ResourceWarning instead of logging warning record.\n\n\n0.7.1 (04-28-2014)\n------------------\n\n- Do not unquote client request urls.\n\n- Allow multple waiters on transport drain.\n\n- Do not return client connection to pool in case of exceptions.\n\n- Rename SocketConnector to TCPConnector and UnixSocketConnector to UnixConnector.\n\n\n0.7.0 (04-16-2014)\n------------------\n\n- Connection flow control.\n\n- Http client session/connection pool refactoring.\n\n- Better handling for bad server requests.\n\n\n0.6.5 (03-29-2014)\n------------------\n\n- Added client session reuse timeout.\n\n- Better client request cancellation support.\n\n- Better handling responses without content length.\n\n- Added HttpClient verify_ssl parameter support.\n\n\n0.6.4 (02-27-2014)\n------------------\n\n- Log content-length missing warning only for put and post requests.\n\n\n0.6.3 (02-27-2014)\n------------------\n\n- Better support for server exit.\n\n- Read response body until eof if content-length is not defined #14\n\n\n0.6.2 (02-18-2014)\n------------------\n\n- Fix trailing char in allowed_methods.\n\n- Start slow request timer for first request.\n\n\n0.6.1 (02-17-2014)\n------------------\n\n- Added utility method HttpResponse.read_and_close()\n\n- Added slow request timeout.\n\n- Enable socket SO_KEEPALIVE if available. (@polymorphm)\n\n\n0.6.0 (02-12-2014)\n------------------\n\n- Better handling for process exit.\n\n\n0.5.0 (01-29-2014)\n------------------\n\n- Allow to use custom HttpRequest client class.\n\n- Use gunicorn keepalive setting for async worker.\n\n- Log leaking responses.\n\n- python 3.4 compatibility\n\n\n0.4.4 (11-15-2013)\n------------------\n\n- Resolve only AF_INET family, because it is not clear how to pass extra info to asyncio.\n\n\n0.4.3 (11-15-2013)\n------------------\n\n- Allow to wait completion of request with `HttpResponse.wait_for_close()`\n\n\n0.4.2 (11-14-2013)\n------------------\n\n- Handle exception in client request stream.\n\n- Prevent host resolving for each client request.\n\n\n0.4.1 (11-12-2013)\n------------------\n\n- Added client support for `expect: 100-continue` header.\n\n\n0.4 (11-06-2013)\n----------------\n\n- Added custom wsgi application close procedure\n\n- Fixed concurrent host failure in HttpClient\n\n\n0.3 (11-04-2013)\n----------------\n\n- Added PortMapperWorker\n\n- Added HttpClient\n\n- Added tcp connection timeout to http client\n\n- Better client connection errors handling\n\n- Gracefully handle process exit\n\n\n0.2\n---\n\n- Fix packaging\n",
            "header": {
                "file": {
                    "path": "CHANGES.txt"
                },
                "misc_line": null
            },
            "index_line": {
                "old_commit_hash": "11d067c9",
                "new_commit_hash": "2eb634f6",
                "mode": "100644"
            },
            "is_binary_file": false,
            "binary_line": null,
            "minus_file": {
                "path": "a/CHANGES.txt"
            },
            "plus_file": {
                "path": "b/CHANGES.txt"
            },
            "hunks": [
                {
                    "descriptor": {
                        "old_range": {
                            "start": 1,
                            "length": 6
                        },
                        "new_range": {
                            "start": 1,
                            "length": 11
                        },
                        "section": ""
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "CHANGES",
                                "type": "context"
                            },
                            {
                                "content": "=======",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "0.10.2 (11-19-2014)",
                                "type": "added"
                            },
                            {
                                "content": "-------------------",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "- Don't unquote `environ['PATH_INFO']` in wsgi.py #177",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "0.10.1 (11-17-2014)",
                                "type": "context"
                            },
                            {
                                "content": "-------------------",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [],
                    "added_entities": [],
                    "deleted_entities": []
                }
            ]
        },
        {
            "old_file_content": "# This relies on each of the submodules having an __all__ variable.\n\n__version__ = '0.10.1'\n\n\nfrom .protocol import *  # noqa\nfrom .connector import *  # noqa\nfrom .client import *  # noqa\nfrom .errors import *  # noqa\nfrom .helpers import *  # noqa\nfrom .parsers import *  # noqa\nfrom .streams import *  # noqa\n\n\n__all__ = (client.__all__ +\n           errors.__all__ +\n           helpers.__all__ +\n           parsers.__all__ +\n           protocol.__all__ +\n           connector.__all__ +\n           streams.__all__ +\n           ['__version__'])\n",
            "new_file_content": "# This relies on each of the submodules having an __all__ variable.\n\n__version__ = '0.10.2'\n\n\nfrom .protocol import *  # noqa\nfrom .connector import *  # noqa\nfrom .client import *  # noqa\nfrom .errors import *  # noqa\nfrom .helpers import *  # noqa\nfrom .parsers import *  # noqa\nfrom .streams import *  # noqa\n\n\n__all__ = (client.__all__ +\n           errors.__all__ +\n           helpers.__all__ +\n           parsers.__all__ +\n           protocol.__all__ +\n           connector.__all__ +\n           streams.__all__ +\n           ['__version__'])\n",
            "header": {
                "file": {
                    "path": "aiohttp/__init__.py"
                },
                "misc_line": null
            },
            "index_line": {
                "old_commit_hash": "c404e367",
                "new_commit_hash": "9b101c9d",
                "mode": "100644"
            },
            "is_binary_file": false,
            "binary_line": null,
            "minus_file": {
                "path": "a/aiohttp/__init__.py"
            },
            "plus_file": {
                "path": "b/aiohttp/__init__.py"
            },
            "hunks": [
                {
                    "descriptor": {
                        "old_range": {
                            "start": 1,
                            "length": 6
                        },
                        "new_range": {
                            "start": 1,
                            "length": 6
                        },
                        "section": ""
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "# This relies on each of the submodules having an __all__ variable.",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "__version__ = '0.10.1'",
                                "type": "deleted"
                            },
                            {
                                "content": "__version__ = '0.10.2'",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "from .protocol import *  # noqa",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [],
                    "added_entities": [
                        {
                            "file_name": "aiohttp/__init__.py",
                            "type": "statement",
                            "name": "",
                            "content": "__version__ = '0.10.2'",
                            "ast_type_str": "Assign",
                            "start_lineno": 3,
                            "end_lineno": 3,
                            "parent": null
                        }
                    ],
                    "deleted_entities": [
                        {
                            "file_name": "aiohttp/__init__.py",
                            "type": "statement",
                            "name": "",
                            "content": "__version__ = '0.10.1'",
                            "ast_type_str": "Assign",
                            "start_lineno": 3,
                            "end_lineno": 3,
                            "parent": null
                        }
                    ]
                }
            ]
        },
        {
            "old_file_content": "\"\"\"wsgi server.\n\nTODO:\n  * proxy protocol\n  * x-forward security\n  * wsgi file support (os.sendfile)\n\"\"\"\n\n__all__ = ['WSGIServerHttpProtocol']\n\nimport asyncio\nimport inspect\nimport io\nimport os\nimport sys\nimport time\nfrom urllib.parse import unquote, urlsplit\n\nimport aiohttp\nfrom aiohttp import server\n\n\nclass WSGIServerHttpProtocol(server.ServerHttpProtocol):\n    \"\"\"HTTP Server that implements the Python WSGI protocol.\n\n    It uses 'wsgi.async' of 'True'. 'wsgi.input' can behave differently\n    depends on 'readpayload' constructor parameter. If readpayload is set to\n    True, wsgi server reads all incoming data into BytesIO object and\n    sends it as 'wsgi.input' environ var. If readpayload is set to false\n    'wsgi.input' is a StreamReader and application should read incoming\n    data with \"yield from environ['wsgi.input'].read()\". It defaults to False.\n    \"\"\"\n\n    SCRIPT_NAME = os.environ.get('SCRIPT_NAME', '')\n\n    def __init__(self, app, readpayload=False, is_ssl=False, *args, **kw):\n        super().__init__(*args, **kw)\n\n        self.wsgi = app\n        self.is_ssl = is_ssl\n        self.readpayload = readpayload\n\n    def create_wsgi_response(self, message):\n        return WsgiResponse(self.writer, message)\n\n    def create_wsgi_environ(self, message, payload):\n        uri_parts = urlsplit(message.path)\n        url_scheme = 'https' if self.is_ssl else 'http'\n\n        environ = {\n            'wsgi.input': payload,\n            'wsgi.errors': sys.stderr,\n            'wsgi.version': (1, 0),\n            'wsgi.async': True,\n            'wsgi.multithread': False,\n            'wsgi.multiprocess': False,\n            'wsgi.run_once': False,\n            'wsgi.file_wrapper': FileWrapper,\n            'wsgi.url_scheme': url_scheme,\n            'SERVER_SOFTWARE': aiohttp.HttpMessage.SERVER_SOFTWARE,\n            'REQUEST_METHOD': message.method,\n            'QUERY_STRING': uri_parts.query or '',\n            'RAW_URI': message.path,\n            'SERVER_PROTOCOL': 'HTTP/%s.%s' % message.version\n        }\n\n        # authors should be aware that REMOTE_HOST and REMOTE_ADDR\n        # may not qualify the remote addr:\n        # http://www.ietf.org/rfc/rfc3875\n        forward = self.transport.get_extra_info('addr', '127.0.0.1')\n        script_name = self.SCRIPT_NAME\n        server = forward\n\n        for hdr_name, hdr_value in message.headers.items(getall=True):\n            if hdr_name == 'HOST':\n                server = hdr_value\n            elif hdr_name == 'SCRIPT_NAME':\n                script_name = hdr_value\n            elif hdr_name == 'CONTENT-TYPE':\n                environ['CONTENT_TYPE'] = hdr_value\n                continue\n            elif hdr_name == 'CONTENT-LENGTH':\n                environ['CONTENT_LENGTH'] = hdr_value\n                continue\n\n            key = 'HTTP_%s' % hdr_name.replace('-', '_')\n            if key in environ:\n                hdr_value = '%s,%s' % (environ[key], hdr_value)\n\n            environ[key] = hdr_value\n\n        if isinstance(forward, str):\n            # we only took the last one\n            # http://en.wikipedia.org/wiki/X-Forwarded-For\n            if ',' in forward:\n                forward = forward.rsplit(',', 1)[-1].strip()\n\n            # find host and port on ipv6 address\n            if '[' in forward and ']' in forward:\n                host = forward.split(']')[0][1:].lower()\n            elif ':' in forward and forward.count(':') == 1:\n                host = forward.split(':')[0].lower()\n            else:\n                host = forward\n\n            forward = forward.split(']')[-1]\n            if ':' in forward and forward.count(':') == 1:\n                port = forward.split(':', 1)[1]\n            else:\n                port = 80\n\n            remote = (host, port)\n        else:\n            remote = forward\n\n        environ['REMOTE_ADDR'] = remote[0]\n        environ['REMOTE_PORT'] = str(remote[1])\n\n        if isinstance(server, str):\n            server = server.split(':')\n            if len(server) == 1:\n                server.append('80' if url_scheme == 'http' else '443')\n\n        environ['SERVER_NAME'] = server[0]\n        environ['SERVER_PORT'] = str(server[1])\n\n        path_info = uri_parts.path\n        if script_name:\n            path_info = path_info.split(script_name, 1)[-1]\n\n        environ['PATH_INFO'] = unquote(path_info)\n        environ['SCRIPT_NAME'] = script_name\n\n        environ['async.reader'] = self.reader\n        environ['async.writer'] = self.writer\n\n        return environ\n\n    @asyncio.coroutine\n    def handle_request(self, message, payload):\n        \"\"\"Handle a single HTTP request\"\"\"\n        now = time.time()\n\n        if self.readpayload:\n            wsgiinput = io.BytesIO()\n            wsgiinput.write((yield from payload.read()))\n            wsgiinput.seek(0)\n            payload = wsgiinput\n\n        environ = self.create_wsgi_environ(message, payload)\n        response = self.create_wsgi_response(message)\n\n        riter = self.wsgi(environ, response.start_response)\n        if isinstance(riter, asyncio.Future) or inspect.isgenerator(riter):\n            riter = yield from riter\n\n        resp = response.response\n        try:\n            for item in riter:\n                if isinstance(item, asyncio.Future):\n                    item = yield from item\n                yield from resp.write(item)\n\n            yield from resp.write_eof()\n        finally:\n            if hasattr(riter, 'close'):\n                riter.close()\n\n        if resp.keep_alive():\n            self.keep_alive(True)\n\n        self.log_access(\n            message, environ, response.response, time.time() - now)\n\n\nclass FileWrapper:\n    \"\"\"Custom file wrapper.\"\"\"\n\n    def __init__(self, fobj, chunk_size=8192):\n        self.fobj = fobj\n        self.chunk_size = chunk_size\n        if hasattr(fobj, 'close'):\n            self.close = fobj.close\n\n    def __iter__(self):\n        return self\n\n    def __next__(self):\n        data = self.fobj.read(self.chunk_size)\n        if data:\n            return data\n        raise StopIteration\n\n\nclass WsgiResponse:\n    \"\"\"Implementation of start_response() callable as specified by PEP 3333\"\"\"\n\n    status = None\n\n    def __init__(self, writer, message):\n        self.writer = writer\n        self.message = message\n\n    def start_response(self, status, headers, exc_info=None):\n        if exc_info:\n            try:\n                if self.status:\n                    raise exc_info[1]\n            finally:\n                exc_info = None\n\n        status_code = int(status.split(' ', 1)[0])\n\n        self.status = status\n        resp = self.response = aiohttp.Response(\n            self.writer, status_code,\n            self.message.version, self.message.should_close)\n        resp.add_headers(*headers)\n\n        # send headers immediately for websocket connection\n        if status_code == 101 and resp.upgrade and resp.websocket:\n            resp.send_headers()\n        else:\n            resp._send_headers = True\n        return self.response.write\n",
            "new_file_content": "\"\"\"wsgi server.\n\nTODO:\n  * proxy protocol\n  * x-forward security\n  * wsgi file support (os.sendfile)\n\"\"\"\n\n__all__ = ['WSGIServerHttpProtocol']\n\nimport asyncio\nimport inspect\nimport io\nimport os\nimport sys\nimport time\nfrom urllib.parse import urlsplit\n\nimport aiohttp\nfrom aiohttp import server\n\n\nclass WSGIServerHttpProtocol(server.ServerHttpProtocol):\n    \"\"\"HTTP Server that implements the Python WSGI protocol.\n\n    It uses 'wsgi.async' of 'True'. 'wsgi.input' can behave differently\n    depends on 'readpayload' constructor parameter. If readpayload is set to\n    True, wsgi server reads all incoming data into BytesIO object and\n    sends it as 'wsgi.input' environ var. If readpayload is set to false\n    'wsgi.input' is a StreamReader and application should read incoming\n    data with \"yield from environ['wsgi.input'].read()\". It defaults to False.\n    \"\"\"\n\n    SCRIPT_NAME = os.environ.get('SCRIPT_NAME', '')\n\n    def __init__(self, app, readpayload=False, is_ssl=False, *args, **kw):\n        super().__init__(*args, **kw)\n\n        self.wsgi = app\n        self.is_ssl = is_ssl\n        self.readpayload = readpayload\n\n    def create_wsgi_response(self, message):\n        return WsgiResponse(self.writer, message)\n\n    def create_wsgi_environ(self, message, payload):\n        uri_parts = urlsplit(message.path)\n        url_scheme = 'https' if self.is_ssl else 'http'\n\n        environ = {\n            'wsgi.input': payload,\n            'wsgi.errors': sys.stderr,\n            'wsgi.version': (1, 0),\n            'wsgi.async': True,\n            'wsgi.multithread': False,\n            'wsgi.multiprocess': False,\n            'wsgi.run_once': False,\n            'wsgi.file_wrapper': FileWrapper,\n            'wsgi.url_scheme': url_scheme,\n            'SERVER_SOFTWARE': aiohttp.HttpMessage.SERVER_SOFTWARE,\n            'REQUEST_METHOD': message.method,\n            'QUERY_STRING': uri_parts.query or '',\n            'RAW_URI': message.path,\n            'SERVER_PROTOCOL': 'HTTP/%s.%s' % message.version\n        }\n\n        # authors should be aware that REMOTE_HOST and REMOTE_ADDR\n        # may not qualify the remote addr:\n        # http://www.ietf.org/rfc/rfc3875\n        forward = self.transport.get_extra_info('addr', '127.0.0.1')\n        script_name = self.SCRIPT_NAME\n        server = forward\n\n        for hdr_name, hdr_value in message.headers.items(getall=True):\n            if hdr_name == 'HOST':\n                server = hdr_value\n            elif hdr_name == 'SCRIPT_NAME':\n                script_name = hdr_value\n            elif hdr_name == 'CONTENT-TYPE':\n                environ['CONTENT_TYPE'] = hdr_value\n                continue\n            elif hdr_name == 'CONTENT-LENGTH':\n                environ['CONTENT_LENGTH'] = hdr_value\n                continue\n\n            key = 'HTTP_%s' % hdr_name.replace('-', '_')\n            if key in environ:\n                hdr_value = '%s,%s' % (environ[key], hdr_value)\n\n            environ[key] = hdr_value\n\n        if isinstance(forward, str):\n            # we only took the last one\n            # http://en.wikipedia.org/wiki/X-Forwarded-For\n            if ',' in forward:\n                forward = forward.rsplit(',', 1)[-1].strip()\n\n            # find host and port on ipv6 address\n            if '[' in forward and ']' in forward:\n                host = forward.split(']')[0][1:].lower()\n            elif ':' in forward and forward.count(':') == 1:\n                host = forward.split(':')[0].lower()\n            else:\n                host = forward\n\n            forward = forward.split(']')[-1]\n            if ':' in forward and forward.count(':') == 1:\n                port = forward.split(':', 1)[1]\n            else:\n                port = 80\n\n            remote = (host, port)\n        else:\n            remote = forward\n\n        environ['REMOTE_ADDR'] = remote[0]\n        environ['REMOTE_PORT'] = str(remote[1])\n\n        if isinstance(server, str):\n            server = server.split(':')\n            if len(server) == 1:\n                server.append('80' if url_scheme == 'http' else '443')\n\n        environ['SERVER_NAME'] = server[0]\n        environ['SERVER_PORT'] = str(server[1])\n\n        path_info = uri_parts.path\n        if script_name:\n            path_info = path_info.split(script_name, 1)[-1]\n\n        environ['PATH_INFO'] = path_info\n        environ['SCRIPT_NAME'] = script_name\n\n        environ['async.reader'] = self.reader\n        environ['async.writer'] = self.writer\n\n        return environ\n\n    @asyncio.coroutine\n    def handle_request(self, message, payload):\n        \"\"\"Handle a single HTTP request\"\"\"\n        now = time.time()\n\n        if self.readpayload:\n            wsgiinput = io.BytesIO()\n            wsgiinput.write((yield from payload.read()))\n            wsgiinput.seek(0)\n            payload = wsgiinput\n\n        environ = self.create_wsgi_environ(message, payload)\n        response = self.create_wsgi_response(message)\n\n        riter = self.wsgi(environ, response.start_response)\n        if isinstance(riter, asyncio.Future) or inspect.isgenerator(riter):\n            riter = yield from riter\n\n        resp = response.response\n        try:\n            for item in riter:\n                if isinstance(item, asyncio.Future):\n                    item = yield from item\n                yield from resp.write(item)\n\n            yield from resp.write_eof()\n        finally:\n            if hasattr(riter, 'close'):\n                riter.close()\n\n        if resp.keep_alive():\n            self.keep_alive(True)\n\n        self.log_access(\n            message, environ, response.response, time.time() - now)\n\n\nclass FileWrapper:\n    \"\"\"Custom file wrapper.\"\"\"\n\n    def __init__(self, fobj, chunk_size=8192):\n        self.fobj = fobj\n        self.chunk_size = chunk_size\n        if hasattr(fobj, 'close'):\n            self.close = fobj.close\n\n    def __iter__(self):\n        return self\n\n    def __next__(self):\n        data = self.fobj.read(self.chunk_size)\n        if data:\n            return data\n        raise StopIteration\n\n\nclass WsgiResponse:\n    \"\"\"Implementation of start_response() callable as specified by PEP 3333\"\"\"\n\n    status = None\n\n    def __init__(self, writer, message):\n        self.writer = writer\n        self.message = message\n\n    def start_response(self, status, headers, exc_info=None):\n        if exc_info:\n            try:\n                if self.status:\n                    raise exc_info[1]\n            finally:\n                exc_info = None\n\n        status_code = int(status.split(' ', 1)[0])\n\n        self.status = status\n        resp = self.response = aiohttp.Response(\n            self.writer, status_code,\n            self.message.version, self.message.should_close)\n        resp.add_headers(*headers)\n\n        # send headers immediately for websocket connection\n        if status_code == 101 and resp.upgrade and resp.websocket:\n            resp.send_headers()\n        else:\n            resp._send_headers = True\n        return self.response.write\n",
            "header": {
                "file": {
                    "path": "aiohttp/wsgi.py"
                },
                "misc_line": null
            },
            "index_line": {
                "old_commit_hash": "510ba07b",
                "new_commit_hash": "e83972fd",
                "mode": "100644"
            },
            "is_binary_file": false,
            "binary_line": null,
            "minus_file": {
                "path": "a/aiohttp/wsgi.py"
            },
            "plus_file": {
                "path": "b/aiohttp/wsgi.py"
            },
            "hunks": [
                {
                    "descriptor": {
                        "old_range": {
                            "start": 14,
                            "length": 7
                        },
                        "new_range": {
                            "start": 14,
                            "length": 7
                        },
                        "section": "import io"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "import os",
                                "type": "context"
                            },
                            {
                                "content": "import sys",
                                "type": "context"
                            },
                            {
                                "content": "import time",
                                "type": "context"
                            },
                            {
                                "content": "from urllib.parse import unquote, urlsplit",
                                "type": "deleted"
                            },
                            {
                                "content": "from urllib.parse import urlsplit",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "import aiohttp",
                                "type": "context"
                            },
                            {
                                "content": "from aiohttp import server",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [],
                    "added_entities": [
                        {
                            "file_name": "aiohttp/wsgi.py",
                            "type": "statement",
                            "name": "",
                            "content": "from urllib.parse import urlsplit",
                            "ast_type_str": "ImportFrom",
                            "start_lineno": 17,
                            "end_lineno": 17,
                            "parent": null
                        }
                    ],
                    "deleted_entities": [
                        {
                            "file_name": "aiohttp/wsgi.py",
                            "type": "statement",
                            "name": "",
                            "content": "from urllib.parse import unquote, urlsplit",
                            "ast_type_str": "ImportFrom",
                            "start_lineno": 17,
                            "end_lineno": 17,
                            "parent": null
                        }
                    ]
                },
                {
                    "descriptor": {
                        "old_range": {
                            "start": 128,
                            "length": 7
                        },
                        "new_range": {
                            "start": 128,
                            "length": 7
                        },
                        "section": "class WSGIServerHttpProtocol(server.ServerHttpProtocol):"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "        if script_name:",
                                "type": "context"
                            },
                            {
                                "content": "            path_info = path_info.split(script_name, 1)[-1]",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "        environ['PATH_INFO'] = unquote(path_info)",
                                "type": "deleted"
                            },
                            {
                                "content": "        environ['PATH_INFO'] = path_info",
                                "type": "added"
                            },
                            {
                                "content": "        environ['SCRIPT_NAME'] = script_name",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "        environ['async.reader'] = self.reader",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [
                        {
                            "file_name": "aiohttp/wsgi.py",
                            "type": "method",
                            "name": "WSGIServerHttpProtocol.create_wsgi_environ",
                            "content": "class WSGIServerHttpProtocol(server.ServerHttpProtocol):\n    \"\"\"HTTP Server that implements the Python WSGI protocol.\n\n    It uses 'wsgi.async' of 'True'. 'wsgi.input' can behave differently\n    depends on 'readpayload' constructor parameter. If readpayload is set to\n    True, wsgi server reads all incoming data into BytesIO object and\n    sends it as 'wsgi.input' environ var. If readpayload is set to false\n    'wsgi.input' is a StreamReader and application should read incoming\n    data with \"yield from environ['wsgi.input'].read()\". It defaults to False.\n    \"\"\"\n\n    SCRIPT_NAME = os.environ.get('SCRIPT_NAME', '')\n\n    def __init__(self, app, readpayload=False, is_ssl=False, *args, **kw):\n        super().__init__(*args, **kw)\n\n        self.wsgi = app\n        self.is_ssl = is_ssl\n        self.readpayload = readpayload\n\n    def create_wsgi_response(self, message):\n        return WsgiResponse(self.writer, message)\n\n    def create_wsgi_environ(self, message, payload):\n        uri_parts = urlsplit(message.path)\n        url_scheme = 'https' if self.is_ssl else 'http'\n\n        environ = {\n            'wsgi.input': payload,\n            'wsgi.errors': sys.stderr,\n            'wsgi.version': (1, 0),\n            'wsgi.async': True,\n            'wsgi.multithread': False,\n            'wsgi.multiprocess': False,\n            'wsgi.run_once': False,\n            'wsgi.file_wrapper': FileWrapper,\n            'wsgi.url_scheme': url_scheme,\n            'SERVER_SOFTWARE': aiohttp.HttpMessage.SERVER_SOFTWARE,\n            'REQUEST_METHOD': message.method,\n            'QUERY_STRING': uri_parts.query or '',\n            'RAW_URI': message.path,\n            'SERVER_PROTOCOL': 'HTTP/%s.%s' % message.version\n        }\n\n        # authors should be aware that REMOTE_HOST and REMOTE_ADDR\n        # may not qualify the remote addr:\n        # http://www.ietf.org/rfc/rfc3875\n        forward = self.transport.get_extra_info('addr', '127.0.0.1')\n        script_name = self.SCRIPT_NAME\n        server = forward\n\n        for hdr_name, hdr_value in message.headers.items(getall=True):\n            if hdr_name == 'HOST':\n                server = hdr_value\n            elif hdr_name == 'SCRIPT_NAME':\n                script_name = hdr_value\n            elif hdr_name == 'CONTENT-TYPE':\n                environ['CONTENT_TYPE'] = hdr_value\n                continue\n            elif hdr_name == 'CONTENT-LENGTH':\n                environ['CONTENT_LENGTH'] = hdr_value\n                continue\n\n            key = 'HTTP_%s' % hdr_name.replace('-', '_')\n            if key in environ:\n                hdr_value = '%s,%s' % (environ[key], hdr_value)\n\n            environ[key] = hdr_value\n\n        if isinstance(forward, str):\n            # we only took the last one\n            # http://en.wikipedia.org/wiki/X-Forwarded-For\n            if ',' in forward:\n                forward = forward.rsplit(',', 1)[-1].strip()\n\n            # find host and port on ipv6 address\n            if '[' in forward and ']' in forward:\n                host = forward.split(']')[0][1:].lower()\n            elif ':' in forward and forward.count(':') == 1:\n                host = forward.split(':')[0].lower()\n            else:\n                host = forward\n\n            forward = forward.split(']')[-1]\n            if ':' in forward and forward.count(':') == 1:\n                port = forward.split(':', 1)[1]\n            else:\n                port = 80\n\n            remote = (host, port)\n        else:\n            remote = forward\n\n        environ['REMOTE_ADDR'] = remote[0]\n        environ['REMOTE_PORT'] = str(remote[1])\n\n        if isinstance(server, str):\n            server = server.split(':')\n            if len(server) == 1:\n                server.append('80' if url_scheme == 'http' else '443')\n\n        environ['SERVER_NAME'] = server[0]\n        environ['SERVER_PORT'] = str(server[1])\n\n        path_info = uri_parts.path\n        if script_name:\n            path_info = path_info.split(script_name, 1)[-1]\n\n        environ['PATH_INFO'] = unquote(path_info)\n        environ['SCRIPT_NAME'] = script_name\n\n        environ['async.reader'] = self.reader\n        environ['async.writer'] = self.writer\n\n        return environ\n\n    @asyncio.coroutine\n    def handle_request(self, message, payload):\n        \"\"\"Handle a single HTTP request\"\"\"\n        now = time.time()\n\n        if self.readpayload:\n            wsgiinput = io.BytesIO()\n            wsgiinput.write((yield from payload.read()))\n            wsgiinput.seek(0)\n            payload = wsgiinput\n\n        environ = self.create_wsgi_environ(message, payload)\n        response = self.create_wsgi_response(message)\n\n        riter = self.wsgi(environ, response.start_response)\n        if isinstance(riter, asyncio.Future) or inspect.isgenerator(riter):\n            riter = yield from riter\n\n        resp = response.response\n        try:\n            for item in riter:\n                if isinstance(item, asyncio.Future):\n                    item = yield from item\n                yield from resp.write(item)\n\n            yield from resp.write_eof()\n        finally:\n            if hasattr(riter, 'close'):\n                riter.close()\n\n        if resp.keep_alive():\n            self.keep_alive(True)\n\n        self.log_access(\n            message, environ, response.response, time.time() - now)",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 46,
                            "end_lineno": 137,
                            "parent": {
                                "file_name": "aiohttp/wsgi.py",
                                "type": "class",
                                "name": "WSGIServerHttpProtocol",
                                "content": "class WSGIServerHttpProtocol(server.ServerHttpProtocol):\n    \"\"\"HTTP Server that implements the Python WSGI protocol.\n\n    It uses 'wsgi.async' of 'True'. 'wsgi.input' can behave differently\n    depends on 'readpayload' constructor parameter. If readpayload is set to\n    True, wsgi server reads all incoming data into BytesIO object and\n    sends it as 'wsgi.input' environ var. If readpayload is set to false\n    'wsgi.input' is a StreamReader and application should read incoming\n    data with \"yield from environ['wsgi.input'].read()\". It defaults to False.\n    \"\"\"\n\n    SCRIPT_NAME = os.environ.get('SCRIPT_NAME', '')\n\n    def __init__(self, app, readpayload=False, is_ssl=False, *args, **kw):\n        super().__init__(*args, **kw)\n\n        self.wsgi = app\n        self.is_ssl = is_ssl\n        self.readpayload = readpayload\n\n    def create_wsgi_response(self, message):\n        return WsgiResponse(self.writer, message)\n\n    def create_wsgi_environ(self, message, payload):\n        uri_parts = urlsplit(message.path)\n        url_scheme = 'https' if self.is_ssl else 'http'\n\n        environ = {\n            'wsgi.input': payload,\n            'wsgi.errors': sys.stderr,\n            'wsgi.version': (1, 0),\n            'wsgi.async': True,\n            'wsgi.multithread': False,\n            'wsgi.multiprocess': False,\n            'wsgi.run_once': False,\n            'wsgi.file_wrapper': FileWrapper,\n            'wsgi.url_scheme': url_scheme,\n            'SERVER_SOFTWARE': aiohttp.HttpMessage.SERVER_SOFTWARE,\n            'REQUEST_METHOD': message.method,\n            'QUERY_STRING': uri_parts.query or '',\n            'RAW_URI': message.path,\n            'SERVER_PROTOCOL': 'HTTP/%s.%s' % message.version\n        }\n\n        # authors should be aware that REMOTE_HOST and REMOTE_ADDR\n        # may not qualify the remote addr:\n        # http://www.ietf.org/rfc/rfc3875\n        forward = self.transport.get_extra_info('addr', '127.0.0.1')\n        script_name = self.SCRIPT_NAME\n        server = forward\n\n        for hdr_name, hdr_value in message.headers.items(getall=True):\n            if hdr_name == 'HOST':\n                server = hdr_value\n            elif hdr_name == 'SCRIPT_NAME':\n                script_name = hdr_value\n            elif hdr_name == 'CONTENT-TYPE':\n                environ['CONTENT_TYPE'] = hdr_value\n                continue\n            elif hdr_name == 'CONTENT-LENGTH':\n                environ['CONTENT_LENGTH'] = hdr_value\n                continue\n\n            key = 'HTTP_%s' % hdr_name.replace('-', '_')\n            if key in environ:\n                hdr_value = '%s,%s' % (environ[key], hdr_value)\n\n            environ[key] = hdr_value\n\n        if isinstance(forward, str):\n            # we only took the last one\n            # http://en.wikipedia.org/wiki/X-Forwarded-For\n            if ',' in forward:\n                forward = forward.rsplit(',', 1)[-1].strip()\n\n            # find host and port on ipv6 address\n            if '[' in forward and ']' in forward:\n                host = forward.split(']')[0][1:].lower()\n            elif ':' in forward and forward.count(':') == 1:\n                host = forward.split(':')[0].lower()\n            else:\n                host = forward\n\n            forward = forward.split(']')[-1]\n            if ':' in forward and forward.count(':') == 1:\n                port = forward.split(':', 1)[1]\n            else:\n                port = 80\n\n            remote = (host, port)\n        else:\n            remote = forward\n\n        environ['REMOTE_ADDR'] = remote[0]\n        environ['REMOTE_PORT'] = str(remote[1])\n\n        if isinstance(server, str):\n            server = server.split(':')\n            if len(server) == 1:\n                server.append('80' if url_scheme == 'http' else '443')\n\n        environ['SERVER_NAME'] = server[0]\n        environ['SERVER_PORT'] = str(server[1])\n\n        path_info = uri_parts.path\n        if script_name:\n            path_info = path_info.split(script_name, 1)[-1]\n\n        environ['PATH_INFO'] = unquote(path_info)\n        environ['SCRIPT_NAME'] = script_name\n\n        environ['async.reader'] = self.reader\n        environ['async.writer'] = self.writer\n\n        return environ\n\n    @asyncio.coroutine\n    def handle_request(self, message, payload):\n        \"\"\"Handle a single HTTP request\"\"\"\n        now = time.time()\n\n        if self.readpayload:\n            wsgiinput = io.BytesIO()\n            wsgiinput.write((yield from payload.read()))\n            wsgiinput.seek(0)\n            payload = wsgiinput\n\n        environ = self.create_wsgi_environ(message, payload)\n        response = self.create_wsgi_response(message)\n\n        riter = self.wsgi(environ, response.start_response)\n        if isinstance(riter, asyncio.Future) or inspect.isgenerator(riter):\n            riter = yield from riter\n\n        resp = response.response\n        try:\n            for item in riter:\n                if isinstance(item, asyncio.Future):\n                    item = yield from item\n                yield from resp.write(item)\n\n            yield from resp.write_eof()\n        finally:\n            if hasattr(riter, 'close'):\n                riter.close()\n\n        if resp.keep_alive():\n            self.keep_alive(True)\n\n        self.log_access(\n            message, environ, response.response, time.time() - now)",
                                "ast_type_str": "ClassDef",
                                "start_lineno": 23,
                                "end_lineno": 173,
                                "parent": null
                            }
                        },
                        {
                            "file_name": "aiohttp/wsgi.py",
                            "type": "class",
                            "name": "WSGIServerHttpProtocol",
                            "content": "class WSGIServerHttpProtocol(server.ServerHttpProtocol):\n    \"\"\"HTTP Server that implements the Python WSGI protocol.\n\n    It uses 'wsgi.async' of 'True'. 'wsgi.input' can behave differently\n    depends on 'readpayload' constructor parameter. If readpayload is set to\n    True, wsgi server reads all incoming data into BytesIO object and\n    sends it as 'wsgi.input' environ var. If readpayload is set to false\n    'wsgi.input' is a StreamReader and application should read incoming\n    data with \"yield from environ['wsgi.input'].read()\". It defaults to False.\n    \"\"\"\n\n    SCRIPT_NAME = os.environ.get('SCRIPT_NAME', '')\n\n    def __init__(self, app, readpayload=False, is_ssl=False, *args, **kw):\n        super().__init__(*args, **kw)\n\n        self.wsgi = app\n        self.is_ssl = is_ssl\n        self.readpayload = readpayload\n\n    def create_wsgi_response(self, message):\n        return WsgiResponse(self.writer, message)\n\n    def create_wsgi_environ(self, message, payload):\n        uri_parts = urlsplit(message.path)\n        url_scheme = 'https' if self.is_ssl else 'http'\n\n        environ = {\n            'wsgi.input': payload,\n            'wsgi.errors': sys.stderr,\n            'wsgi.version': (1, 0),\n            'wsgi.async': True,\n            'wsgi.multithread': False,\n            'wsgi.multiprocess': False,\n            'wsgi.run_once': False,\n            'wsgi.file_wrapper': FileWrapper,\n            'wsgi.url_scheme': url_scheme,\n            'SERVER_SOFTWARE': aiohttp.HttpMessage.SERVER_SOFTWARE,\n            'REQUEST_METHOD': message.method,\n            'QUERY_STRING': uri_parts.query or '',\n            'RAW_URI': message.path,\n            'SERVER_PROTOCOL': 'HTTP/%s.%s' % message.version\n        }\n\n        # authors should be aware that REMOTE_HOST and REMOTE_ADDR\n        # may not qualify the remote addr:\n        # http://www.ietf.org/rfc/rfc3875\n        forward = self.transport.get_extra_info('addr', '127.0.0.1')\n        script_name = self.SCRIPT_NAME\n        server = forward\n\n        for hdr_name, hdr_value in message.headers.items(getall=True):\n            if hdr_name == 'HOST':\n                server = hdr_value\n            elif hdr_name == 'SCRIPT_NAME':\n                script_name = hdr_value\n            elif hdr_name == 'CONTENT-TYPE':\n                environ['CONTENT_TYPE'] = hdr_value\n                continue\n            elif hdr_name == 'CONTENT-LENGTH':\n                environ['CONTENT_LENGTH'] = hdr_value\n                continue\n\n            key = 'HTTP_%s' % hdr_name.replace('-', '_')\n            if key in environ:\n                hdr_value = '%s,%s' % (environ[key], hdr_value)\n\n            environ[key] = hdr_value\n\n        if isinstance(forward, str):\n            # we only took the last one\n            # http://en.wikipedia.org/wiki/X-Forwarded-For\n            if ',' in forward:\n                forward = forward.rsplit(',', 1)[-1].strip()\n\n            # find host and port on ipv6 address\n            if '[' in forward and ']' in forward:\n                host = forward.split(']')[0][1:].lower()\n            elif ':' in forward and forward.count(':') == 1:\n                host = forward.split(':')[0].lower()\n            else:\n                host = forward\n\n            forward = forward.split(']')[-1]\n            if ':' in forward and forward.count(':') == 1:\n                port = forward.split(':', 1)[1]\n            else:\n                port = 80\n\n            remote = (host, port)\n        else:\n            remote = forward\n\n        environ['REMOTE_ADDR'] = remote[0]\n        environ['REMOTE_PORT'] = str(remote[1])\n\n        if isinstance(server, str):\n            server = server.split(':')\n            if len(server) == 1:\n                server.append('80' if url_scheme == 'http' else '443')\n\n        environ['SERVER_NAME'] = server[0]\n        environ['SERVER_PORT'] = str(server[1])\n\n        path_info = uri_parts.path\n        if script_name:\n            path_info = path_info.split(script_name, 1)[-1]\n\n        environ['PATH_INFO'] = unquote(path_info)\n        environ['SCRIPT_NAME'] = script_name\n\n        environ['async.reader'] = self.reader\n        environ['async.writer'] = self.writer\n\n        return environ\n\n    @asyncio.coroutine\n    def handle_request(self, message, payload):\n        \"\"\"Handle a single HTTP request\"\"\"\n        now = time.time()\n\n        if self.readpayload:\n            wsgiinput = io.BytesIO()\n            wsgiinput.write((yield from payload.read()))\n            wsgiinput.seek(0)\n            payload = wsgiinput\n\n        environ = self.create_wsgi_environ(message, payload)\n        response = self.create_wsgi_response(message)\n\n        riter = self.wsgi(environ, response.start_response)\n        if isinstance(riter, asyncio.Future) or inspect.isgenerator(riter):\n            riter = yield from riter\n\n        resp = response.response\n        try:\n            for item in riter:\n                if isinstance(item, asyncio.Future):\n                    item = yield from item\n                yield from resp.write(item)\n\n            yield from resp.write_eof()\n        finally:\n            if hasattr(riter, 'close'):\n                riter.close()\n\n        if resp.keep_alive():\n            self.keep_alive(True)\n\n        self.log_access(\n            message, environ, response.response, time.time() - now)",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 23,
                            "end_lineno": 173,
                            "parent": null
                        }
                    ],
                    "added_entities": [],
                    "deleted_entities": []
                }
            ]
        },
        {
            "old_file_content": "\"\"\"Tests for http/wsgi.py\"\"\"\n\nimport io\nimport asyncio\nimport unittest\nimport unittest.mock\n\nimport aiohttp\nfrom aiohttp import multidict\nfrom aiohttp import wsgi\nfrom aiohttp import protocol\n\n\nclass HttpWsgiServerProtocolTests(unittest.TestCase):\n\n    def setUp(self):\n        self.loop = asyncio.new_event_loop()\n        asyncio.set_event_loop(None)\n\n        self.wsgi = unittest.mock.Mock()\n        self.reader = unittest.mock.Mock()\n        self.writer = unittest.mock.Mock()\n        self.writer.drain.return_value = ()\n        self.transport = unittest.mock.Mock()\n        self.transport.get_extra_info.return_value = '127.0.0.1'\n\n        self.headers = multidict.MutableMultiDict()\n        self.message = protocol.RawRequestMessage(\n            'GET', '/path', (1, 0), self.headers, True, 'deflate')\n        self.payload = aiohttp.FlowControlDataQueue(self.reader)\n        self.payload.feed_data(b'data')\n        self.payload.feed_data(b'data')\n        self.payload.feed_eof()\n\n    def tearDown(self):\n        self.loop.close()\n\n    def test_ctor(self):\n        srv = wsgi.WSGIServerHttpProtocol(self.wsgi, loop=self.loop)\n        self.assertIs(srv.wsgi, self.wsgi)\n        self.assertFalse(srv.readpayload)\n\n    def _make_one(self, **kw):\n        srv = wsgi.WSGIServerHttpProtocol(self.wsgi, loop=self.loop, **kw)\n        srv.reader = self.reader\n        srv.writer = self.writer\n        srv.transport = self.transport\n        return srv.create_wsgi_environ(self.message, self.payload)\n\n    def _make_srv(self, app=None, **kw):\n        if app is None:\n            app = self.wsgi\n        srv = wsgi.WSGIServerHttpProtocol(app, loop=self.loop, **kw)\n        srv.reader = self.reader\n        srv.writer = self.writer\n        srv.transport = self.transport\n        return srv\n\n    def test_environ(self):\n        environ = self._make_one()\n        self.assertEqual(environ['RAW_URI'], '/path')\n        self.assertEqual(environ['wsgi.async'], True)\n\n    def test_environ_headers(self):\n        self.headers.extend(\n            (('HOST', 'python.org'),\n             ('SCRIPT_NAME', 'script'),\n             ('CONTENT-TYPE', 'text/plain'),\n             ('CONTENT-LENGTH', '209'),\n             ('X_TEST', '123'),\n             ('X_TEST', '456')))\n        environ = self._make_one(is_ssl=True)\n        self.assertEqual(environ['CONTENT_TYPE'], 'text/plain')\n        self.assertEqual(environ['CONTENT_LENGTH'], '209')\n        self.assertEqual(environ['HTTP_X_TEST'], '123,456')\n        self.assertEqual(environ['SCRIPT_NAME'], 'script')\n        self.assertEqual(environ['SERVER_NAME'], 'python.org')\n        self.assertEqual(environ['SERVER_PORT'], '443')\n\n    def test_environ_host_header(self):\n        self.headers.add('HOST', 'python.org')\n        environ = self._make_one()\n\n        self.assertEqual(environ['HTTP_HOST'], 'python.org')\n        self.assertEqual(environ['SERVER_NAME'], 'python.org')\n        self.assertEqual(environ['SERVER_PORT'], '80')\n        self.assertEqual(environ['SERVER_PROTOCOL'], 'HTTP/1.0')\n\n    def test_environ_host_port_header(self):\n        self.message = protocol.RawRequestMessage(\n            'GET', '/path', (1, 1), self.headers, True, 'deflate')\n        self.headers.add('HOST', 'python.org:443')\n        environ = self._make_one()\n\n        self.assertEqual(environ['HTTP_HOST'], 'python.org:443')\n        self.assertEqual(environ['SERVER_NAME'], 'python.org')\n        self.assertEqual(environ['SERVER_PORT'], '443')\n        self.assertEqual(environ['SERVER_PROTOCOL'], 'HTTP/1.1')\n\n    def test_environ_forward(self):\n        self.transport.get_extra_info.return_value = 'localhost,127.0.0.1'\n        environ = self._make_one()\n\n        self.assertEqual(environ['REMOTE_ADDR'], '127.0.0.1')\n        self.assertEqual(environ['REMOTE_PORT'], '80')\n\n        self.transport.get_extra_info.return_value = 'localhost,127.0.0.1:443'\n        environ = self._make_one()\n\n        self.assertEqual(environ['REMOTE_ADDR'], '127.0.0.1')\n        self.assertEqual(environ['REMOTE_PORT'], '443')\n\n        self.transport.get_extra_info.return_value = ('127.0.0.1', 443)\n        environ = self._make_one()\n\n        self.assertEqual(environ['REMOTE_ADDR'], '127.0.0.1')\n        self.assertEqual(environ['REMOTE_PORT'], '443')\n\n        self.transport.get_extra_info.return_value = '[::1]'\n        environ = self._make_one()\n\n        self.assertEqual(environ['REMOTE_ADDR'], '::1')\n        self.assertEqual(environ['REMOTE_PORT'], '80')\n\n    def test_wsgi_response(self):\n        srv = self._make_srv()\n        resp = srv.create_wsgi_response(self.message)\n        self.assertIsInstance(resp, wsgi.WsgiResponse)\n\n    def test_wsgi_response_start_response(self):\n        srv = self._make_srv()\n        resp = srv.create_wsgi_response(self.message)\n        resp.start_response(\n            '200 OK', [('CONTENT-TYPE', 'text/plain')])\n        self.assertEqual(resp.status, '200 OK')\n        self.assertIsInstance(resp.response, protocol.Response)\n\n    def test_wsgi_response_start_response_exc(self):\n        srv = self._make_srv()\n        resp = srv.create_wsgi_response(self.message)\n        resp.start_response(\n            '200 OK', [('CONTENT-TYPE', 'text/plain')], ['', ValueError()])\n        self.assertEqual(resp.status, '200 OK')\n        self.assertIsInstance(resp.response, protocol.Response)\n\n    def test_wsgi_response_start_response_exc_status(self):\n        srv = self._make_srv()\n        resp = srv.create_wsgi_response(self.message)\n        resp.start_response('200 OK', [('CONTENT-TYPE', 'text/plain')])\n\n        self.assertRaises(\n            ValueError,\n            resp.start_response,\n            '500 Err', [('CONTENT-TYPE', 'text/plain')], ['', ValueError()])\n\n    @unittest.mock.patch('aiohttp.wsgi.aiohttp')\n    def test_wsgi_response_101_upgrade_to_websocket(self, m_asyncio):\n        srv = self._make_srv()\n        resp = srv.create_wsgi_response(self.message)\n        resp.start_response(\n            '101 Switching Protocols', (('UPGRADE', 'websocket'),\n                                        ('CONNECTION', 'upgrade')))\n        self.assertEqual(resp.status, '101 Switching Protocols')\n        self.assertTrue(m_asyncio.Response.return_value.send_headers.called)\n\n    def test_file_wrapper(self):\n        fobj = io.BytesIO(b'data')\n        wrapper = wsgi.FileWrapper(fobj, 2)\n        self.assertIs(wrapper, iter(wrapper))\n        self.assertTrue(hasattr(wrapper, 'close'))\n\n        self.assertEqual(next(wrapper), b'da')\n        self.assertEqual(next(wrapper), b'ta')\n        self.assertRaises(StopIteration, next, wrapper)\n\n        wrapper = wsgi.FileWrapper(b'data', 2)\n        self.assertFalse(hasattr(wrapper, 'close'))\n\n    def test_handle_request_futures(self):\n\n        def wsgi_app(env, start):\n            start('200 OK', [('Content-Type', 'text/plain')])\n            f1 = asyncio.Future(loop=self.loop)\n            f1.set_result(b'data')\n            fut = asyncio.Future(loop=self.loop)\n            fut.set_result([f1])\n            return fut\n\n        srv = self._make_srv(wsgi_app)\n        self.loop.run_until_complete(\n            srv.handle_request(self.message, self.payload))\n\n        content = b''.join(\n            [c[1][0] for c in self.writer.write.mock_calls])\n        self.assertTrue(content.startswith(b'HTTP/1.0 200 OK'))\n        self.assertTrue(content.endswith(b'data'))\n\n    def test_handle_request_simple(self):\n\n        def wsgi_app(env, start):\n            start('200 OK', [('Content-Type', 'text/plain')])\n            return [b'data']\n\n        stream = asyncio.StreamReader(loop=self.loop)\n        stream.feed_data(b'data')\n        stream.feed_eof()\n\n        self.message = protocol.RawRequestMessage(\n            'GET', '/path', (1, 1), self.headers, True, 'deflate')\n\n        srv = self._make_srv(wsgi_app, readpayload=True)\n        self.loop.run_until_complete(\n            srv.handle_request(self.message, self.payload))\n\n        content = b''.join(\n            [c[1][0] for c in self.writer.write.mock_calls])\n        self.assertTrue(content.startswith(b'HTTP/1.1 200 OK'))\n        self.assertTrue(content.endswith(b'data\\r\\n0\\r\\n\\r\\n'))\n        self.assertFalse(srv._keep_alive)\n\n    def test_handle_request_io(self):\n\n        def wsgi_app(env, start):\n            start('200 OK', [('Content-Type', 'text/plain')])\n            return io.BytesIO(b'data')\n\n        srv = self._make_srv(wsgi_app)\n\n        self.loop.run_until_complete(\n            srv.handle_request(self.message, self.payload))\n\n        content = b''.join(\n            [c[1][0] for c in self.writer.write.mock_calls])\n        self.assertTrue(content.startswith(b'HTTP/1.0 200 OK'))\n        self.assertTrue(content.endswith(b'data'))\n\n    def test_handle_request_keep_alive(self):\n\n        def wsgi_app(env, start):\n            start('200 OK', [('Content-Type', 'text/plain')])\n            return [b'data']\n\n        stream = asyncio.StreamReader(loop=self.loop)\n        stream.feed_data(b'data')\n        stream.feed_eof()\n\n        self.message = protocol.RawRequestMessage(\n            'GET', '/path', (1, 1), self.headers, False, 'deflate')\n\n        srv = self._make_srv(wsgi_app, readpayload=True)\n\n        self.loop.run_until_complete(\n            srv.handle_request(self.message, self.payload))\n\n        content = b''.join(\n            [c[1][0] for c in self.writer.write.mock_calls])\n        self.assertTrue(content.startswith(b'HTTP/1.1 200 OK'))\n        self.assertTrue(content.endswith(b'data\\r\\n0\\r\\n\\r\\n'))\n        self.assertTrue(srv._keep_alive)\n\n    def test_handle_request_readpayload(self):\n\n        def wsgi_app(env, start):\n            start('200 OK', [('Content-Type', 'text/plain')])\n            return [env['wsgi.input'].read()]\n\n        srv = self._make_srv(wsgi_app, readpayload=True)\n\n        self.loop.run_until_complete(\n            srv.handle_request(self.message, self.payload))\n\n        content = b''.join(\n            [c[1][0] for c in self.writer.write.mock_calls])\n        self.assertTrue(content.startswith(b'HTTP/1.0 200 OK'))\n        self.assertTrue(content.endswith(b'data'))\n",
            "new_file_content": "\"\"\"Tests for http/wsgi.py\"\"\"\n\nimport io\nimport asyncio\nimport unittest\nimport unittest.mock\n\nimport aiohttp\nfrom aiohttp import multidict\nfrom aiohttp import wsgi\nfrom aiohttp import protocol\n\n\nclass HttpWsgiServerProtocolTests(unittest.TestCase):\n\n    def setUp(self):\n        self.loop = asyncio.new_event_loop()\n        asyncio.set_event_loop(None)\n\n        self.wsgi = unittest.mock.Mock()\n        self.reader = unittest.mock.Mock()\n        self.writer = unittest.mock.Mock()\n        self.writer.drain.return_value = ()\n        self.transport = unittest.mock.Mock()\n        self.transport.get_extra_info.return_value = '127.0.0.1'\n\n        self.headers = multidict.MutableMultiDict()\n        self.message = protocol.RawRequestMessage(\n            'GET', '/path', (1, 0), self.headers, True, 'deflate')\n        self.payload = aiohttp.FlowControlDataQueue(self.reader)\n        self.payload.feed_data(b'data')\n        self.payload.feed_data(b'data')\n        self.payload.feed_eof()\n\n    def tearDown(self):\n        self.loop.close()\n\n    def test_ctor(self):\n        srv = wsgi.WSGIServerHttpProtocol(self.wsgi, loop=self.loop)\n        self.assertIs(srv.wsgi, self.wsgi)\n        self.assertFalse(srv.readpayload)\n\n    def _make_one(self, **kw):\n        srv = wsgi.WSGIServerHttpProtocol(self.wsgi, loop=self.loop, **kw)\n        srv.reader = self.reader\n        srv.writer = self.writer\n        srv.transport = self.transport\n        return srv.create_wsgi_environ(self.message, self.payload)\n\n    def _make_srv(self, app=None, **kw):\n        if app is None:\n            app = self.wsgi\n        srv = wsgi.WSGIServerHttpProtocol(app, loop=self.loop, **kw)\n        srv.reader = self.reader\n        srv.writer = self.writer\n        srv.transport = self.transport\n        return srv\n\n    def test_environ(self):\n        environ = self._make_one()\n        self.assertEqual(environ['RAW_URI'], '/path')\n        self.assertEqual(environ['wsgi.async'], True)\n\n    def test_environ_headers(self):\n        self.headers.extend(\n            (('HOST', 'python.org'),\n             ('SCRIPT_NAME', 'script'),\n             ('CONTENT-TYPE', 'text/plain'),\n             ('CONTENT-LENGTH', '209'),\n             ('X_TEST', '123'),\n             ('X_TEST', '456')))\n        environ = self._make_one(is_ssl=True)\n        self.assertEqual(environ['CONTENT_TYPE'], 'text/plain')\n        self.assertEqual(environ['CONTENT_LENGTH'], '209')\n        self.assertEqual(environ['HTTP_X_TEST'], '123,456')\n        self.assertEqual(environ['SCRIPT_NAME'], 'script')\n        self.assertEqual(environ['SERVER_NAME'], 'python.org')\n        self.assertEqual(environ['SERVER_PORT'], '443')\n\n    def test_environ_host_header(self):\n        self.headers.add('HOST', 'python.org')\n        environ = self._make_one()\n\n        self.assertEqual(environ['HTTP_HOST'], 'python.org')\n        self.assertEqual(environ['SERVER_NAME'], 'python.org')\n        self.assertEqual(environ['SERVER_PORT'], '80')\n        self.assertEqual(environ['SERVER_PROTOCOL'], 'HTTP/1.0')\n\n    def test_environ_host_port_header(self):\n        self.message = protocol.RawRequestMessage(\n            'GET', '/path', (1, 1), self.headers, True, 'deflate')\n        self.headers.add('HOST', 'python.org:443')\n        environ = self._make_one()\n\n        self.assertEqual(environ['HTTP_HOST'], 'python.org:443')\n        self.assertEqual(environ['SERVER_NAME'], 'python.org')\n        self.assertEqual(environ['SERVER_PORT'], '443')\n        self.assertEqual(environ['SERVER_PROTOCOL'], 'HTTP/1.1')\n\n    def test_environ_forward(self):\n        self.transport.get_extra_info.return_value = 'localhost,127.0.0.1'\n        environ = self._make_one()\n\n        self.assertEqual(environ['REMOTE_ADDR'], '127.0.0.1')\n        self.assertEqual(environ['REMOTE_PORT'], '80')\n\n        self.transport.get_extra_info.return_value = 'localhost,127.0.0.1:443'\n        environ = self._make_one()\n\n        self.assertEqual(environ['REMOTE_ADDR'], '127.0.0.1')\n        self.assertEqual(environ['REMOTE_PORT'], '443')\n\n        self.transport.get_extra_info.return_value = ('127.0.0.1', 443)\n        environ = self._make_one()\n\n        self.assertEqual(environ['REMOTE_ADDR'], '127.0.0.1')\n        self.assertEqual(environ['REMOTE_PORT'], '443')\n\n        self.transport.get_extra_info.return_value = '[::1]'\n        environ = self._make_one()\n\n        self.assertEqual(environ['REMOTE_ADDR'], '::1')\n        self.assertEqual(environ['REMOTE_PORT'], '80')\n\n    def test_wsgi_response(self):\n        srv = self._make_srv()\n        resp = srv.create_wsgi_response(self.message)\n        self.assertIsInstance(resp, wsgi.WsgiResponse)\n\n    def test_wsgi_response_start_response(self):\n        srv = self._make_srv()\n        resp = srv.create_wsgi_response(self.message)\n        resp.start_response(\n            '200 OK', [('CONTENT-TYPE', 'text/plain')])\n        self.assertEqual(resp.status, '200 OK')\n        self.assertIsInstance(resp.response, protocol.Response)\n\n    def test_wsgi_response_start_response_exc(self):\n        srv = self._make_srv()\n        resp = srv.create_wsgi_response(self.message)\n        resp.start_response(\n            '200 OK', [('CONTENT-TYPE', 'text/plain')], ['', ValueError()])\n        self.assertEqual(resp.status, '200 OK')\n        self.assertIsInstance(resp.response, protocol.Response)\n\n    def test_wsgi_response_start_response_exc_status(self):\n        srv = self._make_srv()\n        resp = srv.create_wsgi_response(self.message)\n        resp.start_response('200 OK', [('CONTENT-TYPE', 'text/plain')])\n\n        self.assertRaises(\n            ValueError,\n            resp.start_response,\n            '500 Err', [('CONTENT-TYPE', 'text/plain')], ['', ValueError()])\n\n    @unittest.mock.patch('aiohttp.wsgi.aiohttp')\n    def test_wsgi_response_101_upgrade_to_websocket(self, m_asyncio):\n        srv = self._make_srv()\n        resp = srv.create_wsgi_response(self.message)\n        resp.start_response(\n            '101 Switching Protocols', (('UPGRADE', 'websocket'),\n                                        ('CONNECTION', 'upgrade')))\n        self.assertEqual(resp.status, '101 Switching Protocols')\n        self.assertTrue(m_asyncio.Response.return_value.send_headers.called)\n\n    def test_file_wrapper(self):\n        fobj = io.BytesIO(b'data')\n        wrapper = wsgi.FileWrapper(fobj, 2)\n        self.assertIs(wrapper, iter(wrapper))\n        self.assertTrue(hasattr(wrapper, 'close'))\n\n        self.assertEqual(next(wrapper), b'da')\n        self.assertEqual(next(wrapper), b'ta')\n        self.assertRaises(StopIteration, next, wrapper)\n\n        wrapper = wsgi.FileWrapper(b'data', 2)\n        self.assertFalse(hasattr(wrapper, 'close'))\n\n    def test_handle_request_futures(self):\n\n        def wsgi_app(env, start):\n            start('200 OK', [('Content-Type', 'text/plain')])\n            f1 = asyncio.Future(loop=self.loop)\n            f1.set_result(b'data')\n            fut = asyncio.Future(loop=self.loop)\n            fut.set_result([f1])\n            return fut\n\n        srv = self._make_srv(wsgi_app)\n        self.loop.run_until_complete(\n            srv.handle_request(self.message, self.payload))\n\n        content = b''.join(\n            [c[1][0] for c in self.writer.write.mock_calls])\n        self.assertTrue(content.startswith(b'HTTP/1.0 200 OK'))\n        self.assertTrue(content.endswith(b'data'))\n\n    def test_handle_request_simple(self):\n\n        def wsgi_app(env, start):\n            start('200 OK', [('Content-Type', 'text/plain')])\n            return [b'data']\n\n        stream = asyncio.StreamReader(loop=self.loop)\n        stream.feed_data(b'data')\n        stream.feed_eof()\n\n        self.message = protocol.RawRequestMessage(\n            'GET', '/path', (1, 1), self.headers, True, 'deflate')\n\n        srv = self._make_srv(wsgi_app, readpayload=True)\n        self.loop.run_until_complete(\n            srv.handle_request(self.message, self.payload))\n\n        content = b''.join(\n            [c[1][0] for c in self.writer.write.mock_calls])\n        self.assertTrue(content.startswith(b'HTTP/1.1 200 OK'))\n        self.assertTrue(content.endswith(b'data\\r\\n0\\r\\n\\r\\n'))\n        self.assertFalse(srv._keep_alive)\n\n    def test_handle_request_io(self):\n\n        def wsgi_app(env, start):\n            start('200 OK', [('Content-Type', 'text/plain')])\n            return io.BytesIO(b'data')\n\n        srv = self._make_srv(wsgi_app)\n\n        self.loop.run_until_complete(\n            srv.handle_request(self.message, self.payload))\n\n        content = b''.join(\n            [c[1][0] for c in self.writer.write.mock_calls])\n        self.assertTrue(content.startswith(b'HTTP/1.0 200 OK'))\n        self.assertTrue(content.endswith(b'data'))\n\n    def test_handle_request_keep_alive(self):\n\n        def wsgi_app(env, start):\n            start('200 OK', [('Content-Type', 'text/plain')])\n            return [b'data']\n\n        stream = asyncio.StreamReader(loop=self.loop)\n        stream.feed_data(b'data')\n        stream.feed_eof()\n\n        self.message = protocol.RawRequestMessage(\n            'GET', '/path', (1, 1), self.headers, False, 'deflate')\n\n        srv = self._make_srv(wsgi_app, readpayload=True)\n\n        self.loop.run_until_complete(\n            srv.handle_request(self.message, self.payload))\n\n        content = b''.join(\n            [c[1][0] for c in self.writer.write.mock_calls])\n        self.assertTrue(content.startswith(b'HTTP/1.1 200 OK'))\n        self.assertTrue(content.endswith(b'data\\r\\n0\\r\\n\\r\\n'))\n        self.assertTrue(srv._keep_alive)\n\n    def test_handle_request_readpayload(self):\n\n        def wsgi_app(env, start):\n            start('200 OK', [('Content-Type', 'text/plain')])\n            return [env['wsgi.input'].read()]\n\n        srv = self._make_srv(wsgi_app, readpayload=True)\n\n        self.loop.run_until_complete(\n            srv.handle_request(self.message, self.payload))\n\n        content = b''.join(\n            [c[1][0] for c in self.writer.write.mock_calls])\n        self.assertTrue(content.startswith(b'HTTP/1.0 200 OK'))\n        self.assertTrue(content.endswith(b'data'))\n\n    def test_dont_unquote_environ_path_info(self):\n        path = '/path/some%20text'\n        print(path)\n        self.message = protocol.RawRequestMessage(\n            'GET', path, (1, 0), self.headers, True, 'deflate')\n        environ = self._make_one()\n        self.assertEqual(environ['PATH_INFO'], path)\n",
            "header": {
                "file": {
                    "path": "tests/test_wsgi.py"
                },
                "misc_line": null
            },
            "index_line": {
                "old_commit_hash": "2e083064",
                "new_commit_hash": "58a48423",
                "mode": "100644"
            },
            "is_binary_file": false,
            "binary_line": null,
            "minus_file": {
                "path": "a/tests/test_wsgi.py"
            },
            "plus_file": {
                "path": "b/tests/test_wsgi.py"
            },
            "hunks": [
                {
                    "descriptor": {
                        "old_range": {
                            "start": 273,
                            "length": 3
                        },
                        "new_range": {
                            "start": 273,
                            "length": 11
                        },
                        "section": "class HttpWsgiServerProtocolTests(unittest.TestCase):"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "            [c[1][0] for c in self.writer.write.mock_calls])",
                                "type": "context"
                            },
                            {
                                "content": "        self.assertTrue(content.startswith(b'HTTP/1.0 200 OK'))",
                                "type": "context"
                            },
                            {
                                "content": "        self.assertTrue(content.endswith(b'data'))",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "    def test_dont_unquote_environ_path_info(self):",
                                "type": "added"
                            },
                            {
                                "content": "        path = '/path/some%20text'",
                                "type": "added"
                            },
                            {
                                "content": "        print(path)",
                                "type": "added"
                            },
                            {
                                "content": "        self.message = protocol.RawRequestMessage(",
                                "type": "added"
                            },
                            {
                                "content": "            'GET', path, (1, 0), self.headers, True, 'deflate')",
                                "type": "added"
                            },
                            {
                                "content": "        environ = self._make_one()",
                                "type": "added"
                            },
                            {
                                "content": "        self.assertEqual(environ['PATH_INFO'], path)",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [
                        {
                            "file_name": "tests/test_wsgi.py",
                            "type": "class",
                            "name": "HttpWsgiServerProtocolTests",
                            "content": "class HttpWsgiServerProtocolTests(unittest.TestCase):\n\n    def setUp(self):\n        self.loop = asyncio.new_event_loop()\n        asyncio.set_event_loop(None)\n\n        self.wsgi = unittest.mock.Mock()\n        self.reader = unittest.mock.Mock()\n        self.writer = unittest.mock.Mock()\n        self.writer.drain.return_value = ()\n        self.transport = unittest.mock.Mock()\n        self.transport.get_extra_info.return_value = '127.0.0.1'\n\n        self.headers = multidict.MutableMultiDict()\n        self.message = protocol.RawRequestMessage(\n            'GET', '/path', (1, 0), self.headers, True, 'deflate')\n        self.payload = aiohttp.FlowControlDataQueue(self.reader)\n        self.payload.feed_data(b'data')\n        self.payload.feed_data(b'data')\n        self.payload.feed_eof()\n\n    def tearDown(self):\n        self.loop.close()\n\n    def test_ctor(self):\n        srv = wsgi.WSGIServerHttpProtocol(self.wsgi, loop=self.loop)\n        self.assertIs(srv.wsgi, self.wsgi)\n        self.assertFalse(srv.readpayload)\n\n    def _make_one(self, **kw):\n        srv = wsgi.WSGIServerHttpProtocol(self.wsgi, loop=self.loop, **kw)\n        srv.reader = self.reader\n        srv.writer = self.writer\n        srv.transport = self.transport\n        return srv.create_wsgi_environ(self.message, self.payload)\n\n    def _make_srv(self, app=None, **kw):\n        if app is None:\n            app = self.wsgi\n        srv = wsgi.WSGIServerHttpProtocol(app, loop=self.loop, **kw)\n        srv.reader = self.reader\n        srv.writer = self.writer\n        srv.transport = self.transport\n        return srv\n\n    def test_environ(self):\n        environ = self._make_one()\n        self.assertEqual(environ['RAW_URI'], '/path')\n        self.assertEqual(environ['wsgi.async'], True)\n\n    def test_environ_headers(self):\n        self.headers.extend(\n            (('HOST', 'python.org'),\n             ('SCRIPT_NAME', 'script'),\n             ('CONTENT-TYPE', 'text/plain'),\n             ('CONTENT-LENGTH', '209'),\n             ('X_TEST', '123'),\n             ('X_TEST', '456')))\n        environ = self._make_one(is_ssl=True)\n        self.assertEqual(environ['CONTENT_TYPE'], 'text/plain')\n        self.assertEqual(environ['CONTENT_LENGTH'], '209')\n        self.assertEqual(environ['HTTP_X_TEST'], '123,456')\n        self.assertEqual(environ['SCRIPT_NAME'], 'script')\n        self.assertEqual(environ['SERVER_NAME'], 'python.org')\n        self.assertEqual(environ['SERVER_PORT'], '443')\n\n    def test_environ_host_header(self):\n        self.headers.add('HOST', 'python.org')\n        environ = self._make_one()\n\n        self.assertEqual(environ['HTTP_HOST'], 'python.org')\n        self.assertEqual(environ['SERVER_NAME'], 'python.org')\n        self.assertEqual(environ['SERVER_PORT'], '80')\n        self.assertEqual(environ['SERVER_PROTOCOL'], 'HTTP/1.0')\n\n    def test_environ_host_port_header(self):\n        self.message = protocol.RawRequestMessage(\n            'GET', '/path', (1, 1), self.headers, True, 'deflate')\n        self.headers.add('HOST', 'python.org:443')\n        environ = self._make_one()\n\n        self.assertEqual(environ['HTTP_HOST'], 'python.org:443')\n        self.assertEqual(environ['SERVER_NAME'], 'python.org')\n        self.assertEqual(environ['SERVER_PORT'], '443')\n        self.assertEqual(environ['SERVER_PROTOCOL'], 'HTTP/1.1')\n\n    def test_environ_forward(self):\n        self.transport.get_extra_info.return_value = 'localhost,127.0.0.1'\n        environ = self._make_one()\n\n        self.assertEqual(environ['REMOTE_ADDR'], '127.0.0.1')\n        self.assertEqual(environ['REMOTE_PORT'], '80')\n\n        self.transport.get_extra_info.return_value = 'localhost,127.0.0.1:443'\n        environ = self._make_one()\n\n        self.assertEqual(environ['REMOTE_ADDR'], '127.0.0.1')\n        self.assertEqual(environ['REMOTE_PORT'], '443')\n\n        self.transport.get_extra_info.return_value = ('127.0.0.1', 443)\n        environ = self._make_one()\n\n        self.assertEqual(environ['REMOTE_ADDR'], '127.0.0.1')\n        self.assertEqual(environ['REMOTE_PORT'], '443')\n\n        self.transport.get_extra_info.return_value = '[::1]'\n        environ = self._make_one()\n\n        self.assertEqual(environ['REMOTE_ADDR'], '::1')\n        self.assertEqual(environ['REMOTE_PORT'], '80')\n\n    def test_wsgi_response(self):\n        srv = self._make_srv()\n        resp = srv.create_wsgi_response(self.message)\n        self.assertIsInstance(resp, wsgi.WsgiResponse)\n\n    def test_wsgi_response_start_response(self):\n        srv = self._make_srv()\n        resp = srv.create_wsgi_response(self.message)\n        resp.start_response(\n            '200 OK', [('CONTENT-TYPE', 'text/plain')])\n        self.assertEqual(resp.status, '200 OK')\n        self.assertIsInstance(resp.response, protocol.Response)\n\n    def test_wsgi_response_start_response_exc(self):\n        srv = self._make_srv()\n        resp = srv.create_wsgi_response(self.message)\n        resp.start_response(\n            '200 OK', [('CONTENT-TYPE', 'text/plain')], ['', ValueError()])\n        self.assertEqual(resp.status, '200 OK')\n        self.assertIsInstance(resp.response, protocol.Response)\n\n    def test_wsgi_response_start_response_exc_status(self):\n        srv = self._make_srv()\n        resp = srv.create_wsgi_response(self.message)\n        resp.start_response('200 OK', [('CONTENT-TYPE', 'text/plain')])\n\n        self.assertRaises(\n            ValueError,\n            resp.start_response,\n            '500 Err', [('CONTENT-TYPE', 'text/plain')], ['', ValueError()])\n\n    @unittest.mock.patch('aiohttp.wsgi.aiohttp')\n    def test_wsgi_response_101_upgrade_to_websocket(self, m_asyncio):\n        srv = self._make_srv()\n        resp = srv.create_wsgi_response(self.message)\n        resp.start_response(\n            '101 Switching Protocols', (('UPGRADE', 'websocket'),\n                                        ('CONNECTION', 'upgrade')))\n        self.assertEqual(resp.status, '101 Switching Protocols')\n        self.assertTrue(m_asyncio.Response.return_value.send_headers.called)\n\n    def test_file_wrapper(self):\n        fobj = io.BytesIO(b'data')\n        wrapper = wsgi.FileWrapper(fobj, 2)\n        self.assertIs(wrapper, iter(wrapper))\n        self.assertTrue(hasattr(wrapper, 'close'))\n\n        self.assertEqual(next(wrapper), b'da')\n        self.assertEqual(next(wrapper), b'ta')\n        self.assertRaises(StopIteration, next, wrapper)\n\n        wrapper = wsgi.FileWrapper(b'data', 2)\n        self.assertFalse(hasattr(wrapper, 'close'))\n\n    def test_handle_request_futures(self):\n\n        def wsgi_app(env, start):\n            start('200 OK', [('Content-Type', 'text/plain')])\n            f1 = asyncio.Future(loop=self.loop)\n            f1.set_result(b'data')\n            fut = asyncio.Future(loop=self.loop)\n            fut.set_result([f1])\n            return fut\n\n        srv = self._make_srv(wsgi_app)\n        self.loop.run_until_complete(\n            srv.handle_request(self.message, self.payload))\n\n        content = b''.join(\n            [c[1][0] for c in self.writer.write.mock_calls])\n        self.assertTrue(content.startswith(b'HTTP/1.0 200 OK'))\n        self.assertTrue(content.endswith(b'data'))\n\n    def test_handle_request_simple(self):\n\n        def wsgi_app(env, start):\n            start('200 OK', [('Content-Type', 'text/plain')])\n            return [b'data']\n\n        stream = asyncio.StreamReader(loop=self.loop)\n        stream.feed_data(b'data')\n        stream.feed_eof()\n\n        self.message = protocol.RawRequestMessage(\n            'GET', '/path', (1, 1), self.headers, True, 'deflate')\n\n        srv = self._make_srv(wsgi_app, readpayload=True)\n        self.loop.run_until_complete(\n            srv.handle_request(self.message, self.payload))\n\n        content = b''.join(\n            [c[1][0] for c in self.writer.write.mock_calls])\n        self.assertTrue(content.startswith(b'HTTP/1.1 200 OK'))\n        self.assertTrue(content.endswith(b'data\\r\\n0\\r\\n\\r\\n'))\n        self.assertFalse(srv._keep_alive)\n\n    def test_handle_request_io(self):\n\n        def wsgi_app(env, start):\n            start('200 OK', [('Content-Type', 'text/plain')])\n            return io.BytesIO(b'data')\n\n        srv = self._make_srv(wsgi_app)\n\n        self.loop.run_until_complete(\n            srv.handle_request(self.message, self.payload))\n\n        content = b''.join(\n            [c[1][0] for c in self.writer.write.mock_calls])\n        self.assertTrue(content.startswith(b'HTTP/1.0 200 OK'))\n        self.assertTrue(content.endswith(b'data'))\n\n    def test_handle_request_keep_alive(self):\n\n        def wsgi_app(env, start):\n            start('200 OK', [('Content-Type', 'text/plain')])\n            return [b'data']\n\n        stream = asyncio.StreamReader(loop=self.loop)\n        stream.feed_data(b'data')\n        stream.feed_eof()\n\n        self.message = protocol.RawRequestMessage(\n            'GET', '/path', (1, 1), self.headers, False, 'deflate')\n\n        srv = self._make_srv(wsgi_app, readpayload=True)\n\n        self.loop.run_until_complete(\n            srv.handle_request(self.message, self.payload))\n\n        content = b''.join(\n            [c[1][0] for c in self.writer.write.mock_calls])\n        self.assertTrue(content.startswith(b'HTTP/1.1 200 OK'))\n        self.assertTrue(content.endswith(b'data\\r\\n0\\r\\n\\r\\n'))\n        self.assertTrue(srv._keep_alive)\n\n    def test_handle_request_readpayload(self):\n\n        def wsgi_app(env, start):\n            start('200 OK', [('Content-Type', 'text/plain')])\n            return [env['wsgi.input'].read()]\n\n        srv = self._make_srv(wsgi_app, readpayload=True)\n\n        self.loop.run_until_complete(\n            srv.handle_request(self.message, self.payload))\n\n        content = b''.join(\n            [c[1][0] for c in self.writer.write.mock_calls])\n        self.assertTrue(content.startswith(b'HTTP/1.0 200 OK'))\n        self.assertTrue(content.endswith(b'data'))\n\n    def test_dont_unquote_environ_path_info(self):\n        path = '/path/some%20text'\n        print(path)\n        self.message = protocol.RawRequestMessage(\n            'GET', path, (1, 0), self.headers, True, 'deflate')\n        environ = self._make_one()\n        self.assertEqual(environ['PATH_INFO'], path)",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 14,
                            "end_lineno": 283,
                            "parent": null
                        }
                    ],
                    "added_entities": [
                        {
                            "file_name": "tests/test_wsgi.py",
                            "type": "method",
                            "name": "HttpWsgiServerProtocolTests.test_dont_unquote_environ_path_info",
                            "content": "class HttpWsgiServerProtocolTests(unittest.TestCase):\n\n    def setUp(self):\n        self.loop = asyncio.new_event_loop()\n        asyncio.set_event_loop(None)\n\n        self.wsgi = unittest.mock.Mock()\n        self.reader = unittest.mock.Mock()\n        self.writer = unittest.mock.Mock()\n        self.writer.drain.return_value = ()\n        self.transport = unittest.mock.Mock()\n        self.transport.get_extra_info.return_value = '127.0.0.1'\n\n        self.headers = multidict.MutableMultiDict()\n        self.message = protocol.RawRequestMessage(\n            'GET', '/path', (1, 0), self.headers, True, 'deflate')\n        self.payload = aiohttp.FlowControlDataQueue(self.reader)\n        self.payload.feed_data(b'data')\n        self.payload.feed_data(b'data')\n        self.payload.feed_eof()\n\n    def tearDown(self):\n        self.loop.close()\n\n    def test_ctor(self):\n        srv = wsgi.WSGIServerHttpProtocol(self.wsgi, loop=self.loop)\n        self.assertIs(srv.wsgi, self.wsgi)\n        self.assertFalse(srv.readpayload)\n\n    def _make_one(self, **kw):\n        srv = wsgi.WSGIServerHttpProtocol(self.wsgi, loop=self.loop, **kw)\n        srv.reader = self.reader\n        srv.writer = self.writer\n        srv.transport = self.transport\n        return srv.create_wsgi_environ(self.message, self.payload)\n\n    def _make_srv(self, app=None, **kw):\n        if app is None:\n            app = self.wsgi\n        srv = wsgi.WSGIServerHttpProtocol(app, loop=self.loop, **kw)\n        srv.reader = self.reader\n        srv.writer = self.writer\n        srv.transport = self.transport\n        return srv\n\n    def test_environ(self):\n        environ = self._make_one()\n        self.assertEqual(environ['RAW_URI'], '/path')\n        self.assertEqual(environ['wsgi.async'], True)\n\n    def test_environ_headers(self):\n        self.headers.extend(\n            (('HOST', 'python.org'),\n             ('SCRIPT_NAME', 'script'),\n             ('CONTENT-TYPE', 'text/plain'),\n             ('CONTENT-LENGTH', '209'),\n             ('X_TEST', '123'),\n             ('X_TEST', '456')))\n        environ = self._make_one(is_ssl=True)\n        self.assertEqual(environ['CONTENT_TYPE'], 'text/plain')\n        self.assertEqual(environ['CONTENT_LENGTH'], '209')\n        self.assertEqual(environ['HTTP_X_TEST'], '123,456')\n        self.assertEqual(environ['SCRIPT_NAME'], 'script')\n        self.assertEqual(environ['SERVER_NAME'], 'python.org')\n        self.assertEqual(environ['SERVER_PORT'], '443')\n\n    def test_environ_host_header(self):\n        self.headers.add('HOST', 'python.org')\n        environ = self._make_one()\n\n        self.assertEqual(environ['HTTP_HOST'], 'python.org')\n        self.assertEqual(environ['SERVER_NAME'], 'python.org')\n        self.assertEqual(environ['SERVER_PORT'], '80')\n        self.assertEqual(environ['SERVER_PROTOCOL'], 'HTTP/1.0')\n\n    def test_environ_host_port_header(self):\n        self.message = protocol.RawRequestMessage(\n            'GET', '/path', (1, 1), self.headers, True, 'deflate')\n        self.headers.add('HOST', 'python.org:443')\n        environ = self._make_one()\n\n        self.assertEqual(environ['HTTP_HOST'], 'python.org:443')\n        self.assertEqual(environ['SERVER_NAME'], 'python.org')\n        self.assertEqual(environ['SERVER_PORT'], '443')\n        self.assertEqual(environ['SERVER_PROTOCOL'], 'HTTP/1.1')\n\n    def test_environ_forward(self):\n        self.transport.get_extra_info.return_value = 'localhost,127.0.0.1'\n        environ = self._make_one()\n\n        self.assertEqual(environ['REMOTE_ADDR'], '127.0.0.1')\n        self.assertEqual(environ['REMOTE_PORT'], '80')\n\n        self.transport.get_extra_info.return_value = 'localhost,127.0.0.1:443'\n        environ = self._make_one()\n\n        self.assertEqual(environ['REMOTE_ADDR'], '127.0.0.1')\n        self.assertEqual(environ['REMOTE_PORT'], '443')\n\n        self.transport.get_extra_info.return_value = ('127.0.0.1', 443)\n        environ = self._make_one()\n\n        self.assertEqual(environ['REMOTE_ADDR'], '127.0.0.1')\n        self.assertEqual(environ['REMOTE_PORT'], '443')\n\n        self.transport.get_extra_info.return_value = '[::1]'\n        environ = self._make_one()\n\n        self.assertEqual(environ['REMOTE_ADDR'], '::1')\n        self.assertEqual(environ['REMOTE_PORT'], '80')\n\n    def test_wsgi_response(self):\n        srv = self._make_srv()\n        resp = srv.create_wsgi_response(self.message)\n        self.assertIsInstance(resp, wsgi.WsgiResponse)\n\n    def test_wsgi_response_start_response(self):\n        srv = self._make_srv()\n        resp = srv.create_wsgi_response(self.message)\n        resp.start_response(\n            '200 OK', [('CONTENT-TYPE', 'text/plain')])\n        self.assertEqual(resp.status, '200 OK')\n        self.assertIsInstance(resp.response, protocol.Response)\n\n    def test_wsgi_response_start_response_exc(self):\n        srv = self._make_srv()\n        resp = srv.create_wsgi_response(self.message)\n        resp.start_response(\n            '200 OK', [('CONTENT-TYPE', 'text/plain')], ['', ValueError()])\n        self.assertEqual(resp.status, '200 OK')\n        self.assertIsInstance(resp.response, protocol.Response)\n\n    def test_wsgi_response_start_response_exc_status(self):\n        srv = self._make_srv()\n        resp = srv.create_wsgi_response(self.message)\n        resp.start_response('200 OK', [('CONTENT-TYPE', 'text/plain')])\n\n        self.assertRaises(\n            ValueError,\n            resp.start_response,\n            '500 Err', [('CONTENT-TYPE', 'text/plain')], ['', ValueError()])\n\n    @unittest.mock.patch('aiohttp.wsgi.aiohttp')\n    def test_wsgi_response_101_upgrade_to_websocket(self, m_asyncio):\n        srv = self._make_srv()\n        resp = srv.create_wsgi_response(self.message)\n        resp.start_response(\n            '101 Switching Protocols', (('UPGRADE', 'websocket'),\n                                        ('CONNECTION', 'upgrade')))\n        self.assertEqual(resp.status, '101 Switching Protocols')\n        self.assertTrue(m_asyncio.Response.return_value.send_headers.called)\n\n    def test_file_wrapper(self):\n        fobj = io.BytesIO(b'data')\n        wrapper = wsgi.FileWrapper(fobj, 2)\n        self.assertIs(wrapper, iter(wrapper))\n        self.assertTrue(hasattr(wrapper, 'close'))\n\n        self.assertEqual(next(wrapper), b'da')\n        self.assertEqual(next(wrapper), b'ta')\n        self.assertRaises(StopIteration, next, wrapper)\n\n        wrapper = wsgi.FileWrapper(b'data', 2)\n        self.assertFalse(hasattr(wrapper, 'close'))\n\n    def test_handle_request_futures(self):\n\n        def wsgi_app(env, start):\n            start('200 OK', [('Content-Type', 'text/plain')])\n            f1 = asyncio.Future(loop=self.loop)\n            f1.set_result(b'data')\n            fut = asyncio.Future(loop=self.loop)\n            fut.set_result([f1])\n            return fut\n\n        srv = self._make_srv(wsgi_app)\n        self.loop.run_until_complete(\n            srv.handle_request(self.message, self.payload))\n\n        content = b''.join(\n            [c[1][0] for c in self.writer.write.mock_calls])\n        self.assertTrue(content.startswith(b'HTTP/1.0 200 OK'))\n        self.assertTrue(content.endswith(b'data'))\n\n    def test_handle_request_simple(self):\n\n        def wsgi_app(env, start):\n            start('200 OK', [('Content-Type', 'text/plain')])\n            return [b'data']\n\n        stream = asyncio.StreamReader(loop=self.loop)\n        stream.feed_data(b'data')\n        stream.feed_eof()\n\n        self.message = protocol.RawRequestMessage(\n            'GET', '/path', (1, 1), self.headers, True, 'deflate')\n\n        srv = self._make_srv(wsgi_app, readpayload=True)\n        self.loop.run_until_complete(\n            srv.handle_request(self.message, self.payload))\n\n        content = b''.join(\n            [c[1][0] for c in self.writer.write.mock_calls])\n        self.assertTrue(content.startswith(b'HTTP/1.1 200 OK'))\n        self.assertTrue(content.endswith(b'data\\r\\n0\\r\\n\\r\\n'))\n        self.assertFalse(srv._keep_alive)\n\n    def test_handle_request_io(self):\n\n        def wsgi_app(env, start):\n            start('200 OK', [('Content-Type', 'text/plain')])\n            return io.BytesIO(b'data')\n\n        srv = self._make_srv(wsgi_app)\n\n        self.loop.run_until_complete(\n            srv.handle_request(self.message, self.payload))\n\n        content = b''.join(\n            [c[1][0] for c in self.writer.write.mock_calls])\n        self.assertTrue(content.startswith(b'HTTP/1.0 200 OK'))\n        self.assertTrue(content.endswith(b'data'))\n\n    def test_handle_request_keep_alive(self):\n\n        def wsgi_app(env, start):\n            start('200 OK', [('Content-Type', 'text/plain')])\n            return [b'data']\n\n        stream = asyncio.StreamReader(loop=self.loop)\n        stream.feed_data(b'data')\n        stream.feed_eof()\n\n        self.message = protocol.RawRequestMessage(\n            'GET', '/path', (1, 1), self.headers, False, 'deflate')\n\n        srv = self._make_srv(wsgi_app, readpayload=True)\n\n        self.loop.run_until_complete(\n            srv.handle_request(self.message, self.payload))\n\n        content = b''.join(\n            [c[1][0] for c in self.writer.write.mock_calls])\n        self.assertTrue(content.startswith(b'HTTP/1.1 200 OK'))\n        self.assertTrue(content.endswith(b'data\\r\\n0\\r\\n\\r\\n'))\n        self.assertTrue(srv._keep_alive)\n\n    def test_handle_request_readpayload(self):\n\n        def wsgi_app(env, start):\n            start('200 OK', [('Content-Type', 'text/plain')])\n            return [env['wsgi.input'].read()]\n\n        srv = self._make_srv(wsgi_app, readpayload=True)\n\n        self.loop.run_until_complete(\n            srv.handle_request(self.message, self.payload))\n\n        content = b''.join(\n            [c[1][0] for c in self.writer.write.mock_calls])\n        self.assertTrue(content.startswith(b'HTTP/1.0 200 OK'))\n        self.assertTrue(content.endswith(b'data'))\n\n    def test_dont_unquote_environ_path_info(self):\n        path = '/path/some%20text'\n        print(path)\n        self.message = protocol.RawRequestMessage(\n            'GET', path, (1, 0), self.headers, True, 'deflate')\n        environ = self._make_one()\n        self.assertEqual(environ['PATH_INFO'], path)",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 277,
                            "end_lineno": 283,
                            "parent": {
                                "file_name": "tests/test_wsgi.py",
                                "type": "class",
                                "name": "HttpWsgiServerProtocolTests",
                                "content": "class HttpWsgiServerProtocolTests(unittest.TestCase):\n\n    def setUp(self):\n        self.loop = asyncio.new_event_loop()\n        asyncio.set_event_loop(None)\n\n        self.wsgi = unittest.mock.Mock()\n        self.reader = unittest.mock.Mock()\n        self.writer = unittest.mock.Mock()\n        self.writer.drain.return_value = ()\n        self.transport = unittest.mock.Mock()\n        self.transport.get_extra_info.return_value = '127.0.0.1'\n\n        self.headers = multidict.MutableMultiDict()\n        self.message = protocol.RawRequestMessage(\n            'GET', '/path', (1, 0), self.headers, True, 'deflate')\n        self.payload = aiohttp.FlowControlDataQueue(self.reader)\n        self.payload.feed_data(b'data')\n        self.payload.feed_data(b'data')\n        self.payload.feed_eof()\n\n    def tearDown(self):\n        self.loop.close()\n\n    def test_ctor(self):\n        srv = wsgi.WSGIServerHttpProtocol(self.wsgi, loop=self.loop)\n        self.assertIs(srv.wsgi, self.wsgi)\n        self.assertFalse(srv.readpayload)\n\n    def _make_one(self, **kw):\n        srv = wsgi.WSGIServerHttpProtocol(self.wsgi, loop=self.loop, **kw)\n        srv.reader = self.reader\n        srv.writer = self.writer\n        srv.transport = self.transport\n        return srv.create_wsgi_environ(self.message, self.payload)\n\n    def _make_srv(self, app=None, **kw):\n        if app is None:\n            app = self.wsgi\n        srv = wsgi.WSGIServerHttpProtocol(app, loop=self.loop, **kw)\n        srv.reader = self.reader\n        srv.writer = self.writer\n        srv.transport = self.transport\n        return srv\n\n    def test_environ(self):\n        environ = self._make_one()\n        self.assertEqual(environ['RAW_URI'], '/path')\n        self.assertEqual(environ['wsgi.async'], True)\n\n    def test_environ_headers(self):\n        self.headers.extend(\n            (('HOST', 'python.org'),\n             ('SCRIPT_NAME', 'script'),\n             ('CONTENT-TYPE', 'text/plain'),\n             ('CONTENT-LENGTH', '209'),\n             ('X_TEST', '123'),\n             ('X_TEST', '456')))\n        environ = self._make_one(is_ssl=True)\n        self.assertEqual(environ['CONTENT_TYPE'], 'text/plain')\n        self.assertEqual(environ['CONTENT_LENGTH'], '209')\n        self.assertEqual(environ['HTTP_X_TEST'], '123,456')\n        self.assertEqual(environ['SCRIPT_NAME'], 'script')\n        self.assertEqual(environ['SERVER_NAME'], 'python.org')\n        self.assertEqual(environ['SERVER_PORT'], '443')\n\n    def test_environ_host_header(self):\n        self.headers.add('HOST', 'python.org')\n        environ = self._make_one()\n\n        self.assertEqual(environ['HTTP_HOST'], 'python.org')\n        self.assertEqual(environ['SERVER_NAME'], 'python.org')\n        self.assertEqual(environ['SERVER_PORT'], '80')\n        self.assertEqual(environ['SERVER_PROTOCOL'], 'HTTP/1.0')\n\n    def test_environ_host_port_header(self):\n        self.message = protocol.RawRequestMessage(\n            'GET', '/path', (1, 1), self.headers, True, 'deflate')\n        self.headers.add('HOST', 'python.org:443')\n        environ = self._make_one()\n\n        self.assertEqual(environ['HTTP_HOST'], 'python.org:443')\n        self.assertEqual(environ['SERVER_NAME'], 'python.org')\n        self.assertEqual(environ['SERVER_PORT'], '443')\n        self.assertEqual(environ['SERVER_PROTOCOL'], 'HTTP/1.1')\n\n    def test_environ_forward(self):\n        self.transport.get_extra_info.return_value = 'localhost,127.0.0.1'\n        environ = self._make_one()\n\n        self.assertEqual(environ['REMOTE_ADDR'], '127.0.0.1')\n        self.assertEqual(environ['REMOTE_PORT'], '80')\n\n        self.transport.get_extra_info.return_value = 'localhost,127.0.0.1:443'\n        environ = self._make_one()\n\n        self.assertEqual(environ['REMOTE_ADDR'], '127.0.0.1')\n        self.assertEqual(environ['REMOTE_PORT'], '443')\n\n        self.transport.get_extra_info.return_value = ('127.0.0.1', 443)\n        environ = self._make_one()\n\n        self.assertEqual(environ['REMOTE_ADDR'], '127.0.0.1')\n        self.assertEqual(environ['REMOTE_PORT'], '443')\n\n        self.transport.get_extra_info.return_value = '[::1]'\n        environ = self._make_one()\n\n        self.assertEqual(environ['REMOTE_ADDR'], '::1')\n        self.assertEqual(environ['REMOTE_PORT'], '80')\n\n    def test_wsgi_response(self):\n        srv = self._make_srv()\n        resp = srv.create_wsgi_response(self.message)\n        self.assertIsInstance(resp, wsgi.WsgiResponse)\n\n    def test_wsgi_response_start_response(self):\n        srv = self._make_srv()\n        resp = srv.create_wsgi_response(self.message)\n        resp.start_response(\n            '200 OK', [('CONTENT-TYPE', 'text/plain')])\n        self.assertEqual(resp.status, '200 OK')\n        self.assertIsInstance(resp.response, protocol.Response)\n\n    def test_wsgi_response_start_response_exc(self):\n        srv = self._make_srv()\n        resp = srv.create_wsgi_response(self.message)\n        resp.start_response(\n            '200 OK', [('CONTENT-TYPE', 'text/plain')], ['', ValueError()])\n        self.assertEqual(resp.status, '200 OK')\n        self.assertIsInstance(resp.response, protocol.Response)\n\n    def test_wsgi_response_start_response_exc_status(self):\n        srv = self._make_srv()\n        resp = srv.create_wsgi_response(self.message)\n        resp.start_response('200 OK', [('CONTENT-TYPE', 'text/plain')])\n\n        self.assertRaises(\n            ValueError,\n            resp.start_response,\n            '500 Err', [('CONTENT-TYPE', 'text/plain')], ['', ValueError()])\n\n    @unittest.mock.patch('aiohttp.wsgi.aiohttp')\n    def test_wsgi_response_101_upgrade_to_websocket(self, m_asyncio):\n        srv = self._make_srv()\n        resp = srv.create_wsgi_response(self.message)\n        resp.start_response(\n            '101 Switching Protocols', (('UPGRADE', 'websocket'),\n                                        ('CONNECTION', 'upgrade')))\n        self.assertEqual(resp.status, '101 Switching Protocols')\n        self.assertTrue(m_asyncio.Response.return_value.send_headers.called)\n\n    def test_file_wrapper(self):\n        fobj = io.BytesIO(b'data')\n        wrapper = wsgi.FileWrapper(fobj, 2)\n        self.assertIs(wrapper, iter(wrapper))\n        self.assertTrue(hasattr(wrapper, 'close'))\n\n        self.assertEqual(next(wrapper), b'da')\n        self.assertEqual(next(wrapper), b'ta')\n        self.assertRaises(StopIteration, next, wrapper)\n\n        wrapper = wsgi.FileWrapper(b'data', 2)\n        self.assertFalse(hasattr(wrapper, 'close'))\n\n    def test_handle_request_futures(self):\n\n        def wsgi_app(env, start):\n            start('200 OK', [('Content-Type', 'text/plain')])\n            f1 = asyncio.Future(loop=self.loop)\n            f1.set_result(b'data')\n            fut = asyncio.Future(loop=self.loop)\n            fut.set_result([f1])\n            return fut\n\n        srv = self._make_srv(wsgi_app)\n        self.loop.run_until_complete(\n            srv.handle_request(self.message, self.payload))\n\n        content = b''.join(\n            [c[1][0] for c in self.writer.write.mock_calls])\n        self.assertTrue(content.startswith(b'HTTP/1.0 200 OK'))\n        self.assertTrue(content.endswith(b'data'))\n\n    def test_handle_request_simple(self):\n\n        def wsgi_app(env, start):\n            start('200 OK', [('Content-Type', 'text/plain')])\n            return [b'data']\n\n        stream = asyncio.StreamReader(loop=self.loop)\n        stream.feed_data(b'data')\n        stream.feed_eof()\n\n        self.message = protocol.RawRequestMessage(\n            'GET', '/path', (1, 1), self.headers, True, 'deflate')\n\n        srv = self._make_srv(wsgi_app, readpayload=True)\n        self.loop.run_until_complete(\n            srv.handle_request(self.message, self.payload))\n\n        content = b''.join(\n            [c[1][0] for c in self.writer.write.mock_calls])\n        self.assertTrue(content.startswith(b'HTTP/1.1 200 OK'))\n        self.assertTrue(content.endswith(b'data\\r\\n0\\r\\n\\r\\n'))\n        self.assertFalse(srv._keep_alive)\n\n    def test_handle_request_io(self):\n\n        def wsgi_app(env, start):\n            start('200 OK', [('Content-Type', 'text/plain')])\n            return io.BytesIO(b'data')\n\n        srv = self._make_srv(wsgi_app)\n\n        self.loop.run_until_complete(\n            srv.handle_request(self.message, self.payload))\n\n        content = b''.join(\n            [c[1][0] for c in self.writer.write.mock_calls])\n        self.assertTrue(content.startswith(b'HTTP/1.0 200 OK'))\n        self.assertTrue(content.endswith(b'data'))\n\n    def test_handle_request_keep_alive(self):\n\n        def wsgi_app(env, start):\n            start('200 OK', [('Content-Type', 'text/plain')])\n            return [b'data']\n\n        stream = asyncio.StreamReader(loop=self.loop)\n        stream.feed_data(b'data')\n        stream.feed_eof()\n\n        self.message = protocol.RawRequestMessage(\n            'GET', '/path', (1, 1), self.headers, False, 'deflate')\n\n        srv = self._make_srv(wsgi_app, readpayload=True)\n\n        self.loop.run_until_complete(\n            srv.handle_request(self.message, self.payload))\n\n        content = b''.join(\n            [c[1][0] for c in self.writer.write.mock_calls])\n        self.assertTrue(content.startswith(b'HTTP/1.1 200 OK'))\n        self.assertTrue(content.endswith(b'data\\r\\n0\\r\\n\\r\\n'))\n        self.assertTrue(srv._keep_alive)\n\n    def test_handle_request_readpayload(self):\n\n        def wsgi_app(env, start):\n            start('200 OK', [('Content-Type', 'text/plain')])\n            return [env['wsgi.input'].read()]\n\n        srv = self._make_srv(wsgi_app, readpayload=True)\n\n        self.loop.run_until_complete(\n            srv.handle_request(self.message, self.payload))\n\n        content = b''.join(\n            [c[1][0] for c in self.writer.write.mock_calls])\n        self.assertTrue(content.startswith(b'HTTP/1.0 200 OK'))\n        self.assertTrue(content.endswith(b'data'))\n\n    def test_dont_unquote_environ_path_info(self):\n        path = '/path/some%20text'\n        print(path)\n        self.message = protocol.RawRequestMessage(\n            'GET', path, (1, 0), self.headers, True, 'deflate')\n        environ = self._make_one()\n        self.assertEqual(environ['PATH_INFO'], path)",
                                "ast_type_str": "ClassDef",
                                "start_lineno": 14,
                                "end_lineno": 283,
                                "parent": null
                            }
                        }
                    ],
                    "deleted_entities": []
                }
            ]
        }
    ],
    "old_commit_hash": "0813710e44b911e40809131521e108cdb8451c7b^",
    "new_commit_hash": "0813710e44b911e40809131521e108cdb8451c7b",
    "commit_message": "Fix #177: Don't unquote  in wsgi.py",
    "commit_date": "2014-11-19T18:47:35+02:00",
    "metadata": {}
}
{
    "repo_name": "aiohttp",
    "new_commit_hash": "0813710e44b911e40809131521e108cdb8451c7b",
    "test_file_codes": [
        "\"\"\"Tests for http/wsgi.py\"\"\"\n\nimport io\nimport asyncio\nimport unittest\nimport unittest.mock\n\nimport aiohttp\nfrom aiohttp import multidict\nfrom aiohttp import wsgi\nfrom aiohttp import protocol\n\n\nclass HttpWsgiServerProtocolTests(unittest.TestCase):\n\n    def setUp(self):\n        self.loop = asyncio.new_event_loop()\n        asyncio.set_event_loop(None)\n\n        self.wsgi = unittest.mock.Mock()\n        self.reader = unittest.mock.Mock()\n        self.writer = unittest.mock.Mock()\n        self.writer.drain.return_value = ()\n        self.transport = unittest.mock.Mock()\n        self.transport.get_extra_info.return_value = '127.0.0.1'\n\n        self.headers = multidict.MutableMultiDict()\n        self.message = protocol.RawRequestMessage(\n            'GET', '/path', (1, 0), self.headers, True, 'deflate')\n        self.payload = aiohttp.FlowControlDataQueue(self.reader)\n        self.payload.feed_data(b'data')\n        self.payload.feed_data(b'data')\n        self.payload.feed_eof()\n\n    def tearDown(self):\n        self.loop.close()\n\n    def test_ctor(self):\n        srv = wsgi.WSGIServerHttpProtocol(self.wsgi, loop=self.loop)\n        self.assertIs(srv.wsgi, self.wsgi)\n        self.assertFalse(srv.readpayload)\n\n    def _make_one(self, **kw):\n        srv = wsgi.WSGIServerHttpProtocol(self.wsgi, loop=self.loop, **kw)\n        srv.reader = self.reader\n        srv.writer = self.writer\n        srv.transport = self.transport\n        return srv.create_wsgi_environ(self.message, self.payload)\n\n    def _make_srv(self, app=None, **kw):\n        if app is None:\n            app = self.wsgi\n        srv = wsgi.WSGIServerHttpProtocol(app, loop=self.loop, **kw)\n        srv.reader = self.reader\n        srv.writer = self.writer\n        srv.transport = self.transport\n        return srv\n\n    def test_environ(self):\n        environ = self._make_one()\n        self.assertEqual(environ['RAW_URI'], '/path')\n        self.assertEqual(environ['wsgi.async'], True)\n\n    def test_environ_headers(self):\n        self.headers.extend(\n            (('HOST', 'python.org'),\n             ('SCRIPT_NAME', 'script'),\n             ('CONTENT-TYPE', 'text/plain'),\n             ('CONTENT-LENGTH', '209'),\n             ('X_TEST', '123'),\n             ('X_TEST', '456')))\n        environ = self._make_one(is_ssl=True)\n        self.assertEqual(environ['CONTENT_TYPE'], 'text/plain')\n        self.assertEqual(environ['CONTENT_LENGTH'], '209')\n        self.assertEqual(environ['HTTP_X_TEST'], '123,456')\n        self.assertEqual(environ['SCRIPT_NAME'], 'script')\n        self.assertEqual(environ['SERVER_NAME'], 'python.org')\n        self.assertEqual(environ['SERVER_PORT'], '443')\n\n    def test_environ_host_header(self):\n        self.headers.add('HOST', 'python.org')\n        environ = self._make_one()\n\n        self.assertEqual(environ['HTTP_HOST'], 'python.org')\n        self.assertEqual(environ['SERVER_NAME'], 'python.org')\n        self.assertEqual(environ['SERVER_PORT'], '80')\n        self.assertEqual(environ['SERVER_PROTOCOL'], 'HTTP/1.0')\n\n    def test_environ_host_port_header(self):\n        self.message = protocol.RawRequestMessage(\n            'GET', '/path', (1, 1), self.headers, True, 'deflate')\n        self.headers.add('HOST', 'python.org:443')\n        environ = self._make_one()\n\n        self.assertEqual(environ['HTTP_HOST'], 'python.org:443')\n        self.assertEqual(environ['SERVER_NAME'], 'python.org')\n        self.assertEqual(environ['SERVER_PORT'], '443')\n        self.assertEqual(environ['SERVER_PROTOCOL'], 'HTTP/1.1')\n\n    def test_environ_forward(self):\n        self.transport.get_extra_info.return_value = 'localhost,127.0.0.1'\n        environ = self._make_one()\n\n        self.assertEqual(environ['REMOTE_ADDR'], '127.0.0.1')\n        self.assertEqual(environ['REMOTE_PORT'], '80')\n\n        self.transport.get_extra_info.return_value = 'localhost,127.0.0.1:443'\n        environ = self._make_one()\n\n        self.assertEqual(environ['REMOTE_ADDR'], '127.0.0.1')\n        self.assertEqual(environ['REMOTE_PORT'], '443')\n\n        self.transport.get_extra_info.return_value = ('127.0.0.1', 443)\n        environ = self._make_one()\n\n        self.assertEqual(environ['REMOTE_ADDR'], '127.0.0.1')\n        self.assertEqual(environ['REMOTE_PORT'], '443')\n\n        self.transport.get_extra_info.return_value = '[::1]'\n        environ = self._make_one()\n\n        self.assertEqual(environ['REMOTE_ADDR'], '::1')\n        self.assertEqual(environ['REMOTE_PORT'], '80')\n\n    def test_wsgi_response(self):\n        srv = self._make_srv()\n        resp = srv.create_wsgi_response(self.message)\n        self.assertIsInstance(resp, wsgi.WsgiResponse)\n\n    def test_wsgi_response_start_response(self):\n        srv = self._make_srv()\n        resp = srv.create_wsgi_response(self.message)\n        resp.start_response(\n            '200 OK', [('CONTENT-TYPE', 'text/plain')])\n        self.assertEqual(resp.status, '200 OK')\n        self.assertIsInstance(resp.response, protocol.Response)\n\n    def test_wsgi_response_start_response_exc(self):\n        srv = self._make_srv()\n        resp = srv.create_wsgi_response(self.message)\n        resp.start_response(\n            '200 OK', [('CONTENT-TYPE', 'text/plain')], ['', ValueError()])\n        self.assertEqual(resp.status, '200 OK')\n        self.assertIsInstance(resp.response, protocol.Response)\n\n    def test_wsgi_response_start_response_exc_status(self):\n        srv = self._make_srv()\n        resp = srv.create_wsgi_response(self.message)\n        resp.start_response('200 OK', [('CONTENT-TYPE', 'text/plain')])\n\n        self.assertRaises(\n            ValueError,\n            resp.start_response,\n            '500 Err', [('CONTENT-TYPE', 'text/plain')], ['', ValueError()])\n\n    @unittest.mock.patch('aiohttp.wsgi.aiohttp')\n    def test_wsgi_response_101_upgrade_to_websocket(self, m_asyncio):\n        srv = self._make_srv()\n        resp = srv.create_wsgi_response(self.message)\n        resp.start_response(\n            '101 Switching Protocols', (('UPGRADE', 'websocket'),\n                                        ('CONNECTION', 'upgrade')))\n        self.assertEqual(resp.status, '101 Switching Protocols')\n        self.assertTrue(m_asyncio.Response.return_value.send_headers.called)\n\n    def test_file_wrapper(self):\n        fobj = io.BytesIO(b'data')\n        wrapper = wsgi.FileWrapper(fobj, 2)\n        self.assertIs(wrapper, iter(wrapper))\n        self.assertTrue(hasattr(wrapper, 'close'))\n\n        self.assertEqual(next(wrapper), b'da')\n        self.assertEqual(next(wrapper), b'ta')\n        self.assertRaises(StopIteration, next, wrapper)\n\n        wrapper = wsgi.FileWrapper(b'data', 2)\n        self.assertFalse(hasattr(wrapper, 'close'))\n\n    def test_handle_request_futures(self):\n\n        def wsgi_app(env, start):\n            start('200 OK', [('Content-Type', 'text/plain')])\n            f1 = asyncio.Future(loop=self.loop)\n            f1.set_result(b'data')\n            fut = asyncio.Future(loop=self.loop)\n            fut.set_result([f1])\n            return fut\n\n        srv = self._make_srv(wsgi_app)\n        self.loop.run_until_complete(\n            srv.handle_request(self.message, self.payload))\n\n        content = b''.join(\n            [c[1][0] for c in self.writer.write.mock_calls])\n        self.assertTrue(content.startswith(b'HTTP/1.0 200 OK'))\n        self.assertTrue(content.endswith(b'data'))\n\n    def test_handle_request_simple(self):\n\n        def wsgi_app(env, start):\n            start('200 OK', [('Content-Type', 'text/plain')])\n            return [b'data']\n\n        stream = asyncio.StreamReader(loop=self.loop)\n        stream.feed_data(b'data')\n        stream.feed_eof()\n\n        self.message = protocol.RawRequestMessage(\n            'GET', '/path', (1, 1), self.headers, True, 'deflate')\n\n        srv = self._make_srv(wsgi_app, readpayload=True)\n        self.loop.run_until_complete(\n            srv.handle_request(self.message, self.payload))\n\n        content = b''.join(\n            [c[1][0] for c in self.writer.write.mock_calls])\n        self.assertTrue(content.startswith(b'HTTP/1.1 200 OK'))\n        self.assertTrue(content.endswith(b'data\\r\\n0\\r\\n\\r\\n'))\n        self.assertFalse(srv._keep_alive)\n\n    def test_handle_request_io(self):\n\n        def wsgi_app(env, start):\n            start('200 OK', [('Content-Type', 'text/plain')])\n            return io.BytesIO(b'data')\n\n        srv = self._make_srv(wsgi_app)\n\n        self.loop.run_until_complete(\n            srv.handle_request(self.message, self.payload))\n\n        content = b''.join(\n            [c[1][0] for c in self.writer.write.mock_calls])\n        self.assertTrue(content.startswith(b'HTTP/1.0 200 OK'))\n        self.assertTrue(content.endswith(b'data'))\n\n    def test_handle_request_keep_alive(self):\n\n        def wsgi_app(env, start):\n            start('200 OK', [('Content-Type', 'text/plain')])\n            return [b'data']\n\n        stream = asyncio.StreamReader(loop=self.loop)\n        stream.feed_data(b'data')\n        stream.feed_eof()\n\n        self.message = protocol.RawRequestMessage(\n            'GET', '/path', (1, 1), self.headers, False, 'deflate')\n\n        srv = self._make_srv(wsgi_app, readpayload=True)\n\n        self.loop.run_until_complete(\n            srv.handle_request(self.message, self.payload))\n\n        content = b''.join(\n            [c[1][0] for c in self.writer.write.mock_calls])\n        self.assertTrue(content.startswith(b'HTTP/1.1 200 OK'))\n        self.assertTrue(content.endswith(b'data\\r\\n0\\r\\n\\r\\n'))\n        self.assertTrue(srv._keep_alive)\n\n    def test_handle_request_readpayload(self):\n\n        def wsgi_app(env, start):\n            start('200 OK', [('Content-Type', 'text/plain')])\n            return [env['wsgi.input'].read()]\n\n        srv = self._make_srv(wsgi_app, readpayload=True)\n\n        self.loop.run_until_complete(\n            srv.handle_request(self.message, self.payload))\n\n        content = b''.join(\n            [c[1][0] for c in self.writer.write.mock_calls])\n        self.assertTrue(content.startswith(b'HTTP/1.0 200 OK'))\n        self.assertTrue(content.endswith(b'data'))\n\n    def test_dont_unquote_environ_path_info(self):\n        path = '/path/some%20text'\n        print(path)\n        self.message = protocol.RawRequestMessage(\n            'GET', path, (1, 0), self.headers, True, 'deflate')\n        environ = self._make_one()\n        self.assertEqual(environ['PATH_INFO'], path)\n"
    ],
    "test_file_names": [
        "test_1.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 25ms\nInstalled 26 packages in 49ms\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_0813710e44b911e40809131521e108cdb8451c7b\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 ..................                                   [100%]\n\n==================================== PASSES ====================================\n_______ HttpWsgiServerProtocolTests.test_dont_unquote_environ_path_info ________\n----------------------------- Captured stdout call -----------------------------\n/path/some%20text\n=========================== short test summary info ============================\nPASSED r2e_tests/test_1.py::HttpWsgiServerProtocolTests::test_ctor\nPASSED r2e_tests/test_1.py::HttpWsgiServerProtocolTests::test_dont_unquote_environ_path_info\nPASSED r2e_tests/test_1.py::HttpWsgiServerProtocolTests::test_environ\nPASSED r2e_tests/test_1.py::HttpWsgiServerProtocolTests::test_environ_forward\nPASSED r2e_tests/test_1.py::HttpWsgiServerProtocolTests::test_environ_headers\nPASSED r2e_tests/test_1.py::HttpWsgiServerProtocolTests::test_environ_host_header\nPASSED r2e_tests/test_1.py::HttpWsgiServerProtocolTests::test_environ_host_port_header\nPASSED r2e_tests/test_1.py::HttpWsgiServerProtocolTests::test_file_wrapper\nPASSED r2e_tests/test_1.py::HttpWsgiServerProtocolTests::test_handle_request_futures\nPASSED r2e_tests/test_1.py::HttpWsgiServerProtocolTests::test_handle_request_io\nPASSED r2e_tests/test_1.py::HttpWsgiServerProtocolTests::test_handle_request_keep_alive\nPASSED r2e_tests/test_1.py::HttpWsgiServerProtocolTests::test_handle_request_readpayload\nPASSED r2e_tests/test_1.py::HttpWsgiServerProtocolTests::test_handle_request_simple\nPASSED r2e_tests/test_1.py::HttpWsgiServerProtocolTests::test_wsgi_response\nPASSED r2e_tests/test_1.py::HttpWsgiServerProtocolTests::test_wsgi_response_101_upgrade_to_websocket\nPASSED r2e_tests/test_1.py::HttpWsgiServerProtocolTests::test_wsgi_response_start_response\nPASSED r2e_tests/test_1.py::HttpWsgiServerProtocolTests::test_wsgi_response_start_response_exc\nPASSED r2e_tests/test_1.py::HttpWsgiServerProtocolTests::test_wsgi_response_start_response_exc_status\n============================== 18 passed in 0.49s ==============================\n",
    "new_commit_res_stderr": "/home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_0813710e44b911e40809131521e108cdb8451c7b/.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_0813710e44b911e40809131521e108cdb8451c7b\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 .F................                                   [100%]\n\n=================================== FAILURES ===================================\n_______ HttpWsgiServerProtocolTests.test_dont_unquote_environ_path_info ________\n\nself = <r2e_tests.test_1.HttpWsgiServerProtocolTests testMethod=test_dont_unquote_environ_path_info>\n\n    def test_dont_unquote_environ_path_info(self):\n        path = '/path/some%20text'\n        print(path)\n        self.message = protocol.RawRequestMessage(\n            'GET', path, (1, 0), self.headers, True, 'deflate')\n        environ = self._make_one()\n>       self.assertEqual(environ['PATH_INFO'], path)\nE       AssertionError: '/path/some text' != '/path/some%20text'\nE       - /path/some text\nE       ?           ^\nE       + /path/some%20text\nE       ?           ^^^\n\nr2e_tests/test_1.py:283: AssertionError\n----------------------------- Captured stdout call -----------------------------\n/path/some%20text\n==================================== PASSES ====================================\n=========================== short test summary info ============================\nPASSED r2e_tests/test_1.py::HttpWsgiServerProtocolTests::test_ctor\nPASSED r2e_tests/test_1.py::HttpWsgiServerProtocolTests::test_environ\nPASSED r2e_tests/test_1.py::HttpWsgiServerProtocolTests::test_environ_forward\nPASSED r2e_tests/test_1.py::HttpWsgiServerProtocolTests::test_environ_headers\nPASSED r2e_tests/test_1.py::HttpWsgiServerProtocolTests::test_environ_host_header\nPASSED r2e_tests/test_1.py::HttpWsgiServerProtocolTests::test_environ_host_port_header\nPASSED r2e_tests/test_1.py::HttpWsgiServerProtocolTests::test_file_wrapper\nPASSED r2e_tests/test_1.py::HttpWsgiServerProtocolTests::test_handle_request_futures\nPASSED r2e_tests/test_1.py::HttpWsgiServerProtocolTests::test_handle_request_io\nPASSED r2e_tests/test_1.py::HttpWsgiServerProtocolTests::test_handle_request_keep_alive\nPASSED r2e_tests/test_1.py::HttpWsgiServerProtocolTests::test_handle_request_readpayload\nPASSED r2e_tests/test_1.py::HttpWsgiServerProtocolTests::test_handle_request_simple\nPASSED r2e_tests/test_1.py::HttpWsgiServerProtocolTests::test_wsgi_response\nPASSED r2e_tests/test_1.py::HttpWsgiServerProtocolTests::test_wsgi_response_101_upgrade_to_websocket\nPASSED r2e_tests/test_1.py::HttpWsgiServerProtocolTests::test_wsgi_response_start_response\nPASSED r2e_tests/test_1.py::HttpWsgiServerProtocolTests::test_wsgi_response_start_response_exc\nPASSED r2e_tests/test_1.py::HttpWsgiServerProtocolTests::test_wsgi_response_start_response_exc_status\nFAILED r2e_tests/test_1.py::HttpWsgiServerProtocolTests::test_dont_unquote_environ_path_info\n========================= 1 failed, 17 passed in 0.12s =========================\n",
    "old_commit_res_stderr": "/home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_0813710e44b911e40809131521e108cdb8451c7b/.venv/lib/python3.9/site-packages/pytest_asyncio/plugin.py:207: PytestDeprecationWarning: The configuration option \"asyncio_default_fixture_loop_scope\" is unset.\nThe event loop scope for asynchronous fixtures will default to the fixture caching scope. Future versions of pytest-asyncio will default the loop scope for asynchronous fixtures to function scope. Set the default fixture loop scope explicitly in order to avoid unexpected behavior in the future. Valid fixture loop scopes are: \"function\", \"class\", \"module\", \"package\", \"session\"\n\n  warnings.warn(PytestDeprecationWarning(_DEFAULT_FIXTURE_LOOP_SCOPE_UNSET))\n"
}
CHANGES.txt aiohttp/__init__.py aiohttp/wsgi.py tests/test_wsgi.py
We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
[ISSUE]
**Title:** `PATH_INFO` is incorrectly unquoted in `wsgi.py`, causing encoded characters to be decoded

**Description:**
When processing a WSGI request, the `PATH_INFO` environment variable should retain the original URL-encoded characters. However, it appears that `PATH_INFO` is being unquoted, which decodes characters like `%20` into spaces. This leads to discrepancies when handling URLs with encoded characters.

**Example Code:**
```python
def test_dont_unquote_environ_path_info():
    path = '/path/some%20text'
    message = protocol.RawRequestMessage('GET', path, (1, 0), headers, True, 'deflate')
    environ = create_wsgi_environ(message)
    assert environ['PATH_INFO'] == path
```

**Expected Behavior:**
The `PATH_INFO` should remain as `'/path/some%20text'`, preserving the `%20` encoding.

**Actual Behavior:**
The `PATH_INFO` is unquoted and becomes `'/path/some text'`, where `%20` is replaced by a space.

[/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/wsgi.py
"""wsgi server.

TODO:
  * proxy protocol
  * x-forward security
  * wsgi file support (os.sendfile)
"""

__all__ = ['WSGIServerHttpProtocol']

import asyncio
import inspect
import io
import os
import sys
import time
from urllib.parse import unquote, urlsplit

import aiohttp
from aiohttp import server


class WSGIServerHttpProtocol(server.ServerHttpProtocol):
    """HTTP Server that implements the Python WSGI protocol.

    It uses 'wsgi.async' of 'True'. 'wsgi.input' can behave differently
    depends on 'readpayload' constructor parameter. If readpayload is set to
    True, wsgi server reads all incoming data into BytesIO object and
    sends it as 'wsgi.input' environ var. If readpayload is set to false
    'wsgi.input' is a StreamReader and application should read incoming
    data with "yield from environ['wsgi.input'].read()". It defaults to False.
    """

    SCRIPT_NAME = os.environ.get('SCRIPT_NAME', '')

    def __init__(self, app, readpayload=False, is_ssl=False, *args, **kw):
        super().__init__(*args, **kw)

        self.wsgi = app
        self.is_ssl = is_ssl
        self.readpayload = readpayload

    def create_wsgi_response(self, message):
        return WsgiResponse(self.writer, message)

    def create_wsgi_environ(self, message, payload):
        uri_parts = urlsplit(message.path)
        url_scheme = 'https' if self.is_ssl else 'http'

        environ = {
            'wsgi.input': payload,
            'wsgi.errors': sys.stderr,
            'wsgi.version': (1, 0),
            'wsgi.async': True,
            'wsgi.multithread': False,
            'wsgi.multiprocess': False,
            'wsgi.run_once': False,
            'wsgi.file_wrapper': FileWrapper,
            'wsgi.url_scheme': url_scheme,
            'SERVER_SOFTWARE': aiohttp.HttpMessage.SERVER_SOFTWARE,
            'REQUEST_METHOD': message.method,
            'QUERY_STRING': uri_parts.query or '',
            'RAW_URI': message.path,
            'SERVER_PROTOCOL': 'HTTP/%s.%s' % message.version
        }

        # authors should be aware that REMOTE_HOST and REMOTE_ADDR
        # may not qualify the remote addr:
        # http://www.ietf.org/rfc/rfc3875
        forward = self.transport.get_extra_info('addr', '127.0.0.1')
        script_name = self.SCRIPT_NAME
        server = forward

        for hdr_name, hdr_value in message.headers.items(getall=True):
            if hdr_name == 'HOST':
                server = hdr_value
            elif hdr_name == 'SCRIPT_NAME':
                script_name = hdr_value
            elif hdr_name == 'CONTENT-TYPE':
                environ['CONTENT_TYPE'] = hdr_value
                continue
            elif hdr_name == 'CONTENT-LENGTH':
                environ['CONTENT_LENGTH'] = hdr_value
                continue

            key = 'HTTP_%s' % hdr_name.replace('-', '_')
            if key in environ:
                hdr_value = '%s,%s' % (environ[key], hdr_value)

            environ[key] = hdr_value

        if isinstance(forward, str):
            # we only took the last one
            # http://en.wikipedia.org/wiki/X-Forwarded-For
            if ',' in forward:
                forward = forward.rsplit(',', 1)[-1].strip()

            # find host and port on ipv6 address
            if '[' in forward and ']' in forward:
                host = forward.split(']')[0][1:].lower()
            elif ':' in forward and forward.count(':') == 1:
                host = forward.split(':')[0].lower()
            else:
                host = forward

            forward = forward.split(']')[-1]
            if ':' in forward and forward.count(':') == 1:
                port = forward.split(':', 1)[1]
            else:
                port = 80

            remote = (host, port)
        else:
            remote = forward

        environ['REMOTE_ADDR'] = remote[0]
        environ['REMOTE_PORT'] = str(remote[1])

        if isinstance(server, str):
            server = server.split(':')
            if len(server) == 1:
                server.append('80' if url_scheme == 'http' else '443')

        environ['SERVER_NAME'] = server[0]
        environ['SERVER_PORT'] = str(server[1])

        path_info = uri_parts.path
        if script_name:
            path_info = path_info.split(script_name, 1)[-1]

        environ['PATH_INFO'] = unquote(path_info)
        environ['SCRIPT_NAME'] = script_name

        environ['async.reader'] = self.reader
        environ['async.writer'] = self.writer

        return environ

    @asyncio.coroutine
    def handle_request(self, message, payload):
        """Handle a single HTTP request"""
        now = time.time()

        if self.readpayload:
            wsgiinput = io.BytesIO()
            wsgiinput.write((yield from payload.read()))
            wsgiinput.seek(0)
            payload = wsgiinput

        environ = self.create_wsgi_environ(message, payload)
        response = self.create_wsgi_response(message)

        riter = self.wsgi(environ, response.start_response)
        if isinstance(riter, asyncio.Future) or inspect.isgenerator(riter):
            riter = yield from riter

        resp = response.response
        try:
            for item in riter:
                if isinstance(item, asyncio.Future):
                    item = yield from item
                yield from resp.write(item)

            yield from resp.write_eof()
        finally:
            if hasattr(riter, 'close'):
                riter.close()

        if resp.keep_alive():
            self.keep_alive(True)

        self.log_access(
            message, environ, response.response, time.time() - now)


class FileWrapper:
    """Custom file wrapper."""

    def __init__(self, fobj, chunk_size=8192):
        self.fobj = fobj
        self.chunk_size = chunk_size
        if hasattr(fobj, 'close'):
            self.close = fobj.close

    def __iter__(self):
        return self

    def __next__(self):
        data = self.fobj.read(self.chunk_size)
        if data:
            return data
        raise StopIteration


class WsgiResponse:
    """Implementation of start_response() callable as specified by PEP 3333"""

    status = None

    def __init__(self, writer, message):
        self.writer = writer
        self.message = message

    def start_response(self, status, headers, exc_info=None):
        if exc_info:
            try:
                if self.status:
                    raise exc_info[1]
            finally:
                exc_info = None

        status_code = int(status.split(' ', 1)[0])

        self.status = status
        resp = self.response = aiohttp.Response(
            self.writer, status_code,
            self.message.version, self.message.should_close)
        resp.add_headers(*headers)

        # send headers immediately for websocket connection
        if status_code == 101 and resp.upgrade and resp.websocket:
            resp.send_headers()
        else:
            resp._send_headers = True
        return self.response.write

```
--- 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:** `PATH_INFO` is incorrectly unquoted in `wsgi.py`, causing encoded characters to be decoded

**Description:**
When processing a WSGI request, the `PATH_INFO` environment variable should retain the original URL-encoded characters. However, it appears that `PATH_INFO` is being unquoted, which decodes characters like `%20` into spaces. This leads to discrepancies when handling URLs with encoded characters.

**Example Code:**
```python
def test_dont_unquote_environ_path_info():
    path = '/path/some%20text'
    message = protocol.RawRequestMessage('GET', path, (1, 0), headers, True, 'deflate')
    environ = create_wsgi_environ(message)
    assert environ['PATH_INFO'] == path
```

**Expected Behavior:**
The `PATH_INFO` should remain as `'/path/some%20text'`, preserving the `%20` encoding.

**Actual Behavior:**
The `PATH_INFO` is unquoted and becomes `'/path/some text'`, where `%20` is replaced by a space.

[/ISSUE]
{
    "HttpWsgiServerProtocolTests.test_ctor": "PASSED",
    "HttpWsgiServerProtocolTests.test_dont_unquote_environ_path_info": "PASSED",
    "HttpWsgiServerProtocolTests.test_environ": "PASSED",
    "HttpWsgiServerProtocolTests.test_environ_forward": "PASSED",
    "HttpWsgiServerProtocolTests.test_environ_headers": "PASSED",
    "HttpWsgiServerProtocolTests.test_environ_host_header": "PASSED",
    "HttpWsgiServerProtocolTests.test_environ_host_port_header": "PASSED",
    "HttpWsgiServerProtocolTests.test_file_wrapper": "PASSED",
    "HttpWsgiServerProtocolTests.test_handle_request_futures": "PASSED",
    "HttpWsgiServerProtocolTests.test_handle_request_io": "PASSED",
    "HttpWsgiServerProtocolTests.test_handle_request_keep_alive": "PASSED",
    "HttpWsgiServerProtocolTests.test_handle_request_readpayload": "PASSED",
    "HttpWsgiServerProtocolTests.test_handle_request_simple": "PASSED",
    "HttpWsgiServerProtocolTests.test_wsgi_response": "PASSED",
    "HttpWsgiServerProtocolTests.test_wsgi_response_101_upgrade_to_websocket": "PASSED",
    "HttpWsgiServerProtocolTests.test_wsgi_response_start_response": "PASSED",
    "HttpWsgiServerProtocolTests.test_wsgi_response_start_response_exc": "PASSED",
    "HttpWsgiServerProtocolTests.test_wsgi_response_start_response_exc_status": "PASSED"
}
diff --git a/aiohttp/__init__.py b/aiohttp/__init__.py
index c404e367..9b101c9d 100644
--- a/aiohttp/__init__.py
+++ b/aiohttp/__init__.py
@@ -1,6 +1,6 @@
 # This relies on each of the submodules having an __all__ variable.
 
-__version__ = '0.10.1'
+__version__ = '0.10.2'
 
 
 from .protocol import *  # noqa
diff --git a/aiohttp/wsgi.py b/aiohttp/wsgi.py
index 510ba07b..e83972fd 100644
--- a/aiohttp/wsgi.py
+++ b/aiohttp/wsgi.py
@@ -14,7 +14,7 @@ import io
 import os
 import sys
 import time
-from urllib.parse import unquote, urlsplit
+from urllib.parse import urlsplit
 
 import aiohttp
 from aiohttp import server
@@ -128,7 +128,7 @@ class WSGIServerHttpProtocol(server.ServerHttpProtocol):
         if script_name:
             path_info = path_info.split(script_name, 1)[-1]
 
-        environ['PATH_INFO'] = unquote(path_info)
+        environ['PATH_INFO'] = path_info
         environ['SCRIPT_NAME'] = script_name
 
         environ['async.reader'] = self.reader

{"aiohttp/wsgi.py": "\"\"\"wsgi server.\n\nTODO:\n  * proxy protocol\n  * x-forward security\n  * wsgi file support (os.sendfile)\n\"\"\"\n\n__all__ = ['WSGIServerHttpProtocol']\n\nimport asyncio\nimport inspect\nimport io\nimport os\nimport sys\nimport time\nfrom urllib.parse import unquote, urlsplit\n\nimport aiohttp\nfrom aiohttp import server\n\n\nclass WSGIServerHttpProtocol(server.ServerHttpProtocol):\n    \"\"\"HTTP Server that implements the Python WSGI protocol.\n\n    It uses 'wsgi.async' of 'True'. 'wsgi.input' can behave differently\n    depends on 'readpayload' constructor parameter. If readpayload is set to\n    True, wsgi server reads all incoming data into BytesIO object and\n    sends it as 'wsgi.input' environ var. If readpayload is set to false\n    'wsgi.input' is a StreamReader and application should read incoming\n    data with \"yield from environ['wsgi.input'].read()\". It defaults to False.\n    \"\"\"\n\n    SCRIPT_NAME = os.environ.get('SCRIPT_NAME', '')\n\n    def __init__(self, app, readpayload=False, is_ssl=False, *args, **kw):\n        super().__init__(*args, **kw)\n\n        self.wsgi = app\n        self.is_ssl = is_ssl\n        self.readpayload = readpayload\n\n    def create_wsgi_response(self, message):\n        return WsgiResponse(self.writer, message)\n\n    def create_wsgi_environ(self, message, payload):\n        uri_parts = urlsplit(message.path)\n        url_scheme = 'https' if self.is_ssl else 'http'\n\n        environ = {\n            'wsgi.input': payload,\n            'wsgi.errors': sys.stderr,\n            'wsgi.version': (1, 0),\n            'wsgi.async': True,\n            'wsgi.multithread': False,\n            'wsgi.multiprocess': False,\n            'wsgi.run_once': False,\n            'wsgi.file_wrapper': FileWrapper,\n            'wsgi.url_scheme': url_scheme,\n            'SERVER_SOFTWARE': aiohttp.HttpMessage.SERVER_SOFTWARE,\n            'REQUEST_METHOD': message.method,\n            'QUERY_STRING': uri_parts.query or '',\n            'RAW_URI': message.path,\n            'SERVER_PROTOCOL': 'HTTP/%s.%s' % message.version\n        }\n\n        # authors should be aware that REMOTE_HOST and REMOTE_ADDR\n        # may not qualify the remote addr:\n        # http://www.ietf.org/rfc/rfc3875\n        forward = self.transport.get_extra_info('addr', '127.0.0.1')\n        script_name = self.SCRIPT_NAME\n        server = forward\n\n        for hdr_name, hdr_value in message.headers.items(getall=True):\n            if hdr_name == 'HOST':\n                server = hdr_value\n            elif hdr_name == 'SCRIPT_NAME':\n                script_name = hdr_value\n            elif hdr_name == 'CONTENT-TYPE':\n                environ['CONTENT_TYPE'] = hdr_value\n                continue\n            elif hdr_name == 'CONTENT-LENGTH':\n                environ['CONTENT_LENGTH'] = hdr_value\n                continue\n\n            key = 'HTTP_%s' % hdr_name.replace('-', '_')\n            if key in environ:\n                hdr_value = '%s,%s' % (environ[key], hdr_value)\n\n            environ[key] = hdr_value\n\n        if isinstance(forward, str):\n            # we only took the last one\n            # http://en.wikipedia.org/wiki/X-Forwarded-For\n            if ',' in forward:\n                forward = forward.rsplit(',', 1)[-1].strip()\n\n            # find host and port on ipv6 address\n            if '[' in forward and ']' in forward:\n                host = forward.split(']')[0][1:].lower()\n            elif ':' in forward and forward.count(':') == 1:\n                host = forward.split(':')[0].lower()\n            else:\n                host = forward\n\n            forward = forward.split(']')[-1]\n            if ':' in forward and forward.count(':') == 1:\n                port = forward.split(':', 1)[1]\n            else:\n                port = 80\n\n            remote = (host, port)\n        else:\n            remote = forward\n\n        environ['REMOTE_ADDR'] = remote[0]\n        environ['REMOTE_PORT'] = str(remote[1])\n\n        if isinstance(server, str):\n            server = server.split(':')\n            if len(server) == 1:\n                server.append('80' if url_scheme == 'http' else '443')\n\n        environ['SERVER_NAME'] = server[0]\n        environ['SERVER_PORT'] = str(server[1])\n\n        path_info = uri_parts.path\n        if script_name:\n            path_info = path_info.split(script_name, 1)[-1]\n\n        environ['PATH_INFO'] = unquote(path_info)\n        environ['SCRIPT_NAME'] = script_name\n\n        environ['async.reader'] = self.reader\n        environ['async.writer'] = self.writer\n\n        return environ\n\n    @asyncio.coroutine\n    def handle_request(self, message, payload):\n        \"\"\"Handle a single HTTP request\"\"\"\n        now = time.time()\n\n        if self.readpayload:\n            wsgiinput = io.BytesIO()\n            wsgiinput.write((yield from payload.read()))\n            wsgiinput.seek(0)\n            payload = wsgiinput\n\n        environ = self.create_wsgi_environ(message, payload)\n        response = self.create_wsgi_response(message)\n\n        riter = self.wsgi(environ, response.start_response)\n        if isinstance(riter, asyncio.Future) or inspect.isgenerator(riter):\n            riter = yield from riter\n\n        resp = response.response\n        try:\n            for item in riter:\n                if isinstance(item, asyncio.Future):\n                    item = yield from item\n                yield from resp.write(item)\n\n            yield from resp.write_eof()\n        finally:\n            if hasattr(riter, 'close'):\n                riter.close()\n\n        if resp.keep_alive():\n            self.keep_alive(True)\n\n        self.log_access(\n            message, environ, response.response, time.time() - now)\n\n\nclass FileWrapper:\n    \"\"\"Custom file wrapper.\"\"\"\n\n    def __init__(self, fobj, chunk_size=8192):\n        self.fobj = fobj\n        self.chunk_size = chunk_size\n        if hasattr(fobj, 'close'):\n            self.close = fobj.close\n\n    def __iter__(self):\n        return self\n\n    def __next__(self):\n        data = self.fobj.read(self.chunk_size)\n        if data:\n            return data\n        raise StopIteration\n\n\nclass WsgiResponse:\n    \"\"\"Implementation of start_response() callable as specified by PEP 3333\"\"\"\n\n    status = None\n\n    def __init__(self, writer, message):\n        self.writer = writer\n        self.message = message\n\n    def start_response(self, status, headers, exc_info=None):\n        if exc_info:\n            try:\n                if self.status:\n                    raise exc_info[1]\n            finally:\n                exc_info = None\n\n        status_code = int(status.split(' ', 1)[0])\n\n        self.status = status\n        resp = self.response = aiohttp.Response(\n            self.writer, status_code,\n            self.message.version, self.message.should_close)\n        resp.add_headers(*headers)\n\n        # send headers immediately for websocket connection\n        if status_code == 101 and resp.upgrade and resp.websocket:\n            resp.send_headers()\n        else:\n            resp._send_headers = True\n        return self.response.write\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:** `PATH_INFO` is incorrectly unquoted in `wsgi.py`, causing encoded characters to be decoded

**Description:**
When processing a WSGI request, the `PATH_INFO` environment variable should retain the original URL-encoded characters. However, it appears that `PATH_INFO` is being unquoted, which decodes characters like `%20` into spaces. This leads to discrepancies when handling URLs with encoded characters.

**Example Code:**
```python
def test_dont_unquote_environ_path_info():
    path = '/path/some%20text'
    message = protocol.RawRequestMessage('GET', path, (1, 0), headers, True, 'deflate')
    environ = create_wsgi_environ(message)
    assert environ['PATH_INFO'] == path
```

**Expected Behavior:**
The `PATH_INFO` should remain as `'/path/some%20text'`, preserving the `%20` encoding.

**Actual Behavior:**
The `PATH_INFO` is unquoted and becomes `'/path/some text'`, where `%20` is replaced by a space.

[/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/wsgi.py
"""wsgi server.

TODO:
  * proxy protocol
  * x-forward security
  * wsgi file support (os.sendfile)
"""

__all__ = ['WSGIServerHttpProtocol']

import asyncio
import inspect
import io
import os
import sys
import time
from urllib.parse import unquote, urlsplit

import aiohttp
from aiohttp import server


class WSGIServerHttpProtocol(server.ServerHttpProtocol):
    """HTTP Server that implements the Python WSGI protocol.

    It uses 'wsgi.async' of 'True'. 'wsgi.input' can behave differently
    depends on 'readpayload' constructor parameter. If readpayload is set to
    True, wsgi server reads all incoming data into BytesIO object and
    sends it as 'wsgi.input' environ var. If readpayload is set to false
    'wsgi.input' is a StreamReader and application should read incoming
    data with "yield from environ['wsgi.input'].read()". It defaults to False.
    """

    SCRIPT_NAME = os.environ.get('SCRIPT_NAME', '')

    def __init__(self, app, readpayload=False, is_ssl=False, *args, **kw):
        super().__init__(*args, **kw)

        self.wsgi = app
        self.is_ssl = is_ssl
        self.readpayload = readpayload

    def create_wsgi_response(self, message):
        return WsgiResponse(self.writer, message)

    def create_wsgi_environ(self, message, payload):
        uri_parts = urlsplit(message.path)
        url_scheme = 'https' if self.is_ssl else 'http'

        environ = {
            'wsgi.input': payload,
            'wsgi.errors': sys.stderr,
            'wsgi.version': (1, 0),
            'wsgi.async': True,
            'wsgi.multithread': False,
            'wsgi.multiprocess': False,
            'wsgi.run_once': False,
            'wsgi.file_wrapper': FileWrapper,
            'wsgi.url_scheme': url_scheme,
            'SERVER_SOFTWARE': aiohttp.HttpMessage.SERVER_SOFTWARE,
            'REQUEST_METHOD': message.method,
            'QUERY_STRING': uri_parts.query or '',
            'RAW_URI': message.path,
            'SERVER_PROTOCOL': 'HTTP/%s.%s' % message.version
        }

        # authors should be aware that REMOTE_HOST and REMOTE_ADDR
        # may not qualify the remote addr:
        # http://www.ietf.org/rfc/rfc3875
        forward = self.transport.get_extra_info('addr', '127.0.0.1')
        script_name = self.SCRIPT_NAME
        server = forward

        for hdr_name, hdr_value in message.headers.items(getall=True):
            if hdr_name == 'HOST':
                server = hdr_value
            elif hdr_name == 'SCRIPT_NAME':
                script_name = hdr_value
            elif hdr_name == 'CONTENT-TYPE':
                environ['CONTENT_TYPE'] = hdr_value
                continue
            elif hdr_name == 'CONTENT-LENGTH':
                environ['CONTENT_LENGTH'] = hdr_value
                continue

            key = 'HTTP_%s' % hdr_name.replace('-', '_')
            if key in environ:
                hdr_value = '%s,%s' % (environ[key], hdr_value)

            environ[key] = hdr_value

        if isinstance(forward, str):
            # we only took the last one
            # http://en.wikipedia.org/wiki/X-Forwarded-For
            if ',' in forward:
                forward = forward.rsplit(',', 1)[-1].strip()

            # find host and port on ipv6 address
            if '[' in forward and ']' in forward:
                host = forward.split(']')[0][1:].lower()
            elif ':' in forward and forward.count(':') == 1:
                host = forward.split(':')[0].lower()
            else:
                host = forward

            forward = forward.split(']')[-1]
            if ':' in forward and forward.count(':') == 1:
                port = forward.split(':', 1)[1]
            else:
                port = 80

            remote = (host, port)
        else:
            remote = forward

        environ['REMOTE_ADDR'] = remote[0]
        environ['REMOTE_PORT'] = str(remote[1])

        if isinstance(server, str):
            server = server.split(':')
            if len(server) == 1:
                server.append('80' if url_scheme == 'http' else '443')

        environ['SERVER_NAME'] = server[0]
        environ['SERVER_PORT'] = str(server[1])

        path_info = uri_parts.path
        if script_name:
            path_info = path_info.split(script_name, 1)[-1]

        environ['PATH_INFO'] = unquote(path_info)
        environ['SCRIPT_NAME'] = script_name

        environ['async.reader'] = self.reader
        environ['async.writer'] = self.writer

        return environ

    @asyncio.coroutine
    def handle_request(self, message, payload):
        """Handle a single HTTP request"""
        now = time.time()

        if self.readpayload:
            wsgiinput = io.BytesIO()
            wsgiinput.write((yield from payload.read()))
            wsgiinput.seek(0)
            payload = wsgiinput

        environ = self.create_wsgi_environ(message, payload)
        response = self.create_wsgi_response(message)

        riter = self.wsgi(environ, response.start_response)
        if isinstance(riter, asyncio.Future) or inspect.isgenerator(riter):
            riter = yield from riter

        resp = response.response
        try:
            for item in riter:
                if isinstance(item, asyncio.Future):
                    item = yield from item
                yield from resp.write(item)

            yield from resp.write_eof()
        finally:
            if hasattr(riter, 'close'):
                riter.close()

        if resp.keep_alive():
            self.keep_alive(True)

        self.log_access(
            message, environ, response.response, time.time() - now)


class FileWrapper:
    """Custom file wrapper."""

    def __init__(self, fobj, chunk_size=8192):
        self.fobj = fobj
        self.chunk_size = chunk_size
        if hasattr(fobj, 'close'):
            self.close = fobj.close

    def __iter__(self):
        return self

    def __next__(self):
        data = self.fobj.read(self.chunk_size)
        if data:
            return data
        raise StopIteration


class WsgiResponse:
    """Implementation of start_response() callable as specified by PEP 3333"""

    status = None

    def __init__(self, writer, message):
        self.writer = writer
        self.message = message

    def start_response(self, status, headers, exc_info=None):
        if exc_info:
            try:
                if self.status:
                    raise exc_info[1]
            finally:
                exc_info = None

        status_code = int(status.split(' ', 1)[0])

        self.status = status
        resp = self.response = aiohttp.Response(
            self.writer, status_code,
            self.message.version, self.message.should_close)
        resp.add_headers(*headers)

        # send headers immediately for websocket connection
        if status_code == 101 and resp.upgrade and resp.websocket:
            resp.send_headers()
        else:
            resp._send_headers = True
        return self.response.write

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