Add SslCloseCompletionEvent that is fired once a close_notify was received
Motivation: For the completion of a handshake we already fire a SslHandshakeCompletionEvent which the user can intercept. We should do the same for the receiving of close_notify. Modifications: Add SslCloseCompletionEvent and test-case. Result: More consistent API.
This commit is contained in:
parent
cd9008f95b
commit
d55c321306
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright 2017 The Netty Project
|
||||
*
|
||||
* The Netty Project licenses this file to you under the Apache License,
|
||||
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package io.netty.handler.ssl;
|
||||
|
||||
/**
|
||||
* Event that is fired once the close_notify was received or if an failure happens before it was received.
|
||||
*/
|
||||
public final class SslCloseCompletionEvent extends SslCompletionEvent {
|
||||
|
||||
public static final SslCloseCompletionEvent SUCCESS = new SslCloseCompletionEvent();
|
||||
|
||||
/**
|
||||
* Creates a new event that indicates a successful receiving of close_notify.
|
||||
*/
|
||||
private SslCloseCompletionEvent() { }
|
||||
|
||||
/**
|
||||
* Creates a new event that indicates an close_notify was not received because of an previous error.
|
||||
* Use {@link #SUCCESS} to indicate a success.
|
||||
*/
|
||||
public SslCloseCompletionEvent(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright 2017 The Netty Project
|
||||
*
|
||||
* The Netty Project licenses this file to you under the Apache License,
|
||||
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package io.netty.handler.ssl;
|
||||
|
||||
import io.netty.util.internal.ObjectUtil;
|
||||
|
||||
public abstract class SslCompletionEvent {
|
||||
|
||||
private final Throwable cause;
|
||||
|
||||
SslCompletionEvent() {
|
||||
cause = null;
|
||||
}
|
||||
|
||||
SslCompletionEvent(Throwable cause) {
|
||||
this.cause = ObjectUtil.checkNotNull(cause, "cause");
|
||||
}
|
||||
|
||||
/**
|
||||
* Return {@code true} if the completion was successful
|
||||
*/
|
||||
public final boolean isSuccess() {
|
||||
return cause == null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the {@link Throwable} if {@link #isSuccess()} returns {@code false}
|
||||
* and so the completion failed.
|
||||
*/
|
||||
public final Throwable cause() {
|
||||
return cause;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String toString() {
|
||||
final Throwable cause = cause();
|
||||
return cause == null? getClass().getSimpleName() + "(SUCCESS)" :
|
||||
getClass().getSimpleName() + '(' + cause + ')';
|
||||
}
|
||||
}
|
@ -772,7 +772,7 @@ public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundH
|
||||
setHandshakeFailure(ctx, CHANNEL_CLOSED, !outboundClosed);
|
||||
|
||||
// Ensure we always notify the sslClosePromise as well
|
||||
sslClosePromise.tryFailure(CHANNEL_CLOSED);
|
||||
notifyClosePromise(CHANNEL_CLOSED);
|
||||
super.channelInactive(ctx);
|
||||
}
|
||||
|
||||
@ -1133,7 +1133,7 @@ public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundH
|
||||
}
|
||||
|
||||
if (notifyClosure) {
|
||||
sslClosePromise.trySuccess(ctx.channel());
|
||||
notifyClosePromise(null);
|
||||
}
|
||||
} finally {
|
||||
if (decodeOut != null) {
|
||||
@ -1292,6 +1292,18 @@ public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundH
|
||||
}
|
||||
}
|
||||
|
||||
private void notifyClosePromise(Throwable cause) {
|
||||
if (cause == null) {
|
||||
if (sslClosePromise.trySuccess(ctx.channel())) {
|
||||
ctx.fireUserEventTriggered(SslCloseCompletionEvent.SUCCESS);
|
||||
}
|
||||
} else {
|
||||
if (sslClosePromise.tryFailure(cause)) {
|
||||
ctx.fireUserEventTriggered(new SslCloseCompletionEvent(cause));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void closeOutboundAndChannel(
|
||||
final ChannelHandlerContext ctx, final ChannelPromise promise, boolean disconnect) throws Exception {
|
||||
if (!ctx.channel().isActive()) {
|
||||
|
@ -20,48 +20,20 @@ package io.netty.handler.ssl;
|
||||
* Event that is fired once the SSL handshake is complete, which may be because it was successful or there
|
||||
* was an error.
|
||||
*/
|
||||
public final class SslHandshakeCompletionEvent {
|
||||
public final class SslHandshakeCompletionEvent extends SslCompletionEvent {
|
||||
|
||||
public static final SslHandshakeCompletionEvent SUCCESS = new SslHandshakeCompletionEvent();
|
||||
|
||||
private final Throwable cause;
|
||||
|
||||
/**
|
||||
* Creates a new event that indicates a successful handshake.
|
||||
*/
|
||||
private SslHandshakeCompletionEvent() {
|
||||
cause = null;
|
||||
}
|
||||
private SslHandshakeCompletionEvent() { }
|
||||
|
||||
/**
|
||||
* Creates a new event that indicates an unsuccessful handshake.
|
||||
* Use {@link #SUCCESS} to indicate a successful handshake.
|
||||
*/
|
||||
public SslHandshakeCompletionEvent(Throwable cause) {
|
||||
if (cause == null) {
|
||||
throw new NullPointerException("cause");
|
||||
}
|
||||
this.cause = cause;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return {@code true} if the handshake was successful
|
||||
*/
|
||||
public boolean isSuccess() {
|
||||
return cause == null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the {@link Throwable} if {@link #isSuccess()} returns {@code false}
|
||||
* and so the handshake failed.
|
||||
*/
|
||||
public Throwable cause() {
|
||||
return cause;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final Throwable cause = cause();
|
||||
return cause == null? "SslHandshakeCompletionEvent(SUCCESS)" : "SslHandshakeCompletionEvent(" + cause + ')';
|
||||
super(cause);
|
||||
}
|
||||
}
|
||||
|
@ -66,6 +66,8 @@ import java.nio.channels.ClosedChannelException;
|
||||
import java.security.KeyStore;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
|
||||
public class SslHandlerTest {
|
||||
|
||||
@ -384,4 +386,29 @@ public class SslHandlerTest {
|
||||
assertTrue(handler.handshakeFuture().cause() instanceof ClosedChannelException);
|
||||
assertTrue(handler.sslCloseFuture().cause() instanceof ClosedChannelException);
|
||||
}
|
||||
|
||||
@Test(timeout = 5000)
|
||||
public void testEventsFired() throws Exception {
|
||||
SSLEngine engine = SSLContext.getDefault().createSSLEngine();
|
||||
final BlockingQueue<SslCompletionEvent> events = new LinkedBlockingQueue<SslCompletionEvent>();
|
||||
EmbeddedChannel channel = new EmbeddedChannel(new SslHandler(engine), new ChannelInboundHandlerAdapter() {
|
||||
@Override
|
||||
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
|
||||
if (evt instanceof SslCompletionEvent) {
|
||||
events.add((SslCompletionEvent) evt);
|
||||
}
|
||||
}
|
||||
});
|
||||
assertTrue(events.isEmpty());
|
||||
assertTrue(channel.finishAndReleaseAll());
|
||||
|
||||
SslCompletionEvent evt = events.take();
|
||||
assertTrue(evt instanceof SslHandshakeCompletionEvent);
|
||||
assertTrue(evt.cause() instanceof ClosedChannelException);
|
||||
|
||||
evt = events.take();
|
||||
assertTrue(evt instanceof SslCloseCompletionEvent);
|
||||
assertTrue(evt.cause() instanceof ClosedChannelException);
|
||||
assertTrue(events.isEmpty());
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user