From f48d9fa8d05cfe5848509d0ed2739cc857d071ce 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) 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) * Remove enforced origin headers. * Update tests Fixes #9673: Origin header is always sent from WebSocket client --- .../websocketx/WebSocketClientHandshaker.java | 30 --------------- .../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(+), 54 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 d9bdd93f111..0043c67b335 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 @@ -40,7 +40,6 @@ import java.net.URI; import java.nio.channels.ClosedChannelException; -import java.util.Locale; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; @@ -50,8 +49,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; @@ -576,31 +573,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 8c609ed24ea..fbb0b5d2c8e 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 @@ -193,10 +193,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 3cf81435a73..e657ac4ba9b 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,20 +31,28 @@ 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(); @@ -361,4 +369,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 759539becdf..86b449c80a0 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 @@ -116,7 +116,7 @@ protected void messageReceived(ChannelHandlerContext ctx, Object msg) throws Exc 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