diff --git a/gunicorn/asgi/parser.py b/gunicorn/asgi/parser.py index 34e4af8d..3f4c8bea 100644 --- a/gunicorn/asgi/parser.py +++ b/gunicorn/asgi/parser.py @@ -460,6 +460,13 @@ class PythonProtocol: if self.path == b'*' and self.method != b'OPTIONS': raise InvalidRequestLine("Invalid request line") + # RFC 9112 section 3.2.3: authority-form is only valid with CONNECT. + if (self.method != b'CONNECT' + and self.path != b'*' + and not self.path.startswith(b'/') + and b'://' not in self.path): + raise InvalidRequestLine("Invalid request line") + # Parse version version = parts[2] if version == b'HTTP/1.1': diff --git a/gunicorn/http/message.py b/gunicorn/http/message.py index 0236bc35..7e835f9f 100644 --- a/gunicorn/http/message.py +++ b/gunicorn/http/message.py @@ -811,6 +811,15 @@ class Request(Message): if self.uri == "*" and self.method != "OPTIONS": raise InvalidRequestLine(bytes_to_str(line_bytes)) + # RFC 9112 section 3.2.3: authority-form ("host:port") is only valid + # with CONNECT. origin-form starts with "/"; absolute-form contains + # "://". Anything else on a non-CONNECT request is authority-form. + if (self.method != "CONNECT" + and self.uri != "*" + and not self.uri.startswith("/") + and "://" not in self.uri): + raise InvalidRequestLine(bytes_to_str(line_bytes)) + try: parts = split_request_uri(self.uri) except ValueError: