Allow to turn off Utf8FrameValidator creation for websocket with Bina… (#9417)

…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.
This commit is contained in:
Dmitriy Dumanskiy 2019-08-03 13:35:47 +03:00 committed by Norman Maurer
parent 005fd55b88
commit 7c5a3c5898
3 changed files with 63 additions and 4 deletions

View File

@ -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);
}
}
}

View File

@ -217,7 +217,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());

View File

@ -121,6 +121,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();