We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Catch `HttpParserInvalidMethodError` exception
`uvicorn==0.1.1` is throwing these errors

```
uvicorn[7423]: Unhandled exception in event loop
uvicorn[7423]: Traceback (most recent call last):
uvicorn[7423]:   File "uvloop/handles/stream.pyx", line 784, in uvloop.loop.__uv_stream_on_read_impl
uvicorn[7423]:   File "uvloop/handles/stream.pyx", line 563, in uvloop.loop.UVStream._on_read
uvicorn[7423]:   File "/home/web/.virtualenvs/mesh/lib/python3.5/site-packages/uvicorn/protocols/http.py", line 212, in data_received
uvicorn[7423]:     self.request_parser.feed_data(data)
uvicorn[7423]:   File "httptools/parser/parser.pyx", line 193, in httptools.parser.parser.HttpParser.feed_data
uvicorn[7423]: httptools.parser.errors.HttpParserInvalidMethodError: invalid HTTP method
```

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `uvicorn/protocols/http/httptools.py`
Content:
```
1 import asyncio
2 from email.utils import formatdate
3 import http
4 import logging
5 import time
6 import traceback
7 from urllib.parse import unquote
8 from uvicorn.protocols.websockets.websockets import websocket_upgrade
9 
10 import httptools
11 
12 
13 def _get_default_headers():
14     current_time = time.time()
15     current_date = formatdate(current_time, usegmt=True).encode()
16     return b"".join([b"server: uvicorn\r\ndate: ", current_date, b"\r\n"])
17 
18 
19 def _get_status_line(status_code):
20     try:
21         phrase = http.HTTPStatus(status_code).phrase.encode()
22     except ValueError:
23         phrase = b""
24     return b"".join([b"HTTP/1.1 ", str(status_code).encode(), b" ", phrase, b"\r\n"])
25 
26 
27 STATUS_LINE = {
28     status_code: _get_status_line(status_code) for status_code in range(100, 600)
29 }
30 
31 DEFAULT_HEADERS = _get_default_headers()
32 
33 
34 class HttpToolsProtocol(asyncio.Protocol):
35     __slots__ = (
36         'app', 'loop', 'state', 'logger', 'access_logs', 'parser',
37         'transport', 'server', 'client', 'scheme',
38         'scope', 'headers', 'cycle', 'client_event',
39         'readable', 'writable', 'writable_event'
40     )
41 
42     def __init__(self, app, loop=None, state=None, logger=None):
43         self.app = app
44         self.loop = loop or asyncio.get_event_loop()
45         self.state = {"total_requests": 0} if state is None else state
46         self.logger = logger or logging.getLogger()
47         self.access_logs = self.logger.level >= logging.INFO
48         self.parser = httptools.HttpRequestParser(self)
49 
50         # Per-connection state
51         self.transport = None
52         self.server = None
53         self.client = None
54         self.scheme = None
55 
56         # Per-request state
57         self.scope = None
58         self.headers = None
59         self.cycle = None
60         self.client_event = asyncio.Event()
61 
62         # Flow control
63         self.readable = True
64         self.writable = True
65         self.writable_event = asyncio.Event()
66         self.writable_event.set()
67 
68     @classmethod
69     def tick(cls):
70         global DEFAULT_HEADERS
71         DEFAULT_HEADERS = _get_default_headers()
72 
73     # Protocol interface
74     def connection_made(self, transport):
75         self.transport = transport
76         self.server = transport.get_extra_info("sockname")
77         self.client = transport.get_extra_info("peername")
78         self.scheme = "https" if transport.get_extra_info("sslcontext") else "http"
79         if self.access_logs:
80             self.logger.debug("%s - Connected", self.server[0])
81 
82     def connection_lost(self, exc):
83         if self.access_logs:
84             self.logger.debug("%s - Disconnected", self.server[0])
85 
86         if self.cycle and self.cycle.more_body:
87             self.cycle.disconnected = True
88         self.client_event.set()
89 
90     def eof_received(self):
91         pass
92 
93     def data_received(self, data):
94         try:
95             self.parser.feed_data(data)
96         except httptools.HttpParserUpgrade:
97             websocket_upgrade(self)
98 
99     # Parser callbacks
100     def on_url(self, url):
101         method = self.parser.get_method()
102         parsed_url = httptools.parse_url(url)
103         self.headers = []
104         self.scope = {
105             "type": "http",
106             "http_version": "1.1",
107             "server": self.server,
108             "client": self.client,
109             "scheme": self.scheme,
110             "method": method.decode("ascii"),
111             "path": parsed_url.path.decode("ascii"),
112             "query_string": parsed_url.query if parsed_url.query else b"",
113             "headers": self.headers,
114         }
115 
116     def on_header(self, name: bytes, value: bytes):
117         self.headers.append((name.lower(), value))
118 
119     def on_headers_complete(self):
120         http_version = self.parser.get_http_version()
121         if http_version != "1.1":
122             self.scope["http_version"] = http_version
123         if self.parser.should_upgrade():
124             return
125         self.cycle = RequestResponseCycle(self.scope, self)
126         self.loop.create_task(self.cycle.run_asgi(self.app))
127 
128     def on_body(self, body: bytes):
129         if self.parser.should_upgrade() or self.cycle.response_complete:
130             return
131         self.cycle.body += body
132         self.pause_reading()
133         self.client_event.set()
134 
135     def on_message_complete(self):
136         if self.parser.should_upgrade() or self.cycle.response_complete:
137             return
138         self.cycle.more_body = False
139         self.pause_reading()
140         self.client_event.set()
141 
142     # Flow control
143     def pause_reading(self):
144         if self.readable:
145             self.readable = False
146             self.transport.pause_reading()
147 
148     def resume_reading(self):
149         if not self.readable:
150             self.readable = True
151             self.transport.resume_reading()
152 
153     def pause_writing(self):
154         if self.writable:
155             self.writable = False
156             self.writable_event.clear()
157 
158     def resume_writing(self):
159         if not self.writable:
160             self.writable = True
161             self.writable_event.set()
162 
163 
164 class RequestResponseCycle:
165     __slots__ = (
166         'scope', 'protocol',
167         'body', 'more_body', 'disconnected', 'receive_finished',
168         'response_started', 'response_complete', 'keep_alive', 'chunked_encoding', 'expected_content_length'
169     )
170 
171     def __init__(self, scope, protocol):
172         self.scope = scope
173         self.protocol = protocol
174 
175         # Request state
176         self.body = b""
177         self.more_body = True
178         self.disconnected = False
179         self.receive_finished = False
180 
181         # Response state
182         self.response_started = False
183         self.response_complete = False
184         self.keep_alive = True
185         self.chunked_encoding = None
186         self.expected_content_length = 0
187 
188     # ASGI exception wrapper
189     async def run_asgi(self, app):
190         try:
191             asgi = app(self.scope)
192             result = await asgi(self.receive, self.send)
193         except:
194             msg = "Exception in ASGI application\n%s"
195             traceback_text = "".join(traceback.format_exc())
196             self.protocol.logger.error(msg, traceback_text)
197             if not self.response_started:
198                 await self.send_500_response()
199             else:
200                 self.protocol.transport.close()
201         else:
202             if not self.response_started:
203                 msg = "ASGI callable returned without starting response."
204                 self.protocol.logger.error(msg)
205                 await self.send_500_response()
206             elif not self.response_complete:
207                 msg = "ASGI callable returned without completing response."
208                 self.protocol.logger.error(msg)
209                 self.protocol.transport.close()
210             elif result is not None:
211                 msg = "ASGI callable should return None, but returned '%s'."
212                 self.protocol.logger.error(msg, result)
213                 self.protocol.transport.close()
214         finally:
215             self.protocol.state["total_requests"] += 1
216 
217     async def send_500_response(self):
218         await self.send(
219             {
220                 "type": "http.response.start",
221                 "status": 500,
222                 "headers": [
223                     (b"content-type", b"text/plain; charset=utf-8"),
224                     (b"connection", b"close"),
225                 ],
226             }
227         )
228         await self.send(
229             {"type": "http.response.body", "body": b"Internal Server Error"}
230         )
231 
232     # ASGI interface
233     async def send(self, message):
234         protocol = self.protocol
235         message_type = message["type"]
236 
237         if not protocol.writable:
238             await protocol.writable_event.wait()
239 
240         if not self.response_started:
241             # Sending response status line and headers
242             if message_type != "http.response.start":
243                 msg = "Expected ASGI message 'http.response.start', but got '%s'."
244                 raise RuntimeError(msg % message_type)
245 
246             self.response_started = True
247 
248             status_code = message["status"]
249             headers = message.get("headers", [])
250 
251             if protocol.access_logs:
252                 protocol.logger.info(
253                     '%s - "%s %s HTTP/%s" %d',
254                     self.scope["server"][0],
255                     self.scope["method"],
256                     self.scope["path"],
257                     self.scope["http_version"],
258                     status_code,
259                 )
260 
261             # Write response status line and headers
262             content = [STATUS_LINE[status_code], DEFAULT_HEADERS]
263 
264             for name, value in headers:
265                 name = name.lower()
266                 if name == b"content-length" and self.chunked_encoding is None:
267                     self.expected_content_length = int(value.decode())
268                     self.chunked_encoding = False
269                 elif name == b"transfer-encoding" and value.lower() == b"chunked":
270                     self.chunked_encoding = True
271                 elif name == b"connection" and value.lower() == b"close":
272                     self.keep_alive = False
273                 content.extend([name, b": ", value, b"\r\n"])
274 
275             if self.chunked_encoding is None:
276                 # Neither content-length nor transfer-encoding specified
277                 self.chunked_encoding = True
278                 content.append(b"transfer-encoding: chunked\r\n")
279 
280             content.append(b"\r\n")
281             protocol.transport.write(b"".join(content))
282 
283         elif not self.response_complete:
284             # Sending response body
285             if message_type != "http.response.body":
286                 msg = "Expected ASGI message 'http.response.body', but got '%s'."
287                 raise RuntimeError(msg % message_type)
288 
289             body = message.get("body", b"")
290             more_body = message.get("more_body", False)
291 
292             # Write response body
293             if self.chunked_encoding:
294                 content = [b"%x\r\n" % len(body), body, b"\r\n"]
295                 if not more_body:
296                     content.append(b"0\r\n\r\n")
297                 protocol.transport.write(b"".join(content))
298             else:
299                 num_bytes = len(body)
300                 if num_bytes > self.expected_content_length:
301                     raise RuntimeError("Response content longer than Content-Length")
302                 else:
303                     self.expected_content_length -= num_bytes
304                 protocol.transport.write(body)
305 
306             # Handle response completion
307             if not more_body:
308                 if self.expected_content_length != 0:
309                     raise RuntimeError("Response content shorter than Content-Length")
310                 self.response_complete = True
311                 if not self.keep_alive:
312                     protocol.transport.close()
313                 else:
314                     protocol.resume_reading()
315         else:
316             # Response already sent
317             msg = "Unexpected ASGI message '%s' sent, after response already completed."
318             raise RuntimeError(msg % message_type)
319 
320     async def receive(self):
321         protocol = self.protocol
322 
323         if self.receive_finished:
324             msg = "Receive channel fully consumed."
325             raise RuntimeError(msg)
326 
327         if self.more_body and not self.body and not self.disconnected:
328             protocol.resume_reading()
329             await protocol.client_event.wait()
330             protocol.client_event.clear()
331 
332         if self.disconnected:
333             message = {"type": "http.disconnect"}
334             self.receive_finished = True
335         else:
336             message = {
337                 "type": "http.request",
338                 "body": self.body,
339                 "more_body": self.more_body,
340             }
341             self.receive_finished = not (self.more_body)
342             self.body = b""
343             protocol.resume_reading()
344 
345         return message
346
```
--- 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/uvicorn/protocols/http/httptools.py b/uvicorn/protocols/http/httptools.py
--- a/uvicorn/protocols/http/httptools.py
+++ b/uvicorn/protocols/http/httptools.py
@@ -93,6 +93,10 @@
     def data_received(self, data):
         try:
             self.parser.feed_data(data)
+        except httptools.parser.errors.HttpParserError:
+            msg = "Invalid HTTP request received."
+            self.logger.warn(msg)
+            self.transport.close()
         except httptools.HttpParserUpgrade:
             websocket_upgrade(self)

{"golden_diff": "diff --git a/uvicorn/protocols/http/httptools.py b/uvicorn/protocols/http/httptools.py\n--- a/uvicorn/protocols/http/httptools.py\n+++ b/uvicorn/protocols/http/httptools.py\n@@ -93,6 +93,10 @@\n     def data_received(self, data):\n         try:\n             self.parser.feed_data(data)\n+        except httptools.parser.errors.HttpParserError:\n+            msg = \"Invalid HTTP request received.\"\n+            self.logger.warn(msg)\n+            self.transport.close()\n         except httptools.HttpParserUpgrade:\n             websocket_upgrade(self)\n", "issue": "Catch `HttpParserInvalidMethodError` exception\n`uvicorn==0.1.1` is throwing these errors\r\n\r\n```\r\nuvicorn[7423]: Unhandled exception in event loop\r\nuvicorn[7423]: Traceback (most recent call last):\r\nuvicorn[7423]:   File \"uvloop/handles/stream.pyx\", line 784, in uvloop.loop.__uv_stream_on_read_impl\r\nuvicorn[7423]:   File \"uvloop/handles/stream.pyx\", line 563, in uvloop.loop.UVStream._on_read\r\nuvicorn[7423]:   File \"/home/web/.virtualenvs/mesh/lib/python3.5/site-packages/uvicorn/protocols/http.py\", line 212, in data_received\r\nuvicorn[7423]:     self.request_parser.feed_data(data)\r\nuvicorn[7423]:   File \"httptools/parser/parser.pyx\", line 193, in httptools.parser.parser.HttpParser.feed_data\r\nuvicorn[7423]: httptools.parser.errors.HttpParserInvalidMethodError: invalid HTTP method\r\n```\n", "before_files": [{"content": "import asyncio\nfrom email.utils import formatdate\nimport http\nimport logging\nimport time\nimport traceback\nfrom urllib.parse import unquote\nfrom uvicorn.protocols.websockets.websockets import websocket_upgrade\n\nimport httptools\n\n\ndef _get_default_headers():\n    current_time = time.time()\n    current_date = formatdate(current_time, usegmt=True).encode()\n    return b\"\".join([b\"server: uvicorn\\r\\ndate: \", current_date, b\"\\r\\n\"])\n\n\ndef _get_status_line(status_code):\n    try:\n        phrase = http.HTTPStatus(status_code).phrase.encode()\n    except ValueError:\n        phrase = b\"\"\n    return b\"\".join([b\"HTTP/1.1 \", str(status_code).encode(), b\" \", phrase, b\"\\r\\n\"])\n\n\nSTATUS_LINE = {\n    status_code: _get_status_line(status_code) for status_code in range(100, 600)\n}\n\nDEFAULT_HEADERS = _get_default_headers()\n\n\nclass HttpToolsProtocol(asyncio.Protocol):\n    __slots__ = (\n        'app', 'loop', 'state', 'logger', 'access_logs', 'parser',\n        'transport', 'server', 'client', 'scheme',\n        'scope', 'headers', 'cycle', 'client_event',\n        'readable', 'writable', 'writable_event'\n    )\n\n    def __init__(self, app, loop=None, state=None, logger=None):\n        self.app = app\n        self.loop = loop or asyncio.get_event_loop()\n        self.state = {\"total_requests\": 0} if state is None else state\n        self.logger = logger or logging.getLogger()\n        self.access_logs = self.logger.level >= logging.INFO\n        self.parser = httptools.HttpRequestParser(self)\n\n        # Per-connection state\n        self.transport = None\n        self.server = None\n        self.client = None\n        self.scheme = None\n\n        # Per-request state\n        self.scope = None\n        self.headers = None\n        self.cycle = None\n        self.client_event = asyncio.Event()\n\n        # Flow control\n        self.readable = True\n        self.writable = True\n        self.writable_event = asyncio.Event()\n        self.writable_event.set()\n\n    @classmethod\n    def tick(cls):\n        global DEFAULT_HEADERS\n        DEFAULT_HEADERS = _get_default_headers()\n\n    # Protocol interface\n    def connection_made(self, transport):\n        self.transport = transport\n        self.server = transport.get_extra_info(\"sockname\")\n        self.client = transport.get_extra_info(\"peername\")\n        self.scheme = \"https\" if transport.get_extra_info(\"sslcontext\") else \"http\"\n        if self.access_logs:\n            self.logger.debug(\"%s - Connected\", self.server[0])\n\n    def connection_lost(self, exc):\n        if self.access_logs:\n            self.logger.debug(\"%s - Disconnected\", self.server[0])\n\n        if self.cycle and self.cycle.more_body:\n            self.cycle.disconnected = True\n        self.client_event.set()\n\n    def eof_received(self):\n        pass\n\n    def data_received(self, data):\n        try:\n            self.parser.feed_data(data)\n        except httptools.HttpParserUpgrade:\n            websocket_upgrade(self)\n\n    # Parser callbacks\n    def on_url(self, url):\n        method = self.parser.get_method()\n        parsed_url = httptools.parse_url(url)\n        self.headers = []\n        self.scope = {\n            \"type\": \"http\",\n            \"http_version\": \"1.1\",\n            \"server\": self.server,\n            \"client\": self.client,\n            \"scheme\": self.scheme,\n            \"method\": method.decode(\"ascii\"),\n            \"path\": parsed_url.path.decode(\"ascii\"),\n            \"query_string\": parsed_url.query if parsed_url.query else b\"\",\n            \"headers\": self.headers,\n        }\n\n    def on_header(self, name: bytes, value: bytes):\n        self.headers.append((name.lower(), value))\n\n    def on_headers_complete(self):\n        http_version = self.parser.get_http_version()\n        if http_version != \"1.1\":\n            self.scope[\"http_version\"] = http_version\n        if self.parser.should_upgrade():\n            return\n        self.cycle = RequestResponseCycle(self.scope, self)\n        self.loop.create_task(self.cycle.run_asgi(self.app))\n\n    def on_body(self, body: bytes):\n        if self.parser.should_upgrade() or self.cycle.response_complete:\n            return\n        self.cycle.body += body\n        self.pause_reading()\n        self.client_event.set()\n\n    def on_message_complete(self):\n        if self.parser.should_upgrade() or self.cycle.response_complete:\n            return\n        self.cycle.more_body = False\n        self.pause_reading()\n        self.client_event.set()\n\n    # Flow control\n    def pause_reading(self):\n        if self.readable:\n            self.readable = False\n            self.transport.pause_reading()\n\n    def resume_reading(self):\n        if not self.readable:\n            self.readable = True\n            self.transport.resume_reading()\n\n    def pause_writing(self):\n        if self.writable:\n            self.writable = False\n            self.writable_event.clear()\n\n    def resume_writing(self):\n        if not self.writable:\n            self.writable = True\n            self.writable_event.set()\n\n\nclass RequestResponseCycle:\n    __slots__ = (\n        'scope', 'protocol',\n        'body', 'more_body', 'disconnected', 'receive_finished',\n        'response_started', 'response_complete', 'keep_alive', 'chunked_encoding', 'expected_content_length'\n    )\n\n    def __init__(self, scope, protocol):\n        self.scope = scope\n        self.protocol = protocol\n\n        # Request state\n        self.body = b\"\"\n        self.more_body = True\n        self.disconnected = False\n        self.receive_finished = False\n\n        # Response state\n        self.response_started = False\n        self.response_complete = False\n        self.keep_alive = True\n        self.chunked_encoding = None\n        self.expected_content_length = 0\n\n    # ASGI exception wrapper\n    async def run_asgi(self, app):\n        try:\n            asgi = app(self.scope)\n            result = await asgi(self.receive, self.send)\n        except:\n            msg = \"Exception in ASGI application\\n%s\"\n            traceback_text = \"\".join(traceback.format_exc())\n            self.protocol.logger.error(msg, traceback_text)\n            if not self.response_started:\n                await self.send_500_response()\n            else:\n                self.protocol.transport.close()\n        else:\n            if not self.response_started:\n                msg = \"ASGI callable returned without starting response.\"\n                self.protocol.logger.error(msg)\n                await self.send_500_response()\n            elif not self.response_complete:\n                msg = \"ASGI callable returned without completing response.\"\n                self.protocol.logger.error(msg)\n                self.protocol.transport.close()\n            elif result is not None:\n                msg = \"ASGI callable should return None, but returned '%s'.\"\n                self.protocol.logger.error(msg, result)\n                self.protocol.transport.close()\n        finally:\n            self.protocol.state[\"total_requests\"] += 1\n\n    async def send_500_response(self):\n        await self.send(\n            {\n                \"type\": \"http.response.start\",\n                \"status\": 500,\n                \"headers\": [\n                    (b\"content-type\", b\"text/plain; charset=utf-8\"),\n                    (b\"connection\", b\"close\"),\n                ],\n            }\n        )\n        await self.send(\n            {\"type\": \"http.response.body\", \"body\": b\"Internal Server Error\"}\n        )\n\n    # ASGI interface\n    async def send(self, message):\n        protocol = self.protocol\n        message_type = message[\"type\"]\n\n        if not protocol.writable:\n            await protocol.writable_event.wait()\n\n        if not self.response_started:\n            # Sending response status line and headers\n            if message_type != \"http.response.start\":\n                msg = \"Expected ASGI message 'http.response.start', but got '%s'.\"\n                raise RuntimeError(msg % message_type)\n\n            self.response_started = True\n\n            status_code = message[\"status\"]\n            headers = message.get(\"headers\", [])\n\n            if protocol.access_logs:\n                protocol.logger.info(\n                    '%s - \"%s %s HTTP/%s\" %d',\n                    self.scope[\"server\"][0],\n                    self.scope[\"method\"],\n                    self.scope[\"path\"],\n                    self.scope[\"http_version\"],\n                    status_code,\n                )\n\n            # Write response status line and headers\n            content = [STATUS_LINE[status_code], DEFAULT_HEADERS]\n\n            for name, value in headers:\n                name = name.lower()\n                if name == b\"content-length\" and self.chunked_encoding is None:\n                    self.expected_content_length = int(value.decode())\n                    self.chunked_encoding = False\n                elif name == b\"transfer-encoding\" and value.lower() == b\"chunked\":\n                    self.chunked_encoding = True\n                elif name == b\"connection\" and value.lower() == b\"close\":\n                    self.keep_alive = False\n                content.extend([name, b\": \", value, b\"\\r\\n\"])\n\n            if self.chunked_encoding is None:\n                # Neither content-length nor transfer-encoding specified\n                self.chunked_encoding = True\n                content.append(b\"transfer-encoding: chunked\\r\\n\")\n\n            content.append(b\"\\r\\n\")\n            protocol.transport.write(b\"\".join(content))\n\n        elif not self.response_complete:\n            # Sending response body\n            if message_type != \"http.response.body\":\n                msg = \"Expected ASGI message 'http.response.body', but got '%s'.\"\n                raise RuntimeError(msg % message_type)\n\n            body = message.get(\"body\", b\"\")\n            more_body = message.get(\"more_body\", False)\n\n            # Write response body\n            if self.chunked_encoding:\n                content = [b\"%x\\r\\n\" % len(body), body, b\"\\r\\n\"]\n                if not more_body:\n                    content.append(b\"0\\r\\n\\r\\n\")\n                protocol.transport.write(b\"\".join(content))\n            else:\n                num_bytes = len(body)\n                if num_bytes > self.expected_content_length:\n                    raise RuntimeError(\"Response content longer than Content-Length\")\n                else:\n                    self.expected_content_length -= num_bytes\n                protocol.transport.write(body)\n\n            # Handle response completion\n            if not more_body:\n                if self.expected_content_length != 0:\n                    raise RuntimeError(\"Response content shorter than Content-Length\")\n                self.response_complete = True\n                if not self.keep_alive:\n                    protocol.transport.close()\n                else:\n                    protocol.resume_reading()\n        else:\n            # Response already sent\n            msg = \"Unexpected ASGI message '%s' sent, after response already completed.\"\n            raise RuntimeError(msg % message_type)\n\n    async def receive(self):\n        protocol = self.protocol\n\n        if self.receive_finished:\n            msg = \"Receive channel fully consumed.\"\n            raise RuntimeError(msg)\n\n        if self.more_body and not self.body and not self.disconnected:\n            protocol.resume_reading()\n            await protocol.client_event.wait()\n            protocol.client_event.clear()\n\n        if self.disconnected:\n            message = {\"type\": \"http.disconnect\"}\n            self.receive_finished = True\n        else:\n            message = {\n                \"type\": \"http.request\",\n                \"body\": self.body,\n                \"more_body\": self.more_body,\n            }\n            self.receive_finished = not (self.more_body)\n            self.body = b\"\"\n            protocol.resume_reading()\n\n        return message\n", "path": "uvicorn/protocols/http/httptools.py"}], "after_files": [{"content": "import asyncio\nfrom email.utils import formatdate\nimport http\nimport logging\nimport time\nimport traceback\nfrom urllib.parse import unquote\nfrom uvicorn.protocols.websockets.websockets import websocket_upgrade\n\nimport httptools\n\n\ndef _get_default_headers():\n    current_time = time.time()\n    current_date = formatdate(current_time, usegmt=True).encode()\n    return b\"\".join([b\"server: uvicorn\\r\\ndate: \", current_date, b\"\\r\\n\"])\n\n\ndef _get_status_line(status_code):\n    try:\n        phrase = http.HTTPStatus(status_code).phrase.encode()\n    except ValueError:\n        phrase = b\"\"\n    return b\"\".join([b\"HTTP/1.1 \", str(status_code).encode(), b\" \", phrase, b\"\\r\\n\"])\n\n\nSTATUS_LINE = {\n    status_code: _get_status_line(status_code) for status_code in range(100, 600)\n}\n\nDEFAULT_HEADERS = _get_default_headers()\n\n\nclass HttpToolsProtocol(asyncio.Protocol):\n    __slots__ = (\n        'app', 'loop', 'state', 'logger', 'access_logs', 'parser',\n        'transport', 'server', 'client', 'scheme',\n        'scope', 'headers', 'cycle', 'client_event',\n        'readable', 'writable', 'writable_event'\n    )\n\n    def __init__(self, app, loop=None, state=None, logger=None):\n        self.app = app\n        self.loop = loop or asyncio.get_event_loop()\n        self.state = {\"total_requests\": 0} if state is None else state\n        self.logger = logger or logging.getLogger()\n        self.access_logs = self.logger.level >= logging.INFO\n        self.parser = httptools.HttpRequestParser(self)\n\n        # Per-connection state\n        self.transport = None\n        self.server = None\n        self.client = None\n        self.scheme = None\n\n        # Per-request state\n        self.scope = None\n        self.headers = None\n        self.cycle = None\n        self.client_event = asyncio.Event()\n\n        # Flow control\n        self.readable = True\n        self.writable = True\n        self.writable_event = asyncio.Event()\n        self.writable_event.set()\n\n    @classmethod\n    def tick(cls):\n        global DEFAULT_HEADERS\n        DEFAULT_HEADERS = _get_default_headers()\n\n    # Protocol interface\n    def connection_made(self, transport):\n        self.transport = transport\n        self.server = transport.get_extra_info(\"sockname\")\n        self.client = transport.get_extra_info(\"peername\")\n        self.scheme = \"https\" if transport.get_extra_info(\"sslcontext\") else \"http\"\n        if self.access_logs:\n            self.logger.debug(\"%s - Connected\", self.server[0])\n\n    def connection_lost(self, exc):\n        if self.access_logs:\n            self.logger.debug(\"%s - Disconnected\", self.server[0])\n\n        if self.cycle and self.cycle.more_body:\n            self.cycle.disconnected = True\n        self.client_event.set()\n\n    def eof_received(self):\n        pass\n\n    def data_received(self, data):\n        try:\n            self.parser.feed_data(data)\n        except httptools.parser.errors.HttpParserError:\n            msg = \"Invalid HTTP request received.\"\n            self.logger.warn(msg)\n            self.transport.close()\n        except httptools.HttpParserUpgrade:\n            websocket_upgrade(self)\n\n    # Parser callbacks\n    def on_url(self, url):\n        method = self.parser.get_method()\n        parsed_url = httptools.parse_url(url)\n        self.headers = []\n        self.scope = {\n            \"type\": \"http\",\n            \"http_version\": \"1.1\",\n            \"server\": self.server,\n            \"client\": self.client,\n            \"scheme\": self.scheme,\n            \"method\": method.decode(\"ascii\"),\n            \"path\": parsed_url.path.decode(\"ascii\"),\n            \"query_string\": parsed_url.query if parsed_url.query else b\"\",\n            \"headers\": self.headers,\n        }\n\n    def on_header(self, name: bytes, value: bytes):\n        self.headers.append((name.lower(), value))\n\n    def on_headers_complete(self):\n        http_version = self.parser.get_http_version()\n        if http_version != \"1.1\":\n            self.scope[\"http_version\"] = http_version\n        if self.parser.should_upgrade():\n            return\n        self.cycle = RequestResponseCycle(self.scope, self)\n        self.loop.create_task(self.cycle.run_asgi(self.app))\n\n    def on_body(self, body: bytes):\n        if self.parser.should_upgrade() or self.cycle.response_complete:\n            return\n        self.cycle.body += body\n        self.pause_reading()\n        self.client_event.set()\n\n    def on_message_complete(self):\n        if self.parser.should_upgrade() or self.cycle.response_complete:\n            return\n        self.cycle.more_body = False\n        self.pause_reading()\n        self.client_event.set()\n\n    # Flow control\n    def pause_reading(self):\n        if self.readable:\n            self.readable = False\n            self.transport.pause_reading()\n\n    def resume_reading(self):\n        if not self.readable:\n            self.readable = True\n            self.transport.resume_reading()\n\n    def pause_writing(self):\n        if self.writable:\n            self.writable = False\n            self.writable_event.clear()\n\n    def resume_writing(self):\n        if not self.writable:\n            self.writable = True\n            self.writable_event.set()\n\n\nclass RequestResponseCycle:\n    __slots__ = (\n        'scope', 'protocol',\n        'body', 'more_body', 'disconnected', 'receive_finished',\n        'response_started', 'response_complete', 'keep_alive', 'chunked_encoding', 'expected_content_length'\n    )\n\n    def __init__(self, scope, protocol):\n        self.scope = scope\n        self.protocol = protocol\n\n        # Request state\n        self.body = b\"\"\n        self.more_body = True\n        self.disconnected = False\n        self.receive_finished = False\n\n        # Response state\n        self.response_started = False\n        self.response_complete = False\n        self.keep_alive = True\n        self.chunked_encoding = None\n        self.expected_content_length = 0\n\n    # ASGI exception wrapper\n    async def run_asgi(self, app):\n        try:\n            asgi = app(self.scope)\n            result = await asgi(self.receive, self.send)\n        except:\n            msg = \"Exception in ASGI application\\n%s\"\n            traceback_text = \"\".join(traceback.format_exc())\n            self.protocol.logger.error(msg, traceback_text)\n            if not self.response_started:\n                await self.send_500_response()\n            else:\n                self.protocol.transport.close()\n        else:\n            if not self.response_started:\n                msg = \"ASGI callable returned without starting response.\"\n                self.protocol.logger.error(msg)\n                await self.send_500_response()\n            elif not self.response_complete:\n                msg = \"ASGI callable returned without completing response.\"\n                self.protocol.logger.error(msg)\n                self.protocol.transport.close()\n            elif result is not None:\n                msg = \"ASGI callable should return None, but returned '%s'.\"\n                self.protocol.logger.error(msg, result)\n                self.protocol.transport.close()\n        finally:\n            self.protocol.state[\"total_requests\"] += 1\n\n    async def send_500_response(self):\n        await self.send(\n            {\n                \"type\": \"http.response.start\",\n                \"status\": 500,\n                \"headers\": [\n                    (b\"content-type\", b\"text/plain; charset=utf-8\"),\n                    (b\"connection\", b\"close\"),\n                ],\n            }\n        )\n        await self.send(\n            {\"type\": \"http.response.body\", \"body\": b\"Internal Server Error\"}\n        )\n\n    # ASGI interface\n    async def send(self, message):\n        protocol = self.protocol\n        message_type = message[\"type\"]\n\n        if not protocol.writable:\n            await protocol.writable_event.wait()\n\n        if not self.response_started:\n            # Sending response status line and headers\n            if message_type != \"http.response.start\":\n                msg = \"Expected ASGI message 'http.response.start', but got '%s'.\"\n                raise RuntimeError(msg % message_type)\n\n            self.response_started = True\n\n            status_code = message[\"status\"]\n            headers = message.get(\"headers\", [])\n\n            if protocol.access_logs:\n                protocol.logger.info(\n                    '%s - \"%s %s HTTP/%s\" %d',\n                    self.scope[\"server\"][0],\n                    self.scope[\"method\"],\n                    self.scope[\"path\"],\n                    self.scope[\"http_version\"],\n                    status_code,\n                )\n\n            # Write response status line and headers\n            content = [STATUS_LINE[status_code], DEFAULT_HEADERS]\n\n            for name, value in headers:\n                name = name.lower()\n                if name == b\"content-length\" and self.chunked_encoding is None:\n                    self.expected_content_length = int(value.decode())\n                    self.chunked_encoding = False\n                elif name == b\"transfer-encoding\" and value.lower() == b\"chunked\":\n                    self.chunked_encoding = True\n                elif name == b\"connection\" and value.lower() == b\"close\":\n                    self.keep_alive = False\n                content.extend([name, b\": \", value, b\"\\r\\n\"])\n\n            if self.chunked_encoding is None:\n                # Neither content-length nor transfer-encoding specified\n                self.chunked_encoding = True\n                content.append(b\"transfer-encoding: chunked\\r\\n\")\n\n            content.append(b\"\\r\\n\")\n            protocol.transport.write(b\"\".join(content))\n\n        elif not self.response_complete:\n            # Sending response body\n            if message_type != \"http.response.body\":\n                msg = \"Expected ASGI message 'http.response.body', but got '%s'.\"\n                raise RuntimeError(msg % message_type)\n\n            body = message.get(\"body\", b\"\")\n            more_body = message.get(\"more_body\", False)\n\n            # Write response body\n            if self.chunked_encoding:\n                content = [b\"%x\\r\\n\" % len(body), body, b\"\\r\\n\"]\n                if not more_body:\n                    content.append(b\"0\\r\\n\\r\\n\")\n                protocol.transport.write(b\"\".join(content))\n            else:\n                num_bytes = len(body)\n                if num_bytes > self.expected_content_length:\n                    raise RuntimeError(\"Response content longer than Content-Length\")\n                else:\n                    self.expected_content_length -= num_bytes\n                protocol.transport.write(body)\n\n            # Handle response completion\n            if not more_body:\n                if self.expected_content_length != 0:\n                    raise RuntimeError(\"Response content shorter than Content-Length\")\n                self.response_complete = True\n                if not self.keep_alive:\n                    protocol.transport.close()\n                else:\n                    protocol.resume_reading()\n        else:\n            # Response already sent\n            msg = \"Unexpected ASGI message '%s' sent, after response already completed.\"\n            raise RuntimeError(msg % message_type)\n\n    async def receive(self):\n        protocol = self.protocol\n\n        if self.receive_finished:\n            msg = \"Receive channel fully consumed.\"\n            raise RuntimeError(msg)\n\n        if self.more_body and not self.body and not self.disconnected:\n            protocol.resume_reading()\n            await protocol.client_event.wait()\n            protocol.client_event.clear()\n\n        if self.disconnected:\n            message = {\"type\": \"http.disconnect\"}\n            self.receive_finished = True\n        else:\n            message = {\n                \"type\": \"http.request\",\n                \"body\": self.body,\n                \"more_body\": self.more_body,\n            }\n            self.receive_finished = not (self.more_body)\n            self.body = b\"\"\n            protocol.resume_reading()\n\n        return message\n", "path": "uvicorn/protocols/http/httptools.py"}]}