-
Notifications
You must be signed in to change notification settings - Fork 650
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
WIP: HTTPDecoder: Reenable Parsing After Failed Upgrade #2570
base: main
Are you sure you want to change the base?
Conversation
I believe I've verified that my fix works (local server can be used to pass the Alamofire test that previously hung), but I still need guidance around the proper conditions and unit test. |
You can use
I think for now this is appropriate.
I think you want a few scenarios:
To achieve "do not accept the upgrade" you don't actually need an encoder, you can just write the response head into the pipeline. |
@swift-nio-bot test performance please |
@swift-nio-bot performance test please |
@swift-server-bot test performance please |
@swift-server-bot add to allowlist |
@swift-server-bot test perf please |
performance reportbuild id: 151 timestamp: Thu Oct 26 07:07:05 UTC 2023 results
comparison
significant differences found |
The change as written does runtime type checks. My review feedback above would replace it with a jump based on an enum value, which should perform a lot better. |
Missed that, sorry. That's great! |
I've pushed the kind check up, feel free to test that, but I think there will still be an impact due to the |
@swift-server-bot test perf please |
!!! Couldn't read commit file !!! |
@swift-server-bot test perf please |
!!! Couldn't read commit file !!! |
I've added two tests, one for successful upgrade and one for failed upgrade. @Lukasa What does a pipelined request pair look like? Do I just shove both through in one buffer? |
Yeah, that's the easiest way to do it. |
@Lukasa I can write a pipelined test for the current behavior just fine, as parsing is stopped as soon as the first request is parsed, but I'm not clear what behavior I should be seeing in the unsuccessful upgrade case. As far as I can tell, the data just disappears, and the channel is empty. I'm guessing that with parsing stopped, the additional data is just lost, and the unsuccessful upgrade turns parsing back on for a decoder that doesn't receive any additional data. To support the pipeline case I think I'd need to buffer any additional requests until we can tell whether the upgrade was successful, or some other change in behavior. |
I don't think the data is lost, I think you need a way to re-spin the decoder. To test, can you try amending your current test case for the pipeline to send an extra empty |
@Lukasa You're correct, sending an empty buffer lets the test pass. Instead of just setting |
@Lukasa I've investigated how to restart parsing in |
Reenable parsing in
HTTPDecoder
after an upgrade is attempted but failed by the response.Motivation:
Currently,
HTTPDecoder
setsstopParsing = true
whenever a message is parsed and an upgrade is detected (isUpgrade == true
). Unfortunately, this means that if the upgrade wasn't successful, the decoder silently blocks any attempt to reuse the connection, essentially hanging the client until they timeout.Modifications:
I've attempted to generalize
HTTPDecoder
's conformance toWriteObservingByteToMessageDecoder
so that it can reenable parsing based on the outgoingHTTPServerResponsePart
.Result:
A properly reusable decoder.
WIP:
I need a few things to finish this PR.
write(data:)
implementation. Right now I just check the decoder's full metatype. What's the preferred pattern here?HTTPDecoderTest
but it's not clear what kind of test would be best here, or how to simulate this scenario exactly.Thinking about this more, how can I ensure that the outgoing response is for the incoming request?