Fix --limit-request-line 0 to mean unlimited

Per documentation, limit_request_line=0 means unlimited. The code was
incorrectly treating 0 as "use default max" by checking <= 0 instead
of < 0.

For the fast C parser (gunicorn_h1c), which doesn't support 0 as
unlimited, pass a large value (1MB) instead. This applies to both
WSGI workers (http/message.py) and ASGI workers (asgi/protocol.py).

Fixes #3563
This commit is contained in:
Benoit Chesneau 2026-03-26 23:39:01 +01:00
parent d40a374547
commit 8d08aaa2cb
4 changed files with 21 additions and 18 deletions

View File

@ -419,12 +419,18 @@ class ASGIProtocol(asyncio.Protocol):
else:
parser_class = PythonProtocol
# Handle limit_request_line=0 (unlimited per documentation)
# PythonProtocol handles 0 correctly, but C parser needs a large value
limit_request_line = self.cfg.limit_request_line
if limit_request_line == 0 and parser_class != PythonProtocol:
limit_request_line = 1024 * 1024 # 1MB for C parser
# Create parser with callbacks and limit parameters (both parsers support them)
self._callback_parser = parser_class(
on_headers_complete=self._on_headers_complete,
on_body=self._on_body,
on_message_complete=self._on_message_complete,
limit_request_line=self.cfg.limit_request_line,
limit_request_line=limit_request_line,
limit_request_fields=self.cfg.limit_request_fields,
limit_request_field_size=self.cfg.limit_request_field_size,
permit_unconventional_http_method=self.cfg.permit_unconventional_http_method,

View File

@ -387,11 +387,19 @@ class Request(Message):
self.query = None
self.fragment = None
# get max request line size
# get max request line size (0 means unlimited per documentation)
self.limit_request_line = cfg.limit_request_line
if (self.limit_request_line <= 0
or self.limit_request_line >= MAX_REQUEST_LINE):
if self.limit_request_line < 0:
self.limit_request_line = MAX_REQUEST_LINE
# For fast parser: use large value when unlimited (0), since C parser
# doesn't support 0 as unlimited. 1MB should be more than enough.
if self.limit_request_line == 0:
self._fast_limit_request_line = 1024 * 1024 # 1MB
elif self.limit_request_line >= MAX_REQUEST_LINE:
self._fast_limit_request_line = MAX_REQUEST_LINE
self.limit_request_line = MAX_REQUEST_LINE
else:
self._fast_limit_request_line = self.limit_request_line
self.req_number = req_number
self.proxy_protocol_info = None
@ -433,10 +441,11 @@ class Request(Message):
while True:
try:
# Pass all limit parameters to C parser
# Use _fast_limit_request_line which handles 0=unlimited
result = _fast_parser_module.parse_request(
data,
last_len=last_len,
limit_request_line=self.limit_request_line,
limit_request_line=self._fast_limit_request_line,
limit_request_fields=self.limit_request_fields,
limit_request_field_size=self.limit_request_field_size,
permit_unconventional_http_method=self.cfg.permit_unconventional_http_method,
@ -447,7 +456,7 @@ class Request(Message):
last_len = len(data)
self.read_into(unreader, buf)
data = bytes(buf)
if len(data) > self.max_buffer_headers + self.limit_request_line:
if len(data) > self.max_buffer_headers + self._fast_limit_request_line:
raise LimitRequestHeaders("max buffer headers")
except _fast_parser_module.LimitRequestLine as e:
raise LimitRequestLine(str(e))

File diff suppressed because one or more lines are too long

View File

@ -1,11 +0,0 @@
#
# This file is part of gunicorn released under the MIT license.
# See the NOTICE for more information.
from gunicorn.config import Config
from gunicorn.http.errors import LimitRequestLine
cfg = Config()
# Setting limit_request_line=0 should use default max (8190)
cfg.set('limit_request_line', 0)
request = LimitRequestLine