swift-server / swift-server/swift-http-server
HTTP/1.1 server ignores the request's `Connection` header
Nobody has claimed this yet.
- Dominant language
- Swift
- Stars
- 44
- Forks
- 13
- Avg merge
- 4d 3h
- Merged PRs (30d)
- 8
Description
Related to #53 but this concerns outbound connection lifetimes.
The HTTP1 Server doesn't respect RFC 9112 and doesn't close the connection on a complete response when the client sends a Connection: close in the header. The server should send Connection: close in the response.
Expected behavior
Per RFC 9112 § 9.6, a client sending Connection: close is stating that this is the last request on the connection. The server should close the once the response is complete, and should send Connection: close in the response.
| Request | Response | Connection closed within 1s? |
|---|---|---|
GET /hello HTTP/1.1 + Connection: close |
HTTP/1.1 200 OK … Content-Length: 2 (no Connection header) |
no |
GET /hello HTTP/1.0 (no Connection header) |
HTTP/1.1 200 OK … Content-Length: 2 |
no |
GET /hello HTTP/1.0 + Connection: keep-alive |
same | no |
HTTP/1.0 goes against the spec as well and keeps the connection open when it shouldn't.
Root cause
HTTPKeepAliveHandler never reads the inbound Connection header. Its channelRead case .head only resets requestEndReceived / closeAfterResponseEnd, and the only reference to the header in the whole NIOHTTPServer module is a write in the keep alive handler. So the client's request to close isn't accounted for anywhere.
Impact
The connection stays open for the full read-header timeout after the client has said it is finished
Fix
closeAfterResponseEnd does exactly the right thing when response .end is written, we just need to update it to also be set from the request side:
- on
.head, read the request'sConnectionheader:
setcloseAfterResponseEnd = truefor HTTP/1.1 withConnection: close, and for HTTP/1.0 unless
Connection: keep-aliveis present - when closing because of that, add
Connection: closeto the response head
Steps to reproduce
printf 'GET /hello HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n' | nc localhost 8080
nc stays connected for ~30s after the response arrives; it should return as soon as the response is
complete.
Environment
- swift-http-server @
13b8e725554b5d10dbf704f9abc39d7c1c80b30a - Swift 6.4 development snapshot (2026-08-14), macOS 15 arm64
- Found while adding HTTP conformance tests to Vapor 5
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start at HTTPKeepAliveHandler.channelRead in the NIOHTTPServer module, where request heads and response .end events update connection state. Reproduce the behavior with the provided nc command, then verify HTTP/1.1 Connection: close and HTTP/1.0 without keep-alive close promptly and include Connection: close in the response.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- swift
- Domain
- networking
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 76/100