diff --git a/netty-websocket-http2/src/main/java/com/jauntsdn/netty/handler/codec/http2/websocketx/Http2WebSocketEvent.java b/netty-websocket-http2/src/main/java/com/jauntsdn/netty/handler/codec/http2/websocketx/Http2WebSocketEvent.java index cc3df98..67345d2 100644 --- a/netty-websocket-http2/src/main/java/com/jauntsdn/netty/handler/codec/http2/websocketx/Http2WebSocketEvent.java +++ b/netty-websocket-http2/src/main/java/com/jauntsdn/netty/handler/codec/http2/websocketx/Http2WebSocketEvent.java @@ -16,6 +16,9 @@ package com.jauntsdn.netty.handler.codec.http2.websocketx; +import com.jauntsdn.netty.handler.codec.http2.websocketx.WebSocketEvent.WebSocketHandshakeErrorEvent; +import com.jauntsdn.netty.handler.codec.http2.websocketx.WebSocketEvent.WebSocketHandshakeStartEvent; +import com.jauntsdn.netty.handler.codec.http2.websocketx.WebSocketEvent.WebSocketHandshakeSuccessEvent; import io.netty.channel.Channel; import io.netty.channel.ChannelPipeline; import io.netty.handler.codec.http.websocketx.WebSocketHandshakeException; @@ -74,9 +77,13 @@ static void fireHandshakeStartAndError( parentPipeline.fireUserEventTriggered( new Http2WebSocketHandshakeStartEvent( serial, path, subprotocols, startNanos, requestHeaders)); + parentPipeline.fireUserEventTriggered( + new WebSocketHandshakeStartEvent(serial, path, subprotocols, startNanos, requestHeaders)); parentPipeline.fireUserEventTriggered( new Http2WebSocketHandshakeErrorEvent(serial, path, subprotocols, errorNanos, null, t)); + parentPipeline.fireUserEventTriggered( + new WebSocketHandshakeErrorEvent(serial, path, subprotocols, errorNanos, null, t)); return; } parentPipeline.fireExceptionCaught(t); @@ -97,10 +104,15 @@ static void fireHandshakeStartAndError( parentPipeline.fireUserEventTriggered( new Http2WebSocketHandshakeStartEvent( serial, path, subprotocols, startNanos, requestHeaders)); + parentPipeline.fireUserEventTriggered( + new WebSocketHandshakeStartEvent(serial, path, subprotocols, startNanos, requestHeaders)); parentPipeline.fireUserEventTriggered( new Http2WebSocketHandshakeErrorEvent( serial, path, subprotocols, errorNanos, null, errorName, errorMessage)); + parentPipeline.fireUserEventTriggered( + new WebSocketHandshakeErrorEvent( + serial, path, subprotocols, errorNanos, null, errorName, errorMessage)); } static void fireHandshakeStartAndSuccess( @@ -116,17 +128,26 @@ static void fireHandshakeStartAndSuccess( ChannelPipeline parentPipeline = webSocketChannel.parent().pipeline(); ChannelPipeline webSocketPipeline = webSocketChannel.pipeline(); - Http2WebSocketHandshakeStartEvent startEvent = + Http2WebSocketHandshakeStartEvent http2StartEvent = new Http2WebSocketHandshakeStartEvent( serial, path, subprotocols, startNanos, requestHeaders); - Http2WebSocketHandshakeSuccessEvent successEvent = + WebSocketHandshakeStartEvent startEvent = + new WebSocketHandshakeStartEvent(serial, path, subprotocols, startNanos, requestHeaders); + Http2WebSocketHandshakeSuccessEvent http2SuccessEvent = new Http2WebSocketHandshakeSuccessEvent( serial, path, subprotocols, subprotocol, successNanos, responseHeaders); + WebSocketHandshakeSuccessEvent successEvent = + new WebSocketHandshakeSuccessEvent( + serial, path, subprotocols, subprotocol, successNanos, responseHeaders); + parentPipeline.fireUserEventTriggered(http2StartEvent); parentPipeline.fireUserEventTriggered(startEvent); + parentPipeline.fireUserEventTriggered(http2SuccessEvent); parentPipeline.fireUserEventTriggered(successEvent); + webSocketPipeline.fireUserEventTriggered(http2StartEvent); webSocketPipeline.fireUserEventTriggered(startEvent); + webSocketPipeline.fireUserEventTriggered(http2SuccessEvent); webSocketPipeline.fireUserEventTriggered(successEvent); } @@ -134,16 +155,20 @@ static void fireHandshakeStart( Http2WebSocketChannel webSocketChannel, Http2Headers requestHeaders, long timestampNanos) { ChannelPipeline parentPipeline = webSocketChannel.parent().pipeline(); ChannelPipeline webSocketPipeline = webSocketChannel.pipeline(); + int serial = webSocketChannel.serial(); + String path = webSocketChannel.path(); + String subprotocol = webSocketChannel.subprotocol(); - Http2WebSocketHandshakeStartEvent startEvent = + Http2WebSocketHandshakeStartEvent http2StartEvent = new Http2WebSocketHandshakeStartEvent( - webSocketChannel.serial(), - webSocketChannel.path(), - webSocketChannel.subprotocol(), - timestampNanos, - requestHeaders); + serial, path, subprotocol, timestampNanos, requestHeaders); + + WebSocketHandshakeStartEvent startEvent = + new WebSocketHandshakeStartEvent(serial, path, subprotocol, timestampNanos, requestHeaders); + parentPipeline.fireUserEventTriggered(http2StartEvent); parentPipeline.fireUserEventTriggered(startEvent); + webSocketPipeline.fireUserEventTriggered(http2StartEvent); webSocketPipeline.fireUserEventTriggered(startEvent); } @@ -155,19 +180,22 @@ static void fireHandshakeError( ChannelPipeline parentPipeline = webSocketChannel.parent().pipeline(); if (t instanceof Exception) { - String path = webSocketChannel.path(); ChannelPipeline webSocketPipeline = webSocketChannel.pipeline(); + String path = webSocketChannel.path(); + int serial = webSocketChannel.serial(); + String subprotocol = webSocketChannel.subprotocol(); - Http2WebSocketHandshakeErrorEvent errorEvent = + Http2WebSocketHandshakeErrorEvent http2ErrorEvent = new Http2WebSocketHandshakeErrorEvent( - webSocketChannel.serial(), - path, - webSocketChannel.subprotocol(), - timestampNanos, - responseHeaders, - t); + serial, path, subprotocol, timestampNanos, responseHeaders, t); + WebSocketHandshakeErrorEvent errorEvent = + new WebSocketHandshakeErrorEvent( + serial, path, subprotocol, timestampNanos, responseHeaders, t); + + parentPipeline.fireUserEventTriggered(http2ErrorEvent); parentPipeline.fireUserEventTriggered(errorEvent); + webSocketPipeline.fireUserEventTriggered(http2ErrorEvent); webSocketPipeline.fireUserEventTriggered(errorEvent); return; } @@ -176,21 +204,23 @@ static void fireHandshakeError( static void fireHandshakeSuccess( Http2WebSocketChannel webSocketChannel, Http2Headers responseHeaders, long timestampNanos) { - String path = webSocketChannel.path(); - String subprotocol = webSocketChannel.subprotocol(); ChannelPipeline parentPipeline = webSocketChannel.parent().pipeline(); ChannelPipeline webSocketPipeline = webSocketChannel.pipeline(); + String path = webSocketChannel.path(); + String subprotocol = webSocketChannel.subprotocol(); + int serial = webSocketChannel.serial(); - Http2WebSocketHandshakeSuccessEvent successEvent = + Http2WebSocketHandshakeSuccessEvent http2SuccessEvent = new Http2WebSocketHandshakeSuccessEvent( - webSocketChannel.serial(), - path, - subprotocol, - subprotocol, - timestampNanos, - responseHeaders); + serial, path, subprotocol, subprotocol, timestampNanos, responseHeaders); + + WebSocketHandshakeSuccessEvent successEvent = + new WebSocketHandshakeSuccessEvent( + serial, path, subprotocol, subprotocol, timestampNanos, responseHeaders); + parentPipeline.fireUserEventTriggered(http2SuccessEvent); parentPipeline.fireUserEventTriggered(successEvent); + webSocketPipeline.fireUserEventTriggered(http2SuccessEvent); webSocketPipeline.fireUserEventTriggered(successEvent); } diff --git a/netty-websocket-http2/src/main/java/com/jauntsdn/netty/handler/codec/http2/websocketx/WebSocketEvent.java b/netty-websocket-http2/src/main/java/com/jauntsdn/netty/handler/codec/http2/websocketx/WebSocketEvent.java new file mode 100644 index 0000000..9bcc398 --- /dev/null +++ b/netty-websocket-http2/src/main/java/com/jauntsdn/netty/handler/codec/http2/websocketx/WebSocketEvent.java @@ -0,0 +1,155 @@ +/* + * Copyright 2024 - present Maksym Ostroverkhov. + * + * Licensed 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 com.jauntsdn.netty.handler.codec.http2.websocketx; + +import io.netty.handler.codec.Headers; +import javax.annotation.Nullable; + +/** Base type for transport agnostic websocket lifecycle events */ +public abstract class WebSocketEvent extends Http2WebSocketEvent.Http2WebSocketLifecycleEvent { + + WebSocketEvent( + Http2WebSocketEvent.Type type, + int id, + String path, + String subprotocols, + long timestampNanos) { + super(type, id, path, subprotocols, timestampNanos); + } + + /** websocket handshake start event */ + public static class WebSocketHandshakeStartEvent extends WebSocketEvent { + private final Headers requestHeaders; + + WebSocketHandshakeStartEvent( + int id, + String path, + String subprotocol, + long timestampNanos, + Headers requestHeaders) { + super(Type.HANDSHAKE_START, id, path, subprotocol, timestampNanos); + this.requestHeaders = requestHeaders; + } + + /** @return websocket request headers */ + public Headers requestHeaders() { + return requestHeaders; + } + } + + /** websocket handshake error event */ + public static class WebSocketHandshakeErrorEvent extends WebSocketEvent { + private final Headers responseHeaders; + private final String errorName; + private final String errorMessage; + private final Throwable error; + + WebSocketHandshakeErrorEvent( + int id, + String path, + String subprotocols, + long timestampNanos, + Headers responseHeaders, + Throwable error) { + this(id, path, subprotocols, timestampNanos, responseHeaders, error, null, null); + } + + WebSocketHandshakeErrorEvent( + int id, + String path, + String subprotocols, + long timestampNanos, + Headers responseHeaders, + String errorName, + String errorMessage) { + this(id, path, subprotocols, timestampNanos, responseHeaders, null, errorName, errorMessage); + } + + private WebSocketHandshakeErrorEvent( + int id, + String path, + String subprotocols, + long timestampNanos, + Headers responseHeaders, + Throwable error, + String errorName, + String errorMessage) { + super(Type.HANDSHAKE_ERROR, id, path, subprotocols, timestampNanos); + this.responseHeaders = responseHeaders; + this.errorName = errorName; + this.errorMessage = errorMessage; + this.error = error; + } + + /** @return response headers of failed websocket handshake */ + public Headers responseHeaders() { + return responseHeaders; + } + + /** + * @return exception associated with failed websocket handshake. May be null, in this case + * {@link #errorName()} and {@link #errorMessage()} contain error details. + */ + @Nullable + public Throwable error() { + return error; + } + + /** + * @return name of error associated with failed websocket handshake. May be null, in this case + * {@link #error()} contains respective exception + */ + public String errorName() { + return errorName; + } + + /** + * @return message of error associated with failed websocket handshake. May be null, in this + * case {@link #error()} contains respective exception + */ + public String errorMessage() { + return errorMessage; + } + } + + /** websocket handshake success event */ + public static class WebSocketHandshakeSuccessEvent extends WebSocketEvent { + private final String subprotocol; + private final Headers responseHeaders; + + WebSocketHandshakeSuccessEvent( + int id, + String path, + String subprotocols, + String subprotocol, + long timestampNanos, + Headers responseHeaders) { + super(Type.HANDSHAKE_SUCCESS, id, path, subprotocols, timestampNanos); + this.subprotocol = subprotocol; + this.responseHeaders = responseHeaders; + } + + public String subprotocol() { + return subprotocol; + } + + /** @return response headers of succeeded websocket handshake */ + public Headers responseHeaders() { + return responseHeaders; + } + } +} diff --git a/netty-websocket-http2/src/test/java/com/jauntsdn/netty/handler/codec/http2/websocketx/ApplicationHandshakeTest.java b/netty-websocket-http2/src/test/java/com/jauntsdn/netty/handler/codec/http2/websocketx/ApplicationHandshakeTest.java index f5c55d1..0f3012c 100644 --- a/netty-websocket-http2/src/test/java/com/jauntsdn/netty/handler/codec/http2/websocketx/ApplicationHandshakeTest.java +++ b/netty-websocket-http2/src/test/java/com/jauntsdn/netty/handler/codec/http2/websocketx/ApplicationHandshakeTest.java @@ -19,11 +19,15 @@ import com.jauntsdn.netty.handler.codec.http2.websocketx.Http2WebSocketEvent.Http2WebSocketHandshakeErrorEvent; import com.jauntsdn.netty.handler.codec.http2.websocketx.Http2WebSocketEvent.Http2WebSocketHandshakeStartEvent; import com.jauntsdn.netty.handler.codec.http2.websocketx.Http2WebSocketEvent.Http2WebSocketHandshakeSuccessEvent; +import com.jauntsdn.netty.handler.codec.http2.websocketx.WebSocketEvent.WebSocketHandshakeErrorEvent; +import com.jauntsdn.netty.handler.codec.http2.websocketx.WebSocketEvent.WebSocketHandshakeStartEvent; +import com.jauntsdn.netty.handler.codec.http2.websocketx.WebSocketEvent.WebSocketHandshakeSuccessEvent; import io.netty.channel.Channel; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.handler.codec.Headers; import io.netty.handler.codec.http.websocketx.WebSocketDecoderConfig; import io.netty.handler.codec.http.websocketx.WebSocketHandshakeException; import io.netty.handler.codec.http2.DefaultHttp2Headers; @@ -72,7 +76,7 @@ void knownPathAccepted() throws Exception { .sync() .channel(); - WebsocketEventsHandler eventsRecorder = new WebsocketEventsHandler(2); + WebsocketEventsHandler eventsRecorder = new WebsocketEventsHandler(4); SocketAddress address = server.localAddress(); client = createClient( @@ -96,17 +100,31 @@ void knownPathAccepted() throws Exception { Assertions.assertThat(handshake.isSuccess()).isTrue(); eventsRecorder.eventsReceived().await(5, TimeUnit.SECONDS); + List events = eventsRecorder.events(); - Assertions.assertThat(events).hasSize(2); - Http2WebSocketEvent startEvent = events.get(0); - Http2WebSocketEvent successEvent = events.get(1); - Assertions.assertThat(startEvent).isExactlyInstanceOf(Http2WebSocketHandshakeStartEvent.class); - Assertions.assertThat(startEvent.cast().path()) + Assertions.assertThat(events).hasSize(4); + Http2WebSocketEvent http2startEvent = events.get(0); + Http2WebSocketEvent startEvent = events.get(1); + Http2WebSocketEvent http2SuccessEvent = events.get(2); + Http2WebSocketEvent successEvent = events.get(3); + + Assertions.assertThat(http2startEvent) + .isExactlyInstanceOf(Http2WebSocketHandshakeStartEvent.class); + Assertions.assertThat(http2startEvent.cast().path()) + .isEqualTo("/test"); + + Assertions.assertThat(startEvent).isExactlyInstanceOf(WebSocketHandshakeStartEvent.class); + Assertions.assertThat(startEvent.cast().path()) .isEqualTo("/test"); - Assertions.assertThat(successEvent) + + Assertions.assertThat(http2SuccessEvent) .isExactlyInstanceOf(Http2WebSocketHandshakeSuccessEvent.class); - Assertions.assertThat(startEvent.cast().id()) - .isEqualTo(successEvent.cast().id()); + Assertions.assertThat(http2startEvent.cast().id()) + .isEqualTo(http2SuccessEvent.cast().id()); + + Assertions.assertThat(successEvent).isExactlyInstanceOf(WebSocketHandshakeSuccessEvent.class); + Assertions.assertThat(startEvent.cast().id()) + .isEqualTo(successEvent.cast().id()); } @Test @@ -127,7 +145,7 @@ void unknownPathRejected() throws Exception { .sync() .channel(); - WebsocketEventsHandler eventsRecorder = new WebsocketEventsHandler(2); + WebsocketEventsHandler eventsRecorder = new WebsocketEventsHandler(4); SocketAddress address = server.localAddress(); client = createClient( @@ -156,15 +174,30 @@ void unknownPathRejected() throws Exception { Assertions.assertThat(webSocketChannel.isOpen()).isFalse(); eventsRecorder.eventsReceived().await(5, TimeUnit.SECONDS); + List events = eventsRecorder.events(); - Assertions.assertThat(events).hasSize(2); - Http2WebSocketEvent startEvent = events.get(0); - Http2WebSocketEvent errorEvent = events.get(1); - Assertions.assertThat(startEvent).isExactlyInstanceOf(Http2WebSocketHandshakeStartEvent.class); - Assertions.assertThat(startEvent.cast().path()) + Assertions.assertThat(events).hasSize(4); + Http2WebSocketEvent http2StartEvent = events.get(0); + Http2WebSocketEvent startEvent = events.get(1); + Http2WebSocketEvent http2ErrorEvent = events.get(2); + Http2WebSocketEvent errorEvent = events.get(3); + + Assertions.assertThat(http2StartEvent) + .isExactlyInstanceOf(Http2WebSocketHandshakeStartEvent.class); + Assertions.assertThat(http2StartEvent.cast().path()) .isEqualTo("/test"); - Assertions.assertThat(errorEvent).isExactlyInstanceOf(Http2WebSocketHandshakeErrorEvent.class); - Assertions.assertThat(errorEvent.cast().error()) + + Assertions.assertThat(startEvent).isExactlyInstanceOf(WebSocketHandshakeStartEvent.class); + Assertions.assertThat(startEvent.cast().path()) + .isEqualTo("/test"); + + Assertions.assertThat(http2ErrorEvent) + .isExactlyInstanceOf(Http2WebSocketHandshakeErrorEvent.class); + Assertions.assertThat(http2ErrorEvent.cast().error()) + .isExactlyInstanceOf(WebSocketHandshakeException.class); + + Assertions.assertThat(errorEvent).isExactlyInstanceOf(WebSocketHandshakeErrorEvent.class); + Assertions.assertThat(errorEvent.cast().error()) .isExactlyInstanceOf(WebSocketHandshakeException.class); } @@ -186,7 +219,7 @@ void handshakeTimeout() throws Exception { .sync() .channel(); - WebsocketEventsHandler eventsRecorder = new WebsocketEventsHandler(2); + WebsocketEventsHandler eventsRecorder = new WebsocketEventsHandler(4); SocketAddress address = server.localAddress(); client = createClient( @@ -217,14 +250,28 @@ void handshakeTimeout() throws Exception { eventsRecorder.eventsReceived().await(5, TimeUnit.SECONDS); List events = eventsRecorder.events(); - Assertions.assertThat(events).hasSize(2); - Http2WebSocketEvent startEvent = events.get(0); - Http2WebSocketEvent errorEvent = events.get(1); - Assertions.assertThat(startEvent).isExactlyInstanceOf(Http2WebSocketHandshakeStartEvent.class); - Assertions.assertThat(startEvent.cast().path()) + Assertions.assertThat(events).hasSize(4); + Http2WebSocketEvent http2StartEvent = events.get(0); + Http2WebSocketEvent startEvent = events.get(1); + Http2WebSocketEvent http2ErrorEvent = events.get(2); + Http2WebSocketEvent errorEvent = events.get(3); + + Assertions.assertThat(http2StartEvent) + .isExactlyInstanceOf(Http2WebSocketHandshakeStartEvent.class); + Assertions.assertThat(http2StartEvent.cast().path()) .isEqualTo("/test"); - Assertions.assertThat(errorEvent).isExactlyInstanceOf(Http2WebSocketHandshakeErrorEvent.class); - Assertions.assertThat(errorEvent.cast().error()) + + Assertions.assertThat(startEvent).isExactlyInstanceOf(WebSocketHandshakeStartEvent.class); + Assertions.assertThat(startEvent.cast().path()) + .isEqualTo("/test"); + + Assertions.assertThat(http2ErrorEvent) + .isExactlyInstanceOf(Http2WebSocketHandshakeErrorEvent.class); + Assertions.assertThat(http2ErrorEvent.cast().error()) + .isExactlyInstanceOf(TimeoutException.class); + + Assertions.assertThat(errorEvent).isExactlyInstanceOf(WebSocketHandshakeErrorEvent.class); + Assertions.assertThat(errorEvent.cast().error()) .isExactlyInstanceOf(TimeoutException.class); } @@ -249,7 +296,7 @@ void serverAcceptorAccept() throws Exception { .sync() .channel(); - WebsocketEventsHandler eventsRecorder = new WebsocketEventsHandler(2); + WebsocketEventsHandler eventsRecorder = new WebsocketEventsHandler(4); SocketAddress address = server.localAddress(); client = createClient( @@ -277,17 +324,31 @@ void serverAcceptorAccept() throws Exception { eventsRecorder.eventsReceived().await(5, TimeUnit.SECONDS); List events = eventsRecorder.events(); - Assertions.assertThat(events).hasSize(2); - Http2WebSocketEvent startEvent = events.get(0); - Http2WebSocketEvent successEvent = events.get(1); - Assertions.assertThat(startEvent).isExactlyInstanceOf(Http2WebSocketHandshakeStartEvent.class); - Assertions.assertThat(startEvent.cast().path()) + Assertions.assertThat(events).hasSize(4); + Http2WebSocketEvent http2StartEvent = events.get(0); + Http2WebSocketEvent startEvent = events.get(1); + Http2WebSocketEvent http2SuccessEvent = events.get(2); + Http2WebSocketEvent successEvent = events.get(3); + + Assertions.assertThat(http2StartEvent) + .isExactlyInstanceOf(Http2WebSocketHandshakeStartEvent.class); + Assertions.assertThat(http2StartEvent.cast().path()) .isEqualTo("/test"); - Assertions.assertThat(successEvent) - .isExactlyInstanceOf(Http2WebSocketHandshakeSuccessEvent.class); - Http2Headers responseHeaders = - successEvent.cast().responseHeaders(); + Assertions.assertThat(startEvent).isExactlyInstanceOf(WebSocketHandshakeStartEvent.class); + Assertions.assertThat(startEvent.cast().path()) + .isEqualTo("/test"); + + Assertions.assertThat(http2SuccessEvent) + .isExactlyInstanceOf(Http2WebSocketHandshakeSuccessEvent.class); + Http2Headers http2ResponseHeaders = + http2SuccessEvent.cast().responseHeaders(); + Assertions.assertThat(http2ResponseHeaders.contains("x-request-id")).isTrue(); + Assertions.assertThat(http2ResponseHeaders.get(":status")).isEqualTo(AsciiString.of("200")); + + Assertions.assertThat(successEvent).isExactlyInstanceOf(WebSocketHandshakeSuccessEvent.class); + Headers responseHeaders = + successEvent.cast().responseHeaders(); Assertions.assertThat(responseHeaders.contains("x-request-id")).isTrue(); Assertions.assertThat(responseHeaders.get(":status")).isEqualTo(AsciiString.of("200")); } @@ -313,7 +374,7 @@ void serverAcceptorReject() throws Exception { .sync() .channel(); - WebsocketEventsHandler eventsRecorder = new WebsocketEventsHandler(2); + WebsocketEventsHandler eventsRecorder = new WebsocketEventsHandler(4); SocketAddress address = server.localAddress(); client = createClient( @@ -342,16 +403,30 @@ void serverAcceptorReject() throws Exception { eventsRecorder.eventsReceived().await(5, TimeUnit.SECONDS); List events = eventsRecorder.events(); - Assertions.assertThat(events).hasSize(2); - Http2WebSocketEvent startEvent = events.get(0); - Http2WebSocketEvent errorEvent = events.get(1); - Assertions.assertThat(startEvent).isExactlyInstanceOf(Http2WebSocketHandshakeStartEvent.class); - Assertions.assertThat(startEvent.cast().path()) + Assertions.assertThat(events).hasSize(4); + Http2WebSocketEvent http2startEvent = events.get(0); + Http2WebSocketEvent startEvent = events.get(1); + Http2WebSocketEvent http2ErrorEvent = events.get(2); + Http2WebSocketEvent errorEvent = events.get(3); + + Assertions.assertThat(http2startEvent) + .isExactlyInstanceOf(Http2WebSocketHandshakeStartEvent.class); + Assertions.assertThat(http2startEvent.cast().path()) .isEqualTo("/test"); - Assertions.assertThat(errorEvent).isExactlyInstanceOf(Http2WebSocketHandshakeErrorEvent.class); - Http2Headers responseHeaders = - errorEvent.cast().responseHeaders(); + Assertions.assertThat(startEvent).isExactlyInstanceOf(WebSocketHandshakeStartEvent.class); + Assertions.assertThat(startEvent.cast().path()) + .isEqualTo("/test"); + + Assertions.assertThat(http2ErrorEvent) + .isExactlyInstanceOf(Http2WebSocketHandshakeErrorEvent.class); + Http2Headers http2ResponseHeaders = + http2ErrorEvent.cast().responseHeaders(); + Assertions.assertThat(http2ResponseHeaders.get(":status")).isEqualTo(AsciiString.of("400")); + + Assertions.assertThat(errorEvent).isExactlyInstanceOf(WebSocketHandshakeErrorEvent.class); + Headers responseHeaders = + errorEvent.cast().responseHeaders(); Assertions.assertThat(responseHeaders.get(":status")).isEqualTo(AsciiString.of("400")); } @@ -377,7 +452,7 @@ void knownSubprotocolAccepted() throws Exception { .sync() .channel(); - WebsocketEventsHandler eventsRecorder = new WebsocketEventsHandler(2); + WebsocketEventsHandler eventsRecorder = new WebsocketEventsHandler(4); SocketAddress address = server.localAddress(); client = createClient( @@ -402,17 +477,30 @@ void knownSubprotocolAccepted() throws Exception { eventsRecorder.eventsReceived().await(5, TimeUnit.SECONDS); List events = eventsRecorder.events(); - Assertions.assertThat(events).hasSize(2); - Http2WebSocketEvent startEvent = events.get(0); - Http2WebSocketEvent successEvent = events.get(1); - Assertions.assertThat(startEvent).isExactlyInstanceOf(Http2WebSocketHandshakeStartEvent.class); - Assertions.assertThat(startEvent.cast().path()) + Assertions.assertThat(events).hasSize(4); + Http2WebSocketEvent http2StartEvent = events.get(0); + Http2WebSocketEvent startEvent = events.get(1); + Http2WebSocketEvent http2SuccessEvent = events.get(2); + Http2WebSocketEvent successEvent = events.get(3); + + Assertions.assertThat(http2StartEvent) + .isExactlyInstanceOf(Http2WebSocketHandshakeStartEvent.class); + Assertions.assertThat(http2StartEvent.cast().path()) .isEqualTo("/test"); - Assertions.assertThat(successEvent) + + Assertions.assertThat(startEvent).isExactlyInstanceOf(WebSocketHandshakeStartEvent.class); + Assertions.assertThat(startEvent.cast().path()) + .isEqualTo("/test"); + + Assertions.assertThat(http2SuccessEvent) .isExactlyInstanceOf(Http2WebSocketHandshakeSuccessEvent.class); + Http2Headers http2responseHeaders = + http2SuccessEvent.cast().responseHeaders(); + Assertions.assertThat(http2responseHeaders.get(":status")).isEqualTo(AsciiString.of("200")); - Http2Headers responseHeaders = - successEvent.cast().responseHeaders(); + Assertions.assertThat(successEvent).isExactlyInstanceOf(WebSocketHandshakeSuccessEvent.class); + Headers responseHeaders = + successEvent.cast().responseHeaders(); Assertions.assertThat(responseHeaders.get(":status")).isEqualTo(AsciiString.of("200")); } @@ -438,7 +526,7 @@ void unknownSubprotocolRejected() throws Exception { .sync() .channel(); - WebsocketEventsHandler eventsRecorder = new WebsocketEventsHandler(2); + WebsocketEventsHandler eventsRecorder = new WebsocketEventsHandler(4); SocketAddress address = server.localAddress(); client = createClient( @@ -466,18 +554,34 @@ void unknownSubprotocolRejected() throws Exception { eventsRecorder.eventsReceived().await(5, TimeUnit.SECONDS); List events = eventsRecorder.events(); - Assertions.assertThat(events).hasSize(2); - Http2WebSocketEvent startEvent = events.get(0); - Http2WebSocketEvent errorEvent = events.get(1); - Assertions.assertThat(startEvent).isExactlyInstanceOf(Http2WebSocketHandshakeStartEvent.class); - Assertions.assertThat(startEvent.cast().path()) + Assertions.assertThat(events).hasSize(4); + Http2WebSocketEvent http2StartEvent = events.get(0); + Http2WebSocketEvent startEvent = events.get(1); + Http2WebSocketEvent http2ErrorEvent = events.get(2); + Http2WebSocketEvent errorEvent = events.get(3); + + Assertions.assertThat(http2StartEvent) + .isExactlyInstanceOf(Http2WebSocketHandshakeStartEvent.class); + Assertions.assertThat(http2StartEvent.cast().path()) .isEqualTo("/test"); - Assertions.assertThat(errorEvent).isExactlyInstanceOf(Http2WebSocketHandshakeErrorEvent.class); - Assertions.assertThat(errorEvent.cast().error()) + + Assertions.assertThat(startEvent).isExactlyInstanceOf(WebSocketHandshakeStartEvent.class); + Assertions.assertThat(startEvent.cast().path()) + .isEqualTo("/test"); + + Assertions.assertThat(http2ErrorEvent) + .isExactlyInstanceOf(Http2WebSocketHandshakeErrorEvent.class); + Assertions.assertThat(http2ErrorEvent.cast().error()) .isExactlyInstanceOf(WebSocketHandshakeException.class); + Http2Headers http2responseHeaders = + http2ErrorEvent.cast().responseHeaders(); + Assertions.assertThat(http2responseHeaders.get(":status")).isEqualTo(AsciiString.of("404")); - Http2Headers responseHeaders = - errorEvent.cast().responseHeaders(); + Assertions.assertThat(errorEvent).isExactlyInstanceOf(WebSocketHandshakeErrorEvent.class); + Assertions.assertThat(errorEvent.cast().error()) + .isExactlyInstanceOf(WebSocketHandshakeException.class); + Headers responseHeaders = + http2ErrorEvent.cast().responseHeaders(); Assertions.assertThat(responseHeaders.get(":status")).isEqualTo(AsciiString.of("404")); } @@ -506,7 +610,7 @@ void nonHandshakedSubprotocolRejected() throws Exception { .sync() .channel(); - WebsocketEventsHandler eventsRecorder = new WebsocketEventsHandler(2); + WebsocketEventsHandler eventsRecorder = new WebsocketEventsHandler(4); SocketAddress address = server.localAddress(); client = createClient( @@ -534,18 +638,34 @@ void nonHandshakedSubprotocolRejected() throws Exception { eventsRecorder.eventsReceived().await(5, TimeUnit.SECONDS); List events = eventsRecorder.events(); - Assertions.assertThat(events).hasSize(2); - Http2WebSocketEvent startEvent = events.get(0); - Http2WebSocketEvent errorEvent = events.get(1); - Assertions.assertThat(startEvent).isExactlyInstanceOf(Http2WebSocketHandshakeStartEvent.class); - Assertions.assertThat(startEvent.cast().path()) + Assertions.assertThat(events).hasSize(4); + Http2WebSocketEvent http2StartEvent = events.get(0); + Http2WebSocketEvent startEvent = events.get(1); + Http2WebSocketEvent http2ErrorEvent = events.get(2); + Http2WebSocketEvent errorEvent = events.get(3); + + Assertions.assertThat(http2StartEvent) + .isExactlyInstanceOf(Http2WebSocketHandshakeStartEvent.class); + Assertions.assertThat(http2StartEvent.cast().path()) + .isEqualTo("/test"); + + Assertions.assertThat(startEvent).isExactlyInstanceOf(WebSocketHandshakeStartEvent.class); + Assertions.assertThat(startEvent.cast().path()) .isEqualTo("/test"); - Assertions.assertThat(errorEvent).isExactlyInstanceOf(Http2WebSocketHandshakeErrorEvent.class); - Assertions.assertThat(errorEvent.cast().error()) + + Assertions.assertThat(http2ErrorEvent) + .isExactlyInstanceOf(Http2WebSocketHandshakeErrorEvent.class); + Assertions.assertThat(http2ErrorEvent.cast().error()) .isExactlyInstanceOf(WebSocketHandshakeException.class); + Http2Headers http2responseHeaders = + http2ErrorEvent.cast().responseHeaders(); + Assertions.assertThat(http2responseHeaders.get(":status")).isEqualTo(AsciiString.of("404")); - Http2Headers responseHeaders = - errorEvent.cast().responseHeaders(); + Assertions.assertThat(errorEvent).isExactlyInstanceOf(WebSocketHandshakeErrorEvent.class); + Assertions.assertThat(errorEvent.cast().error()) + .isExactlyInstanceOf(WebSocketHandshakeException.class); + Headers responseHeaders = + errorEvent.cast().responseHeaders(); Assertions.assertThat(responseHeaders.get(":status")).isEqualTo(AsciiString.of("404")); } @@ -572,7 +692,7 @@ void compressionAccepted() throws Exception { .sync() .channel(); - WebsocketEventsHandler eventsRecorder = new WebsocketEventsHandler(2); + WebsocketEventsHandler eventsRecorder = new WebsocketEventsHandler(4); SocketAddress address = server.localAddress(); client = createClient( @@ -602,17 +722,32 @@ void compressionAccepted() throws Exception { eventsRecorder.eventsReceived().await(5, TimeUnit.SECONDS); List events = eventsRecorder.events(); - Assertions.assertThat(events).hasSize(2); - Http2WebSocketEvent startEvent = events.get(0); - Http2WebSocketEvent successEvent = events.get(1); - Assertions.assertThat(startEvent).isExactlyInstanceOf(Http2WebSocketHandshakeStartEvent.class); - Assertions.assertThat(startEvent.cast().path()) + Assertions.assertThat(events).hasSize(4); + Http2WebSocketEvent http2StartEvent = events.get(0); + Http2WebSocketEvent startEvent = events.get(1); + Http2WebSocketEvent http2SuccessEvent = events.get(2); + Http2WebSocketEvent successEvent = events.get(3); + + Assertions.assertThat(http2StartEvent) + .isExactlyInstanceOf(Http2WebSocketHandshakeStartEvent.class); + Assertions.assertThat(http2StartEvent.cast().path()) .isEqualTo("/test"); - Assertions.assertThat(successEvent) + + Assertions.assertThat(startEvent).isExactlyInstanceOf(WebSocketHandshakeStartEvent.class); + Assertions.assertThat(startEvent.cast().path()) + .isEqualTo("/test"); + + Assertions.assertThat(http2SuccessEvent) .isExactlyInstanceOf(Http2WebSocketHandshakeSuccessEvent.class); + Http2Headers http2responseHeaders = + http2SuccessEvent.cast().responseHeaders(); + Assertions.assertThat(http2responseHeaders.get(":status")).isEqualTo(AsciiString.of("200")); + Assertions.assertThat(http2responseHeaders.get("sec-websocket-extensions")) + .isEqualTo(AsciiString.of("permessage-deflate")); - Http2Headers responseHeaders = - successEvent.cast().responseHeaders(); + Assertions.assertThat(successEvent).isExactlyInstanceOf(WebSocketHandshakeSuccessEvent.class); + Headers responseHeaders = + successEvent.cast().responseHeaders(); Assertions.assertThat(responseHeaders.get(":status")).isEqualTo(AsciiString.of("200")); Assertions.assertThat(responseHeaders.get("sec-websocket-extensions")) .isEqualTo(AsciiString.of("permessage-deflate")); @@ -638,7 +773,7 @@ void compressionRejected() throws Exception { .sync() .channel(); - WebsocketEventsHandler eventsRecorder = new WebsocketEventsHandler(2); + WebsocketEventsHandler eventsRecorder = new WebsocketEventsHandler(4); SocketAddress address = server.localAddress(); client = createClient( @@ -668,17 +803,31 @@ void compressionRejected() throws Exception { eventsRecorder.eventsReceived().await(5, TimeUnit.SECONDS); List events = eventsRecorder.events(); - Assertions.assertThat(events).hasSize(2); - Http2WebSocketEvent startEvent = events.get(0); - Http2WebSocketEvent successEvent = events.get(1); - Assertions.assertThat(startEvent).isExactlyInstanceOf(Http2WebSocketHandshakeStartEvent.class); - Assertions.assertThat(startEvent.cast().path()) + Assertions.assertThat(events).hasSize(4); + Http2WebSocketEvent http2StartEvent = events.get(0); + Http2WebSocketEvent startEvent = events.get(1); + Http2WebSocketEvent http2SuccessEvent = events.get(2); + Http2WebSocketEvent successEvent = events.get(3); + + Assertions.assertThat(http2StartEvent) + .isExactlyInstanceOf(Http2WebSocketHandshakeStartEvent.class); + Assertions.assertThat(http2StartEvent.cast().path()) .isEqualTo("/test"); - Assertions.assertThat(successEvent) - .isExactlyInstanceOf(Http2WebSocketHandshakeSuccessEvent.class); - Http2Headers responseHeaders = - successEvent.cast().responseHeaders(); + Assertions.assertThat(startEvent).isExactlyInstanceOf(WebSocketHandshakeStartEvent.class); + Assertions.assertThat(startEvent.cast().path()) + .isEqualTo("/test"); + + Assertions.assertThat(http2SuccessEvent) + .isExactlyInstanceOf(Http2WebSocketHandshakeSuccessEvent.class); + Http2Headers http2responseHeaders = + http2SuccessEvent.cast().responseHeaders(); + Assertions.assertThat(http2responseHeaders.get("sec-websocket-extensions")).isNullOrEmpty(); + Assertions.assertThat(http2responseHeaders.get(":status")).isEqualTo(AsciiString.of("200")); + + Assertions.assertThat(successEvent).isExactlyInstanceOf(WebSocketHandshakeSuccessEvent.class); + Headers responseHeaders = + successEvent.cast().responseHeaders(); Assertions.assertThat(responseHeaders.get("sec-websocket-extensions")).isNullOrEmpty(); Assertions.assertThat(responseHeaders.get(":status")).isEqualTo(AsciiString.of("200")); } @@ -705,7 +854,7 @@ void priorKnowledgeAccepted() throws Exception { .sync() .channel(); - WebsocketEventsHandler eventsRecorder = new WebsocketEventsHandler(2); + WebsocketEventsHandler eventsRecorder = new WebsocketEventsHandler(4); SocketAddress address = server.localAddress(); client = createClient( @@ -730,17 +879,30 @@ void priorKnowledgeAccepted() throws Exception { eventsRecorder.eventsReceived().await(5, TimeUnit.SECONDS); List events = eventsRecorder.events(); - Assertions.assertThat(events).hasSize(2); - Http2WebSocketEvent startEvent = events.get(0); - Http2WebSocketEvent successEvent = events.get(1); - Assertions.assertThat(startEvent).isExactlyInstanceOf(Http2WebSocketHandshakeStartEvent.class); - Assertions.assertThat(startEvent.cast().path()) + Assertions.assertThat(events).hasSize(4); + Http2WebSocketEvent http2startEvent = events.get(0); + Http2WebSocketEvent startEvent = events.get(1); + Http2WebSocketEvent http2successEvent = events.get(2); + Http2WebSocketEvent successEvent = events.get(3); + + Assertions.assertThat(http2startEvent) + .isExactlyInstanceOf(Http2WebSocketHandshakeStartEvent.class); + Assertions.assertThat(http2startEvent.cast().path()) .isEqualTo("/test"); - Assertions.assertThat(successEvent) + + Assertions.assertThat(startEvent).isExactlyInstanceOf(WebSocketHandshakeStartEvent.class); + Assertions.assertThat(startEvent.cast().path()) + .isEqualTo("/test"); + + Assertions.assertThat(http2successEvent) .isExactlyInstanceOf(Http2WebSocketHandshakeSuccessEvent.class); + Http2Headers http2responseHeaders = + http2successEvent.cast().responseHeaders(); + Assertions.assertThat(http2responseHeaders.get(":status")).isEqualTo(AsciiString.of("200")); - Http2Headers responseHeaders = - successEvent.cast().responseHeaders(); + Assertions.assertThat(successEvent).isExactlyInstanceOf(WebSocketHandshakeSuccessEvent.class); + Headers responseHeaders = + successEvent.cast().responseHeaders(); Assertions.assertThat(responseHeaders.get(":status")).isEqualTo(AsciiString.of("200")); } diff --git a/netty-websocket-http2/src/test/java/com/jauntsdn/netty/handler/codec/http2/websocketx/ProtocolHandshakeTest.java b/netty-websocket-http2/src/test/java/com/jauntsdn/netty/handler/codec/http2/websocketx/ProtocolHandshakeTest.java index 2acaf04..f0c70b1 100644 --- a/netty-websocket-http2/src/test/java/com/jauntsdn/netty/handler/codec/http2/websocketx/ProtocolHandshakeTest.java +++ b/netty-websocket-http2/src/test/java/com/jauntsdn/netty/handler/codec/http2/websocketx/ProtocolHandshakeTest.java @@ -19,6 +19,9 @@ import com.jauntsdn.netty.handler.codec.http2.websocketx.Http2WebSocketEvent.Http2WebSocketHandshakeErrorEvent; import com.jauntsdn.netty.handler.codec.http2.websocketx.Http2WebSocketEvent.Http2WebSocketHandshakeStartEvent; import com.jauntsdn.netty.handler.codec.http2.websocketx.Http2WebSocketEvent.Http2WebSocketHandshakeSuccessEvent; +import com.jauntsdn.netty.handler.codec.http2.websocketx.WebSocketEvent.WebSocketHandshakeErrorEvent; +import com.jauntsdn.netty.handler.codec.http2.websocketx.WebSocketEvent.WebSocketHandshakeStartEvent; +import com.jauntsdn.netty.handler.codec.http2.websocketx.WebSocketEvent.WebSocketHandshakeSuccessEvent; import io.netty.channel.Channel; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelHandlerContext; @@ -75,7 +78,7 @@ void settingsEnableConnectAccepted() throws Exception { .sync() .channel(); - WebsocketEventsHandler eventsRecorder = new WebsocketEventsHandler(2); + WebsocketEventsHandler eventsRecorder = new WebsocketEventsHandler(4); SocketAddress address = server.localAddress(); client = createClient( @@ -100,14 +103,25 @@ void settingsEnableConnectAccepted() throws Exception { eventsRecorder.eventsReceived().await(5, TimeUnit.SECONDS); List events = eventsRecorder.events(); - Assertions.assertThat(events).hasSize(2); - Http2WebSocketEvent startEvent = events.get(0); - Http2WebSocketEvent successEvent = events.get(1); - Assertions.assertThat(startEvent).isExactlyInstanceOf(Http2WebSocketHandshakeStartEvent.class); - Assertions.assertThat(startEvent.cast().path()) + Assertions.assertThat(events).hasSize(4); + Http2WebSocketEvent http2startEvent = events.get(0); + Http2WebSocketEvent startEvent = events.get(1); + Http2WebSocketEvent http2successEvent = events.get(2); + Http2WebSocketEvent successEvent = events.get(3); + + Assertions.assertThat(http2startEvent) + .isExactlyInstanceOf(Http2WebSocketHandshakeStartEvent.class); + Assertions.assertThat(http2startEvent.cast().path()) + .isEqualTo("/test"); + + Assertions.assertThat(startEvent).isExactlyInstanceOf(WebSocketHandshakeStartEvent.class); + Assertions.assertThat(startEvent.cast().path()) .isEqualTo("/test"); - Assertions.assertThat(successEvent) + + Assertions.assertThat(http2successEvent) .isExactlyInstanceOf(Http2WebSocketHandshakeSuccessEvent.class); + + Assertions.assertThat(successEvent).isExactlyInstanceOf(WebSocketHandshakeSuccessEvent.class); } @Test @@ -125,7 +139,7 @@ void settingsNoEnableConnectRejected() throws Exception { SocketAddress address = server.localAddress(); SslContext clientSslContext = clientSslContext(); - WebsocketEventsHandler eventsRecorder = new WebsocketEventsHandler(2); + WebsocketEventsHandler eventsRecorder = new WebsocketEventsHandler(4); client = createClient( address, @@ -153,14 +167,28 @@ void settingsNoEnableConnectRejected() throws Exception { eventsRecorder.eventsReceived().await(5, TimeUnit.SECONDS); List events = eventsRecorder.events(); - Assertions.assertThat(events).hasSize(2); - Http2WebSocketEvent startEvent = events.get(0); - Http2WebSocketEvent errorEvent = events.get(1); - Assertions.assertThat(startEvent).isExactlyInstanceOf(Http2WebSocketHandshakeStartEvent.class); - Assertions.assertThat(startEvent.cast().path()) + Assertions.assertThat(events).hasSize(4); + Http2WebSocketEvent http2startEvent = events.get(0); + Http2WebSocketEvent startEvent = events.get(1); + Http2WebSocketEvent http2errorEvent = events.get(2); + Http2WebSocketEvent errorEvent = events.get(3); + + Assertions.assertThat(http2startEvent) + .isExactlyInstanceOf(Http2WebSocketHandshakeStartEvent.class); + Assertions.assertThat(http2startEvent.cast().path()) .isEqualTo("/test"); - Assertions.assertThat(errorEvent).isExactlyInstanceOf(Http2WebSocketHandshakeErrorEvent.class); - Assertions.assertThat(errorEvent.cast().error()) + + Assertions.assertThat(startEvent).isExactlyInstanceOf(WebSocketHandshakeStartEvent.class); + Assertions.assertThat(startEvent.cast().path()) + .isEqualTo("/test"); + + Assertions.assertThat(http2errorEvent) + .isExactlyInstanceOf(Http2WebSocketHandshakeErrorEvent.class); + Assertions.assertThat(http2errorEvent.cast().error()) + .isExactlyInstanceOf(WebSocketHandshakeException.class); + + Assertions.assertThat(errorEvent).isExactlyInstanceOf(WebSocketHandshakeErrorEvent.class); + Assertions.assertThat(errorEvent.cast().error()) .isExactlyInstanceOf(WebSocketHandshakeException.class); }