From 302dac8c45266bba54bea59823a5757a496f5fdc Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 17 Dec 2018 19:42:50 +0100 Subject: [PATCH] Support 1012, 1013 and 1014 WebSocket close status code (#8664) Motivation: RFC 6455 doesn't define close status codes 1012, 1013 and 1014. Yet, since then, IANA has defined them and web browsers support them. From https://www.iana.org/assignments/websocket/websocket.xhtml: * 1012: Service Restart * 1013: Try Again Later * 1014: The server was acting as a gateway or proxy and received an invalid response from the upstream server. This is similar to 502 HTTP Status Code. Modification: Make status codes 1012, 1013 and 1014 legit. Result: WebSocket status codes as defined by IANA are supported. --- .../websocketx/WebSocket08FrameDecoder.java | 2 +- .../WebSocket08FrameDecoderTest.java | 51 +++++++++++++++++-- 2 files changed, 48 insertions(+), 5 deletions(-) diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocket08FrameDecoder.java b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocket08FrameDecoder.java index 604746c5ae..f5a6dc1936 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocket08FrameDecoder.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocket08FrameDecoder.java @@ -451,7 +451,7 @@ public class WebSocket08FrameDecoder extends ByteToMessageDecoder // Must have 2 byte integer within the valid range int statusCode = buffer.readShort(); if (statusCode >= 0 && statusCode <= 999 || statusCode >= 1004 && statusCode <= 1006 - || statusCode >= 1012 && statusCode <= 2999) { + || statusCode >= 1015 && statusCode <= 2999) { protocolViolation(ctx, "Invalid close frame getStatus code: " + statusCode); } diff --git a/codec-http/src/test/java/io/netty/handler/codec/http/websocketx/WebSocket08FrameDecoderTest.java b/codec-http/src/test/java/io/netty/handler/codec/http/websocketx/WebSocket08FrameDecoderTest.java index 547eed6174..cb6c187efc 100644 --- a/codec-http/src/test/java/io/netty/handler/codec/http/websocketx/WebSocket08FrameDecoderTest.java +++ b/codec-http/src/test/java/io/netty/handler/codec/http/websocketx/WebSocket08FrameDecoderTest.java @@ -12,18 +12,61 @@ */ package io.netty.handler.codec.http.websocketx; +import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; - +import io.netty.channel.embedded.EmbeddedChannel; import org.junit.Test; -import org.mockito.Mockito; + +import java.util.HashSet; +import java.util.Set; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; public class WebSocket08FrameDecoderTest { @Test public void channelInactive() throws Exception { final WebSocket08FrameDecoder decoder = new WebSocket08FrameDecoder(true, true, 65535, false); - final ChannelHandlerContext ctx = Mockito.mock(ChannelHandlerContext.class); + final ChannelHandlerContext ctx = mock(ChannelHandlerContext.class); decoder.channelInactive(ctx); - Mockito.verify(ctx).fireChannelInactive(); + verify(ctx).fireChannelInactive(); + } + + @Test + public void supportIanaStatusCodes() throws Exception { + Set forbiddenIanaCodes = new HashSet(); + forbiddenIanaCodes.add(1004); + forbiddenIanaCodes.add(1005); + forbiddenIanaCodes.add(1006); + Set validIanaCodes = new HashSet(); + for (int i = 1000; i < 1015; i++) { + validIanaCodes.add(i); + } + validIanaCodes.removeAll(forbiddenIanaCodes); + + for (int statusCode: validIanaCodes) { + EmbeddedChannel encoderChannel = new EmbeddedChannel(new WebSocket08FrameEncoder(true)); + EmbeddedChannel decoderChannel = new EmbeddedChannel(new WebSocket08FrameDecoder(true, true, 65535, false)); + + assertTrue(encoderChannel.writeOutbound(new CloseWebSocketFrame(statusCode, "Bye"))); + assertTrue(encoderChannel.finish()); + ByteBuf serializedCloseFrame = encoderChannel.readOutbound(); + assertNull(encoderChannel.readOutbound()); + + assertTrue(decoderChannel.writeInbound(serializedCloseFrame)); + assertTrue(decoderChannel.finish()); + + CloseWebSocketFrame outputFrame = decoderChannel.readInbound(); + assertNull(decoderChannel.readOutbound()); + try { + assertEquals(statusCode, outputFrame.statusCode()); + } finally { + outputFrame.release(); + } + } } }