httptools: Connection: Close does not close the connection #3071
Replies: 1 comment
|
Two things worth adding, because the fix is a bit wider than the httptools request check and the obvious one-liner doesn't cover all three of your cases. First, the exact-match constant isn't local to httptools. It's defined in CLOSE_HEADER = (b"connection", b"close")if CLOSE_HEADER in self.scope["headers"] and CLOSE_HEADER not in headers:
headers = headers + [CLOSE_HEADER]That's Second, lowercasing alone won't fix if name == b"connection":
connection = [token.lower().strip() for token in value.split(b",")]if b"upgrade" in connection:Split, strip, lowercase each token, membership test. That's exactly what the close check needs, and it makes the change an argument about consistency with existing code rather than a new convention — which is usually an easier sell. So the tidy shape is probably a small helper next to Worth extending the test matrix past your three too — |
Uh oh!
There was an error while loading. Please reload this page.
On the
httptoolsHTTP implementation (what--http autoselects when httptools is installed), Uvicorn only honors a requestConnection: closewhen the header value is exactly lowercaseclose.Connection: CloseandConnection: keep-alive, closeleave the TCP connection open and do not echoConnection: closeon the response.h11andzttpclose in all three cases.This looks like a bug rather than intentional behavior:
docs/server-behavior.mdsays aConnection: Closeheader must close the connection, and that HTTP headers are case-insensitive.closeconnection option MUST close after the final response, and SHOULD sendConnection: closeon that response. Tokens are case-insensitive (RFC 9110 §7.6.1).Connectionvalue as case-insensitive (value.lower() == b"close"). The request check is an exact tuple match on(b"connection", b"close"). Existing tests only send lowercaseclose.Versions
Reproduced on current
main.Reproduction
Actual
Expected
All three implementations close after the response and echo
Connection: closewhenever the request Connection header contains aclosetoken, regardless of case or sibling tokens.Cause
Header names are lowercased; values are not.
b"Close"andb"keep-alive, close"never match. httptools then never setskeep_alive = False(that flag is only flipped when writing a responseconnection: closeheader). h11 still closes viaMUST_CLOSE; zttp still closes viashould_close().Question
Does this match what you’d want fixed? If so, I can open a PR that parses
Connectionas a comma-separated, case-insensitive token list (httptools required; h11/zttp so they also echoConnection: closefor mixed-case / multi-token values), plus a regression test parametrized across implementations.All reactions