We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
aiohttp request exceptions can't be caught sometimes when encountering bad http message
## Long story short

When encountering bad http message, aiohttp request exceptions can't be caught sometimes.

For example, I use code like below to detect if a proxy is working:

```Python
import sys
import asyncio
import logging

import aiohttp


DETECT_WEBSITE = 'httpbin.org'


async def proxy_req(proxy_url):
    if proxy_url.startswith('https://'):
        protocol = 'https'
    else:
        protocol = 'http'
    detect_url = f'{protocol}://{DETECT_WEBSITE}/get'
    proxy_url = proxy_url.replace('https://', 'http://')
    print('Detect url:', detect_url)
    print('Proxy url:', proxy_url)
    try:
        async with aiohttp.ClientSession() as session:
            async with session.get(detect_url,
                                   proxy=proxy_url,
                                   headers={'User-Agent': 'Mozilla/5.0'},
                                   timeout=10) as resp:
                text = await resp.text()
                print('Response text:')
                print(text)
    except Exception as exc:
        logging.error(exc)


if __name__ == '__main__':
    proxy_url = sys.argv[1]
    loop = asyncio.get_event_loop()
    loop.run_until_complete(proxy_req(proxy_url))
```


## Expected behaviour

In the above code, I tried to catch all exceptions when doing request, so if a request exception happened, it should always be logged normally.

## Actual behaviour

When I detect some broken proxies, for that proxy, sometimes the exception can be caught normally and logged, but sometimes the exception is not caught but are thrown directly.

For example, detect the broken proxy http://218.106.205.145:8080 ( When using this broken proxy to doing requests, it will return two different groups of reponse headers ), the output may look like below ( The first execution thrown exception, the second execution caught exception and logged ):

```
✗ python test.py http://218.106.205.145:8080
Detect url: http://httpbin.org/get
Proxy url: http://218.106.205.145:8080
Exception in callback None()
handle: <Handle cancelled>
Traceback (most recent call last):
  File "/Users/xxx/Coding/zzz/venv/lib/python3.6/site-packages/aiohttp/client_proto.py", line 161, in data_received
    messages, upgraded, tail = self._parser.feed_data(data)
  File "aiohttp/_http_parser.pyx", line 297, in aiohttp._http_parser.HttpParser.feed_data
aiohttp.http_exceptions.BadHttpMessage: 400, message='invalid constant string'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/local/Cellar/python/3.6.4_4/Frameworks/Python.framework/Versions/3.6/lib/python3.6/asyncio/events.py", line 145, in _run
    self._callback(*self._args)
  File "/usr/local/Cellar/python/3.6.4_4/Frameworks/Python.framework/Versions/3.6/lib/python3.6/asyncio/selector_events.py", line 730, in _read_ready
    self._protocol.data_received(data)
  File "/Users/xxx/Coding/zzz/venv/lib/python3.6/site-packages/aiohttp/client_proto.py", line 177, in data_received
    self.transport.close()
AttributeError: 'NoneType' object has no attribute 'close'
Response text:
HTTP/1.1 500 OK
Date: Mon, 28 May 2018 09:43:07 GMT
Cache-Control: no-cache
Pragma: no-cache
Content-Type: text/html; charset="UTF-8"
Content-Length: 2173
Accep

✗ python test.py http://218.106.205.145:8080
Detect url: http://httpbin.org/get
Proxy url: http://218.106.205.145:8080
ERROR:root:400, message='invalid constant string'
```

## Steps to reproduce

Run the code above to detect the broken proxy like http://218.106.205.145:8080

## Your environment

aiohttp 3.2.1
Mac OS X
aiohttp client



--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `aiohttp/client_proto.py`
Content:
```
1 from contextlib import suppress
2 
3 from .base_protocol import BaseProtocol
4 from .client_exceptions import (ClientOSError, ClientPayloadError,
5                                 ServerDisconnectedError, ServerTimeoutError)
6 from .http import HttpResponseParser
7 from .streams import EMPTY_PAYLOAD, DataQueue
8 
9 
10 class ResponseHandler(BaseProtocol, DataQueue):
11     """Helper class to adapt between Protocol and StreamReader."""
12 
13     def __init__(self, *, loop=None):
14         BaseProtocol.__init__(self, loop=loop)
15         DataQueue.__init__(self, loop=loop)
16 
17         self._should_close = False
18 
19         self._payload = None
20         self._skip_payload = False
21         self._payload_parser = None
22         self._reading_paused = False
23 
24         self._timer = None
25 
26         self._tail = b''
27         self._upgraded = False
28         self._parser = None
29 
30         self._read_timeout = None
31         self._read_timeout_handle = None
32 
33     @property
34     def upgraded(self):
35         return self._upgraded
36 
37     @property
38     def should_close(self):
39         if (self._payload is not None and
40                 not self._payload.is_eof() or self._upgraded):
41             return True
42 
43         return (self._should_close or self._upgraded or
44                 self.exception() is not None or
45                 self._payload_parser is not None or
46                 len(self) or self._tail)
47 
48     def force_close(self):
49         self._should_close = True
50 
51     def close(self):
52         transport = self.transport
53         if transport is not None:
54             transport.close()
55             self.transport = None
56             self._payload = None
57             self._drop_timeout()
58         return transport
59 
60     def is_connected(self):
61         return self.transport is not None
62 
63     def connection_lost(self, exc):
64         self._drop_timeout()
65 
66         if self._payload_parser is not None:
67             with suppress(Exception):
68                 self._payload_parser.feed_eof()
69 
70         try:
71             uncompleted = self._parser.feed_eof()
72         except Exception:
73             uncompleted = None
74             if self._payload is not None:
75                 self._payload.set_exception(
76                     ClientPayloadError('Response payload is not completed'))
77 
78         if not self.is_eof():
79             if isinstance(exc, OSError):
80                 exc = ClientOSError(*exc.args)
81             if exc is None:
82                 exc = ServerDisconnectedError(uncompleted)
83             # assigns self._should_close to True as side effect,
84             # we do it anyway below
85             self.set_exception(exc)
86 
87         self._should_close = True
88         self._parser = None
89         self._payload = None
90         self._payload_parser = None
91         self._reading_paused = False
92 
93         super().connection_lost(exc)
94 
95     def eof_received(self):
96         # should call parser.feed_eof() most likely
97         self._drop_timeout()
98 
99     def pause_reading(self):
100         if not self._reading_paused:
101             try:
102                 self.transport.pause_reading()
103             except (AttributeError, NotImplementedError, RuntimeError):
104                 pass
105             self._reading_paused = True
106             self._drop_timeout()
107 
108     def resume_reading(self):
109         if self._reading_paused:
110             try:
111                 self.transport.resume_reading()
112             except (AttributeError, NotImplementedError, RuntimeError):
113                 pass
114             self._reading_paused = False
115             self._reschedule_timeout()
116 
117     def set_exception(self, exc):
118         self._should_close = True
119         self._drop_timeout()
120         super().set_exception(exc)
121 
122     def set_parser(self, parser, payload):
123         self._payload = payload
124         self._payload_parser = parser
125 
126         self._drop_timeout()
127 
128         if self._tail:
129             data, self._tail = self._tail, b''
130             self.data_received(data)
131 
132     def set_response_params(self, *, timer=None,
133                             skip_payload=False,
134                             read_until_eof=False,
135                             auto_decompress=True,
136                             read_timeout=None):
137         self._skip_payload = skip_payload
138 
139         self._read_timeout = read_timeout
140         self._reschedule_timeout()
141 
142         self._parser = HttpResponseParser(
143             self, self._loop, timer=timer,
144             payload_exception=ClientPayloadError,
145             read_until_eof=read_until_eof,
146             auto_decompress=auto_decompress)
147 
148         if self._tail:
149             data, self._tail = self._tail, b''
150             self.data_received(data)
151 
152     def _drop_timeout(self):
153         if self._read_timeout_handle is not None:
154             self._read_timeout_handle.cancel()
155             self._read_timeout_handle = None
156 
157     def _reschedule_timeout(self):
158         timeout = self._read_timeout
159         if self._read_timeout_handle is not None:
160             self._read_timeout_handle.cancel()
161 
162         if timeout:
163             self._read_timeout_handle = self._loop.call_later(
164                 timeout, self._on_read_timeout)
165         else:
166             self._read_timeout_handle = None
167 
168     def _on_read_timeout(self):
169         exc = ServerTimeoutError("Timeout on reading data from socket")
170         self.set_exception(exc)
171         if self._payload is not None:
172             self._payload.set_exception(exc)
173 
174     def data_received(self, data):
175         if not data:
176             return
177 
178         # custom payload parser
179         if self._payload_parser is not None:
180             eof, tail = self._payload_parser.feed_data(data)
181             if eof:
182                 self._payload = None
183                 self._payload_parser = None
184 
185                 if tail:
186                     self.data_received(tail)
187             return
188         else:
189             if self._upgraded or self._parser is None:
190                 # i.e. websocket connection, websocket parser is not set yet
191                 self._tail += data
192             else:
193                 # parse http messages
194                 try:
195                     messages, upgraded, tail = self._parser.feed_data(data)
196                 except BaseException as exc:
197                     self.transport.close()
198                     # should_close is True after the call
199                     self.set_exception(exc)
200                     return
201 
202                 self._upgraded = upgraded
203 
204                 payload = None
205                 for message, payload in messages:
206                     if message.should_close:
207                         self._should_close = True
208 
209                     self._payload = payload
210 
211                     if self._skip_payload or message.code in (204, 304):
212                         self.feed_data((message, EMPTY_PAYLOAD), 0)
213                     else:
214                         self.feed_data((message, payload), 0)
215                 if payload is not None:
216                     # new message(s) was processed
217                     # register timeout handler unsubscribing
218                     # either on end-of-stream or immediatelly for
219                     # EMPTY_PAYLOAD
220                     if payload is not EMPTY_PAYLOAD:
221                         payload.on_eof(self._drop_timeout)
222                     else:
223                         self._drop_timeout()
224 
225                 if tail:
226                     if upgraded:
227                         self.data_received(tail)
228                     else:
229                         self._tail = tail
230
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/aiohttp/client_proto.py b/aiohttp/client_proto.py
--- a/aiohttp/client_proto.py
+++ b/aiohttp/client_proto.py
@@ -194,7 +194,11 @@
                 try:
                     messages, upgraded, tail = self._parser.feed_data(data)
                 except BaseException as exc:
-                    self.transport.close()
+                    if self.transport is not None:
+                        # connection.release() could be called BEFORE
+                        # data_received(), the transport is already
+                        # closed in this case
+                        self.transport.close()
                     # should_close is True after the call
                     self.set_exception(exc)
                     return

{"golden_diff": "diff --git a/aiohttp/client_proto.py b/aiohttp/client_proto.py\n--- a/aiohttp/client_proto.py\n+++ b/aiohttp/client_proto.py\n@@ -194,7 +194,11 @@\n                 try:\n                     messages, upgraded, tail = self._parser.feed_data(data)\n                 except BaseException as exc:\n-                    self.transport.close()\n+                    if self.transport is not None:\n+                        # connection.release() could be called BEFORE\n+                        # data_received(), the transport is already\n+                        # closed in this case\n+                        self.transport.close()\n                     # should_close is True after the call\n                     self.set_exception(exc)\n                     return\n", "issue": "aiohttp request exceptions can't be caught sometimes when encountering bad http message\n## Long story short\r\n\r\nWhen encountering bad http message, aiohttp request exceptions can't be caught sometimes.\r\n\r\nFor example, I use code like below to detect if a proxy is working:\r\n\r\n```Python\r\nimport sys\r\nimport asyncio\r\nimport logging\r\n\r\nimport aiohttp\r\n\r\n\r\nDETECT_WEBSITE = 'httpbin.org'\r\n\r\n\r\nasync def proxy_req(proxy_url):\r\n    if proxy_url.startswith('https://'):\r\n        protocol = 'https'\r\n    else:\r\n        protocol = 'http'\r\n    detect_url = f'{protocol}://{DETECT_WEBSITE}/get'\r\n    proxy_url = proxy_url.replace('https://', 'http://')\r\n    print('Detect url:', detect_url)\r\n    print('Proxy url:', proxy_url)\r\n    try:\r\n        async with aiohttp.ClientSession() as session:\r\n            async with session.get(detect_url,\r\n                                   proxy=proxy_url,\r\n                                   headers={'User-Agent': 'Mozilla/5.0'},\r\n                                   timeout=10) as resp:\r\n                text = await resp.text()\r\n                print('Response text:')\r\n                print(text)\r\n    except Exception as exc:\r\n        logging.error(exc)\r\n\r\n\r\nif __name__ == '__main__':\r\n    proxy_url = sys.argv[1]\r\n    loop = asyncio.get_event_loop()\r\n    loop.run_until_complete(proxy_req(proxy_url))\r\n```\r\n\r\n\r\n## Expected behaviour\r\n\r\nIn the above code, I tried to catch all exceptions when doing request, so if a request exception happened, it should always be logged normally.\r\n\r\n## Actual behaviour\r\n\r\nWhen I detect some broken proxies, for that proxy, sometimes the exception can be caught normally and logged, but sometimes the exception is not caught but are thrown directly.\r\n\r\nFor example, detect the broken proxy http://218.106.205.145:8080 ( When using this broken proxy to doing requests, it will return two different groups of reponse headers ), the output may look like below ( The first execution thrown exception, the second execution caught exception and logged ):\r\n\r\n```\r\n\u2717 python test.py http://218.106.205.145:8080\r\nDetect url: http://httpbin.org/get\r\nProxy url: http://218.106.205.145:8080\r\nException in callback None()\r\nhandle: <Handle cancelled>\r\nTraceback (most recent call last):\r\n  File \"/Users/xxx/Coding/zzz/venv/lib/python3.6/site-packages/aiohttp/client_proto.py\", line 161, in data_received\r\n    messages, upgraded, tail = self._parser.feed_data(data)\r\n  File \"aiohttp/_http_parser.pyx\", line 297, in aiohttp._http_parser.HttpParser.feed_data\r\naiohttp.http_exceptions.BadHttpMessage: 400, message='invalid constant string'\r\n\r\nDuring handling of the above exception, another exception occurred:\r\n\r\nTraceback (most recent call last):\r\n  File \"/usr/local/Cellar/python/3.6.4_4/Frameworks/Python.framework/Versions/3.6/lib/python3.6/asyncio/events.py\", line 145, in _run\r\n    self._callback(*self._args)\r\n  File \"/usr/local/Cellar/python/3.6.4_4/Frameworks/Python.framework/Versions/3.6/lib/python3.6/asyncio/selector_events.py\", line 730, in _read_ready\r\n    self._protocol.data_received(data)\r\n  File \"/Users/xxx/Coding/zzz/venv/lib/python3.6/site-packages/aiohttp/client_proto.py\", line 177, in data_received\r\n    self.transport.close()\r\nAttributeError: 'NoneType' object has no attribute 'close'\r\nResponse text:\r\nHTTP/1.1 500 OK\r\nDate: Mon, 28 May 2018 09:43:07 GMT\r\nCache-Control: no-cache\r\nPragma: no-cache\r\nContent-Type: text/html; charset=\"UTF-8\"\r\nContent-Length: 2173\r\nAccep\r\n\r\n\u2717 python test.py http://218.106.205.145:8080\r\nDetect url: http://httpbin.org/get\r\nProxy url: http://218.106.205.145:8080\r\nERROR:root:400, message='invalid constant string'\r\n```\r\n\r\n## Steps to reproduce\r\n\r\nRun the code above to detect the broken proxy like http://218.106.205.145:8080\r\n\r\n## Your environment\r\n\r\naiohttp 3.2.1\r\nMac OS X\r\naiohttp client\r\n\r\n\n", "before_files": [{"content": "from contextlib import suppress\n\nfrom .base_protocol import BaseProtocol\nfrom .client_exceptions import (ClientOSError, ClientPayloadError,\n                                ServerDisconnectedError, ServerTimeoutError)\nfrom .http import HttpResponseParser\nfrom .streams import EMPTY_PAYLOAD, DataQueue\n\n\nclass ResponseHandler(BaseProtocol, DataQueue):\n    \"\"\"Helper class to adapt between Protocol and StreamReader.\"\"\"\n\n    def __init__(self, *, loop=None):\n        BaseProtocol.__init__(self, loop=loop)\n        DataQueue.__init__(self, loop=loop)\n\n        self._should_close = False\n\n        self._payload = None\n        self._skip_payload = False\n        self._payload_parser = None\n        self._reading_paused = False\n\n        self._timer = None\n\n        self._tail = b''\n        self._upgraded = False\n        self._parser = None\n\n        self._read_timeout = None\n        self._read_timeout_handle = None\n\n    @property\n    def upgraded(self):\n        return self._upgraded\n\n    @property\n    def should_close(self):\n        if (self._payload is not None and\n                not self._payload.is_eof() or self._upgraded):\n            return True\n\n        return (self._should_close or self._upgraded or\n                self.exception() is not None or\n                self._payload_parser is not None or\n                len(self) or self._tail)\n\n    def force_close(self):\n        self._should_close = True\n\n    def close(self):\n        transport = self.transport\n        if transport is not None:\n            transport.close()\n            self.transport = None\n            self._payload = None\n            self._drop_timeout()\n        return transport\n\n    def is_connected(self):\n        return self.transport is not None\n\n    def connection_lost(self, exc):\n        self._drop_timeout()\n\n        if self._payload_parser is not None:\n            with suppress(Exception):\n                self._payload_parser.feed_eof()\n\n        try:\n            uncompleted = self._parser.feed_eof()\n        except Exception:\n            uncompleted = None\n            if self._payload is not None:\n                self._payload.set_exception(\n                    ClientPayloadError('Response payload is not completed'))\n\n        if not self.is_eof():\n            if isinstance(exc, OSError):\n                exc = ClientOSError(*exc.args)\n            if exc is None:\n                exc = ServerDisconnectedError(uncompleted)\n            # assigns self._should_close to True as side effect,\n            # we do it anyway below\n            self.set_exception(exc)\n\n        self._should_close = True\n        self._parser = None\n        self._payload = None\n        self._payload_parser = None\n        self._reading_paused = False\n\n        super().connection_lost(exc)\n\n    def eof_received(self):\n        # should call parser.feed_eof() most likely\n        self._drop_timeout()\n\n    def pause_reading(self):\n        if not self._reading_paused:\n            try:\n                self.transport.pause_reading()\n            except (AttributeError, NotImplementedError, RuntimeError):\n                pass\n            self._reading_paused = True\n            self._drop_timeout()\n\n    def resume_reading(self):\n        if self._reading_paused:\n            try:\n                self.transport.resume_reading()\n            except (AttributeError, NotImplementedError, RuntimeError):\n                pass\n            self._reading_paused = False\n            self._reschedule_timeout()\n\n    def set_exception(self, exc):\n        self._should_close = True\n        self._drop_timeout()\n        super().set_exception(exc)\n\n    def set_parser(self, parser, payload):\n        self._payload = payload\n        self._payload_parser = parser\n\n        self._drop_timeout()\n\n        if self._tail:\n            data, self._tail = self._tail, b''\n            self.data_received(data)\n\n    def set_response_params(self, *, timer=None,\n                            skip_payload=False,\n                            read_until_eof=False,\n                            auto_decompress=True,\n                            read_timeout=None):\n        self._skip_payload = skip_payload\n\n        self._read_timeout = read_timeout\n        self._reschedule_timeout()\n\n        self._parser = HttpResponseParser(\n            self, self._loop, timer=timer,\n            payload_exception=ClientPayloadError,\n            read_until_eof=read_until_eof,\n            auto_decompress=auto_decompress)\n\n        if self._tail:\n            data, self._tail = self._tail, b''\n            self.data_received(data)\n\n    def _drop_timeout(self):\n        if self._read_timeout_handle is not None:\n            self._read_timeout_handle.cancel()\n            self._read_timeout_handle = None\n\n    def _reschedule_timeout(self):\n        timeout = self._read_timeout\n        if self._read_timeout_handle is not None:\n            self._read_timeout_handle.cancel()\n\n        if timeout:\n            self._read_timeout_handle = self._loop.call_later(\n                timeout, self._on_read_timeout)\n        else:\n            self._read_timeout_handle = None\n\n    def _on_read_timeout(self):\n        exc = ServerTimeoutError(\"Timeout on reading data from socket\")\n        self.set_exception(exc)\n        if self._payload is not None:\n            self._payload.set_exception(exc)\n\n    def data_received(self, data):\n        if not data:\n            return\n\n        # custom payload parser\n        if self._payload_parser is not None:\n            eof, tail = self._payload_parser.feed_data(data)\n            if eof:\n                self._payload = None\n                self._payload_parser = None\n\n                if tail:\n                    self.data_received(tail)\n            return\n        else:\n            if self._upgraded or self._parser is None:\n                # i.e. websocket connection, websocket parser is not set yet\n                self._tail += data\n            else:\n                # parse http messages\n                try:\n                    messages, upgraded, tail = self._parser.feed_data(data)\n                except BaseException as exc:\n                    self.transport.close()\n                    # should_close is True after the call\n                    self.set_exception(exc)\n                    return\n\n                self._upgraded = upgraded\n\n                payload = None\n                for message, payload in messages:\n                    if message.should_close:\n                        self._should_close = True\n\n                    self._payload = payload\n\n                    if self._skip_payload or message.code in (204, 304):\n                        self.feed_data((message, EMPTY_PAYLOAD), 0)\n                    else:\n                        self.feed_data((message, payload), 0)\n                if payload is not None:\n                    # new message(s) was processed\n                    # register timeout handler unsubscribing\n                    # either on end-of-stream or immediatelly for\n                    # EMPTY_PAYLOAD\n                    if payload is not EMPTY_PAYLOAD:\n                        payload.on_eof(self._drop_timeout)\n                    else:\n                        self._drop_timeout()\n\n                if tail:\n                    if upgraded:\n                        self.data_received(tail)\n                    else:\n                        self._tail = tail\n", "path": "aiohttp/client_proto.py"}], "after_files": [{"content": "from contextlib import suppress\n\nfrom .base_protocol import BaseProtocol\nfrom .client_exceptions import (ClientOSError, ClientPayloadError,\n                                ServerDisconnectedError, ServerTimeoutError)\nfrom .http import HttpResponseParser\nfrom .streams import EMPTY_PAYLOAD, DataQueue\n\n\nclass ResponseHandler(BaseProtocol, DataQueue):\n    \"\"\"Helper class to adapt between Protocol and StreamReader.\"\"\"\n\n    def __init__(self, *, loop=None):\n        BaseProtocol.__init__(self, loop=loop)\n        DataQueue.__init__(self, loop=loop)\n\n        self._should_close = False\n\n        self._payload = None\n        self._skip_payload = False\n        self._payload_parser = None\n        self._reading_paused = False\n\n        self._timer = None\n\n        self._tail = b''\n        self._upgraded = False\n        self._parser = None\n\n        self._read_timeout = None\n        self._read_timeout_handle = None\n\n    @property\n    def upgraded(self):\n        return self._upgraded\n\n    @property\n    def should_close(self):\n        if (self._payload is not None and\n                not self._payload.is_eof() or self._upgraded):\n            return True\n\n        return (self._should_close or self._upgraded or\n                self.exception() is not None or\n                self._payload_parser is not None or\n                len(self) or self._tail)\n\n    def force_close(self):\n        self._should_close = True\n\n    def close(self):\n        transport = self.transport\n        if transport is not None:\n            transport.close()\n            self.transport = None\n            self._payload = None\n            self._drop_timeout()\n        return transport\n\n    def is_connected(self):\n        return self.transport is not None\n\n    def connection_lost(self, exc):\n        self._drop_timeout()\n\n        if self._payload_parser is not None:\n            with suppress(Exception):\n                self._payload_parser.feed_eof()\n\n        try:\n            uncompleted = self._parser.feed_eof()\n        except Exception:\n            uncompleted = None\n            if self._payload is not None:\n                self._payload.set_exception(\n                    ClientPayloadError('Response payload is not completed'))\n\n        if not self.is_eof():\n            if isinstance(exc, OSError):\n                exc = ClientOSError(*exc.args)\n            if exc is None:\n                exc = ServerDisconnectedError(uncompleted)\n            # assigns self._should_close to True as side effect,\n            # we do it anyway below\n            self.set_exception(exc)\n\n        self._should_close = True\n        self._parser = None\n        self._payload = None\n        self._payload_parser = None\n        self._reading_paused = False\n\n        super().connection_lost(exc)\n\n    def eof_received(self):\n        # should call parser.feed_eof() most likely\n        self._drop_timeout()\n\n    def pause_reading(self):\n        if not self._reading_paused:\n            try:\n                self.transport.pause_reading()\n            except (AttributeError, NotImplementedError, RuntimeError):\n                pass\n            self._reading_paused = True\n            self._drop_timeout()\n\n    def resume_reading(self):\n        if self._reading_paused:\n            try:\n                self.transport.resume_reading()\n            except (AttributeError, NotImplementedError, RuntimeError):\n                pass\n            self._reading_paused = False\n            self._reschedule_timeout()\n\n    def set_exception(self, exc):\n        self._should_close = True\n        self._drop_timeout()\n        super().set_exception(exc)\n\n    def set_parser(self, parser, payload):\n        self._payload = payload\n        self._payload_parser = parser\n\n        self._drop_timeout()\n\n        if self._tail:\n            data, self._tail = self._tail, b''\n            self.data_received(data)\n\n    def set_response_params(self, *, timer=None,\n                            skip_payload=False,\n                            read_until_eof=False,\n                            auto_decompress=True,\n                            read_timeout=None):\n        self._skip_payload = skip_payload\n\n        self._read_timeout = read_timeout\n        self._reschedule_timeout()\n\n        self._parser = HttpResponseParser(\n            self, self._loop, timer=timer,\n            payload_exception=ClientPayloadError,\n            read_until_eof=read_until_eof,\n            auto_decompress=auto_decompress)\n\n        if self._tail:\n            data, self._tail = self._tail, b''\n            self.data_received(data)\n\n    def _drop_timeout(self):\n        if self._read_timeout_handle is not None:\n            self._read_timeout_handle.cancel()\n            self._read_timeout_handle = None\n\n    def _reschedule_timeout(self):\n        timeout = self._read_timeout\n        if self._read_timeout_handle is not None:\n            self._read_timeout_handle.cancel()\n\n        if timeout:\n            self._read_timeout_handle = self._loop.call_later(\n                timeout, self._on_read_timeout)\n        else:\n            self._read_timeout_handle = None\n\n    def _on_read_timeout(self):\n        exc = ServerTimeoutError(\"Timeout on reading data from socket\")\n        self.set_exception(exc)\n        if self._payload is not None:\n            self._payload.set_exception(exc)\n\n    def data_received(self, data):\n        if not data:\n            return\n\n        # custom payload parser\n        if self._payload_parser is not None:\n            eof, tail = self._payload_parser.feed_data(data)\n            if eof:\n                self._payload = None\n                self._payload_parser = None\n\n                if tail:\n                    self.data_received(tail)\n            return\n        else:\n            if self._upgraded or self._parser is None:\n                # i.e. websocket connection, websocket parser is not set yet\n                self._tail += data\n            else:\n                # parse http messages\n                try:\n                    messages, upgraded, tail = self._parser.feed_data(data)\n                except BaseException as exc:\n                    if self.transport is not None:\n                        # connection.release() could be called BEFORE\n                        # data_received(), the transport is already\n                        # closed in this case\n                        self.transport.close()\n                    # should_close is True after the call\n                    self.set_exception(exc)\n                    return\n\n                self._upgraded = upgraded\n\n                payload = None\n                for message, payload in messages:\n                    if message.should_close:\n                        self._should_close = True\n\n                    self._payload = payload\n\n                    if self._skip_payload or message.code in (204, 304):\n                        self.feed_data((message, EMPTY_PAYLOAD), 0)\n                    else:\n                        self.feed_data((message, payload), 0)\n                if payload is not None:\n                    # new message(s) was processed\n                    # register timeout handler unsubscribing\n                    # either on end-of-stream or immediatelly for\n                    # EMPTY_PAYLOAD\n                    if payload is not EMPTY_PAYLOAD:\n                        payload.on_eof(self._drop_timeout)\n                    else:\n                        self._drop_timeout()\n\n                if tail:\n                    if upgraded:\n                        self.data_received(tail)\n                    else:\n                        self._tail = tail\n", "path": "aiohttp/client_proto.py"}]}