From db6d94f82a0f860131392aa483f4d1e21dc74249 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Fri, 14 Dec 2018 10:27:37 +0100 Subject: [PATCH] Support 1012, 1013 and 1014 WebSocket status code Motivation: RFC 6455 doesn't define status codes 1012, 1013 and 1014. Yet, since then, IANA has defined them, web browsers support them, applications in the wild do use them but it's currently not possible to buid a Netty based client for those services. 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 | 55 +++++++++++++++++++ 2 files changed, 56 insertions(+), 1 deletion(-) 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..029f7db447 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,11 +12,20 @@ */ package io.netty.handler.codec.http.websocketx; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.UnpooledByteBufAllocator; +import io.netty.channel.Channel; import io.netty.channel.ChannelHandlerContext; import org.junit.Test; +import static org.junit.Assert.*; import org.mockito.Mockito; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + public class WebSocket08FrameDecoderTest { @Test @@ -26,4 +35,50 @@ public class WebSocket08FrameDecoderTest { decoder.channelInactive(ctx); Mockito.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); + + ChannelHandlerContext ctx = Mockito.mock(ChannelHandlerContext.class); + Mockito.when(ctx.alloc()).thenReturn(UnpooledByteBufAllocator.DEFAULT); + + Channel channel = Mockito.mock(Channel.class); + Mockito.when(channel.isActive()).thenReturn(false); + Mockito.when(ctx.channel()).thenReturn(channel); + + List out = new ArrayList(); + + for (int statusCode: validIanaCodes) { + WebSocket08FrameEncoder encoder = new WebSocket08FrameEncoder(true); + WebSocket08FrameDecoder decoder = new WebSocket08FrameDecoder(true, true, 65535, false); + + CloseWebSocketFrame inputFrame = new CloseWebSocketFrame(statusCode, "Bye"); + try { + encoder.encode(ctx, inputFrame, out); + ByteBuf serializedCloseFrame = (ByteBuf) out.get(0); + out.clear(); + + decoder.decode(ctx, serializedCloseFrame, out); + CloseWebSocketFrame outputFrame = (CloseWebSocketFrame) out.get(0); + out.clear(); + + try { + assertEquals(statusCode, outputFrame.statusCode()); + } finally { + outputFrame.release(); + } + } finally { + inputFrame.release(); + } + } + } }