Handle Daphne-Root-Path for websockets, adding root_path to scope. (#453)

Signed-off-by: Alejandro R. Sedeño <asedeno@mit.edu>
This commit is contained in:
Alejandro R. Sedeño 2024-02-06 03:15:03 -05:00 committed by GitHub
parent 5fdc9176e5
commit 9a282dd627
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 31 additions and 2 deletions

View File

@ -31,17 +31,21 @@ class WebSocketProtocol(WebSocketServerProtocol):
self.server.protocol_connected(self) self.server.protocol_connected(self)
self.request = request self.request = request
self.protocol_to_accept = None self.protocol_to_accept = None
self.root_path = self.server.root_path
self.socket_opened = time.time() self.socket_opened = time.time()
self.last_ping = time.time() self.last_ping = time.time()
try: try:
# Sanitize and decode headers # Sanitize and decode headers, potentially extracting root path
self.clean_headers = [] self.clean_headers = []
for name, value in request.headers.items(): for name, value in request.headers.items():
name = name.encode("ascii") name = name.encode("ascii")
# Prevent CVE-2015-0219 # Prevent CVE-2015-0219
if b"_" in name: if b"_" in name:
continue continue
self.clean_headers.append((name.lower(), value.encode("latin1"))) if name.lower() == b"daphne-root-path":
self.root_path = unquote(value)
else:
self.clean_headers.append((name.lower(), value.encode("latin1")))
# Get client address if possible # Get client address if possible
peer = self.transport.getPeer() peer = self.transport.getPeer()
host = self.transport.getHost() host = self.transport.getHost()
@ -76,6 +80,7 @@ class WebSocketProtocol(WebSocketServerProtocol):
"type": "websocket", "type": "websocket",
"path": unquote(self.path.decode("ascii")), "path": unquote(self.path.decode("ascii")),
"raw_path": self.path, "raw_path": self.path,
"root_path": self.root_path,
"headers": self.clean_headers, "headers": self.clean_headers,
"query_string": self._raw_query_string, # Passed by HTTP protocol "query_string": self._raw_query_string, # Passed by HTTP protocol
"client": self.client_addr, "client": self.client_addr,

View File

@ -192,6 +192,30 @@ class TestWebsocket(DaphneTestCase):
self.assertEqual(scope["path"], "/foo/bar") self.assertEqual(scope["path"], "/foo/bar")
self.assertEqual(scope["raw_path"], b"/foo%2Fbar") self.assertEqual(scope["raw_path"], b"/foo%2Fbar")
@given(daphne_path=http_strategies.http_path())
@settings(max_examples=5, deadline=2000)
def test_root_path(self, *, daphne_path):
"""
Tests root_path handling.
"""
headers = [("Daphne-Root-Path", parse.quote(daphne_path))]
with DaphneTestingInstance() as test_app:
test_app.add_send_messages([{"type": "websocket.accept"}])
self.websocket_handshake(
test_app,
path="/",
headers=headers,
)
# Validate the scope and messages we got
scope, _ = test_app.get_received()
# Daphne-Root-Path is not included in the returned 'headers' section.
self.assertNotIn(
"daphne-root-path", (header[0].lower() for header in scope["headers"])
)
# And what we're looking for, root_path being set.
self.assertEqual(scope["root_path"], daphne_path)
def test_text_frames(self): def test_text_frames(self):
""" """
Tests we can send and receive text frames. Tests we can send and receive text frames.