We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Update 'websockets' to 8.x
I realize that https://github.com/encode/uvicorn/pull/396 was done because the tests appear to be failing with `websockets>=8.0`, but that release also fixed a bunch of DeprecationWarnings that we've been seeing in [httpx builds on 3.8](https://travis-ci.org/encode/httpx/jobs/574949180).

Since it's only a `DeprecationWarning`, and only on 3.8 ([3.7 and below is fine](https://travis-ci.org/encode/httpx/jobs/574949179)), I definitely would agree that this is a low priority issue.

I dug into the tests to try and figure out what exactly was going wrong, but the `AttributeError`s I looked at looks like the main issue is two missing functions in [websockets_impl.py](https://github.com/encode/uvicorn/blob/master/uvicorn/protocols/websockets/websockets_impl.py)

`15 AttributeError: 'Server' object has no attribute 'is_serving'` --> https://github.com/aaugustin/websockets/blob/8.0.2/src/websockets/server.py#L642-L668
` 9 AttributeError: 'WebSocketProtocol' object has no attribute 'transfer_data_task'` --> https://github.com/aaugustin/websockets/blob/8.0.2/src/websockets/protocol.py#L276-L313

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `setup.py`
Content:
```
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3 
4 import os
5 import re
6 import sys
7 import platform
8 
9 from setuptools import setup
10 
11 
12 def get_version(package):
13     """
14     Return package version as listed in `__version__` in `init.py`.
15     """
16     path = os.path.join(package, '__init__.py')
17     init_py = open(path, 'r', encoding='utf8').read()
18     return re.search("__version__ = ['\"]([^'\"]+)['\"]", init_py).group(1)
19 
20 
21 def get_long_description():
22     """
23     Return the README.
24     """
25     return open('README.md', 'r', encoding='utf8').read()
26 
27 
28 def get_packages(package):
29     """
30     Return root package and all sub-packages.
31     """
32     return [dirpath
33             for dirpath, dirnames, filenames in os.walk(package)
34             if os.path.exists(os.path.join(dirpath, '__init__.py'))]
35 
36 
37 env_marker = (
38     "sys_platform != 'win32'"
39     " and sys_platform != 'cygwin'"
40     " and platform_python_implementation != 'pypy'"
41 )
42 
43 requirements = [
44     "click==7.*",
45     "h11==0.8.*",
46     "websockets==7.*",
47     "httptools==0.0.13 ;" + env_marker,
48     "uvloop==0.* ;" + env_marker,
49 ]
50 
51 
52 setup(
53     name='uvicorn',
54     version=get_version('uvicorn'),
55     url='https://github.com/encode/uvicorn',
56     license='BSD',
57     description='The lightning-fast ASGI server.',
58     long_description=get_long_description(),
59     long_description_content_type='text/markdown',
60     author='Tom Christie',
61     author_email='tom@tomchristie.com',
62     packages=get_packages('uvicorn'),
63     install_requires=requirements,
64     data_files = [("", ["LICENSE.md"])],
65     classifiers=[
66         'Development Status :: 3 - Alpha',
67         'Environment :: Web Environment',
68         'Intended Audience :: Developers',
69         'License :: OSI Approved :: BSD License',
70         'Operating System :: OS Independent',
71         'Topic :: Internet :: WWW/HTTP',
72         'Programming Language :: Python :: 3',
73         'Programming Language :: Python :: 3.5',
74         'Programming Language :: Python :: 3.6',
75         'Programming Language :: Python :: 3.7',
76         'Programming Language :: Python :: Implementation :: CPython',
77         'Programming Language :: Python :: Implementation :: PyPy',
78     ],
79     entry_points="""
80     [console_scripts]
81     uvicorn=uvicorn.main:main
82     """
83 )
84
```

Path: `uvicorn/protocols/websockets/websockets_impl.py`
Content:
```
1 import asyncio
2 import http
3 from urllib.parse import unquote
4 
5 import websockets
6 
7 from uvicorn.protocols.utils import get_local_addr, get_remote_addr, is_ssl
8 
9 
10 class Server:
11     closing = False
12 
13     def register(self, ws):
14         pass
15 
16     def unregister(self, ws):
17         pass
18 
19 
20 class WebSocketProtocol(websockets.WebSocketServerProtocol):
21     def __init__(self, config, server_state, _loop=None):
22         if not config.loaded:
23             config.load()
24 
25         self.config = config
26         self.app = config.loaded_app
27         self.loop = _loop or asyncio.get_event_loop()
28         self.logger = config.logger_instance
29         self.root_path = config.root_path
30 
31         # Shared server state
32         self.connections = server_state.connections
33         self.tasks = server_state.tasks
34 
35         # Connection state
36         self.transport = None
37         self.server = None
38         self.client = None
39         self.scheme = None
40 
41         # Connection events
42         self.scope = None
43         self.handshake_started_event = asyncio.Event()
44         self.handshake_completed_event = asyncio.Event()
45         self.closed_event = asyncio.Event()
46         self.initial_response = None
47         self.connect_sent = False
48         self.accepted_subprotocol = None
49 
50         server = Server()
51 
52         super().__init__(ws_handler=self.ws_handler, ws_server=server)
53 
54     def connection_made(self, transport):
55         self.connections.add(self)
56         self.transport = transport
57         self.server = get_local_addr(transport)
58         self.client = get_remote_addr(transport)
59         self.scheme = "wss" if is_ssl(transport) else "ws"
60         super().connection_made(transport)
61 
62     def connection_lost(self, exc):
63         self.connections.remove(self)
64         self.handshake_completed_event.set()
65         super().connection_lost(exc)
66 
67     def shutdown(self):
68         self.transport.close()
69 
70     def on_task_complete(self, task):
71         self.tasks.discard(task)
72 
73     async def process_request(self, path, headers):
74         """
75         This hook is called to determine if the websocket should return
76         an HTTP response and close.
77 
78         Our behavior here is to start the ASGI application, and then wait
79         for either `accept` or `close` in order to determine if we should
80         close the connection.
81         """
82         path_portion, _, query_string = path.partition("?")
83 
84         websockets.handshake.check_request(headers)
85 
86         subprotocols = []
87         for header in headers.get_all("Sec-WebSocket-Protocol"):
88             subprotocols.extend([token.strip() for token in header.split(",")])
89 
90         asgi_headers = [
91             (name.encode("ascii"), value.encode("ascii"))
92             for name, value in headers.raw_items()
93         ]
94 
95         self.scope = {
96             "type": "websocket",
97             "scheme": self.scheme,
98             "server": self.server,
99             "client": self.client,
100             "root_path": self.root_path,
101             "path": unquote(path_portion),
102             "raw_path": path_portion,
103             "query_string": query_string.encode("ascii"),
104             "headers": asgi_headers,
105             "subprotocols": subprotocols,
106         }
107         task = self.loop.create_task(self.run_asgi())
108         task.add_done_callback(self.on_task_complete)
109         self.tasks.add(task)
110         await self.handshake_started_event.wait()
111         return self.initial_response
112 
113     def process_subprotocol(self, headers, available_subprotocols):
114         """
115         We override the standard 'process_subprotocol' behavior here so that
116         we return whatever subprotocol is sent in the 'accept' message.
117         """
118         return self.accepted_subprotocol
119 
120     def send_500_response(self):
121         msg = b"Internal Server Error"
122         content = [
123             b"HTTP/1.1 500 Internal Server Error\r\n"
124             b"content-type: text/plain; charset=utf-8\r\n",
125             b"content-length: " + str(len(msg)).encode("ascii") + b"\r\n",
126             b"connection: close\r\n",
127             b"\r\n",
128             msg,
129         ]
130         self.transport.write(b"".join(content))
131 
132     async def ws_handler(self, protocol, path):
133         """
134         This is the main handler function for the 'websockets' implementation
135         to call into. We just wait for close then return, and instead allow
136         'send' and 'receive' events to drive the flow.
137         """
138         self.handshake_completed_event.set()
139         await self.closed_event.wait()
140 
141     async def run_asgi(self):
142         """
143         Wrapper around the ASGI callable, handling exceptions and unexpected
144         termination states.
145         """
146         try:
147             result = await self.app(self.scope, self.asgi_receive, self.asgi_send)
148         except BaseException as exc:
149             self.closed_event.set()
150             msg = "Exception in ASGI application\n"
151             self.logger.error(msg, exc_info=exc)
152             if not self.handshake_started_event.is_set():
153                 self.send_500_response()
154             else:
155                 await self.handshake_completed_event.wait()
156             self.transport.close()
157         else:
158             self.closed_event.set()
159             if not self.handshake_started_event.is_set():
160                 msg = "ASGI callable returned without sending handshake."
161                 self.logger.error(msg)
162                 self.send_500_response()
163                 self.transport.close()
164             elif result is not None:
165                 msg = "ASGI callable should return None, but returned '%s'."
166                 self.logger.error(msg, result)
167                 await self.handshake_completed_event.wait()
168                 self.transport.close()
169 
170     async def asgi_send(self, message):
171         message_type = message["type"]
172 
173         if not self.handshake_started_event.is_set():
174             if message_type == "websocket.accept":
175                 self.logger.info(
176                     '%s - "WebSocket %s" [accepted]',
177                     self.scope["client"],
178                     self.scope["root_path"] + self.scope["path"],
179                 )
180                 self.initial_response = None
181                 self.accepted_subprotocol = message.get("subprotocol")
182                 self.handshake_started_event.set()
183 
184             elif message_type == "websocket.close":
185                 self.logger.info(
186                     '%s - "WebSocket %s" 403',
187                     self.scope["client"],
188                     self.scope["root_path"] + self.scope["path"],
189                 )
190                 self.initial_response = (http.HTTPStatus.FORBIDDEN, [], b"")
191                 self.handshake_started_event.set()
192                 self.closed_event.set()
193 
194             else:
195                 msg = "Expected ASGI message 'websocket.accept' or 'websocket.close', but got '%s'."
196                 raise RuntimeError(msg % message_type)
197 
198         elif not self.closed_event.is_set():
199             await self.handshake_completed_event.wait()
200 
201             if message_type == "websocket.send":
202                 bytes_data = message.get("bytes")
203                 text_data = message.get("text")
204                 data = text_data if bytes_data is None else bytes_data
205                 await self.send(data)
206 
207             elif message_type == "websocket.close":
208                 code = message.get("code", 1000)
209                 await self.close(code)
210                 self.closed_event.set()
211 
212             else:
213                 msg = "Expected ASGI message 'websocket.send' or 'websocket.close', but got '%s'."
214                 raise RuntimeError(msg % message_type)
215 
216         else:
217             msg = "Unexpected ASGI message '%s', after sending 'websocket.close'."
218             raise RuntimeError(msg % message_type)
219 
220     async def asgi_receive(self):
221         if not self.connect_sent:
222             self.connect_sent = True
223             return {"type": "websocket.connect"}
224 
225         await self.handshake_completed_event.wait()
226         try:
227             data = await self.recv()
228         except websockets.ConnectionClosed as exc:
229             return {"type": "websocket.disconnect", "code": exc.code}
230 
231         msg = {"type": "websocket.receive"}
232 
233         if isinstance(data, str):
234             msg["text"] = data
235         else:
236             msg["bytes"] = data
237 
238         return msg
239
```
--- 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/setup.py b/setup.py
--- a/setup.py
+++ b/setup.py
@@ -43,7 +43,7 @@
 requirements = [
     "click==7.*",
     "h11==0.8.*",
-    "websockets==7.*",
+    "websockets==8.*",
     "httptools==0.0.13 ;" + env_marker,
     "uvloop==0.* ;" + env_marker,
 ]
diff --git a/uvicorn/protocols/websockets/websockets_impl.py b/uvicorn/protocols/websockets/websockets_impl.py
--- a/uvicorn/protocols/websockets/websockets_impl.py
+++ b/uvicorn/protocols/websockets/websockets_impl.py
@@ -16,6 +16,9 @@
     def unregister(self, ws):
         pass
 
+    def is_serving(self):
+        return not self.closing
+
 
 class WebSocketProtocol(websockets.WebSocketServerProtocol):
     def __init__(self, config, server_state, _loop=None):
@@ -46,10 +49,11 @@
         self.initial_response = None
         self.connect_sent = False
         self.accepted_subprotocol = None
+        self.transfer_data_task = None
 
-        server = Server()
+        self.ws_server = Server()
 
-        super().__init__(ws_handler=self.ws_handler, ws_server=server)
+        super().__init__(ws_handler=self.ws_handler, ws_server=self.ws_server)
 
     def connection_made(self, transport):
         self.connections.add(self)
@@ -65,6 +69,7 @@
         super().connection_lost(exc)
 
     def shutdown(self):
+        self.ws_server.closing = True
         self.transport.close()
 
     def on_task_complete(self, task):

{"golden_diff": "diff --git a/setup.py b/setup.py\n--- a/setup.py\n+++ b/setup.py\n@@ -43,7 +43,7 @@\n requirements = [\n     \"click==7.*\",\n     \"h11==0.8.*\",\n-    \"websockets==7.*\",\n+    \"websockets==8.*\",\n     \"httptools==0.0.13 ;\" + env_marker,\n     \"uvloop==0.* ;\" + env_marker,\n ]\ndiff --git a/uvicorn/protocols/websockets/websockets_impl.py b/uvicorn/protocols/websockets/websockets_impl.py\n--- a/uvicorn/protocols/websockets/websockets_impl.py\n+++ b/uvicorn/protocols/websockets/websockets_impl.py\n@@ -16,6 +16,9 @@\n     def unregister(self, ws):\n         pass\n \n+    def is_serving(self):\n+        return not self.closing\n+\n \n class WebSocketProtocol(websockets.WebSocketServerProtocol):\n     def __init__(self, config, server_state, _loop=None):\n@@ -46,10 +49,11 @@\n         self.initial_response = None\n         self.connect_sent = False\n         self.accepted_subprotocol = None\n+        self.transfer_data_task = None\n \n-        server = Server()\n+        self.ws_server = Server()\n \n-        super().__init__(ws_handler=self.ws_handler, ws_server=server)\n+        super().__init__(ws_handler=self.ws_handler, ws_server=self.ws_server)\n \n     def connection_made(self, transport):\n         self.connections.add(self)\n@@ -65,6 +69,7 @@\n         super().connection_lost(exc)\n \n     def shutdown(self):\n+        self.ws_server.closing = True\n         self.transport.close()\n \n     def on_task_complete(self, task):\n", "issue": "Update 'websockets' to 8.x\nI realize that https://github.com/encode/uvicorn/pull/396 was done because the tests appear to be failing with `websockets>=8.0`, but that release also fixed a bunch of DeprecationWarnings that we've been seeing in [httpx builds on 3.8](https://travis-ci.org/encode/httpx/jobs/574949180).\r\n\r\nSince it's only a `DeprecationWarning`, and only on 3.8 ([3.7 and below is fine](https://travis-ci.org/encode/httpx/jobs/574949179)), I definitely would agree that this is a low priority issue.\r\n\r\nI dug into the tests to try and figure out what exactly was going wrong, but the `AttributeError`s I looked at looks like the main issue is two missing functions in [websockets_impl.py](https://github.com/encode/uvicorn/blob/master/uvicorn/protocols/websockets/websockets_impl.py)\r\n\r\n`15 AttributeError: 'Server' object has no attribute 'is_serving'` --> https://github.com/aaugustin/websockets/blob/8.0.2/src/websockets/server.py#L642-L668\r\n` 9 AttributeError: 'WebSocketProtocol' object has no attribute 'transfer_data_task'` --> https://github.com/aaugustin/websockets/blob/8.0.2/src/websockets/protocol.py#L276-L313\n", "before_files": [{"content": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n\nimport os\nimport re\nimport sys\nimport platform\n\nfrom setuptools import setup\n\n\ndef get_version(package):\n    \"\"\"\n    Return package version as listed in `__version__` in `init.py`.\n    \"\"\"\n    path = os.path.join(package, '__init__.py')\n    init_py = open(path, 'r', encoding='utf8').read()\n    return re.search(\"__version__ = ['\\\"]([^'\\\"]+)['\\\"]\", init_py).group(1)\n\n\ndef get_long_description():\n    \"\"\"\n    Return the README.\n    \"\"\"\n    return open('README.md', 'r', encoding='utf8').read()\n\n\ndef get_packages(package):\n    \"\"\"\n    Return root package and all sub-packages.\n    \"\"\"\n    return [dirpath\n            for dirpath, dirnames, filenames in os.walk(package)\n            if os.path.exists(os.path.join(dirpath, '__init__.py'))]\n\n\nenv_marker = (\n    \"sys_platform != 'win32'\"\n    \" and sys_platform != 'cygwin'\"\n    \" and platform_python_implementation != 'pypy'\"\n)\n\nrequirements = [\n    \"click==7.*\",\n    \"h11==0.8.*\",\n    \"websockets==7.*\",\n    \"httptools==0.0.13 ;\" + env_marker,\n    \"uvloop==0.* ;\" + env_marker,\n]\n\n\nsetup(\n    name='uvicorn',\n    version=get_version('uvicorn'),\n    url='https://github.com/encode/uvicorn',\n    license='BSD',\n    description='The lightning-fast ASGI server.',\n    long_description=get_long_description(),\n    long_description_content_type='text/markdown',\n    author='Tom Christie',\n    author_email='tom@tomchristie.com',\n    packages=get_packages('uvicorn'),\n    install_requires=requirements,\n    data_files = [(\"\", [\"LICENSE.md\"])],\n    classifiers=[\n        'Development Status :: 3 - Alpha',\n        'Environment :: Web Environment',\n        'Intended Audience :: Developers',\n        'License :: OSI Approved :: BSD License',\n        'Operating System :: OS Independent',\n        'Topic :: Internet :: WWW/HTTP',\n        'Programming Language :: Python :: 3',\n        'Programming Language :: Python :: 3.5',\n        'Programming Language :: Python :: 3.6',\n        'Programming Language :: Python :: 3.7',\n        'Programming Language :: Python :: Implementation :: CPython',\n        'Programming Language :: Python :: Implementation :: PyPy',\n    ],\n    entry_points=\"\"\"\n    [console_scripts]\n    uvicorn=uvicorn.main:main\n    \"\"\"\n)\n", "path": "setup.py"}, {"content": "import asyncio\nimport http\nfrom urllib.parse import unquote\n\nimport websockets\n\nfrom uvicorn.protocols.utils import get_local_addr, get_remote_addr, is_ssl\n\n\nclass Server:\n    closing = False\n\n    def register(self, ws):\n        pass\n\n    def unregister(self, ws):\n        pass\n\n\nclass WebSocketProtocol(websockets.WebSocketServerProtocol):\n    def __init__(self, config, server_state, _loop=None):\n        if not config.loaded:\n            config.load()\n\n        self.config = config\n        self.app = config.loaded_app\n        self.loop = _loop or asyncio.get_event_loop()\n        self.logger = config.logger_instance\n        self.root_path = config.root_path\n\n        # Shared server state\n        self.connections = server_state.connections\n        self.tasks = server_state.tasks\n\n        # Connection state\n        self.transport = None\n        self.server = None\n        self.client = None\n        self.scheme = None\n\n        # Connection events\n        self.scope = None\n        self.handshake_started_event = asyncio.Event()\n        self.handshake_completed_event = asyncio.Event()\n        self.closed_event = asyncio.Event()\n        self.initial_response = None\n        self.connect_sent = False\n        self.accepted_subprotocol = None\n\n        server = Server()\n\n        super().__init__(ws_handler=self.ws_handler, ws_server=server)\n\n    def connection_made(self, transport):\n        self.connections.add(self)\n        self.transport = transport\n        self.server = get_local_addr(transport)\n        self.client = get_remote_addr(transport)\n        self.scheme = \"wss\" if is_ssl(transport) else \"ws\"\n        super().connection_made(transport)\n\n    def connection_lost(self, exc):\n        self.connections.remove(self)\n        self.handshake_completed_event.set()\n        super().connection_lost(exc)\n\n    def shutdown(self):\n        self.transport.close()\n\n    def on_task_complete(self, task):\n        self.tasks.discard(task)\n\n    async def process_request(self, path, headers):\n        \"\"\"\n        This hook is called to determine if the websocket should return\n        an HTTP response and close.\n\n        Our behavior here is to start the ASGI application, and then wait\n        for either `accept` or `close` in order to determine if we should\n        close the connection.\n        \"\"\"\n        path_portion, _, query_string = path.partition(\"?\")\n\n        websockets.handshake.check_request(headers)\n\n        subprotocols = []\n        for header in headers.get_all(\"Sec-WebSocket-Protocol\"):\n            subprotocols.extend([token.strip() for token in header.split(\",\")])\n\n        asgi_headers = [\n            (name.encode(\"ascii\"), value.encode(\"ascii\"))\n            for name, value in headers.raw_items()\n        ]\n\n        self.scope = {\n            \"type\": \"websocket\",\n            \"scheme\": self.scheme,\n            \"server\": self.server,\n            \"client\": self.client,\n            \"root_path\": self.root_path,\n            \"path\": unquote(path_portion),\n            \"raw_path\": path_portion,\n            \"query_string\": query_string.encode(\"ascii\"),\n            \"headers\": asgi_headers,\n            \"subprotocols\": subprotocols,\n        }\n        task = self.loop.create_task(self.run_asgi())\n        task.add_done_callback(self.on_task_complete)\n        self.tasks.add(task)\n        await self.handshake_started_event.wait()\n        return self.initial_response\n\n    def process_subprotocol(self, headers, available_subprotocols):\n        \"\"\"\n        We override the standard 'process_subprotocol' behavior here so that\n        we return whatever subprotocol is sent in the 'accept' message.\n        \"\"\"\n        return self.accepted_subprotocol\n\n    def send_500_response(self):\n        msg = b\"Internal Server Error\"\n        content = [\n            b\"HTTP/1.1 500 Internal Server Error\\r\\n\"\n            b\"content-type: text/plain; charset=utf-8\\r\\n\",\n            b\"content-length: \" + str(len(msg)).encode(\"ascii\") + b\"\\r\\n\",\n            b\"connection: close\\r\\n\",\n            b\"\\r\\n\",\n            msg,\n        ]\n        self.transport.write(b\"\".join(content))\n\n    async def ws_handler(self, protocol, path):\n        \"\"\"\n        This is the main handler function for the 'websockets' implementation\n        to call into. We just wait for close then return, and instead allow\n        'send' and 'receive' events to drive the flow.\n        \"\"\"\n        self.handshake_completed_event.set()\n        await self.closed_event.wait()\n\n    async def run_asgi(self):\n        \"\"\"\n        Wrapper around the ASGI callable, handling exceptions and unexpected\n        termination states.\n        \"\"\"\n        try:\n            result = await self.app(self.scope, self.asgi_receive, self.asgi_send)\n        except BaseException as exc:\n            self.closed_event.set()\n            msg = \"Exception in ASGI application\\n\"\n            self.logger.error(msg, exc_info=exc)\n            if not self.handshake_started_event.is_set():\n                self.send_500_response()\n            else:\n                await self.handshake_completed_event.wait()\n            self.transport.close()\n        else:\n            self.closed_event.set()\n            if not self.handshake_started_event.is_set():\n                msg = \"ASGI callable returned without sending handshake.\"\n                self.logger.error(msg)\n                self.send_500_response()\n                self.transport.close()\n            elif result is not None:\n                msg = \"ASGI callable should return None, but returned '%s'.\"\n                self.logger.error(msg, result)\n                await self.handshake_completed_event.wait()\n                self.transport.close()\n\n    async def asgi_send(self, message):\n        message_type = message[\"type\"]\n\n        if not self.handshake_started_event.is_set():\n            if message_type == \"websocket.accept\":\n                self.logger.info(\n                    '%s - \"WebSocket %s\" [accepted]',\n                    self.scope[\"client\"],\n                    self.scope[\"root_path\"] + self.scope[\"path\"],\n                )\n                self.initial_response = None\n                self.accepted_subprotocol = message.get(\"subprotocol\")\n                self.handshake_started_event.set()\n\n            elif message_type == \"websocket.close\":\n                self.logger.info(\n                    '%s - \"WebSocket %s\" 403',\n                    self.scope[\"client\"],\n                    self.scope[\"root_path\"] + self.scope[\"path\"],\n                )\n                self.initial_response = (http.HTTPStatus.FORBIDDEN, [], b\"\")\n                self.handshake_started_event.set()\n                self.closed_event.set()\n\n            else:\n                msg = \"Expected ASGI message 'websocket.accept' or 'websocket.close', but got '%s'.\"\n                raise RuntimeError(msg % message_type)\n\n        elif not self.closed_event.is_set():\n            await self.handshake_completed_event.wait()\n\n            if message_type == \"websocket.send\":\n                bytes_data = message.get(\"bytes\")\n                text_data = message.get(\"text\")\n                data = text_data if bytes_data is None else bytes_data\n                await self.send(data)\n\n            elif message_type == \"websocket.close\":\n                code = message.get(\"code\", 1000)\n                await self.close(code)\n                self.closed_event.set()\n\n            else:\n                msg = \"Expected ASGI message 'websocket.send' or 'websocket.close', but got '%s'.\"\n                raise RuntimeError(msg % message_type)\n\n        else:\n            msg = \"Unexpected ASGI message '%s', after sending 'websocket.close'.\"\n            raise RuntimeError(msg % message_type)\n\n    async def asgi_receive(self):\n        if not self.connect_sent:\n            self.connect_sent = True\n            return {\"type\": \"websocket.connect\"}\n\n        await self.handshake_completed_event.wait()\n        try:\n            data = await self.recv()\n        except websockets.ConnectionClosed as exc:\n            return {\"type\": \"websocket.disconnect\", \"code\": exc.code}\n\n        msg = {\"type\": \"websocket.receive\"}\n\n        if isinstance(data, str):\n            msg[\"text\"] = data\n        else:\n            msg[\"bytes\"] = data\n\n        return msg\n", "path": "uvicorn/protocols/websockets/websockets_impl.py"}], "after_files": [{"content": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n\nimport os\nimport re\nimport sys\nimport platform\n\nfrom setuptools import setup\n\n\ndef get_version(package):\n    \"\"\"\n    Return package version as listed in `__version__` in `init.py`.\n    \"\"\"\n    path = os.path.join(package, '__init__.py')\n    init_py = open(path, 'r', encoding='utf8').read()\n    return re.search(\"__version__ = ['\\\"]([^'\\\"]+)['\\\"]\", init_py).group(1)\n\n\ndef get_long_description():\n    \"\"\"\n    Return the README.\n    \"\"\"\n    return open('README.md', 'r', encoding='utf8').read()\n\n\ndef get_packages(package):\n    \"\"\"\n    Return root package and all sub-packages.\n    \"\"\"\n    return [dirpath\n            for dirpath, dirnames, filenames in os.walk(package)\n            if os.path.exists(os.path.join(dirpath, '__init__.py'))]\n\n\nenv_marker = (\n    \"sys_platform != 'win32'\"\n    \" and sys_platform != 'cygwin'\"\n    \" and platform_python_implementation != 'pypy'\"\n)\n\nrequirements = [\n    \"click==7.*\",\n    \"h11==0.8.*\",\n    \"websockets==8.*\",\n    \"httptools==0.0.13 ;\" + env_marker,\n    \"uvloop==0.* ;\" + env_marker,\n]\n\n\nsetup(\n    name='uvicorn',\n    version=get_version('uvicorn'),\n    url='https://github.com/encode/uvicorn',\n    license='BSD',\n    description='The lightning-fast ASGI server.',\n    long_description=get_long_description(),\n    long_description_content_type='text/markdown',\n    author='Tom Christie',\n    author_email='tom@tomchristie.com',\n    packages=get_packages('uvicorn'),\n    install_requires=requirements,\n    data_files = [(\"\", [\"LICENSE.md\"])],\n    classifiers=[\n        'Development Status :: 3 - Alpha',\n        'Environment :: Web Environment',\n        'Intended Audience :: Developers',\n        'License :: OSI Approved :: BSD License',\n        'Operating System :: OS Independent',\n        'Topic :: Internet :: WWW/HTTP',\n        'Programming Language :: Python :: 3',\n        'Programming Language :: Python :: 3.5',\n        'Programming Language :: Python :: 3.6',\n        'Programming Language :: Python :: 3.7',\n        'Programming Language :: Python :: Implementation :: CPython',\n        'Programming Language :: Python :: Implementation :: PyPy',\n    ],\n    entry_points=\"\"\"\n    [console_scripts]\n    uvicorn=uvicorn.main:main\n    \"\"\"\n)\n", "path": "setup.py"}, {"content": "import asyncio\nimport http\nfrom urllib.parse import unquote\n\nimport websockets\n\nfrom uvicorn.protocols.utils import get_local_addr, get_remote_addr, is_ssl\n\n\nclass Server:\n    closing = False\n\n    def register(self, ws):\n        pass\n\n    def unregister(self, ws):\n        pass\n\n    def is_serving(self):\n        return not self.closing\n\n\nclass WebSocketProtocol(websockets.WebSocketServerProtocol):\n    def __init__(self, config, server_state, _loop=None):\n        if not config.loaded:\n            config.load()\n\n        self.config = config\n        self.app = config.loaded_app\n        self.loop = _loop or asyncio.get_event_loop()\n        self.logger = config.logger_instance\n        self.root_path = config.root_path\n\n        # Shared server state\n        self.connections = server_state.connections\n        self.tasks = server_state.tasks\n\n        # Connection state\n        self.transport = None\n        self.server = None\n        self.client = None\n        self.scheme = None\n\n        # Connection events\n        self.scope = None\n        self.handshake_started_event = asyncio.Event()\n        self.handshake_completed_event = asyncio.Event()\n        self.closed_event = asyncio.Event()\n        self.initial_response = None\n        self.connect_sent = False\n        self.accepted_subprotocol = None\n        self.transfer_data_task = None\n\n        self.ws_server = Server()\n\n        super().__init__(ws_handler=self.ws_handler, ws_server=self.ws_server)\n\n    def connection_made(self, transport):\n        self.connections.add(self)\n        self.transport = transport\n        self.server = get_local_addr(transport)\n        self.client = get_remote_addr(transport)\n        self.scheme = \"wss\" if is_ssl(transport) else \"ws\"\n        super().connection_made(transport)\n\n    def connection_lost(self, exc):\n        self.connections.remove(self)\n        self.handshake_completed_event.set()\n        super().connection_lost(exc)\n\n    def shutdown(self):\n        self.ws_server.closing = True\n        self.transport.close()\n\n    def on_task_complete(self, task):\n        self.tasks.discard(task)\n\n    async def process_request(self, path, headers):\n        \"\"\"\n        This hook is called to determine if the websocket should return\n        an HTTP response and close.\n\n        Our behavior here is to start the ASGI application, and then wait\n        for either `accept` or `close` in order to determine if we should\n        close the connection.\n        \"\"\"\n        path_portion, _, query_string = path.partition(\"?\")\n\n        websockets.handshake.check_request(headers)\n\n        subprotocols = []\n        for header in headers.get_all(\"Sec-WebSocket-Protocol\"):\n            subprotocols.extend([token.strip() for token in header.split(\",\")])\n\n        asgi_headers = [\n            (name.encode(\"ascii\"), value.encode(\"ascii\"))\n            for name, value in headers.raw_items()\n        ]\n\n        self.scope = {\n            \"type\": \"websocket\",\n            \"scheme\": self.scheme,\n            \"server\": self.server,\n            \"client\": self.client,\n            \"root_path\": self.root_path,\n            \"path\": unquote(path_portion),\n            \"raw_path\": path_portion,\n            \"query_string\": query_string.encode(\"ascii\"),\n            \"headers\": asgi_headers,\n            \"subprotocols\": subprotocols,\n        }\n        task = self.loop.create_task(self.run_asgi())\n        task.add_done_callback(self.on_task_complete)\n        self.tasks.add(task)\n        await self.handshake_started_event.wait()\n        return self.initial_response\n\n    def process_subprotocol(self, headers, available_subprotocols):\n        \"\"\"\n        We override the standard 'process_subprotocol' behavior here so that\n        we return whatever subprotocol is sent in the 'accept' message.\n        \"\"\"\n        return self.accepted_subprotocol\n\n    def send_500_response(self):\n        msg = b\"Internal Server Error\"\n        content = [\n            b\"HTTP/1.1 500 Internal Server Error\\r\\n\"\n            b\"content-type: text/plain; charset=utf-8\\r\\n\",\n            b\"content-length: \" + str(len(msg)).encode(\"ascii\") + b\"\\r\\n\",\n            b\"connection: close\\r\\n\",\n            b\"\\r\\n\",\n            msg,\n        ]\n        self.transport.write(b\"\".join(content))\n\n    async def ws_handler(self, protocol, path):\n        \"\"\"\n        This is the main handler function for the 'websockets' implementation\n        to call into. We just wait for close then return, and instead allow\n        'send' and 'receive' events to drive the flow.\n        \"\"\"\n        self.handshake_completed_event.set()\n        await self.closed_event.wait()\n\n    async def run_asgi(self):\n        \"\"\"\n        Wrapper around the ASGI callable, handling exceptions and unexpected\n        termination states.\n        \"\"\"\n        try:\n            result = await self.app(self.scope, self.asgi_receive, self.asgi_send)\n        except BaseException as exc:\n            self.closed_event.set()\n            msg = \"Exception in ASGI application\\n\"\n            self.logger.error(msg, exc_info=exc)\n            if not self.handshake_started_event.is_set():\n                self.send_500_response()\n            else:\n                await self.handshake_completed_event.wait()\n            self.transport.close()\n        else:\n            self.closed_event.set()\n            if not self.handshake_started_event.is_set():\n                msg = \"ASGI callable returned without sending handshake.\"\n                self.logger.error(msg)\n                self.send_500_response()\n                self.transport.close()\n            elif result is not None:\n                msg = \"ASGI callable should return None, but returned '%s'.\"\n                self.logger.error(msg, result)\n                await self.handshake_completed_event.wait()\n                self.transport.close()\n\n    async def asgi_send(self, message):\n        message_type = message[\"type\"]\n\n        if not self.handshake_started_event.is_set():\n            if message_type == \"websocket.accept\":\n                self.logger.info(\n                    '%s - \"WebSocket %s\" [accepted]',\n                    self.scope[\"client\"],\n                    self.scope[\"root_path\"] + self.scope[\"path\"],\n                )\n                self.initial_response = None\n                self.accepted_subprotocol = message.get(\"subprotocol\")\n                self.handshake_started_event.set()\n\n            elif message_type == \"websocket.close\":\n                self.logger.info(\n                    '%s - \"WebSocket %s\" 403',\n                    self.scope[\"client\"],\n                    self.scope[\"root_path\"] + self.scope[\"path\"],\n                )\n                self.initial_response = (http.HTTPStatus.FORBIDDEN, [], b\"\")\n                self.handshake_started_event.set()\n                self.closed_event.set()\n\n            else:\n                msg = \"Expected ASGI message 'websocket.accept' or 'websocket.close', but got '%s'.\"\n                raise RuntimeError(msg % message_type)\n\n        elif not self.closed_event.is_set():\n            await self.handshake_completed_event.wait()\n\n            if message_type == \"websocket.send\":\n                bytes_data = message.get(\"bytes\")\n                text_data = message.get(\"text\")\n                data = text_data if bytes_data is None else bytes_data\n                await self.send(data)\n\n            elif message_type == \"websocket.close\":\n                code = message.get(\"code\", 1000)\n                await self.close(code)\n                self.closed_event.set()\n\n            else:\n                msg = \"Expected ASGI message 'websocket.send' or 'websocket.close', but got '%s'.\"\n                raise RuntimeError(msg % message_type)\n\n        else:\n            msg = \"Unexpected ASGI message '%s', after sending 'websocket.close'.\"\n            raise RuntimeError(msg % message_type)\n\n    async def asgi_receive(self):\n        if not self.connect_sent:\n            self.connect_sent = True\n            return {\"type\": \"websocket.connect\"}\n\n        await self.handshake_completed_event.wait()\n        try:\n            data = await self.recv()\n        except websockets.ConnectionClosed as exc:\n            return {\"type\": \"websocket.disconnect\", \"code\": exc.code}\n\n        msg = {\"type\": \"websocket.receive\"}\n\n        if isinstance(data, str):\n            msg[\"text\"] = data\n        else:\n            msg[\"bytes\"] = data\n\n        return msg\n", "path": "uvicorn/protocols/websockets/websockets_impl.py"}]}