-
Notifications
You must be signed in to change notification settings - Fork 656
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
Introduce new typed HTTPServerUpgrader
and WebSocketServerUpgrader
#2517
Conversation
@swift-server-bot test this please |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm only part way through reviewing this but dropping my comments so far.
Could you punt the example client and server into a follow-up PR to make this one a bit smaller?
withPipeliningAssistance pipelining: Bool = true, | ||
withServerUpgrade upgrade: NIOTypedHTTPServerUpgradeConfiguration<UpgradeResult>, | ||
withErrorHandling errorHandling: Bool = true, | ||
withOutboundHeaderValidation headerValidation: Bool = true, | ||
withEncoderConfiguration encoderConfiguration: HTTPResponseEncoder.Configuration = .init() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should avoid all the with
s here as they aren't closures enforcing a lifetime
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree, but the current APIs use this spelling. Do we want to diverge?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should. While there is value in consistency I think diverging from it to make APIs more idiomatic is justified.
withPipeliningAssistance pipelining: Bool = true, | ||
withServerUpgrade upgrade: NIOTypedHTTPServerUpgradeConfiguration<UpgradeResult>, | ||
withErrorHandling errorHandling: Bool = true, | ||
withOutboundHeaderValidation headerValidation: Bool = true, | ||
withEncoderConfiguration encoderConfiguration: HTTPResponseEncoder.Configuration = .init() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same here re: with
|
||
case finished | ||
|
||
case modifying |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We shouldn't need this state: have you validated that we do?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So I was believing that this isn't necessary anymore but from @glbrntt and my recent benchmarking we saw that the compiler can still miss correctly avoiding those CoWs even if everything is inlined. So I am being defensive again until we get switch inout
.
case failUpgradePromise | ||
} | ||
|
||
@inlinable |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We're very inconsistent with the @inlinable
s here, despite all the actions being @usableFromInline
. Why is that?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just me forgetting it in some places. Added it to everything in the state machine now.
5.6 CI failure is due to primary associated type usage. Since we are dropping 5.6 support soon, I will just merge this PR after we dropped it. |
withPipeliningAssistance pipelining: Bool = true, | ||
withServerUpgrade upgrade: NIOTypedHTTPServerUpgradeConfiguration<UpgradeResult>, | ||
withErrorHandling errorHandling: Bool = true, | ||
withOutboundHeaderValidation headerValidation: Bool = true, | ||
withEncoderConfiguration encoderConfiguration: HTTPResponseEncoder.Configuration = .init() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should. While there is value in consistency I think diverging from it to make APIs more idiomatic is justified.
isPipeliningEnabled: Bool = true, | ||
isErrorHandlingEnabled: Bool = true, | ||
isResponseHeaderValidationEnabled: Bool = true, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think is
isn't right here, because it reads like a question. I think enablePipelining
, enableErrorHandling
, and enableResponseHeaderValidation
are more appropriate
I've only had a quick look at this. The websocket upgrade code seems to require that every packet be tested for whether it is an http packet, or an upgraded packet. Can we not do the test on the channel once instead, ie is this channel producing http or websocket packets. I was hoping the websocket server code could be separate from the http server code but this implementation means the two are intertwined and hard to separate into two modules. |
The two are not really intertwined. The |
I wasn't really talking about the |
# Motivation With our new `NIOAsyncChannel` and typed bootstrap APIs we want to be able to let users spell out their pipeline in a typed way. Pipelines can contain handlers that have to make a forking decision such as HTTP upgrading. Our current `HTTPServerUpgradeHandler` is one of those handlers but it lacks strict typing. To interact nicely with our new typed APIs we need to have a new variant of the `HTTPServerUpgradeHandler` that can carry type information. # Modification This PR adds a few things: 1. A new `NIOTypedHTTPServerUpgradeHandler` + `NIOTypedHTTPServeProtocolUpgrader`. I also moved the state handling logic to a separate state machine. I thought about unifying the state machines of the _old_ handler and the new one but they differ in behaviour which makes the state machine more complicated. 2. A new `NIOTypedWebSocketServerUpgrader` that conforms to `NIOTypedHTTPServerProtocolUpgrader` 3. An overhauled WebSocket server example that fully uses Concurrency. # Result We now have a way to fully type the server side of HTTP protocol upgrading. Code review Update parameter names for new API and fix example
d126c9f
to
68c64df
Compare
@Lukasa @glbrntt This PR is now ready to merge. In my last commit, I renamed the methods to |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Couple of nits, looks good otherwise.
let requestDecoder = ByteToMessageHandler(HTTPRequestDecoder(leftOverBytesStrategy: .forwardBytes)) | ||
|
||
var extraHTTPHandlers: [RemovableChannelHandler] = [requestDecoder] | ||
extraHTTPHandlers.reserveCapacity(3) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you'll need to reserve then add the decoder
public var enableResponseHeaderValidation = true | ||
|
||
/// The configuration for the ``HTTPResponseEncoder``. | ||
public var httpResponseEncoderConfiguration = HTTPResponseEncoder.Configuration() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You missed this one, we can drop http
here too
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will fix both in my follow up client PR. Thanks!
3a5392a
to
4da9b3a
Compare
# Motivation In my previous PR apple#2517, I added a new typed `HTTPServerUpgrader` and corresponding implementation for the `WebSocketServerUpgrader`. The goal of those is to carry type information across HTTP upgrades which allows us to build fully typed pipelines. # Modification This PR adds a few things: 1. A new `NIOTypedHttpClientUpgradeHandler` + `NIOTypedHttpClientProtocolUpgrader`. I also moved the state handling to a separate state machine. Similar to the server PR I did not unify the state machine between the newly typed and untyped upgrade handlers since they differ in logic. 2. A new `NIOTypedWebSocketClientUpgrader` 3. An overhauled WebSocket client example. # Result This is the last missing piece of dynamic pipeline changing where we did not carry around the type information. After this PR lands, we can finalize the `AsyncChannel` and async typed NIO pieces.
# Motivation In my previous PR apple#2517, I added a new typed `HTTPServerUpgrader` and corresponding implementation for the `WebSocketServerUpgrader`. The goal of those is to carry type information across HTTP upgrades which allows us to build fully typed pipelines. # Modification This PR adds a few things: 1. A new `NIOTypedHttpClientUpgradeHandler` + `NIOTypedHttpClientProtocolUpgrader`. I also moved the state handling to a separate state machine. Similar to the server PR I did not unify the state machine between the newly typed and untyped upgrade handlers since they differ in logic. 2. A new `NIOTypedWebSocketClientUpgrader` 3. An overhauled WebSocket client example. # Result This is the last missing piece of dynamic pipeline changing where we did not carry around the type information. After this PR lands, we can finalize the `AsyncChannel` and async typed NIO pieces.
# Motivation In my previous PR apple#2517, I added a new typed `HTTPServerUpgrader` and corresponding implementation for the `WebSocketServerUpgrader`. The goal of those is to carry type information across HTTP upgrades which allows us to build fully typed pipelines. # Modification This PR adds a few things: 1. A new `NIOTypedHttpClientUpgradeHandler` + `NIOTypedHttpClientProtocolUpgrader`. I also moved the state handling to a separate state machine. Similar to the server PR I did not unify the state machine between the newly typed and untyped upgrade handlers since they differ in logic. 2. A new `NIOTypedWebSocketClientUpgrader` 3. An overhauled WebSocket client example. # Result This is the last missing piece of dynamic pipeline changing where we did not carry around the type information. After this PR lands, we can finalize the `AsyncChannel` and async typed NIO pieces.
# Motivation In my previous PR apple#2517, I added a new typed `HTTPServerUpgrader` and corresponding implementation for the `WebSocketServerUpgrader`. The goal of those is to carry type information across HTTP upgrades which allows us to build fully typed pipelines. # Modification This PR adds a few things: 1. A new `NIOTypedHttpClientUpgradeHandler` + `NIOTypedHttpClientProtocolUpgrader`. I also moved the state handling to a separate state machine. Similar to the server PR I did not unify the state machine between the newly typed and untyped upgrade handlers since they differ in logic. 2. A new `NIOTypedWebSocketClientUpgrader` 3. An overhauled WebSocket client example. # Result This is the last missing piece of dynamic pipeline changing where we did not carry around the type information. After this PR lands, we can finalize the `AsyncChannel` and async typed NIO pieces.
# Motivation In my previous PR apple#2517, I added a new typed `HTTPServerUpgrader` and corresponding implementation for the `WebSocketServerUpgrader`. The goal of those is to carry type information across HTTP upgrades which allows us to build fully typed pipelines. # Modification This PR adds a few things: 1. A new `NIOTypedHttpClientUpgradeHandler` + `NIOTypedHttpClientProtocolUpgrader`. I also moved the state handling to a separate state machine. Similar to the server PR I did not unify the state machine between the newly typed and untyped upgrade handlers since they differ in logic. 2. A new `NIOTypedWebSocketClientUpgrader` 3. An overhauled WebSocket client example. # Result This is the last missing piece of dynamic pipeline changing where we did not carry around the type information. After this PR lands, we can finalize the `AsyncChannel` and async typed NIO pieces.
#2526) * Introduce new typed `HTTPClientUpgrader` and `WebSocketClientUpgrader` # Motivation In my previous PR #2517, I added a new typed `HTTPServerUpgrader` and corresponding implementation for the `WebSocketServerUpgrader`. The goal of those is to carry type information across HTTP upgrades which allows us to build fully typed pipelines. # Modification This PR adds a few things: 1. A new `NIOTypedHttpClientUpgradeHandler` + `NIOTypedHttpClientProtocolUpgrader`. I also moved the state handling to a separate state machine. Similar to the server PR I did not unify the state machine between the newly typed and untyped upgrade handlers since they differ in logic. 2. A new `NIOTypedWebSocketClientUpgrader` 3. An overhauled WebSocket client example. # Result This is the last missing piece of dynamic pipeline changing where we did not carry around the type information. After this PR lands, we can finalize the `AsyncChannel` and async typed NIO pieces. * Remove availability on the protocols
Motivation
With our new
NIOAsyncChannel
and typed bootstrap APIs we want to be able to let users spell out their pipeline in a typed way. Pipelines can contain handlers that have to make a forking decision such as HTTP upgrading. Our currentHTTPServerUpgradeHandler
is one of those handlers but it lacks strict typing. To interact nicely with our new typed APIs we need to have a new variant of theHTTPServerUpgradeHandler
that can carry type information.Modification
This PR adds a few things:
NIOTypedHTTPServerUpgradeHandler
+NIOTypedHTTPServeProtocolUpgrader
. I also moved the state handling logic to a separate state machine. I thought about unifying the state machines of the old handler and the new one but they differ in behaviour which makes the state machine more complicated.NIOTypedWebSocketServerUpgrader
that conforms toNIOTypedHTTPServerProtocolUpgrader
Result
We now have a way to fully type the server side of HTTP protocol upgrading.