Skip to content

Add request context capability mechanism to HTTPServer#166

Open
ehaydenr wants to merge 6 commits into
apple:mainfrom
ehaydenr:requestcontext
Open

Add request context capability mechanism to HTTPServer#166
ehaydenr wants to merge 6 commits into
apple:mainfrom
ehaydenr:requestcontext

Conversation

@ehaydenr
Copy link
Copy Markdown
Contributor

Introduce HTTPServerCapability namespace with a base RequestContext protocol, mirroring the client-side HTTPClientCapability.RequestOptions pattern. Servers declare a RequestContext associated type that handlers can constrain to require specific capabilities (e.g. connection info, peer certificates) at compile time.

Motivation

Clean up the client/server asymmetry. Afford the server APIs the same generic mechanism for requiring server capabilities.

Modifications

Added HTTPServerCapability.RequestContext protocol.

Result

Middleware and request handlers can now require server capabilities

Test Plan

Added a basic unit test to demonstrate the pattern.

Introduce HTTPServerCapability namespace with a base RequestContext
protocol, mirroring the client-side HTTPClientCapability.RequestOptions
pattern. Servers declare a RequestContext associated type that handlers
can constrain to require specific capabilities (e.g. connection info,
peer certificates) at compile time.
@guoye-zhang guoye-zhang added the ⚠️ semver/major Breaks existing public API. label May 21, 2026
public protocol HTTPServerRequestHandler<RequestReader, ResponseWriter>: Sendable {
public protocol HTTPServerRequestHandler<RequestContext, RequestReader, ResponseWriter>: Sendable {
/// The type of the request context provided by the server.
associatedtype RequestContext: HTTPServerCapability.RequestContext
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.

You'll need to redeclare ~Copyable, ~Escapable requirements here

/// ```
@available(macOS 26.2, iOS 26.2, watchOS 26.2, tvOS 26.2, visionOS 26.2, *)
public struct HTTPServerClosureRequestHandler<
RequestContext: HTTPServerCapability.RequestContext,
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.

& ~Copyable & ~Escapable

public struct HTTPRequestContext: Sendable {
/// The default request context for HTTP server implementations.
@available(macOS 26.2, iOS 26.2, watchOS 26.2, tvOS 26.2, visionOS 26.2, *)
public struct HTTPRequestContext: HTTPServerCapability.RequestContext {
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 type should be moved to swift-http-server?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Moved to HTTPServerForTesting

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.

There's a PR for depending on the NIOHTTPServer as a submodule.
Before that lands, we'll have to make sure that we've also updated NIOHTTPServer to use this new API.

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.

Yeah probably will land that PR when everything settles to reduce the pain of interlocked revisions

/// incoming HTTP connections and process requests using a ``HTTPServerRequestHandler``.
public protocol HTTPServer<RequestConcludingReader, ResponseConcludingWriter>: Sendable, ~Copyable, ~Escapable {
public protocol HTTPServer<RequestContext, RequestConcludingReader, ResponseConcludingWriter>: Sendable, ~Copyable, ~Escapable {
associatedtype RequestContext: HTTPServerCapability.RequestContext
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.

~Copyable, ~Escapable

ehaydenr added 2 commits May 21, 2026 03:05
- Add ~Copyable, ~Escapable constraints to RequestContext associated
  types in HTTPServer, HTTPServerRequestHandler, and
  HTTPServerClosureRequestHandler
- Add consuming ownership to requestContext parameters
- Move HTTPRequestContext concrete type out of HTTPAPIs into the test
  server module
# Conflicts:
#	Sources/HTTPAPIs/Server/HTTPServerRequestHandler.swift
/// This middleware is useful for debugging and monitoring HTTP traffic.
@available(anyAppleOS 26.0, *)
public struct HTTPServerLoggingMiddleware<
RequestContext: HTTPServerCapability.RequestContext,
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 also need ~Copyable & ~Escapable

where
Input == HTTPServerMiddlewareInput<RequestReader, ResponseWriter>,
Input == HTTPServerMiddlewareInput<RequestContext, RequestReader, ResponseWriter>,
RequestContext: HTTPServerCapability.RequestContext,
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 also need ~Copyable & ~Escapable

/// convenient way to pass all request-handling components through the middleware chain.
@available(anyAppleOS 26.0, *)
public struct HTTPServerMiddlewareInput<
RequestContext: HTTPServerCapability.RequestContext,
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 also need ~Copyable & ~Escapable

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I think this would require HTTPServerMiddlewareInput be ~Escapable and it currently isn't. Also RequestReader/Writer aren't ~Escapable here. Should we make HTTPServerMiddlewareInput ~Escapable or only do ~Copyable here?

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.

Yeah it makes sense to keep this Escapable

func handle(
request: HTTPRequest,
requestContext: HTTPRequestContext,
requestContext: consuming RequestContext,
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.

Is consuming the right ownership model? Could the same Sendable & ~Copyable struct with a Mutex be passed to handle multiple times?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

If it's non copyable, how would it be passed multiple times?

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.

Ah I guess borrow wouldn't work since this is invoked concurrently

public protocol HTTPServerRequestHandler<RequestReader, ResponseWriter>: Sendable {
public protocol HTTPServerRequestHandler<RequestContext, RequestReader, ResponseWriter>: Sendable {
/// The type of the request context provided by the server.
associatedtype RequestContext: HTTPServerCapability.RequestContext, ~Copyable, ~Escapable
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.

Do we want it to be ~Copyable? I really don't know, but I'm just wondering since it's basically a bag of things, I wonder if this requirement may make it hard to hold.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The server should be able to give out a Copyable type if it wants. I think it's really the middleware that might having difficulty holding it, but I can't think of a case where it would be an issue. I'm curious if you have any cases in mind.

import HTTPAPIs
import Testing

@available(macOS 26.2, iOS 26.2, watchOS 26.2, tvOS 26.2, visionOS 26.2, *)
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 anyAppleOS

/// It is necessary to box them together so that they can be used with `Middlewares`, as this will be the `Middleware.Input`.
@available(anyAppleOS 26.0, *)
public struct RequestResponseMiddlewareBox<
RequestContext: HTTPServerCapability.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.

If we keep the ~Copyable requirement on the protocol, we should add it here too (and make it consuming below).

//===----------------------------------------------------------------------===//

/// The namespace for all protocols defining HTTP server capabilities.
@available(macOS 26.2, iOS 26.2, watchOS 26.2, tvOS 26.2, visionOS 26.2, *)
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 anyAppleOS

//
//===----------------------------------------------------------------------===//

/// The namespace for all protocols defining HTTP server capabilities.
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 add more docs explaining what a capability is?

Comment on lines +17 to +20
/// The request context protocol.
///
/// Child protocols define additional context that a subset of servers provide,
/// allowing libraries to depend on specific capabilities.
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.

And we could maybe improve this a bit to add an example of how to implement this and how/where it will be used (i.e. middleware, request handlers, etc)?


@Suite("Server Capability Tests")
struct ServerCapabilityTests {
@Test("ConnectionInfo capability constraint compiles and context is accessible")
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're not actually asserting anything anywhere right? Like we aren't actually checking that the context contains the stuff we've filled it with from within the handler.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Correct, right now it's really just testing that it compiles. I'll add some assertions too

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

updated this

…ovements

- Add ~Copyable to RequestContext constraints in middleware examples
  and RequestResponseMiddlewareBox
- Add consuming ownership to requestContext parameters in middleware
  input types
- Drop ~Escapable from RequestContext constraints (inconsistent with
  reader/writer types which are not ~Escapable)
- Use anyAppleOS availability on HTTPServerCapability and tests
- Add comprehensive documentation and examples to HTTPServerCapability
  and RequestContext
- Improve ServerCapabilityTests to assert context values flow through
  the handler via TestClientAndServer
@ehaydenr ehaydenr requested review from gjcairo and guoye-zhang May 22, 2026 18:03
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