-
Notifications
You must be signed in to change notification settings - Fork 125
Fixes bi-directional streaming #344
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
Conversation
@@ -1025,8 +1019,7 @@ extension TaskHandler: ChannelDuplexHandler { | |||
/// Some HTTP Servers can 'forget' to respond with CloseNotify when client is closing connection, | |||
/// this could lead to incomplete SSL shutdown. But since request is already processed, we can ignore this error. | |||
break | |||
case .head where self.ignoreUncleanSSLShutdown, | |||
.body where self.ignoreUncleanSSLShutdown: | |||
case .sending where self.ignoreUncleanSSLShutdown: |
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.
test testNoResponseWithIgnoreErrorForSSLUncleanShutdown
fails if I add .sent
, I'm not sure why yet...
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.
.sending
means that we have not sent client .end
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.
What's the difference between .sent
and .endOrError
? In many cases (content-length
present) after having sent the response body, we're done?
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 are looking at slightly outdated code
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.
this is a slightly weird part, it tries to do the following: if ignoreUncleanSSLShutdown
is set and we received response .head
, then it's allowed to not fail
ce06b45
to
88f4dd3
Compare
@@ -840,23 +839,20 @@ extension TaskHandler: ChannelDuplexHandler { | |||
self.writeBody(request: request, context: context) | |||
}.flatMap { | |||
context.eventLoop.assertInEventLoop() | |||
|
|||
if case .endOrError = self.state { |
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.
could we replace this if case
and the fallthrough by one full switch self.state
?
It's unclear to me why we can move from almost any state to .sent
and why all those transitions are legal.
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.
For example a transition from .sent
to .sent
seems odd, right? Or from .inactive
to .sent
seems wrong 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.
done
case idle | ||
case bodySent | ||
case inactive | ||
case sending |
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 could come up with slightly more prescriptive names? What are wen sending
here? The request, the response, the head, the body, the trailers? Some of them, all of them?
Same for sent
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.
done
@@ -902,7 +898,7 @@ extension TaskHandler: ChannelDuplexHandler { | |||
|
|||
private func writeBodyPart(context: ChannelHandlerContext, part: IOData, promise: EventLoopPromise<Void>) { | |||
switch self.state { | |||
case .idle: | |||
case .sending: |
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.
this seems a little dangerous? Previously we could send in .idle
and now we can't?
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.
A full switch
without the default
would be better too here.
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.
done
@@ -1025,8 +1019,7 @@ extension TaskHandler: ChannelDuplexHandler { | |||
/// Some HTTP Servers can 'forget' to respond with CloseNotify when client is closing connection, | |||
/// this could lead to incomplete SSL shutdown. But since request is already processed, we can ignore this error. | |||
break | |||
case .head where self.ignoreUncleanSSLShutdown, | |||
.body where self.ignoreUncleanSSLShutdown: | |||
case .sending where self.ignoreUncleanSSLShutdown: |
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.
What's the difference between .sent
and .endOrError
? In many cases (content-length
present) after having sent the response body, we're done?
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.
thank you! This looks like a great start, left some comments
case sent | ||
case head | ||
case inactive | ||
case sending_waiting |
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 should use
lowerCamelCase
to match swift's usual style. - I think we can do better than
sendingWaiting
, ie. what are we sending and what are we waiting for?
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.
done
case bodySent | ||
case sent | ||
case head | ||
case inactive |
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.
idle
is probably better than inactive
because the channel is actually isActive = true
, right?
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.
done
4b3c27d
to
06a4098
Compare
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.
Seems reasonable enough to me, nothing obviously problematic in the code.
06a4098
to
f49c143
Compare
case .sendingBodyResponseHeadReceived: | ||
self.state = .bodySentResponseHeadReceived | ||
case .bodySentWaitingResponseHead, .bodySentResponseHeadReceived: | ||
preconditionFailure("should not happen") |
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.
should we print self.state
in that message?
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.
done
self.state = .bodySentResponseHeadReceived | ||
case .bodySentWaitingResponseHead, .bodySentResponseHeadReceived: | ||
preconditionFailure("should not happen") | ||
case .endOrError, .redirected: |
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.
mind adding a comment why that's okay in .endOrError
, or .redirected
? I don't quite get how we can be in .end
before we get the end of the body.
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.
(similar for .redirected
)
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.
rewrote, added a test
Motivation: When we stream request body, current implementation expects that body will finish streaming _before_ we start to receive response body parts. This is not correct, reponse body parts can start to arrive before we finish sending the request. Modifications: - Simplifies state machine, we only case about request being fully sent to prevent sending body parts after .end, but response state machine is mostly ignored and correct flow will be handled by NIOHTTP1 pipeline - Adds HTTPEchoHandler, that replies to each response body part - Adds bi-directional streaming test Result: Closes swift-server#327
f49c143
to
26b1191
Compare
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.
very nice, thank you!
Motivation:
When we stream request body, current implementation expects that body
will finish streaming before we start to receive response body parts.
This is not correct, reponse body parts can start to arrive before we
finish sending the request.
Modifications:
to prevent sending body parts after .end, but response state machine
is mostly ignored and correct flow will be handled by NIOHTTP1
pipeline
Result:
Closes #327