Add request context capability mechanism to HTTPServer#166
Conversation
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.
| 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 |
There was a problem hiding this comment.
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, |
There was a problem hiding this comment.
& ~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 { |
There was a problem hiding this comment.
This type should be moved to swift-http-server?
There was a problem hiding this comment.
Moved to HTTPServerForTesting
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
~Copyable, ~Escapable
- 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, |
There was a problem hiding this comment.
This also need ~Copyable & ~Escapable
| where | ||
| Input == HTTPServerMiddlewareInput<RequestReader, ResponseWriter>, | ||
| Input == HTTPServerMiddlewareInput<RequestContext, RequestReader, ResponseWriter>, | ||
| RequestContext: HTTPServerCapability.RequestContext, |
There was a problem hiding this comment.
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, |
There was a problem hiding this comment.
This also need ~Copyable & ~Escapable
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
Yeah it makes sense to keep this Escapable
| func handle( | ||
| request: HTTPRequest, | ||
| requestContext: HTTPRequestContext, | ||
| requestContext: consuming RequestContext, |
There was a problem hiding this comment.
Is consuming the right ownership model? Could the same Sendable & ~Copyable struct with a Mutex be passed to handle multiple times?
There was a problem hiding this comment.
If it's non copyable, how would it be passed multiple times?
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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, *) |
| /// 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, |
There was a problem hiding this comment.
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, *) |
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| /// The namespace for all protocols defining HTTP server capabilities. |
There was a problem hiding this comment.
Can we add more docs explaining what a capability is?
| /// The request context protocol. | ||
| /// | ||
| /// Child protocols define additional context that a subset of servers provide, | ||
| /// allowing libraries to depend on specific capabilities. |
There was a problem hiding this comment.
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") |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
Correct, right now it's really just testing that it compiles. I'll add some assertions too
…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
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.