From d27942470c3b1a12d3c8831687f2c8d217f55354 Mon Sep 17 00:00:00 2001 From: "Paul J. Dorn" Date: Thu, 20 Mar 2025 22:06:08 +0100 Subject: [PATCH] refuse HTTP method CONNECT Semantics not implemented, and URL parser does not enforce the syntactical requirement for the request-target to include the port. --- gunicorn/http/message.py | 6 ++++++ tests/requests/invalid/method_01.http | 4 ++++ tests/requests/invalid/method_01.py | 3 +++ tests/requests/invalid/method_02.http | 4 ++++ tests/requests/invalid/method_02.py | 3 +++ 5 files changed, 20 insertions(+) create mode 100644 tests/requests/invalid/method_01.http create mode 100644 tests/requests/invalid/method_01.py create mode 100644 tests/requests/invalid/method_02.http create mode 100644 tests/requests/invalid/method_02.py diff --git a/gunicorn/http/message.py b/gunicorn/http/message.py index 59ce0bf4b..dc19c1605 100644 --- a/gunicorn/http/message.py +++ b/gunicorn/http/message.py @@ -417,6 +417,12 @@ def parse_request_line(self, line_bytes): raise InvalidRequestMethod(self.method) if not 3 <= len(bits[0]) <= 20: raise InvalidRequestMethod(self.method) + # this restriction mitigates the failure to validate authority-form below + # ! do not remove simply because cfg.permit_unconventional_http_method is removed + if self.method == "CONNECT": + # BUG: method is not necessarily invalid, merely unsupported + # TODO: improve once Worker.handle_error is refactored + raise InvalidRequestMethod(self.method) # standard restriction: RFC9110 token if not TOKEN_RE.fullmatch(self.method): raise InvalidRequestMethod(self.method) diff --git a/tests/requests/invalid/method_01.http b/tests/requests/invalid/method_01.http new file mode 100644 index 000000000..2c956830b --- /dev/null +++ b/tests/requests/invalid/method_01.http @@ -0,0 +1,4 @@ +CONNECT host:25 HTTP/1.1\r\n +Content-Length: 3\r\n +\r\n +BOO diff --git a/tests/requests/invalid/method_01.py b/tests/requests/invalid/method_01.py new file mode 100644 index 000000000..ab97a34fa --- /dev/null +++ b/tests/requests/invalid/method_01.py @@ -0,0 +1,3 @@ +from gunicorn.http.errors import InvalidRequestMethod + +request = InvalidRequestMethod diff --git a/tests/requests/invalid/method_02.http b/tests/requests/invalid/method_02.http new file mode 100644 index 000000000..47a36e18d --- /dev/null +++ b/tests/requests/invalid/method_02.http @@ -0,0 +1,4 @@ +CONNECT domain.example HTTP/1.1\r\n +Content-Length: 3\r\n +\r\n +FOO diff --git a/tests/requests/invalid/method_02.py b/tests/requests/invalid/method_02.py new file mode 100644 index 000000000..ab97a34fa --- /dev/null +++ b/tests/requests/invalid/method_02.py @@ -0,0 +1,3 @@ +from gunicorn.http.errors import InvalidRequestMethod + +request = InvalidRequestMethod