Make SslHandler work when autoRead is turned off

Related: #2958

Motivation:

SslHandler currently does not issue a read() request when it is
handshaking. It makes a connection with autoRead off stall, because a
user's read() request can be used to read the handshake response which
is invisible to the user.

Modifications:

- SslHandler now issues a read() request when:
  - the current handshake is in progress and channelReadComplete() is
    invoked
  - the current handshake is complete and a user issued a read() request
    during handshake
- Rename flushedBeforeHandshakeDone to flushedBeforeHandshake for
  consistency with the new variable 'readDuringHandshake'

Result:

SslHandler should work regardless whether autoRead is on or off.
This commit is contained in:
Trustin Lee 2014-12-11 17:48:45 +09:00
parent 1dc1831abf
commit d5a24d4f6c

View File

@ -206,7 +206,8 @@ public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundH
private final boolean startTls; private final boolean startTls;
private boolean sentFirstMessage; private boolean sentFirstMessage;
private boolean flushedBeforeHandshakeDone; private boolean flushedBeforeHandshake;
private boolean readDuringHandshake;
private PendingWriteQueue pendingUnencryptedWrites; private PendingWriteQueue pendingUnencryptedWrites;
private Promise<Channel> handshakePromise = new LazyChannelPromise(); private Promise<Channel> handshakePromise = new LazyChannelPromise();
@ -408,7 +409,11 @@ public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundH
} }
@Override @Override
public void read(ChannelHandlerContext ctx) { public void read(ChannelHandlerContext ctx) throws Exception {
if (!handshakePromise.isDone()) {
readDuringHandshake = true;
}
ctx.read(); ctx.read();
} }
@ -431,7 +436,7 @@ public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundH
pendingUnencryptedWrites.add(Unpooled.EMPTY_BUFFER, ctx.voidPromise()); pendingUnencryptedWrites.add(Unpooled.EMPTY_BUFFER, ctx.voidPromise());
} }
if (!handshakePromise.isDone()) { if (!handshakePromise.isDone()) {
flushedBeforeHandshakeDone = true; flushedBeforeHandshake = true;
} }
wrap(ctx, false); wrap(ctx, false);
ctx.flush(); ctx.flush();
@ -888,7 +893,13 @@ public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundH
needsFlush = false; needsFlush = false;
ctx.flush(); ctx.flush();
} }
super.channelReadComplete(ctx);
// If handshake is not finished yet, we need more data.
if (!handshakePromise.isDone() && !ctx.channel().config().isAutoRead()) {
ctx.read();
}
ctx.fireChannelReadComplete();
} }
/** /**
@ -952,11 +963,11 @@ public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundH
wrapLater = true; wrapLater = true;
continue; continue;
} }
if (flushedBeforeHandshakeDone) { if (flushedBeforeHandshake) {
// We need to call wrap(...) in case there was a flush done before the handshake completed. // We need to call wrap(...) in case there was a flush done before the handshake completed.
// //
// See https://github.com/netty/netty/pull/2437 // See https://github.com/netty/netty/pull/2437
flushedBeforeHandshakeDone = false; flushedBeforeHandshake = false;
wrapLater = true; wrapLater = true;
} }
@ -1109,6 +1120,11 @@ public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundH
logger.debug(ctx.channel() + " HANDSHAKEN: " + engine.getSession().getCipherSuite()); logger.debug(ctx.channel() + " HANDSHAKEN: " + engine.getSession().getCipherSuite());
} }
ctx.fireUserEventTriggered(SslHandshakeCompletionEvent.SUCCESS); ctx.fireUserEventTriggered(SslHandshakeCompletionEvent.SUCCESS);
if (readDuringHandshake && !ctx.channel().config().isAutoRead()) {
readDuringHandshake = false;
ctx.read();
}
} }
/** /**