Skip to content

Commit 59ec1de

Browse files
authored
Fix multiple issues in websockets sansio implementation (#2825)
1 parent 2fc0efc commit 59ec1de

1 file changed

Lines changed: 22 additions & 20 deletions

File tree

uvicorn/protocols/websockets/websockets_sansio_impl.py

Lines changed: 22 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
from uvicorn.logging import TRACE_LOG_LEVEL
2929
from uvicorn.protocols.utils import (
3030
ClientDisconnected,
31+
get_client_addr,
3132
get_local_addr,
3233
get_path_with_query_string,
3334
get_remote_addr,
@@ -187,14 +188,14 @@ def handle_connect(self, event: Request) -> None:
187188
raw_path, _, query_string = event.path.partition("?")
188189
self.scope: WebSocketScope = {
189190
"type": "websocket",
190-
"asgi": {"version": self.config.asgi_version, "spec_version": "2.3"},
191+
"asgi": {"version": self.config.asgi_version, "spec_version": "2.4"},
191192
"http_version": "1.1",
192193
"scheme": self.scheme,
193194
"server": self.server,
194195
"client": self.client,
195196
"root_path": self.root_path,
196-
"path": unquote(raw_path),
197-
"raw_path": raw_path.encode("ascii"),
197+
"path": self.root_path + unquote(raw_path),
198+
"raw_path": self.root_path.encode("ascii") + raw_path.encode("ascii"),
198199
"query_string": query_string.encode("ascii"),
199200
"headers": headers,
200201
"subprotocols": event.headers.get_all("Sec-WebSocket-Protocol"),
@@ -301,11 +302,11 @@ async def send(self, message: ASGISendEvent) -> None:
301302
message = cast(WebSocketAcceptEvent, message)
302303
self.logger.info(
303304
'%s - "WebSocket %s" [accepted]',
304-
self.scope["client"],
305+
get_client_addr(self.scope),
305306
get_path_with_query_string(self.scope),
306307
)
307308
headers = [
308-
(name.decode("latin-1").lower(), value.decode("latin-1").lower())
309+
(name.decode("latin-1").lower(), value.decode("latin-1"))
309310
for name, value in (self.default_headers + list(message.get("headers", [])))
310311
]
311312
accepted_subprotocol = message.get("subprotocol")
@@ -324,7 +325,7 @@ async def send(self, message: ASGISendEvent) -> None:
324325
self.queue.put_nowait({"type": "websocket.disconnect", "code": 1006})
325326
self.logger.info(
326327
'%s - "WebSocket %s" 403',
327-
self.scope["client"],
328+
get_client_addr(self.scope),
328329
get_path_with_query_string(self.scope),
329330
)
330331
response = self.conn.reject(HTTPStatus.FORBIDDEN, "")
@@ -340,7 +341,7 @@ async def send(self, message: ASGISendEvent) -> None:
340341
raise RuntimeError("Invalid HTTP status code '%d' in response." % message["status"])
341342
self.logger.info(
342343
'%s - "WebSocket %s" %d',
343-
self.scope["client"],
344+
get_client_addr(self.scope),
344345
get_path_with_query_string(self.scope),
345346
message["status"],
346347
)
@@ -363,23 +364,24 @@ async def send(self, message: ASGISendEvent) -> None:
363364
message = cast(WebSocketSendEvent, message)
364365
bytes_data = message.get("bytes")
365366
text_data = message.get("text")
366-
if text_data:
367-
self.conn.send_text(text_data.encode())
368-
elif bytes_data:
367+
if bytes_data is not None:
369368
self.conn.send_binary(bytes_data)
369+
elif text_data is not None:
370+
self.conn.send_text(text_data.encode())
370371
output = self.conn.data_to_send()
371372
self.transport.write(b"".join(output))
372373

373-
elif message_type == "websocket.close" and not self.transport.is_closing():
374-
message = cast(WebSocketCloseEvent, message)
375-
code = message.get("code", 1000)
376-
reason = message.get("reason", "") or ""
377-
self.queue.put_nowait({"type": "websocket.disconnect", "code": code, "reason": reason})
378-
self.conn.send_close(code, reason)
379-
output = self.conn.data_to_send()
380-
self.transport.write(b"".join(output))
381-
self.close_sent = True
382-
self.transport.close()
374+
elif message_type == "websocket.close":
375+
if not self.transport.is_closing():
376+
message = cast(WebSocketCloseEvent, message)
377+
code = message.get("code", 1000)
378+
reason = message.get("reason", "") or ""
379+
self.queue.put_nowait({"type": "websocket.disconnect", "code": code, "reason": reason})
380+
self.conn.send_close(code, reason)
381+
output = self.conn.data_to_send()
382+
self.transport.write(b"".join(output))
383+
self.close_sent = True
384+
self.transport.close()
383385
else:
384386
msg = "Expected ASGI message 'websocket.send' or 'websocket.close', but got '%s'."
385387
raise RuntimeError(msg % message_type)

0 commit comments

Comments
 (0)