Handle null "origin" header in "Old Hixie 75 handshake" as proper bad request. (#8864)
Motivation: Gracefully respond on bad client request. We have a set of errors produced by Android 7.1.1/7.1.2 clients where both headers `HttpHeaderNames.SEC_WEBSOCKET_VERSION` and `HttpHeaderNames.ORIGIN` are not present. Absence of the first headers leads to WebSocketServerHandshaker00 be applied as a handshaker. However, null 2nd header causes ``` java.lang.NullPointerException: value io.netty.util.internal.ObjectUtil.checkNotNull(ObjectUtil.java:33) io.netty.handler.codec.DefaultHeaders.addObject(DefaultHeaders.java:327) io.netty.handler.codec.http.DefaultHttpHeaders.add(DefaultHttpHeaders.java:123) io.netty.handler.codec.http.websocketx.WebSocketServerHandshaker00.newHandshakeResponse(WebSocketServerHandshaker00.java:162) ``` Which causes connection close with unclear reason. Modification: Added null-check, and in case of null an appropriate WebSocketHandshakeException is thrown. Result: In case of null `HttpHeaderNames.ORIGIN` header a WebSocketHandshakeException is caught by WebSocketServerProtocolHandler which sends a graceful `BAD_REQUEST`.
This commit is contained in:
parent
900d00d5db
commit
1bc7c4900c
@ -159,7 +159,11 @@ public class WebSocketServerHandshaker00 extends WebSocketServerHandshaker {
|
|||||||
res.content().writeBytes(WebSocketUtil.md5(input.array()));
|
res.content().writeBytes(WebSocketUtil.md5(input.array()));
|
||||||
} else {
|
} else {
|
||||||
// Old Hixie 75 handshake getMethod with no challenge:
|
// Old Hixie 75 handshake getMethod with no challenge:
|
||||||
res.headers().add(HttpHeaderNames.WEBSOCKET_ORIGIN, req.headers().get(HttpHeaderNames.ORIGIN));
|
String origin = req.headers().get(HttpHeaderNames.ORIGIN);
|
||||||
|
if (origin == null) {
|
||||||
|
throw new WebSocketHandshakeException("Missing origin header, got only " + req.headers().names());
|
||||||
|
}
|
||||||
|
res.headers().add(HttpHeaderNames.WEBSOCKET_ORIGIN, origin);
|
||||||
res.headers().add(HttpHeaderNames.WEBSOCKET_LOCATION, uri());
|
res.headers().add(HttpHeaderNames.WEBSOCKET_LOCATION, uri());
|
||||||
|
|
||||||
String protocol = req.headers().get(HttpHeaderNames.WEBSOCKET_PROTOCOL);
|
String protocol = req.headers().get(HttpHeaderNames.WEBSOCKET_PROTOCOL);
|
||||||
|
@ -33,7 +33,9 @@ import io.netty.util.CharsetUtil;
|
|||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import static io.netty.handler.codec.http.HttpVersion.*;
|
import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1;
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
public class WebSocketServerHandshaker00Test {
|
public class WebSocketServerHandshaker00Test {
|
||||||
|
|
||||||
@ -47,6 +49,34 @@ public class WebSocketServerHandshaker00Test {
|
|||||||
testPerformOpeningHandshake0(false);
|
testPerformOpeningHandshake0(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPerformHandshakeWithoutOriginHeader() {
|
||||||
|
EmbeddedChannel ch = new EmbeddedChannel(
|
||||||
|
new HttpObjectAggregator(42), new HttpRequestDecoder(), new HttpResponseEncoder());
|
||||||
|
|
||||||
|
FullHttpRequest req = new DefaultFullHttpRequest(
|
||||||
|
HTTP_1_1, HttpMethod.GET, "/chat", Unpooled.copiedBuffer("^n:ds[4U", CharsetUtil.US_ASCII));
|
||||||
|
|
||||||
|
req.headers().set(HttpHeaderNames.HOST, "server.example.com");
|
||||||
|
req.headers().set(HttpHeaderNames.UPGRADE, HttpHeaderValues.WEBSOCKET);
|
||||||
|
req.headers().set(HttpHeaderNames.CONNECTION, "Upgrade");
|
||||||
|
req.headers().set(HttpHeaderNames.SEC_WEBSOCKET_KEY1, "4 @1 46546xW%0l 1 5");
|
||||||
|
req.headers().set(HttpHeaderNames.SEC_WEBSOCKET_PROTOCOL, "chat, superchat");
|
||||||
|
|
||||||
|
WebSocketServerHandshaker00 handshaker00 = new WebSocketServerHandshaker00(
|
||||||
|
"ws://example.com/chat", "chat", Integer.MAX_VALUE);
|
||||||
|
try {
|
||||||
|
handshaker00.handshake(ch, req);
|
||||||
|
fail("Expecting WebSocketHandshakeException");
|
||||||
|
} catch (WebSocketHandshakeException e) {
|
||||||
|
assertEquals("Missing origin header, got only "
|
||||||
|
+ "[host, upgrade, connection, sec-websocket-key1, sec-websocket-protocol]",
|
||||||
|
e.getMessage());
|
||||||
|
} finally {
|
||||||
|
req.release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static void testPerformOpeningHandshake0(boolean subProtocol) {
|
private static void testPerformOpeningHandshake0(boolean subProtocol) {
|
||||||
EmbeddedChannel ch = new EmbeddedChannel(
|
EmbeddedChannel ch = new EmbeddedChannel(
|
||||||
new HttpObjectAggregator(42), new HttpRequestDecoder(), new HttpResponseEncoder());
|
new HttpObjectAggregator(42), new HttpRequestDecoder(), new HttpResponseEncoder());
|
||||||
|
Loading…
Reference in New Issue
Block a user