swift-server / swift-server/swift-http-server

HTTP/1.1 server ignores the request's `Connection` header

Open
#119 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

kind/bug size/S
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 OKContent-Length: 2 (no Connection header) no
GET /hello HTTP/1.0 (no Connection header) HTTP/1.1 200 OKContent-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's Connection header:
    set closeAfterResponseEnd = true for HTTP/1.1 with Connection: close, and for HTTP/1.0 unless
    Connection: keep-alive is present
  • when closing because of that, add Connection: close to 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

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.