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
f46aa75198
commit
0ccab2b55b
@ -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);
|
setHandshakeFailure(ctx, CHANNEL_CLOSED, !outboundClosed);
|
||||||
|
|
||||||
// Ensure we always notify the sslClosePromise as well
|
// Ensure we always notify the sslClosePromise as well
|
||||||
sslClosePromise.tryFailure(CHANNEL_CLOSED);
|
notifyClosePromise(CHANNEL_CLOSED);
|
||||||
super.channelInactive(ctx);
|
super.channelInactive(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1133,7 +1133,7 @@ public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundH
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (notifyClosure) {
|
if (notifyClosure) {
|
||||||
sslClosePromise.trySuccess(ctx.channel());
|
notifyClosePromise(null);
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
if (decodeOut != null) {
|
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(
|
private void closeOutboundAndChannel(
|
||||||
final ChannelHandlerContext ctx, final ChannelPromise promise, boolean disconnect) throws Exception {
|
final ChannelHandlerContext ctx, final ChannelPromise promise, boolean disconnect) throws Exception {
|
||||||
if (!ctx.channel().isActive()) {
|
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
|
* Event that is fired once the SSL handshake is complete, which may be because it was successful or there
|
||||||
* was an error.
|
* was an error.
|
||||||
*/
|
*/
|
||||||
public final class SslHandshakeCompletionEvent {
|
public final class SslHandshakeCompletionEvent extends SslCompletionEvent {
|
||||||
|
|
||||||
public static final SslHandshakeCompletionEvent SUCCESS = new SslHandshakeCompletionEvent();
|
public static final SslHandshakeCompletionEvent SUCCESS = new SslHandshakeCompletionEvent();
|
||||||
|
|
||||||
private final Throwable cause;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new event that indicates a successful handshake.
|
* Creates a new event that indicates a successful handshake.
|
||||||
*/
|
*/
|
||||||
private SslHandshakeCompletionEvent() {
|
private SslHandshakeCompletionEvent() { }
|
||||||
cause = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new event that indicates an unsuccessful handshake.
|
* Creates a new event that indicates an unsuccessful handshake.
|
||||||
* Use {@link #SUCCESS} to indicate a successful handshake.
|
* Use {@link #SUCCESS} to indicate a successful handshake.
|
||||||
*/
|
*/
|
||||||
public SslHandshakeCompletionEvent(Throwable cause) {
|
public SslHandshakeCompletionEvent(Throwable cause) {
|
||||||
if (cause == null) {
|
super(cause);
|
||||||
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 + ')';
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -69,6 +69,8 @@ import java.nio.channels.ClosedChannelException;
|
|||||||
import java.security.KeyStore;
|
import java.security.KeyStore;
|
||||||
import java.security.cert.CertificateException;
|
import java.security.cert.CertificateException;
|
||||||
import java.security.cert.X509Certificate;
|
import java.security.cert.X509Certificate;
|
||||||
|
import java.util.concurrent.BlockingQueue;
|
||||||
|
import java.util.concurrent.LinkedBlockingQueue;
|
||||||
|
|
||||||
public class SslHandlerTest {
|
public class SslHandlerTest {
|
||||||
|
|
||||||
@ -387,4 +389,29 @@ public class SslHandlerTest {
|
|||||||
assertTrue(handler.handshakeFuture().cause() instanceof ClosedChannelException);
|
assertTrue(handler.handshakeFuture().cause() instanceof ClosedChannelException);
|
||||||
assertTrue(handler.sslCloseFuture().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…
x
Reference in New Issue
Block a user