Compare commits

...

3 Commits

Author SHA1 Message Date
Marcelo Trylesinski
cfc5be302f Restore has_close_header tracking
keep_alive can be False from HTTP/1.0 initialization, not only from
a response Connection: close header, so it cannot replace the flag.
2026-03-15 18:25:23 +01:00
Marcelo Trylesinski
cd2f5a59ea Use keep_alive flag instead of tracking has_close_header separately 2026-03-15 18:18:06 +01:00
Marcelo Trylesinski
27e125f123 Reduce allocations in response header construction
httptools: iterate default_headers and response headers directly into
the content buffer instead of building an intermediate combined list.
Track connection close inline to avoid a second scan.

h11: use unpacking instead of list() conversion, and append in-place
instead of allocating a new list for the close header.
2026-03-15 18:14:07 +01:00
2 changed files with 12 additions and 6 deletions

View File

@ -471,10 +471,10 @@ class RequestResponseCycle:
self.waiting_for_100_continue = False
status = message["status"]
headers = self.default_headers + list(message.get("headers", []))
headers = [*self.default_headers, *message.get("headers", [])]
if CLOSE_HEADER in self.scope["headers"] and CLOSE_HEADER not in headers:
headers = headers + [CLOSE_HEADER]
headers.append(CLOSE_HEADER)
if self.access_log:
self.access_logger.info(

View File

@ -474,10 +474,7 @@ class RequestResponseCycle:
self.waiting_for_100_continue = False
status_code = message["status"]
headers = self.default_headers + list(message.get("headers", []))
if CLOSE_HEADER in self.scope["headers"] and CLOSE_HEADER not in headers:
headers = headers + [CLOSE_HEADER]
headers = message.get("headers", [])
if self.access_log:
self.access_logger.info(
@ -491,6 +488,10 @@ class RequestResponseCycle:
# Write response status line and headers
content = [STATUS_LINE[status_code]]
has_close_header = False
for name, value in self.default_headers:
content.extend([name, b": ", value, b"\r\n"])
for name, value in headers:
if HEADER_RE.search(name):
@ -507,8 +508,13 @@ class RequestResponseCycle:
self.chunked_encoding = True
elif name == b"connection" and value.lower() == b"close":
self.keep_alive = False
has_close_header = True
content.extend([name, b": ", value, b"\r\n"])
if not has_close_header and CLOSE_HEADER in self.scope["headers"]:
content.extend([b"connection", b": ", b"close", b"\r\n"])
self.keep_alive = False
if self.chunked_encoding is None and self.scope["method"] != "HEAD" and status_code not in (204, 304):
# Neither content-length nor transfer-encoding specified
self.chunked_encoding = True