Skip to content

Commit

Permalink
Support 1012, 1013 and 1014 WebSocket status code
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
slandelle committed Dec 14, 2018
1 parent 83ab4ef commit db6d94f
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -451,7 +451,7 @@ protected void checkCloseFrameBody(
// 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);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -26,4 +35,50 @@ public void channelInactive() throws Exception {
decoder.channelInactive(ctx);
Mockito.verify(ctx).fireChannelInactive();
}

@Test
public void supportIanaStatusCodes() throws Exception {
Set<Integer> forbiddenIanaCodes = new HashSet<Integer>();
forbiddenIanaCodes.add(1004);
forbiddenIanaCodes.add(1005);
forbiddenIanaCodes.add(1006);
Set<Integer> validIanaCodes = new HashSet<Integer>();
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<Object> out = new ArrayList<Object>();

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

0 comments on commit db6d94f

Please sign in to comment.