mirror of https://github.com/grpc/grpc-java.git
netty: TCP close during TLS handshake should be UNAVAILABLE
Normally the first exception/event experienced is the cause and is followed by a stampede of ClosedChannelExceptions. In this case, SslHandler is manufacturing a ClosedChannelException of its own and propagating it _before_ the trigger event. This might be considered a bug, but changing SslHandler's behavior would be very risky and almost certainly break someone's code. Fixes #7376
This commit is contained in:
parent
0cd56c29d6
commit
ec0d01d7a4
|
@ -58,6 +58,7 @@ import io.netty.util.Attribute;
|
|||
import io.netty.util.AttributeMap;
|
||||
import java.net.SocketAddress;
|
||||
import java.net.URI;
|
||||
import java.nio.channels.ClosedChannelException;
|
||||
import java.util.Arrays;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.logging.Level;
|
||||
|
@ -372,7 +373,18 @@ final class ProtocolNegotiators {
|
|||
ctx.fireExceptionCaught(ex);
|
||||
}
|
||||
} else {
|
||||
ctx.fireExceptionCaught(handshakeEvent.cause());
|
||||
Throwable t = handshakeEvent.cause();
|
||||
if (t instanceof ClosedChannelException) {
|
||||
// On channelInactive(), SslHandler creates its own ClosedChannelException and
|
||||
// propagates it before the actual channelInactive(). So we assume here that any
|
||||
// such exception is from channelInactive() and emulate the normal behavior of
|
||||
// WriteBufferingAndExceptionHandler
|
||||
t = Status.UNAVAILABLE
|
||||
.withDescription("Connection closed while performing TLS negotiation")
|
||||
.withCause(t)
|
||||
.asRuntimeException();
|
||||
}
|
||||
ctx.fireExceptionCaught(t);
|
||||
}
|
||||
} else {
|
||||
super.userEventTriggered0(ctx, evt);
|
||||
|
|
|
@ -33,6 +33,8 @@ import io.grpc.Attributes;
|
|||
import io.grpc.Grpc;
|
||||
import io.grpc.InternalChannelz.Security;
|
||||
import io.grpc.SecurityLevel;
|
||||
import io.grpc.Status;
|
||||
import io.grpc.StatusRuntimeException;
|
||||
import io.grpc.internal.GrpcAttributes;
|
||||
import io.grpc.internal.testing.TestUtils;
|
||||
import io.grpc.netty.ProtocolNegotiators.ClientTlsHandler;
|
||||
|
@ -534,6 +536,20 @@ public class ProtocolNegotiatorsTest {
|
|||
assertNull(grpcHandlerCtx);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void clientTlsHandler_closeDuringNegotiation() throws Exception {
|
||||
ClientTlsHandler handler = new ClientTlsHandler(grpcHandler, sslContext, "authority", null);
|
||||
pipeline.addLast(new WriteBufferingAndExceptionHandler(handler));
|
||||
ChannelFuture pendingWrite = channel.writeAndFlush(NettyClientHandler.NOOP_MESSAGE);
|
||||
|
||||
// SslHandler fires userEventTriggered() before channelInactive()
|
||||
pipeline.fireChannelInactive();
|
||||
|
||||
assertThat(pendingWrite.cause()).isInstanceOf(StatusRuntimeException.class);
|
||||
assertThat(Status.fromThrowable(pendingWrite.cause()).getCode())
|
||||
.isEqualTo(Status.Code.UNAVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void engineLog() {
|
||||
ChannelHandler handler = new ServerTlsHandler(grpcHandler, sslContext, null);
|
||||
|
|
Loading…
Reference in New Issue