Update to gunicorn_h1c >= 0.6.2 for asgi_headers support

- Use asgi_headers property (lowercase names) from fast parser
- Bump version to 25.3.0
- Update changelog with all changes for this release
This commit is contained in:
Benoit Chesneau 2026-03-26 15:02:57 +01:00
parent cbd27e82a2
commit d43acb8fe0
7 changed files with 73 additions and 7 deletions

View File

@ -1,6 +1,36 @@
<span id="news-2026"></span>
# Changelog - 2026
## 25.3.0 - 2026-03-26
### Bug Fixes
- **HTTP/2 ASGI Body Duplication**: Fix request body being received twice in HTTP/2
ASGI requests, causing JSON parsing errors with "Extra data" messages
([#3558](https://github.com/benoitc/gunicorn/issues/3558))
- **ASGI Chunked EOF Handling**: Add `finish()` method to callback parser to handle
chunked encoding edge case where connection closes before final CRLF after zero-chunk
### Security
- **ASGI Parser Header Validation**: Add security checks per RFC 9110/9112:
- Reject duplicate Content-Length headers
- Reject requests with both Content-Length and Transfer-Encoding
- Reject chunked transfer encoding in HTTP/1.0
- Reject stacked chunked encoding
- Validate Transfer-Encoding values
- Strict chunk size validation
### Changes
- **Fast HTTP Parser**: Update to gunicorn_h1c >= 0.6.2 for `asgi_headers` property
which provides headers with lowercase names directly from the C parser
- **ASGI PROXY Protocol**: Add PROXY protocol v1/v2 support to callback parser
---
## 25.2.0 - 2026-03-24
### New Features

View File

@ -1,6 +1,36 @@
<span id="news"></span>
# Changelog
## 25.3.0 - 2026-03-26
### Bug Fixes
- **HTTP/2 ASGI Body Duplication**: Fix request body being received twice in HTTP/2
ASGI requests, causing JSON parsing errors with "Extra data" messages
([#3558](https://github.com/benoitc/gunicorn/issues/3558))
- **ASGI Chunked EOF Handling**: Add `finish()` method to callback parser to handle
chunked encoding edge case where connection closes before final CRLF after zero-chunk
### Security
- **ASGI Parser Header Validation**: Add security checks per RFC 9110/9112:
- Reject duplicate Content-Length headers
- Reject requests with both Content-Length and Transfer-Encoding
- Reject chunked transfer encoding in HTTP/1.0
- Reject stacked chunked encoding
- Validate Transfer-Encoding values
- Strict chunk size validation
### Changes
- **Fast HTTP Parser**: Update to gunicorn_h1c >= 0.6.2 for `asgi_headers` property
which provides headers with lowercase names directly from the C parser
- **ASGI PROXY Protocol**: Add PROXY protocol v1/v2 support to callback parser
---
## 25.2.0 - 2026-03-24
### New Features

View File

@ -2,7 +2,7 @@
# This file is part of gunicorn released under the MIT license.
# See the NOTICE for more information.
version_info = (25, 2, 0)
version_info = (25, 3, 0)
__version__ = ".".join([str(v) for v in version_info])
SERVER = "gunicorn"
SERVER_SOFTWARE = "%s/%s" % (SERVER, __version__)

View File

@ -835,7 +835,9 @@ class CallbackRequest:
req.version = parser.http_version
# Headers - store both bytes (for ASGI scope) and strings (for compatibility)
req.headers_bytes = list(parser.headers)
# Use asgi_headers (lowercase names) if available (fast parser >= 0.6.2),
# otherwise fall back to headers (Python parser already uses lowercase)
req.headers_bytes = list(getattr(parser, 'asgi_headers', None) or parser.headers)
req.headers = [
(n.decode('latin-1').upper(), v.decode('latin-1'))
for n, v in parser.headers

View File

@ -53,7 +53,11 @@ tornado = ["tornado>=6.5.0"]
gthread = []
setproctitle = ["setproctitle"]
http2 = ["h2>=4.1.0"]
fast = ["gunicorn_h1c>=0.6.0"]
fast = ["gunicorn_h1c>=0.6.2"]
testing = [
"gevent>=24.10.1",
"eventlet>=0.40.3",

View File

@ -3,4 +3,4 @@ coverage
pytest>=7.2.0
pytest-cov
pytest-asyncio
gunicorn_h1c>=0.6.0
gunicorn_h1c>=0.6.2

View File

@ -21,7 +21,7 @@ def http_parser(request):
"""Parametrize tests over http_parser implementations."""
if request.param == "fast":
gunicorn_h1c = pytest.importorskip("gunicorn_h1c", reason="gunicorn_h1c required")
# Require >= 0.6.0 for header framing validation
if not hasattr(gunicorn_h1c, 'InvalidHeader'):
pytest.skip("gunicorn_h1c >= 0.6.0 required")
# Require >= 0.6.2 for asgi_headers support
if not hasattr(gunicorn_h1c.H1CProtocol, 'asgi_headers'):
pytest.skip("gunicorn_h1c >= 0.6.2 required")
return request.param