From 10ee697557328a7afc1c0e4c567880a6738c055a Mon Sep 17 00:00:00 2001 From: Dmitriy Dumanskiy Date: Sat, 3 Aug 2019 13:35:47 +0300 Subject: [PATCH] =?UTF-8?q?Allow=20to=20turn=20off=20Utf8FrameValidator=20?= =?UTF-8?q?creation=20for=20websocket=20with=20Bina=E2=80=A6=20(#9417)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit …ryWebSocketFrames Motivation: `Utf8FrameValidator` is always created and added to the pipeline in `WebSocketServerProtocolHandler.handlerAdded` method. However, for websocket connection with only `BinaryWebSocketFrame`'s UTF8 validator is unnecessary overhead. Adding of `Utf8FrameValidator` could be easily avoided by extending of `WebSocketDecoderConfig` with additional property. Specification requires UTF-8 validation only for `TextWebSocketFrame`. Modification: Added `boolean WebSocketDecoderConfig.withUTF8Validator` that allows to avoid adding of `Utf8FrameValidator` during pipeline initialization. Result: Less overhead when using only `BinaryWebSocketFrame`within web socket. --- .../websocketx/WebSocketDecoderConfig.java | 25 ++++++++++-- .../WebSocketServerProtocolHandler.java | 2 +- .../WebSocketServerProtocolHandlerTest.java | 40 +++++++++++++++++++ 3 files changed, 63 insertions(+), 4 deletions(-) diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketDecoderConfig.java b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketDecoderConfig.java index d539458890..9d78834c4c 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketDecoderConfig.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketDecoderConfig.java @@ -27,6 +27,7 @@ public final class WebSocketDecoderConfig { private final boolean allowMaskMismatch; private final boolean allowExtensions; private final boolean closeOnProtocolViolation; + private final boolean withUTF8Validator; /** * Constructor @@ -44,14 +45,20 @@ public final class WebSocketDecoderConfig { * Flag to allow reserved extension bits to be used or not * @param closeOnProtocolViolation * Flag to send close frame immediately on any protocol violation.ion. + * @param withUTF8Validator + * Allows you to avoid adding of Utf8FrameValidator to the pipeline on the + * WebSocketServerProtocolHandler creation. This is useful (less overhead) + * when you use only BinaryWebSocketFrame within your web socket connection. */ private WebSocketDecoderConfig(int maxFramePayloadLength, boolean expectMaskedFrames, boolean allowMaskMismatch, - boolean allowExtensions, boolean closeOnProtocolViolation) { + boolean allowExtensions, boolean closeOnProtocolViolation, + boolean withUTF8Validator) { this.maxFramePayloadLength = maxFramePayloadLength; this.expectMaskedFrames = expectMaskedFrames; this.allowMaskMismatch = allowMaskMismatch; this.allowExtensions = allowExtensions; this.closeOnProtocolViolation = closeOnProtocolViolation; + this.withUTF8Validator = withUTF8Validator; } public int maxFramePayloadLength() { @@ -74,6 +81,10 @@ public final class WebSocketDecoderConfig { return closeOnProtocolViolation; } + public boolean withUTF8Validator() { + return withUTF8Validator; + } + @Override public String toString() { return "WebSocketDecoderConfig" + @@ -82,6 +93,7 @@ public final class WebSocketDecoderConfig { ", allowMaskMismatch=" + allowMaskMismatch + ", allowExtensions=" + allowExtensions + ", closeOnProtocolViolation=" + closeOnProtocolViolation + + ", withUTF8Validator=" + withUTF8Validator + "]"; } @@ -99,6 +111,7 @@ public final class WebSocketDecoderConfig { private boolean allowMaskMismatch; private boolean allowExtensions; private boolean closeOnProtocolViolation = true; + private boolean withUTF8Validator = true; private Builder() { /* No-op */ @@ -111,6 +124,7 @@ public final class WebSocketDecoderConfig { allowMaskMismatch = decoderConfig.allowMaskMismatch(); allowExtensions = decoderConfig.allowExtensions(); closeOnProtocolViolation = decoderConfig.closeOnProtocolViolation(); + withUTF8Validator = decoderConfig.withUTF8Validator(); } public Builder maxFramePayloadLength(int maxFramePayloadLength) { @@ -138,10 +152,15 @@ public final class WebSocketDecoderConfig { return this; } + public Builder withUTF8Validator(boolean withUTF8Validator) { + this.withUTF8Validator = withUTF8Validator; + return this; + } + public WebSocketDecoderConfig build() { return new WebSocketDecoderConfig( - maxFramePayloadLength, expectMaskedFrames, allowMaskMismatch, - allowExtensions, closeOnProtocolViolation); + maxFramePayloadLength, expectMaskedFrames, allowMaskMismatch, + allowExtensions, closeOnProtocolViolation, withUTF8Validator); } } } diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketServerProtocolHandler.java b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketServerProtocolHandler.java index 42de7aff8a..68aae061ff 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketServerProtocolHandler.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketServerProtocolHandler.java @@ -216,7 +216,7 @@ public class WebSocketServerProtocolHandler extends WebSocketProtocolHandler { new WebSocketServerProtocolHandshakeHandler( websocketPath, subprotocols, checkStartsWith, handshakeTimeoutMillis, decoderConfig)); } - if (cp.get(Utf8FrameValidator.class) == null) { + if (decoderConfig.withUTF8Validator() && cp.get(Utf8FrameValidator.class) == null) { // Add the UFT8 checking before this one. cp.addBefore(ctx.name(), Utf8FrameValidator.class.getName(), new Utf8FrameValidator()); diff --git a/codec-http/src/test/java/io/netty/handler/codec/http/websocketx/WebSocketServerProtocolHandlerTest.java b/codec-http/src/test/java/io/netty/handler/codec/http/websocketx/WebSocketServerProtocolHandlerTest.java index 69ec984974..0dd44ee7f7 100644 --- a/codec-http/src/test/java/io/netty/handler/codec/http/websocketx/WebSocketServerProtocolHandlerTest.java +++ b/codec-http/src/test/java/io/netty/handler/codec/http/websocketx/WebSocketServerProtocolHandlerTest.java @@ -120,6 +120,46 @@ public class WebSocketServerProtocolHandlerTest { assertFalse(ch.finish()); } + @Test + public void testCreateUTF8Validator() { + WebSocketDecoderConfig config = WebSocketDecoderConfig.newBuilder() + .withUTF8Validator(true) + .build(); + + EmbeddedChannel ch = new EmbeddedChannel( + new WebSocketServerProtocolHandler("/test", null, false, false, 1000L, config), + new HttpRequestDecoder(), + new HttpResponseEncoder(), + new MockOutboundHandler()); + writeUpgradeRequest(ch); + + FullHttpResponse response = responses.remove(); + assertEquals(SWITCHING_PROTOCOLS, response.status()); + response.release(); + + assertNotNull(ch.pipeline().get(Utf8FrameValidator.class)); + } + + @Test + public void testDoNotCreateUTF8Validator() { + WebSocketDecoderConfig config = WebSocketDecoderConfig.newBuilder() + .withUTF8Validator(false) + .build(); + + EmbeddedChannel ch = new EmbeddedChannel( + new WebSocketServerProtocolHandler("/test", null, false, false, 1000L, config), + new HttpRequestDecoder(), + new HttpResponseEncoder(), + new MockOutboundHandler()); + writeUpgradeRequest(ch); + + FullHttpResponse response = responses.remove(); + assertEquals(SWITCHING_PROTOCOLS, response.status()); + response.release(); + + assertNull(ch.pipeline().get(Utf8FrameValidator.class)); + } + @Test public void testHandleTextFrame() { CustomTextFrameHandler customTextFrameHandler = new CustomTextFrameHandler();