diff --git a/coven_github_adapter.py b/coven_github_adapter.py index 5eb521c..2980ef1 100644 --- a/coven_github_adapter.py +++ b/coven_github_adapter.py @@ -215,7 +215,7 @@ def read_request_body(environ): length = -1 if length > MAX_WEBHOOK_BODY_BYTES: raise PayloadTooLarge - if length > 0: + if length >= 0: return environ["wsgi.input"].read(length) body = environ["wsgi.input"].read(MAX_WEBHOOK_BODY_BYTES + 1) if len(body) > MAX_WEBHOOK_BODY_BYTES: diff --git a/tests/test_webhook_adapter.py b/tests/test_webhook_adapter.py index bc26872..574e868 100644 --- a/tests/test_webhook_adapter.py +++ b/tests/test_webhook_adapter.py @@ -149,6 +149,27 @@ def test_webhook_reads_body_when_content_length_is_unparsable(self): self.assertEqual(status, "200 OK") self.assertTrue(payload["ok"]) + def test_webhook_treats_zero_content_length_as_empty_body(self): + with tempfile.TemporaryDirectory() as tmp: + from pathlib import Path + + secret = "zero-length-secret" + adapter = import_adapter(Path(tmp), secret) + + status, payload = self.call_app( + adapter, + b'{"zen":"Keep it logically awesome."}', + { + "X-GitHub-Event": "ping", + "X-GitHub-Delivery": "delivery-zero-length", + "X-Hub-Signature-256": signature(secret, b""), + }, + content_length=0, + ) + + self.assertEqual(status, "400 Bad Request") + self.assertEqual(payload["error"], "invalid json") + def test_webhook_rejects_oversized_content_length_before_signature_check(self): with tempfile.TemporaryDirectory() as tmp: from pathlib import Path