From 19a46338595beba0ae3854a6346ec6f2ec73a0b9 Mon Sep 17 00:00:00 2001 From: ursa Date: Wed, 27 Nov 2019 07:36:30 +0000 Subject: [PATCH] Bugfix #9673: Origin header is always sent from WebSocket client (#9692) ### Motivation: Those who need 'Origin' or 'Sec-WebSocket-Origin' headers should provide them explicitly, like it is stated in WebSocket specs. E.g. through custom headers: HttpHeaders customHeaders = new DefaultHttpHeaders() .add(HttpHeaderNames.ORIGIN, "http://localhost:8080"); new WebSocketClientProtocolHandler( new URI("ws://localhost:1234/test"), WebSocketVersion.V13, subprotocol, allowExtensions, customHeaders, maxFramePayloadLength, handshakeTimeoutMillis) ### Modification: * Remove enforced origin headers. * Update tests ### Result: Fixes #9673: Origin header is always sent from WebSocket client --- .../websocketx/WebSocketClientHandshaker.java | 29 --------------- .../WebSocketClientHandshaker00.java | 4 -- .../WebSocketClientHandshaker07.java | 5 --- .../WebSocketClientHandshaker08.java | 5 --- .../WebSocketClientHandshaker13.java | 5 --- .../WebSocketServerHandshaker07.java | 1 - .../WebSocketServerHandshaker08.java | 1 - .../WebSocketServerHandshaker13.java | 1 - .../WebSocketClientHandshakerTest.java | 37 ++++++++++++++++++- .../WebSocketHandshakeHandOverTest.java | 2 +- 10 files changed, 37 insertions(+), 53 deletions(-) diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketClientHandshaker.java b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketClientHandshaker.java index 8038c20a30b..371b3127df0 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketClientHandshaker.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketClientHandshaker.java @@ -48,8 +48,6 @@ */ public abstract class WebSocketClientHandshaker { - private static final String HTTP_SCHEME_PREFIX = HttpScheme.HTTP + "://"; - private static final String HTTPS_SCHEME_PREFIX = HttpScheme.HTTPS + "://"; protected static final int DEFAULT_FORCE_CLOSE_TIMEOUT_MILLIS = 10000; private final URI uri; @@ -601,31 +599,4 @@ static CharSequence websocketHostValue(URI wsURL) { // See http://tools.ietf.org/html/rfc6454#section-6.2 return NetUtil.toSocketAddressString(host, port); } - - static CharSequence websocketOriginValue(URI wsURL) { - String scheme = wsURL.getScheme(); - final String schemePrefix; - int port = wsURL.getPort(); - final int defaultPort; - if (WebSocketScheme.WSS.name().contentEquals(scheme) - || HttpScheme.HTTPS.name().contentEquals(scheme) - || (scheme == null && port == WebSocketScheme.WSS.port())) { - - schemePrefix = HTTPS_SCHEME_PREFIX; - defaultPort = WebSocketScheme.WSS.port(); - } else { - schemePrefix = HTTP_SCHEME_PREFIX; - defaultPort = WebSocketScheme.WS.port(); - } - - // Convert uri-host to lower case (by RFC 6454, chapter 4 "Origin of a URI") - String host = wsURL.getHost().toLowerCase(Locale.US); - - if (port != defaultPort && port != -1) { - // if the port is not standard (80/443) its needed to add the port to the header. - // See http://tools.ietf.org/html/rfc6454#section-6.2 - return schemePrefix + NetUtil.toSocketAddressString(host, port); - } - return schemePrefix + host; - } } diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketClientHandshaker00.java b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketClientHandshaker00.java index ef4b6a3cfce..7ec3ed70f2d 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketClientHandshaker00.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketClientHandshaker00.java @@ -192,10 +192,6 @@ protected FullHttpRequest newHandshakeRequest() { .set(HttpHeaderNames.SEC_WEBSOCKET_KEY1, key1) .set(HttpHeaderNames.SEC_WEBSOCKET_KEY2, key2); - if (!headers.contains(HttpHeaderNames.ORIGIN)) { - headers.set(HttpHeaderNames.ORIGIN, websocketOriginValue(wsURL)); - } - String expectedSubprotocol = expectedSubprotocol(); if (expectedSubprotocol != null && !expectedSubprotocol.isEmpty()) { headers.set(HttpHeaderNames.SEC_WEBSOCKET_PROTOCOL, expectedSubprotocol); diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketClientHandshaker07.java b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketClientHandshaker07.java index a2fce7c911c..219b8f6b523 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketClientHandshaker07.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketClientHandshaker07.java @@ -187,7 +187,6 @@ public WebSocketClientHandshaker07(URI webSocketURL, WebSocketVersion version, S * Upgrade: websocket * Connection: Upgrade * Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ== - * Sec-WebSocket-Origin: http://example.com * Sec-WebSocket-Protocol: chat, superchat * Sec-WebSocket-Version: 7 * @@ -225,10 +224,6 @@ protected FullHttpRequest newHandshakeRequest() { .set(HttpHeaderNames.SEC_WEBSOCKET_KEY, key) .set(HttpHeaderNames.HOST, websocketHostValue(wsURL)); - if (!headers.contains(HttpHeaderNames.SEC_WEBSOCKET_ORIGIN)) { - headers.set(HttpHeaderNames.SEC_WEBSOCKET_ORIGIN, websocketOriginValue(wsURL)); - } - String expectedSubprotocol = expectedSubprotocol(); if (expectedSubprotocol != null && !expectedSubprotocol.isEmpty()) { headers.set(HttpHeaderNames.SEC_WEBSOCKET_PROTOCOL, expectedSubprotocol); diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketClientHandshaker08.java b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketClientHandshaker08.java index 245eff87531..5e8935809d5 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketClientHandshaker08.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketClientHandshaker08.java @@ -189,7 +189,6 @@ public WebSocketClientHandshaker08(URI webSocketURL, WebSocketVersion version, S * Upgrade: websocket * Connection: Upgrade * Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ== - * Sec-WebSocket-Origin: http://example.com * Sec-WebSocket-Protocol: chat, superchat * Sec-WebSocket-Version: 8 * @@ -227,10 +226,6 @@ protected FullHttpRequest newHandshakeRequest() { .set(HttpHeaderNames.SEC_WEBSOCKET_KEY, key) .set(HttpHeaderNames.HOST, websocketHostValue(wsURL)); - if (!headers.contains(HttpHeaderNames.SEC_WEBSOCKET_ORIGIN)) { - headers.set(HttpHeaderNames.SEC_WEBSOCKET_ORIGIN, websocketOriginValue(wsURL)); - } - String expectedSubprotocol = expectedSubprotocol(); if (expectedSubprotocol != null && !expectedSubprotocol.isEmpty()) { headers.set(HttpHeaderNames.SEC_WEBSOCKET_PROTOCOL, expectedSubprotocol); diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketClientHandshaker13.java b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketClientHandshaker13.java index 8efbb4a2e53..82a6049a0a1 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketClientHandshaker13.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketClientHandshaker13.java @@ -190,7 +190,6 @@ public WebSocketClientHandshaker13(URI webSocketURL, WebSocketVersion version, S * Upgrade: websocket * Connection: Upgrade * Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ== - * Origin: http://example.com * Sec-WebSocket-Protocol: chat, superchat * Sec-WebSocket-Version: 13 * @@ -228,10 +227,6 @@ protected FullHttpRequest newHandshakeRequest() { .set(HttpHeaderNames.SEC_WEBSOCKET_KEY, key) .set(HttpHeaderNames.HOST, websocketHostValue(wsURL)); - if (!headers.contains(HttpHeaderNames.ORIGIN)) { - headers.set(HttpHeaderNames.ORIGIN, websocketOriginValue(wsURL)); - } - String expectedSubprotocol = expectedSubprotocol(); if (expectedSubprotocol != null && !expectedSubprotocol.isEmpty()) { headers.set(HttpHeaderNames.SEC_WEBSOCKET_PROTOCOL, expectedSubprotocol); diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshaker07.java b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshaker07.java index 54f8ff4fa77..31f5fdb91b5 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshaker07.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshaker07.java @@ -109,7 +109,6 @@ public WebSocketServerHandshaker07(String webSocketURL, String subprotocols, Web * Upgrade: websocket * Connection: Upgrade * Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ== - * Sec-WebSocket-Origin: http://example.com * Sec-WebSocket-Protocol: chat, superchat * Sec-WebSocket-Version: 7 * diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshaker08.java b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshaker08.java index 1e454f43391..7ba5e34489b 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshaker08.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshaker08.java @@ -116,7 +116,6 @@ public WebSocketServerHandshaker08( * Upgrade: websocket * Connection: Upgrade * Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ== - * Sec-WebSocket-Origin: http://example.com * Sec-WebSocket-Protocol: chat, superchat * Sec-WebSocket-Version: 8 * diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshaker13.java b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshaker13.java index 8b445be9225..2f358cab935 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshaker13.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshaker13.java @@ -115,7 +115,6 @@ public WebSocketServerHandshaker13( * Upgrade: websocket * Connection: Upgrade * Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ== - * Origin: http://example.com * Sec-WebSocket-Protocol: chat, superchat * Sec-WebSocket-Version: 13 * diff --git a/codec-http/src/test/java/io/netty/handler/codec/http/websocketx/WebSocketClientHandshakerTest.java b/codec-http/src/test/java/io/netty/handler/codec/http/websocketx/WebSocketClientHandshakerTest.java index 2357e2bb0ee..d9dc169aed7 100644 --- a/codec-http/src/test/java/io/netty/handler/codec/http/websocketx/WebSocketClientHandshakerTest.java +++ b/codec-http/src/test/java/io/netty/handler/codec/http/websocketx/WebSocketClientHandshakerTest.java @@ -31,19 +31,27 @@ import io.netty.handler.codec.http.HttpObjectAggregator; import io.netty.handler.codec.http.HttpRequestEncoder; import io.netty.handler.codec.http.HttpResponseDecoder; +import io.netty.handler.codec.http.HttpScheme; import io.netty.util.CharsetUtil; +import io.netty.util.NetUtil; import org.junit.Test; import java.net.URI; +import java.util.Locale; import static org.junit.Assert.*; public abstract class WebSocketClientHandshakerTest { + private static final String HTTP_SCHEME_PREFIX = HttpScheme.HTTP + "://"; + private static final String HTTPS_SCHEME_PREFIX = HttpScheme.HTTPS + "://"; + protected abstract WebSocketClientHandshaker newHandshaker(URI uri, String subprotocol, HttpHeaders headers, boolean absoluteUpgradeUrl); protected WebSocketClientHandshaker newHandshaker(URI uri) { - return newHandshaker(uri, null, null, false); + HttpHeaders headers = new DefaultHttpHeaders() + .add(getOriginHeaderName(), websocketOriginValue(uri)); + return newHandshaker(uri, null, headers, false); } protected abstract CharSequence getOriginHeaderName(); @@ -360,4 +368,31 @@ public void testDuplicateWebsocketHandshakeHeaders() { request.release(); } + + static CharSequence websocketOriginValue(URI wsURL) { + String scheme = wsURL.getScheme(); + final String schemePrefix; + int port = wsURL.getPort(); + final int defaultPort; + if (WebSocketScheme.WSS.name().contentEquals(scheme) + || HttpScheme.HTTPS.name().contentEquals(scheme) + || (scheme == null && port == WebSocketScheme.WSS.port())) { + + schemePrefix = HTTPS_SCHEME_PREFIX; + defaultPort = WebSocketScheme.WSS.port(); + } else { + schemePrefix = HTTP_SCHEME_PREFIX; + defaultPort = WebSocketScheme.WS.port(); + } + + // Convert uri-host to lower case (by RFC 6454, chapter 4 "Origin of a URI") + String host = wsURL.getHost().toLowerCase(Locale.US); + + if (port != defaultPort && port != -1) { + // if the port is not standard (80/443) its needed to add the port to the header. + // See http://tools.ietf.org/html/rfc6454#section-6.2 + return schemePrefix + NetUtil.toSocketAddressString(host, port); + } + return schemePrefix + host; + } } diff --git a/codec-http/src/test/java/io/netty/handler/codec/http/websocketx/WebSocketHandshakeHandOverTest.java b/codec-http/src/test/java/io/netty/handler/codec/http/websocketx/WebSocketHandshakeHandOverTest.java index 0245078509a..256a119dca2 100644 --- a/codec-http/src/test/java/io/netty/handler/codec/http/websocketx/WebSocketHandshakeHandOverTest.java +++ b/codec-http/src/test/java/io/netty/handler/codec/http/websocketx/WebSocketHandshakeHandOverTest.java @@ -115,7 +115,7 @@ protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Except assertTrue(serverReceivedHandshake); assertNotNull(serverHandshakeComplete); assertEquals("/test", serverHandshakeComplete.requestUri()); - assertEquals(8, serverHandshakeComplete.requestHeaders().size()); + assertEquals(7, serverHandshakeComplete.requestHeaders().size()); assertEquals("test-proto-2", serverHandshakeComplete.selectedSubprotocol()); // Transfer the handshake response and the websocket message to the client