Skip to content

Add connection lifecycle handling#92

Open
gjcairo wants to merge 5 commits into
mainfrom
worktree-connection-lifecycle
Open

Add connection lifecycle handling#92
gjcairo wants to merge 5 commits into
mainfrom
worktree-connection-lifecycle

Conversation

@gjcairo

@gjcairo gjcairo commented Jun 30, 2026

Copy link
Copy Markdown
Collaborator

Summary

Add a connection-lifecycle surface to NIOHTTPServer so users can do per-connection setup (such as loggers, metrics, atomic counters, etc), share state across requests on the same connection, and signal that the current connection should close after the in-flight response. The existing serve(handler:) entry point is preserved unchanged at the call site.

What's new

  • NIOHTTPServer.serve(connectionHandler:): the connection-aware counterpart to serve(handler:).
  • NIOHTTPServerConnectionHandler protocol with handleConnection(connection:context:).
  • NIOHTTPServer.Connection: struct that represents an active HTTP server connection. Consumed by exactly one call to handleRequests; if the handler returns without calling handleRequests, the connection is dropped cleanly on scope exit.
  • NIOHTTPServer.ConnectionContext, which now exposes httpVersion, remoteAddress, localAddress, the existing peerCertificateChain, and a new signalConnectionClose().
  • New HTTPServerCapability capabilities: ConnectionInfo, PeerCertificate, CloseableConnection. NIOHTTPServer.RequestContext is now a concrete struct conforming to all three, so request handlers reach connection-scoped data via requestContext.remoteAddress, requestContext.signalConnectionClose(), etc.
  • The @TaskLocal NIOHTTPServer.connectionContext API is removed, and all access is now through requestContext.

gjcairo added 2 commits June 30, 2026 11:13
# Conflicts:
#	Sources/NIOHTTPServer/NIOHTTPServer+HTTP1_1.swift
@gjcairo gjcairo added the ⚠️ semver/major Breaks existing public API. label Jun 30, 2026
@gjcairo gjcairo force-pushed the worktree-connection-lifecycle branch from d879cfb to 413211a Compare June 30, 2026 11:02
/// peer's address and the local address the connection is bound to. Both
/// are reported best-effort: implementations may return `nil` when the
/// underlying transport cannot report an address.
public protocol ConnectionInfo: RequestContext {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we really wanna add that to the HTTPAPIs. Can you file an issue there?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What would be used as the SocketAddress type in HTTPAPIs?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to add a new SocketAddress currency type in the HTTPAPIs that we need to land in the planned network currency types package

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

/// peer's mTLS-validated certificate chain (when applicable). Implementations
/// return `nil` if mTLS isn't configured, or if no validated chain was
/// derived.
public protocol PeerCertificate: RequestContext {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same for this

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment on lines +72 to +80
let connectionLogger: Logger = {
var logger = rootLogger
let peer = context.remoteAddress.map { "\($0)" } ?? "unknown"
logger[metadataKey: "peer"] = .string(peer)
logger[metadataKey: "http"] = .string("\(context.httpVersion)")
return logger
}()
connectionLogger.info("connection accepted")
defer { connectionLogger.info("connection closed") }

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's use the new task local Logging APIs for this example. Actually the HTTP Server itself should set the task local logger and configure it correctly with metadata. This shouldn't be up to the user.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what metadata should be included? In some applications it may not be desirable to log certain things like peer IP.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The HTTP server should make a decision about the general useful metadata it wants to include. I would say things like HTTP version and peer IP are sensible. The rest the user can extract from the context and add.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO, peer IP is sensitive and shouldn't be logged by default

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we keep the docs updates like this separate?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Even when it's related to the change being introduced in the PR?

extension NIOHTTPServer {
/// Connection-specific information available during request handling.
/// The application-level HTTP version negotiated for a connection.
public enum HTTPVersion: Sendable, Hashable {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should also become part of HTTPAPIs

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gjcairo gjcairo changed the title Worktree connection lifecycle Add connection lifecycle handling Jun 30, 2026

@ehaydenr ehaydenr left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is looking good at a high level. Can we split it up into two PRs, though? I think CloseableConnection might make sense to have as a subsequent PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

⚠️ semver/major Breaks existing public API.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants