DefaultHttp2RemoteFlowController may not write all pending bytes

Motivation:
DefaultHttp2RemoteFlowController attempts to write as many bytes as possible to transition the channel to not writable, and then relies on notification of channelWritabilityChange to continue writing. However the amount of bytes written by DefaultHttp2RemoteFlowController may not be the same number of bytes that is actually written to the channel due to other ChannelHandlers (SslHandler, compression, etc...) in the pipeline. This means there is a potential for the DefaultHttp2RemoteFlowController to be waiting for a channel writaiblity change event that will never come, and thus not write all queued data.

Modifications:
- DefaultHttp2RemoteFlowController should write pending bytes until there are no more, or until the channel is not writable.

Result:
DefaultHttp2RemoteFlowController will write all pending data.
Fixes https://github.com/netty/netty/issues/4242
This commit is contained in:
Scott Mitchell 2015-09-22 10:41:31 -07:00
parent beb75f0a04
commit 24c9407080

View File

@ -297,17 +297,22 @@ public class DefaultHttp2RemoteFlowController implements Http2RemoteFlowControll
*/ */
@Override @Override
public void writePendingBytes() throws Http2Exception { public void writePendingBytes() throws Http2Exception {
Http2Stream connectionStream = connection.connectionStream(); AbstractState connectionState = connectionState();
int connectionWindowSize = writableBytes(state(connectionStream).windowSize()); int connectionWindowSize;
do {
connectionWindowSize = writableBytes(connectionState.windowSize());
if (connectionWindowSize > 0) { if (connectionWindowSize > 0) {
// Allocate the bytes for the connection window to the streams, but do not write. // Allocate the bytes for the connection window to the streams, but do not write.
allocateBytesForTree(connectionStream, connectionWindowSize); allocateBytesForTree(connectionState.stream(), connectionWindowSize);
} }
// Now write all of the allocated bytes, must write as there may be empty frames with // Write all of allocated bytes. We must call this even if no bytes are allocated as it is possible there
// EOS = true // are empty frames indicating the End Of Stream.
connection.forEachActiveStream(WRITE_ALLOCATED_BYTES); connection.forEachActiveStream(WRITE_ALLOCATED_BYTES);
} while (connectionState.streamableBytesForTree() > 0 &&
connectionWindowSize > 0 &&
ctx.channel().isWritable());
} }
/** /**