From ecd7250ca5a9786eac42a6652dedfa380e45535c Mon Sep 17 00:00:00 2001 From: "John L. Villalovos" Date: Thu, 10 Apr 2025 12:59:58 -0700 Subject: [PATCH] fix: allow 'Content-Length' = "0" Shelly devices send a 'Content-Length' header with a value of "0". Allow this as this also means there is not a request body. In addition give a bit more detail in the error message. Closes: #1616 --- src/websockets/http11.py | 7 ++++++- tests/test_http11.py | 20 +++++++++++++++++++- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/src/websockets/http11.py b/src/websockets/http11.py index 530ac3d09..eddec97a8 100644 --- a/src/websockets/http11.py +++ b/src/websockets/http11.py @@ -159,7 +159,12 @@ def parse( raise NotImplementedError("transfer codings aren't supported") if "Content-Length" in headers: - raise ValueError("unsupported request body") + content_length = headers["Content-Length"] + if content_length != "0": + raise ValueError( + f"unsupported request body as 'Content-Length' is " + f"non-zero: {content_length}" + ) return cls(path, headers) diff --git a/tests/test_http11.py b/tests/test_http11.py index 3afb6d02c..86f0b8d08 100644 --- a/tests/test_http11.py +++ b/tests/test_http11.py @@ -83,9 +83,27 @@ def test_parse_body(self): next(self.parse()) self.assertEqual( str(raised.exception), - "unsupported request body", + "unsupported request body as 'Content-Length' is non-zero: 3", ) + def test_parse_body_content_length_zero(self): + # Example from the protocol overview in RFC 6455 + self.reader.feed_data( + b"GET /chat HTTP/1.1\r\n" + b"Host: server.example.com\r\n" + b"Upgrade: websocket\r\n" + b"Connection: Upgrade\r\n" + b"Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n" + b"Origin: http://example.com\r\n" + b"Sec-WebSocket-Protocol: chat, superchat\r\n" + b"Sec-WebSocket-Version: 13\r\n" + b"Content-Length: 0\r\n" + b"\r\n" + ) + request = self.assertGeneratorReturns(self.parse()) + self.assertEqual(request.path, "/chat") + self.assertEqual(request.headers["Content-Length"], "0") + def test_parse_body_with_transfer_encoding(self): self.reader.feed_data(b"GET / HTTP/1.1\r\nTransfer-Encoding: compress\r\n\r\n") with self.assertRaises(NotImplementedError) as raised: