HttpServerUpgradeHandler shouldn't wait for flush to reshape pipeline#7807
Conversation
|
Can we have a unit test ?
… Am 23.03.2018 um 16:34 schrieb Bryce Anderson ***@***.***>:
Motivation:
There is a race between both flushing the upgrade response and receiving
more data before the flush ChannelPromise can fire the listener and reshape
the pipeline. Since We have already committed to an upgrade by writing the
upgrade response, we should immediately prepare for handling the next
protocol.
Modifications:
The pipeline reshaping logic in HttpServerUpgradeHandler has been moved
out of the ChannelFutureListener attached to the write of the upgrade
response and happens immediately after the writeAndFlush call, but
before the method returns.
Result:
The pipeline is no longer subject to receiving more data before the
pipeline has been reformed.
Motivation:
Explain here the context, and why you're making that change.
What is the problem you're trying to solve.
Modification:
Describe the modifications you've done.
Result:
Fixes #.
If there is no issue then describe the changes introduced by this PR.
You can view, comment on, or merge this pull request online at:
#7807
Commit Summary
HttpServerUpgradeHandler shouldn't wait for flush to reshape pipeline
File Changes
M codec-http/src/main/java/io/netty/handler/codec/http/HttpServerUpgradeHandler.java (49)
Patch Links:
https://github.com/netty/netty/pull/7807.patch
https://github.com/netty/netty/pull/7807.diff
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub, or mute the thread.
|
|
I think this should fix #7740, but am not 100% sure. Since the I'm also open to suggestions for tests. Currently there aren't any dedicated tests for |
eb31acc to
514be54
Compare
There was a problem hiding this comment.
please add a license header.
There was a problem hiding this comment.
we use 4 spaces, please fix :)
|
Thanks for the feedback @normanmaurer, I'll address it this afternoon. Cc'ing @ejona86 as he may have comments about correctness. |
|
Didn't look in great detail, but this makes me feel better. There's really no reason I can think of to delay until the write is complete and I agree it just seems to add a race. |
885934c to
c4b1b8a
Compare
|
Thanks for the double check @ejona86. @normanmaurer, I think I addressed your comments. Thanks again for the review. |
There was a problem hiding this comment.
Can we just use Collections.<CharSequence>emptyList() and so remove the dependency on the guava here ?
There was a problem hiding this comment.
Call super.write(....) to ensure we not "leak the message" and also to ensure the promise is notified.
There was a problem hiding this comment.
This was deliberate so that we could be confident that the pipeline reshaping happened in this call stack irrespective of the promise being satisfied.
That said, perhaps it's not something that is likely to regress. And we do need to do something with the outbound message, good catch.
There was a problem hiding this comment.
just use Unpooled.copiedBuffer(upgradeString, CharsetUitl.US_ASCII)
|
@bryce-anderson #3698 does not seem to be the correct issue to reference here... Can you check ? |
c4b1b8a to
d6f0c82
Compare
|
@normanmaurer, sorry, you're right: the issue it attempts to fix is #7740. |
There was a problem hiding this comment.
Is there a reason to delay this until the write succeeds? (I can't think of any)
There was a problem hiding this comment.
The write hasn't necessarily succeeded yet as writeComplete is a ChannelPromise. We should enqueue the write before reshaping the pipeline as the incoming codec may try to write something when it gets added to the pipeline.
There was a problem hiding this comment.
Maybe just delay the write by using ctx.eventLoop().execute(...) and schedule the write via it ?
There was a problem hiding this comment.
That did the trick, thanks @normanmaurer. I'd tried to defer the satisfaction of the promise via indirection through the executor, but the flush() call would run it. Your suggestion is much more reasonable anyway.
There was a problem hiding this comment.
Ah, shoot, my comment was really unclear - I wanted to note that we fireUserEventTriggered before the write is complete and ask if there could be a reason to delay that event until the write finished instead. I'm not sure what the contract around that user event is, but maybe some folks rely on that happening after the write?
There was a problem hiding this comment.
this test LGTM, but as a sanity check, does it fail without your change?
There was a problem hiding this comment.
No, not anymore. Originally it did, but now that the write override on line 96 calls super.write as @normanmaurer requested, it will succeed either way. See his second round of comments.
I'm happy to take suggestions on how to test this cleanly, but the only thing I can think of is to drop the promise (what I had originally, and it did fail without my patch) or to store it somewhere else and fail it later with the former being bad form and the latter being a pretty ugly mess.
There was a problem hiding this comment.
Using normans suggestion it now fails without the changes to HttpServerUpgradeHandler.
There was a problem hiding this comment.
@bryce-anderson did you forget to push this change ?
There was a problem hiding this comment.
@normanmaurer yes, I had. Sorry about that.
0149216 to
e374c04
Compare
There was a problem hiding this comment.
write and flush shouldn't throw ... but consider including it in the try block below just to have less assumptions about releasing the event relative to behavior of this method.
There was a problem hiding this comment.
nit: just put this on the previous line. line length of 120 is permitted.
There was a problem hiding this comment.
The bigger issue was that the comment was incomplete. Sorry about that.
There was a problem hiding this comment.
nit: remove throws Exception
|
@bryce-anderson please address @Scottmitch s comments and ping me once done. I will pull in then. |
e374c04 to
799cc6e
Compare
Motivation: There is a race between both flushing the upgrade response and receiving more data before the flush ChannelPromise can fire and reshape the pipeline. Since We have already committed to an upgrade by writing the upgrade response, we need to be immediately prepared for handling the next protocol. Modifications: The pipeline reshaping logic in HttpServerUpgradeHandler has been moved out of the ChannelFutureListener attached to the write of the upgrade response and happens immediately after the writeAndFlush call, but before the method returns. Result: The pipeline is no longer subject to receiving more data before the pipeline has been reformed.
799cc6e to
0a6a2ab
Compare
|
Thanks for the feedback @Scottmitch. @normanmaurer, should be ready. Thanks again for the reviews folks. |
|
Will merge once CI completes @bryce-anderson ... thanks! |
Motivation:
There is a race between both flushing the upgrade response and receiving
more data before the flush ChannelPromise can fire the listener and reshape
the pipeline. Since We have already committed to an upgrade by writing the
upgrade response, we should immediately prepare for handling the next
protocol.
Modifications:
The pipeline reshaping logic in HttpServerUpgradeHandler has been moved
out of the ChannelFutureListener attached to the write of the upgrade
response and happens immediately after the writeAndFlush call, but
before the method returns.
Result:
The pipeline is no longer subject to receiving more data before the
pipeline has been reformed.