From ba9bc827f44c1a7e08add3789883a2c16ae1bd1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20R=2E=20Sede=C3=B1o?= Date: Tue, 15 Nov 2022 17:04:23 -0500 Subject: [PATCH 1/2] Add a test for Daphne-Root-Path handling for websockets. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Alejandro R. Sedeño Signed-off-by: Alejandro R Sedeño --- tests/test_websocket.py | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/tests/test_websocket.py b/tests/test_websocket.py index e9544863..851143c8 100644 --- a/tests/test_websocket.py +++ b/tests/test_websocket.py @@ -192,6 +192,30 @@ def test_raw_path(self): self.assertEqual(scope["path"], "/foo/bar") 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): """ Tests we can send and receive text frames. From cecd4763354be10df7bfce77a2b0d1da954e4daf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20R=2E=20Sede=C3=B1o?= Date: Tue, 15 Nov 2022 17:04:59 -0500 Subject: [PATCH 2/2] Handle Daphne-Root-Path for websockets, adding root_path to scope. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Alejandro R. Sedeño Signed-off-by: Alejandro R Sedeño --- daphne/ws_protocol.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/daphne/ws_protocol.py b/daphne/ws_protocol.py index 975b1a9e..184515db 100755 --- a/daphne/ws_protocol.py +++ b/daphne/ws_protocol.py @@ -31,17 +31,21 @@ def onConnect(self, request): self.server.protocol_connected(self) self.request = request self.protocol_to_accept = None + self.root_path = self.server.root_path self.socket_opened = time.time() self.last_ping = time.time() try: - # Sanitize and decode headers + # Sanitize and decode headers, potentially extracting root path self.clean_headers = [] for name, value in request.headers.items(): name = name.encode("ascii") # Prevent CVE-2015-0219 if b"_" in name: 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 peer = self.transport.getPeer() host = self.transport.getHost() @@ -76,6 +80,7 @@ def onConnect(self, request): "type": "websocket", "path": unquote(self.path.decode("ascii")), "raw_path": self.path, + "root_path": self.root_path, "headers": self.clean_headers, "query_string": self._raw_query_string, # Passed by HTTP protocol "client": self.client_addr,