We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Websocket invalid upgrade exception handling b0rkage
### Is there an existing issue for this?

- [X] I have searched the existing issues

### Describe the bug

A client apparently sent no Upgrade header to a websocket endpoint, leading to an error as it should. An ugly traceback is printed on terminal even though the error eventually gets handled correctly it would seem.

It would appear that the websockets module attempts to attach its exception on `request._exception` field which Sanic's Request doesn't have a slot for. This could be hidden if Sanic later used `raise BadRequest(...) from None` rather than `raise SanicException(...)`, suppressing the chain and giving a non-500 error for what really is no server error. Not sure though if that would from this context ever reach the client anyway but at least it could avoid a traceback in server log.

If anyone wants to investigate and make a PR, feel free to (I am currently busy and cannot do that unfortunately).

```python
Traceback (most recent call last):
  File "/home/user/.local/lib/python3.10/site-packages/websockets/server.py", line 111, in accept
    ) = self.process_request(request)
  File "/home/user/.local/lib/python3.10/site-packages/websockets/server.py", line 218, in process_request
    raise InvalidUpgrade("Upgrade", ", ".join(upgrade) if upgrade else None)
websockets.exceptions.InvalidUpgrade: missing Upgrade header

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/user/sanic/sanic/server/protocols/websocket_protocol.py", line 120, in websocket_handshake
    resp: "http11.Response" = ws_proto.accept(request)
  File "/home/user/.local/lib/python3.10/site-packages/websockets/server.py", line 122, in accept
    request._exception = exc
AttributeError: 'Request' object has no attribute '_exception'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "handle_request", line 97, in handle_request
  File "/home/user/sanic/sanic/app.py", line 1047, in _websocket_handler
    ws = await protocol.websocket_handshake(request, subprotocols)
  File "/home/user/sanic/sanic/server/protocols/websocket_protocol.py", line 126, in websocket_handshake
    raise SanicException(msg, status_code=500)
sanic.exceptions.SanicException: Failed to open a WebSocket connection.
See server log for more information.
```


### Code snippet

_No response_

### Expected Behavior

400 Bad Request error reaching the client and being more silent on server side. Including the message of **missing Upgrade header** would be helpful for debugging (e.g. in case Nginx proxy config forgot to forward that header).

### How do you run Sanic?

Sanic CLI

### Operating System

Linux

### Sanic Version

Almost 23.03.0 (a git version slightly before release)

### Additional context

_No response_

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `sanic/server/protocols/websocket_protocol.py`
Content:
```
1 from typing import TYPE_CHECKING, Optional, Sequence, cast
2 
3 
4 try:  # websockets < 11.0
5     from websockets.connection import State
6     from websockets.server import ServerConnection as ServerProtocol
7 except ImportError:  # websockets >= 11.0
8     from websockets.protocol import State  # type: ignore
9     from websockets.server import ServerProtocol  # type: ignore
10 
11 from websockets.typing import Subprotocol
12 
13 from sanic.exceptions import SanicException
14 from sanic.log import logger
15 from sanic.server import HttpProtocol
16 
17 from ..websockets.impl import WebsocketImplProtocol
18 
19 
20 if TYPE_CHECKING:
21     from websockets import http11
22 
23 
24 OPEN = State.OPEN
25 CLOSING = State.CLOSING
26 CLOSED = State.CLOSED
27 
28 
29 class WebSocketProtocol(HttpProtocol):
30     __slots__ = (
31         "websocket",
32         "websocket_timeout",
33         "websocket_max_size",
34         "websocket_ping_interval",
35         "websocket_ping_timeout",
36     )
37 
38     def __init__(
39         self,
40         *args,
41         websocket_timeout: float = 10.0,
42         websocket_max_size: Optional[int] = None,
43         websocket_ping_interval: Optional[float] = 20.0,
44         websocket_ping_timeout: Optional[float] = 20.0,
45         **kwargs,
46     ):
47         super().__init__(*args, **kwargs)
48         self.websocket: Optional[WebsocketImplProtocol] = None
49         self.websocket_timeout = websocket_timeout
50         self.websocket_max_size = websocket_max_size
51         self.websocket_ping_interval = websocket_ping_interval
52         self.websocket_ping_timeout = websocket_ping_timeout
53 
54     def connection_lost(self, exc):
55         if self.websocket is not None:
56             self.websocket.connection_lost(exc)
57         super().connection_lost(exc)
58 
59     def data_received(self, data):
60         if self.websocket is not None:
61             self.websocket.data_received(data)
62         else:
63             # Pass it to HttpProtocol handler first
64             # That will (hopefully) upgrade it to a websocket.
65             super().data_received(data)
66 
67     def eof_received(self) -> Optional[bool]:
68         if self.websocket is not None:
69             return self.websocket.eof_received()
70         else:
71             return False
72 
73     def close(self, timeout: Optional[float] = None):
74         # Called by HttpProtocol at the end of connection_task
75         # If we've upgraded to websocket, we do our own closing
76         if self.websocket is not None:
77             # Note, we don't want to use websocket.close()
78             # That is used for user's application code to send a
79             # websocket close packet. This is different.
80             self.websocket.end_connection(1001)
81         else:
82             super().close()
83 
84     def close_if_idle(self):
85         # Called by Sanic Server when shutting down
86         # If we've upgraded to websocket, shut it down
87         if self.websocket is not None:
88             if self.websocket.ws_proto.state in (CLOSING, CLOSED):
89                 return True
90             elif self.websocket.loop is not None:
91                 self.websocket.loop.create_task(self.websocket.close(1001))
92             else:
93                 self.websocket.end_connection(1001)
94         else:
95             return super().close_if_idle()
96 
97     async def websocket_handshake(
98         self, request, subprotocols: Optional[Sequence[str]] = None
99     ):
100         # let the websockets package do the handshake with the client
101         try:
102             if subprotocols is not None:
103                 # subprotocols can be a set or frozenset,
104                 # but ServerProtocol needs a list
105                 subprotocols = cast(
106                     Optional[Sequence[Subprotocol]],
107                     list(
108                         [
109                             Subprotocol(subprotocol)
110                             for subprotocol in subprotocols
111                         ]
112                     ),
113                 )
114             ws_proto = ServerProtocol(
115                 max_size=self.websocket_max_size,
116                 subprotocols=subprotocols,
117                 state=OPEN,
118                 logger=logger,
119             )
120             resp: "http11.Response" = ws_proto.accept(request)
121         except Exception:
122             msg = (
123                 "Failed to open a WebSocket connection.\n"
124                 "See server log for more information.\n"
125             )
126             raise SanicException(msg, status_code=500)
127         if 100 <= resp.status_code <= 299:
128             first_line = (
129                 f"HTTP/1.1 {resp.status_code} {resp.reason_phrase}\r\n"
130             ).encode()
131             rbody = bytearray(first_line)
132             rbody += (
133                 "".join([f"{k}: {v}\r\n" for k, v in resp.headers.items()])
134             ).encode()
135             rbody += b"\r\n"
136             if resp.body is not None:
137                 rbody += resp.body
138                 rbody += b"\r\n\r\n"
139             await super().send(rbody)
140         else:
141             raise SanicException(resp.body, resp.status_code)
142         self.websocket = WebsocketImplProtocol(
143             ws_proto,
144             ping_interval=self.websocket_ping_interval,
145             ping_timeout=self.websocket_ping_timeout,
146             close_timeout=self.websocket_timeout,
147         )
148         loop = (
149             request.transport.loop
150             if hasattr(request, "transport")
151             and hasattr(request.transport, "loop")
152             else None
153         )
154         await self.websocket.connection_made(self, loop=loop)
155         return self.websocket
156
```
--- 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/sanic/server/protocols/websocket_protocol.py b/sanic/server/protocols/websocket_protocol.py
--- a/sanic/server/protocols/websocket_protocol.py
+++ b/sanic/server/protocols/websocket_protocol.py
@@ -1,4 +1,4 @@
-from typing import TYPE_CHECKING, Optional, Sequence, cast
+from typing import Optional, Sequence, cast
 
 
 try:  # websockets < 11.0
@@ -8,19 +8,18 @@
     from websockets.protocol import State  # type: ignore
     from websockets.server import ServerProtocol  # type: ignore
 
+from websockets import http11
+from websockets.datastructures import Headers as WSHeaders
 from websockets.typing import Subprotocol
 
 from sanic.exceptions import SanicException
 from sanic.log import logger
+from sanic.request import Request
 from sanic.server import HttpProtocol
 
 from ..websockets.impl import WebsocketImplProtocol
 
 
-if TYPE_CHECKING:
-    from websockets import http11
-
-
 OPEN = State.OPEN
 CLOSING = State.CLOSING
 CLOSED = State.CLOSED
@@ -94,6 +93,13 @@
         else:
             return super().close_if_idle()
 
+    @staticmethod
+    def sanic_request_to_ws_request(request: Request):
+        return http11.Request(
+            path=request.path,
+            headers=WSHeaders(request.headers),
+        )
+
     async def websocket_handshake(
         self, request, subprotocols: Optional[Sequence[str]] = None
     ):
@@ -117,7 +123,7 @@
                 state=OPEN,
                 logger=logger,
             )
-            resp: "http11.Response" = ws_proto.accept(request)
+            resp = ws_proto.accept(self.sanic_request_to_ws_request(request))
         except Exception:
             msg = (
                 "Failed to open a WebSocket connection.\n"

{"golden_diff": "diff --git a/sanic/server/protocols/websocket_protocol.py b/sanic/server/protocols/websocket_protocol.py\n--- a/sanic/server/protocols/websocket_protocol.py\n+++ b/sanic/server/protocols/websocket_protocol.py\n@@ -1,4 +1,4 @@\n-from typing import TYPE_CHECKING, Optional, Sequence, cast\n+from typing import Optional, Sequence, cast\n \n \n try:  # websockets < 11.0\n@@ -8,19 +8,18 @@\n     from websockets.protocol import State  # type: ignore\n     from websockets.server import ServerProtocol  # type: ignore\n \n+from websockets import http11\n+from websockets.datastructures import Headers as WSHeaders\n from websockets.typing import Subprotocol\n \n from sanic.exceptions import SanicException\n from sanic.log import logger\n+from sanic.request import Request\n from sanic.server import HttpProtocol\n \n from ..websockets.impl import WebsocketImplProtocol\n \n \n-if TYPE_CHECKING:\n-    from websockets import http11\n-\n-\n OPEN = State.OPEN\n CLOSING = State.CLOSING\n CLOSED = State.CLOSED\n@@ -94,6 +93,13 @@\n         else:\n             return super().close_if_idle()\n \n+    @staticmethod\n+    def sanic_request_to_ws_request(request: Request):\n+        return http11.Request(\n+            path=request.path,\n+            headers=WSHeaders(request.headers),\n+        )\n+\n     async def websocket_handshake(\n         self, request, subprotocols: Optional[Sequence[str]] = None\n     ):\n@@ -117,7 +123,7 @@\n                 state=OPEN,\n                 logger=logger,\n             )\n-            resp: \"http11.Response\" = ws_proto.accept(request)\n+            resp = ws_proto.accept(self.sanic_request_to_ws_request(request))\n         except Exception:\n             msg = (\n                 \"Failed to open a WebSocket connection.\\n\"\n", "issue": "Websocket invalid upgrade exception handling b0rkage\n### Is there an existing issue for this?\n\n- [X] I have searched the existing issues\n\n### Describe the bug\n\nA client apparently sent no Upgrade header to a websocket endpoint, leading to an error as it should. An ugly traceback is printed on terminal even though the error eventually gets handled correctly it would seem.\r\n\r\nIt would appear that the websockets module attempts to attach its exception on `request._exception` field which Sanic's Request doesn't have a slot for. This could be hidden if Sanic later used `raise BadRequest(...) from None` rather than `raise SanicException(...)`, suppressing the chain and giving a non-500 error for what really is no server error. Not sure though if that would from this context ever reach the client anyway but at least it could avoid a traceback in server log.\r\n\r\nIf anyone wants to investigate and make a PR, feel free to (I am currently busy and cannot do that unfortunately).\r\n\r\n```python\r\nTraceback (most recent call last):\r\n  File \"/home/user/.local/lib/python3.10/site-packages/websockets/server.py\", line 111, in accept\r\n    ) = self.process_request(request)\r\n  File \"/home/user/.local/lib/python3.10/site-packages/websockets/server.py\", line 218, in process_request\r\n    raise InvalidUpgrade(\"Upgrade\", \", \".join(upgrade) if upgrade else None)\r\nwebsockets.exceptions.InvalidUpgrade: missing Upgrade header\r\n\r\nDuring handling of the above exception, another exception occurred:\r\n\r\nTraceback (most recent call last):\r\n  File \"/home/user/sanic/sanic/server/protocols/websocket_protocol.py\", line 120, in websocket_handshake\r\n    resp: \"http11.Response\" = ws_proto.accept(request)\r\n  File \"/home/user/.local/lib/python3.10/site-packages/websockets/server.py\", line 122, in accept\r\n    request._exception = exc\r\nAttributeError: 'Request' object has no attribute '_exception'\r\n\r\nDuring handling of the above exception, another exception occurred:\r\n\r\nTraceback (most recent call last):\r\n  File \"handle_request\", line 97, in handle_request\r\n  File \"/home/user/sanic/sanic/app.py\", line 1047, in _websocket_handler\r\n    ws = await protocol.websocket_handshake(request, subprotocols)\r\n  File \"/home/user/sanic/sanic/server/protocols/websocket_protocol.py\", line 126, in websocket_handshake\r\n    raise SanicException(msg, status_code=500)\r\nsanic.exceptions.SanicException: Failed to open a WebSocket connection.\r\nSee server log for more information.\r\n```\r\n\n\n### Code snippet\n\n_No response_\n\n### Expected Behavior\n\n400 Bad Request error reaching the client and being more silent on server side. Including the message of **missing Upgrade header** would be helpful for debugging (e.g. in case Nginx proxy config forgot to forward that header).\n\n### How do you run Sanic?\n\nSanic CLI\n\n### Operating System\n\nLinux\n\n### Sanic Version\n\nAlmost 23.03.0 (a git version slightly before release)\n\n### Additional context\n\n_No response_\n", "before_files": [{"content": "from typing import TYPE_CHECKING, Optional, Sequence, cast\n\n\ntry:  # websockets < 11.0\n    from websockets.connection import State\n    from websockets.server import ServerConnection as ServerProtocol\nexcept ImportError:  # websockets >= 11.0\n    from websockets.protocol import State  # type: ignore\n    from websockets.server import ServerProtocol  # type: ignore\n\nfrom websockets.typing import Subprotocol\n\nfrom sanic.exceptions import SanicException\nfrom sanic.log import logger\nfrom sanic.server import HttpProtocol\n\nfrom ..websockets.impl import WebsocketImplProtocol\n\n\nif TYPE_CHECKING:\n    from websockets import http11\n\n\nOPEN = State.OPEN\nCLOSING = State.CLOSING\nCLOSED = State.CLOSED\n\n\nclass WebSocketProtocol(HttpProtocol):\n    __slots__ = (\n        \"websocket\",\n        \"websocket_timeout\",\n        \"websocket_max_size\",\n        \"websocket_ping_interval\",\n        \"websocket_ping_timeout\",\n    )\n\n    def __init__(\n        self,\n        *args,\n        websocket_timeout: float = 10.0,\n        websocket_max_size: Optional[int] = None,\n        websocket_ping_interval: Optional[float] = 20.0,\n        websocket_ping_timeout: Optional[float] = 20.0,\n        **kwargs,\n    ):\n        super().__init__(*args, **kwargs)\n        self.websocket: Optional[WebsocketImplProtocol] = None\n        self.websocket_timeout = websocket_timeout\n        self.websocket_max_size = websocket_max_size\n        self.websocket_ping_interval = websocket_ping_interval\n        self.websocket_ping_timeout = websocket_ping_timeout\n\n    def connection_lost(self, exc):\n        if self.websocket is not None:\n            self.websocket.connection_lost(exc)\n        super().connection_lost(exc)\n\n    def data_received(self, data):\n        if self.websocket is not None:\n            self.websocket.data_received(data)\n        else:\n            # Pass it to HttpProtocol handler first\n            # That will (hopefully) upgrade it to a websocket.\n            super().data_received(data)\n\n    def eof_received(self) -> Optional[bool]:\n        if self.websocket is not None:\n            return self.websocket.eof_received()\n        else:\n            return False\n\n    def close(self, timeout: Optional[float] = None):\n        # Called by HttpProtocol at the end of connection_task\n        # If we've upgraded to websocket, we do our own closing\n        if self.websocket is not None:\n            # Note, we don't want to use websocket.close()\n            # That is used for user's application code to send a\n            # websocket close packet. This is different.\n            self.websocket.end_connection(1001)\n        else:\n            super().close()\n\n    def close_if_idle(self):\n        # Called by Sanic Server when shutting down\n        # If we've upgraded to websocket, shut it down\n        if self.websocket is not None:\n            if self.websocket.ws_proto.state in (CLOSING, CLOSED):\n                return True\n            elif self.websocket.loop is not None:\n                self.websocket.loop.create_task(self.websocket.close(1001))\n            else:\n                self.websocket.end_connection(1001)\n        else:\n            return super().close_if_idle()\n\n    async def websocket_handshake(\n        self, request, subprotocols: Optional[Sequence[str]] = None\n    ):\n        # let the websockets package do the handshake with the client\n        try:\n            if subprotocols is not None:\n                # subprotocols can be a set or frozenset,\n                # but ServerProtocol needs a list\n                subprotocols = cast(\n                    Optional[Sequence[Subprotocol]],\n                    list(\n                        [\n                            Subprotocol(subprotocol)\n                            for subprotocol in subprotocols\n                        ]\n                    ),\n                )\n            ws_proto = ServerProtocol(\n                max_size=self.websocket_max_size,\n                subprotocols=subprotocols,\n                state=OPEN,\n                logger=logger,\n            )\n            resp: \"http11.Response\" = ws_proto.accept(request)\n        except Exception:\n            msg = (\n                \"Failed to open a WebSocket connection.\\n\"\n                \"See server log for more information.\\n\"\n            )\n            raise SanicException(msg, status_code=500)\n        if 100 <= resp.status_code <= 299:\n            first_line = (\n                f\"HTTP/1.1 {resp.status_code} {resp.reason_phrase}\\r\\n\"\n            ).encode()\n            rbody = bytearray(first_line)\n            rbody += (\n                \"\".join([f\"{k}: {v}\\r\\n\" for k, v in resp.headers.items()])\n            ).encode()\n            rbody += b\"\\r\\n\"\n            if resp.body is not None:\n                rbody += resp.body\n                rbody += b\"\\r\\n\\r\\n\"\n            await super().send(rbody)\n        else:\n            raise SanicException(resp.body, resp.status_code)\n        self.websocket = WebsocketImplProtocol(\n            ws_proto,\n            ping_interval=self.websocket_ping_interval,\n            ping_timeout=self.websocket_ping_timeout,\n            close_timeout=self.websocket_timeout,\n        )\n        loop = (\n            request.transport.loop\n            if hasattr(request, \"transport\")\n            and hasattr(request.transport, \"loop\")\n            else None\n        )\n        await self.websocket.connection_made(self, loop=loop)\n        return self.websocket\n", "path": "sanic/server/protocols/websocket_protocol.py"}], "after_files": [{"content": "from typing import Optional, Sequence, cast\n\n\ntry:  # websockets < 11.0\n    from websockets.connection import State\n    from websockets.server import ServerConnection as ServerProtocol\nexcept ImportError:  # websockets >= 11.0\n    from websockets.protocol import State  # type: ignore\n    from websockets.server import ServerProtocol  # type: ignore\n\nfrom websockets import http11\nfrom websockets.datastructures import Headers as WSHeaders\nfrom websockets.typing import Subprotocol\n\nfrom sanic.exceptions import SanicException\nfrom sanic.log import logger\nfrom sanic.request import Request\nfrom sanic.server import HttpProtocol\n\nfrom ..websockets.impl import WebsocketImplProtocol\n\n\nOPEN = State.OPEN\nCLOSING = State.CLOSING\nCLOSED = State.CLOSED\n\n\nclass WebSocketProtocol(HttpProtocol):\n    __slots__ = (\n        \"websocket\",\n        \"websocket_timeout\",\n        \"websocket_max_size\",\n        \"websocket_ping_interval\",\n        \"websocket_ping_timeout\",\n    )\n\n    def __init__(\n        self,\n        *args,\n        websocket_timeout: float = 10.0,\n        websocket_max_size: Optional[int] = None,\n        websocket_ping_interval: Optional[float] = 20.0,\n        websocket_ping_timeout: Optional[float] = 20.0,\n        **kwargs,\n    ):\n        super().__init__(*args, **kwargs)\n        self.websocket: Optional[WebsocketImplProtocol] = None\n        self.websocket_timeout = websocket_timeout\n        self.websocket_max_size = websocket_max_size\n        self.websocket_ping_interval = websocket_ping_interval\n        self.websocket_ping_timeout = websocket_ping_timeout\n\n    def connection_lost(self, exc):\n        if self.websocket is not None:\n            self.websocket.connection_lost(exc)\n        super().connection_lost(exc)\n\n    def data_received(self, data):\n        if self.websocket is not None:\n            self.websocket.data_received(data)\n        else:\n            # Pass it to HttpProtocol handler first\n            # That will (hopefully) upgrade it to a websocket.\n            super().data_received(data)\n\n    def eof_received(self) -> Optional[bool]:\n        if self.websocket is not None:\n            return self.websocket.eof_received()\n        else:\n            return False\n\n    def close(self, timeout: Optional[float] = None):\n        # Called by HttpProtocol at the end of connection_task\n        # If we've upgraded to websocket, we do our own closing\n        if self.websocket is not None:\n            # Note, we don't want to use websocket.close()\n            # That is used for user's application code to send a\n            # websocket close packet. This is different.\n            self.websocket.end_connection(1001)\n        else:\n            super().close()\n\n    def close_if_idle(self):\n        # Called by Sanic Server when shutting down\n        # If we've upgraded to websocket, shut it down\n        if self.websocket is not None:\n            if self.websocket.ws_proto.state in (CLOSING, CLOSED):\n                return True\n            elif self.websocket.loop is not None:\n                self.websocket.loop.create_task(self.websocket.close(1001))\n            else:\n                self.websocket.end_connection(1001)\n        else:\n            return super().close_if_idle()\n\n    @staticmethod\n    def sanic_request_to_ws_request(request: Request):\n        return http11.Request(\n            path=request.path,\n            headers=WSHeaders(request.headers),\n        )\n\n    async def websocket_handshake(\n        self, request, subprotocols: Optional[Sequence[str]] = None\n    ):\n        # let the websockets package do the handshake with the client\n        try:\n            if subprotocols is not None:\n                # subprotocols can be a set or frozenset,\n                # but ServerProtocol needs a list\n                subprotocols = cast(\n                    Optional[Sequence[Subprotocol]],\n                    list(\n                        [\n                            Subprotocol(subprotocol)\n                            for subprotocol in subprotocols\n                        ]\n                    ),\n                )\n            ws_proto = ServerProtocol(\n                max_size=self.websocket_max_size,\n                subprotocols=subprotocols,\n                state=OPEN,\n                logger=logger,\n            )\n            resp = ws_proto.accept(self.sanic_request_to_ws_request(request))\n        except Exception:\n            msg = (\n                \"Failed to open a WebSocket connection.\\n\"\n                \"See server log for more information.\\n\"\n            )\n            raise SanicException(msg, status_code=500)\n        if 100 <= resp.status_code <= 299:\n            first_line = (\n                f\"HTTP/1.1 {resp.status_code} {resp.reason_phrase}\\r\\n\"\n            ).encode()\n            rbody = bytearray(first_line)\n            rbody += (\n                \"\".join([f\"{k}: {v}\\r\\n\" for k, v in resp.headers.items()])\n            ).encode()\n            rbody += b\"\\r\\n\"\n            if resp.body is not None:\n                rbody += resp.body\n                rbody += b\"\\r\\n\\r\\n\"\n            await super().send(rbody)\n        else:\n            raise SanicException(resp.body, resp.status_code)\n        self.websocket = WebsocketImplProtocol(\n            ws_proto,\n            ping_interval=self.websocket_ping_interval,\n            ping_timeout=self.websocket_ping_timeout,\n            close_timeout=self.websocket_timeout,\n        )\n        loop = (\n            request.transport.loop\n            if hasattr(request, \"transport\")\n            and hasattr(request.transport, \"loop\")\n            else None\n        )\n        await self.websocket.connection_made(self, loop=loop)\n        return self.websocket\n", "path": "sanic/server/protocols/websocket_protocol.py"}]}