mirror of
https://github.com/frappe/gunicorn.git
synced 2026-01-14 11:09:11 +08:00
strict HTTP version validation
Note: This is unrelated to a reverse proxy potentially talking HTTP/3 to clients. This is about the HTTP protocol version spoken to Gunicorn, which is HTTP/1.0 or HTTP/1.1. Little legitimate need for processing HTTP 1 requests with ambiguous version numbers. Broadly refuse. Co-authored-by: Ben Kallus <benjamin.p.kallus.gr@dartmouth.edu>
This commit is contained in:
parent
f5501111a2
commit
7ebe442d08
@ -2282,6 +2282,26 @@ class PermitUnconventionalHTTPMethod(Setting):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
class PermitUnconventionalHTTPVersion(Setting):
|
||||||
|
name = "permit_unconventional_http_version"
|
||||||
|
section = "Server Mechanics"
|
||||||
|
cli = ["--permit-unconventional-http-version"]
|
||||||
|
validator = validate_bool
|
||||||
|
action = "store_true"
|
||||||
|
default = False
|
||||||
|
desc = """\
|
||||||
|
Permit HTTP version not matching conventions of 2023
|
||||||
|
|
||||||
|
This disables the refusal of likely malformed request lines.
|
||||||
|
It is unusual to specify HTTP 1 versions other than 1.0 and 1.1.
|
||||||
|
|
||||||
|
This option is provided to diagnose backwards-incompatible changes.
|
||||||
|
Use with care and only if necessary. May be removed in a future version.
|
||||||
|
|
||||||
|
.. versionadded:: 22.0.0
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
class CasefoldHTTPMethod(Setting):
|
class CasefoldHTTPMethod(Setting):
|
||||||
name = "casefold_http_method"
|
name = "casefold_http_method"
|
||||||
section = "Server Mechanics"
|
section = "Server Mechanics"
|
||||||
|
|||||||
@ -26,7 +26,8 @@ DEFAULT_MAX_HEADERFIELD_SIZE = 8190
|
|||||||
RFC9110_5_6_2_TOKEN_SPECIALS = r"!#$%&'*+-.^_`|~"
|
RFC9110_5_6_2_TOKEN_SPECIALS = r"!#$%&'*+-.^_`|~"
|
||||||
TOKEN_RE = re.compile(r"[%s0-9a-zA-Z]+" % (re.escape(RFC9110_5_6_2_TOKEN_SPECIALS)))
|
TOKEN_RE = re.compile(r"[%s0-9a-zA-Z]+" % (re.escape(RFC9110_5_6_2_TOKEN_SPECIALS)))
|
||||||
METHOD_BADCHAR_RE = re.compile("[a-z#]")
|
METHOD_BADCHAR_RE = re.compile("[a-z#]")
|
||||||
VERSION_RE = re.compile(r"HTTP/(\d+)\.(\d+)")
|
# usually 1.0 or 1.1 - RFC9112 permits restricting to single-digit versions
|
||||||
|
VERSION_RE = re.compile(r"HTTP/(\d)\.(\d)")
|
||||||
|
|
||||||
|
|
||||||
class Message(object):
|
class Message(object):
|
||||||
@ -438,6 +439,10 @@ class Request(Message):
|
|||||||
if match is None:
|
if match is None:
|
||||||
raise InvalidHTTPVersion(bits[2])
|
raise InvalidHTTPVersion(bits[2])
|
||||||
self.version = (int(match.group(1)), int(match.group(2)))
|
self.version = (int(match.group(1)), int(match.group(2)))
|
||||||
|
if not (1, 0) <= self.version < (2, 0):
|
||||||
|
# if ever relaxing this, carefully review Content-Encoding processing
|
||||||
|
if not self.cfg.permit_unconventional_http_version:
|
||||||
|
raise InvalidHTTPVersion(self.version)
|
||||||
|
|
||||||
def set_body_reader(self):
|
def set_body_reader(self):
|
||||||
super().set_body_reader()
|
super().set_body_reader()
|
||||||
|
|||||||
4
tests/requests/invalid/prefix_06.http
Normal file
4
tests/requests/invalid/prefix_06.http
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
GET /the/future HTTP/1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111.1\r\n
|
||||||
|
Content-Length: 7\r\n
|
||||||
|
\r\n
|
||||||
|
Old Man
|
||||||
5
tests/requests/invalid/prefix_06.py
Normal file
5
tests/requests/invalid/prefix_06.py
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
from gunicorn.config import Config
|
||||||
|
from gunicorn.http.errors import InvalidHTTPVersion
|
||||||
|
|
||||||
|
cfg = Config()
|
||||||
|
request = InvalidHTTPVersion
|
||||||
2
tests/requests/invalid/version_01.http
Normal file
2
tests/requests/invalid/version_01.http
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
GET /foo HTTP/0.99\r\n
|
||||||
|
\r\n
|
||||||
2
tests/requests/invalid/version_01.py
Normal file
2
tests/requests/invalid/version_01.py
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
from gunicorn.http.errors import InvalidHTTPVersion
|
||||||
|
request = InvalidHTTPVersion
|
||||||
2
tests/requests/invalid/version_02.http
Normal file
2
tests/requests/invalid/version_02.http
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
GET /foo HTTP/2.0\r\n
|
||||||
|
\r\n
|
||||||
2
tests/requests/invalid/version_02.py
Normal file
2
tests/requests/invalid/version_02.py
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
from gunicorn.http.errors import InvalidHTTPVersion
|
||||||
|
request = InvalidHTTPVersion
|
||||||
Loading…
x
Reference in New Issue
Block a user