### 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
This commit is contained in:
parent
6d0c0e991b
commit
19a4633859
@ -48,8 +48,6 @@ import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
|
|||||||
*/
|
*/
|
||||||
public abstract class WebSocketClientHandshaker {
|
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;
|
protected static final int DEFAULT_FORCE_CLOSE_TIMEOUT_MILLIS = 10000;
|
||||||
|
|
||||||
private final URI uri;
|
private final URI uri;
|
||||||
@ -601,31 +599,4 @@ public abstract class WebSocketClientHandshaker {
|
|||||||
// See http://tools.ietf.org/html/rfc6454#section-6.2
|
// See http://tools.ietf.org/html/rfc6454#section-6.2
|
||||||
return NetUtil.toSocketAddressString(host, port);
|
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -192,10 +192,6 @@ public class WebSocketClientHandshaker00 extends WebSocketClientHandshaker {
|
|||||||
.set(HttpHeaderNames.SEC_WEBSOCKET_KEY1, key1)
|
.set(HttpHeaderNames.SEC_WEBSOCKET_KEY1, key1)
|
||||||
.set(HttpHeaderNames.SEC_WEBSOCKET_KEY2, key2);
|
.set(HttpHeaderNames.SEC_WEBSOCKET_KEY2, key2);
|
||||||
|
|
||||||
if (!headers.contains(HttpHeaderNames.ORIGIN)) {
|
|
||||||
headers.set(HttpHeaderNames.ORIGIN, websocketOriginValue(wsURL));
|
|
||||||
}
|
|
||||||
|
|
||||||
String expectedSubprotocol = expectedSubprotocol();
|
String expectedSubprotocol = expectedSubprotocol();
|
||||||
if (expectedSubprotocol != null && !expectedSubprotocol.isEmpty()) {
|
if (expectedSubprotocol != null && !expectedSubprotocol.isEmpty()) {
|
||||||
headers.set(HttpHeaderNames.SEC_WEBSOCKET_PROTOCOL, expectedSubprotocol);
|
headers.set(HttpHeaderNames.SEC_WEBSOCKET_PROTOCOL, expectedSubprotocol);
|
||||||
|
@ -187,7 +187,6 @@ public class WebSocketClientHandshaker07 extends WebSocketClientHandshaker {
|
|||||||
* Upgrade: websocket
|
* Upgrade: websocket
|
||||||
* Connection: Upgrade
|
* Connection: Upgrade
|
||||||
* Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
|
* Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
|
||||||
* Sec-WebSocket-Origin: http://example.com
|
|
||||||
* Sec-WebSocket-Protocol: chat, superchat
|
* Sec-WebSocket-Protocol: chat, superchat
|
||||||
* Sec-WebSocket-Version: 7
|
* Sec-WebSocket-Version: 7
|
||||||
* </pre>
|
* </pre>
|
||||||
@ -225,10 +224,6 @@ public class WebSocketClientHandshaker07 extends WebSocketClientHandshaker {
|
|||||||
.set(HttpHeaderNames.SEC_WEBSOCKET_KEY, key)
|
.set(HttpHeaderNames.SEC_WEBSOCKET_KEY, key)
|
||||||
.set(HttpHeaderNames.HOST, websocketHostValue(wsURL));
|
.set(HttpHeaderNames.HOST, websocketHostValue(wsURL));
|
||||||
|
|
||||||
if (!headers.contains(HttpHeaderNames.SEC_WEBSOCKET_ORIGIN)) {
|
|
||||||
headers.set(HttpHeaderNames.SEC_WEBSOCKET_ORIGIN, websocketOriginValue(wsURL));
|
|
||||||
}
|
|
||||||
|
|
||||||
String expectedSubprotocol = expectedSubprotocol();
|
String expectedSubprotocol = expectedSubprotocol();
|
||||||
if (expectedSubprotocol != null && !expectedSubprotocol.isEmpty()) {
|
if (expectedSubprotocol != null && !expectedSubprotocol.isEmpty()) {
|
||||||
headers.set(HttpHeaderNames.SEC_WEBSOCKET_PROTOCOL, expectedSubprotocol);
|
headers.set(HttpHeaderNames.SEC_WEBSOCKET_PROTOCOL, expectedSubprotocol);
|
||||||
|
@ -189,7 +189,6 @@ public class WebSocketClientHandshaker08 extends WebSocketClientHandshaker {
|
|||||||
* Upgrade: websocket
|
* Upgrade: websocket
|
||||||
* Connection: Upgrade
|
* Connection: Upgrade
|
||||||
* Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
|
* Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
|
||||||
* Sec-WebSocket-Origin: http://example.com
|
|
||||||
* Sec-WebSocket-Protocol: chat, superchat
|
* Sec-WebSocket-Protocol: chat, superchat
|
||||||
* Sec-WebSocket-Version: 8
|
* Sec-WebSocket-Version: 8
|
||||||
* </pre>
|
* </pre>
|
||||||
@ -227,10 +226,6 @@ public class WebSocketClientHandshaker08 extends WebSocketClientHandshaker {
|
|||||||
.set(HttpHeaderNames.SEC_WEBSOCKET_KEY, key)
|
.set(HttpHeaderNames.SEC_WEBSOCKET_KEY, key)
|
||||||
.set(HttpHeaderNames.HOST, websocketHostValue(wsURL));
|
.set(HttpHeaderNames.HOST, websocketHostValue(wsURL));
|
||||||
|
|
||||||
if (!headers.contains(HttpHeaderNames.SEC_WEBSOCKET_ORIGIN)) {
|
|
||||||
headers.set(HttpHeaderNames.SEC_WEBSOCKET_ORIGIN, websocketOriginValue(wsURL));
|
|
||||||
}
|
|
||||||
|
|
||||||
String expectedSubprotocol = expectedSubprotocol();
|
String expectedSubprotocol = expectedSubprotocol();
|
||||||
if (expectedSubprotocol != null && !expectedSubprotocol.isEmpty()) {
|
if (expectedSubprotocol != null && !expectedSubprotocol.isEmpty()) {
|
||||||
headers.set(HttpHeaderNames.SEC_WEBSOCKET_PROTOCOL, expectedSubprotocol);
|
headers.set(HttpHeaderNames.SEC_WEBSOCKET_PROTOCOL, expectedSubprotocol);
|
||||||
|
@ -190,7 +190,6 @@ public class WebSocketClientHandshaker13 extends WebSocketClientHandshaker {
|
|||||||
* Upgrade: websocket
|
* Upgrade: websocket
|
||||||
* Connection: Upgrade
|
* Connection: Upgrade
|
||||||
* Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
|
* Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
|
||||||
* Origin: http://example.com
|
|
||||||
* Sec-WebSocket-Protocol: chat, superchat
|
* Sec-WebSocket-Protocol: chat, superchat
|
||||||
* Sec-WebSocket-Version: 13
|
* Sec-WebSocket-Version: 13
|
||||||
* </pre>
|
* </pre>
|
||||||
@ -228,10 +227,6 @@ public class WebSocketClientHandshaker13 extends WebSocketClientHandshaker {
|
|||||||
.set(HttpHeaderNames.SEC_WEBSOCKET_KEY, key)
|
.set(HttpHeaderNames.SEC_WEBSOCKET_KEY, key)
|
||||||
.set(HttpHeaderNames.HOST, websocketHostValue(wsURL));
|
.set(HttpHeaderNames.HOST, websocketHostValue(wsURL));
|
||||||
|
|
||||||
if (!headers.contains(HttpHeaderNames.ORIGIN)) {
|
|
||||||
headers.set(HttpHeaderNames.ORIGIN, websocketOriginValue(wsURL));
|
|
||||||
}
|
|
||||||
|
|
||||||
String expectedSubprotocol = expectedSubprotocol();
|
String expectedSubprotocol = expectedSubprotocol();
|
||||||
if (expectedSubprotocol != null && !expectedSubprotocol.isEmpty()) {
|
if (expectedSubprotocol != null && !expectedSubprotocol.isEmpty()) {
|
||||||
headers.set(HttpHeaderNames.SEC_WEBSOCKET_PROTOCOL, expectedSubprotocol);
|
headers.set(HttpHeaderNames.SEC_WEBSOCKET_PROTOCOL, expectedSubprotocol);
|
||||||
|
@ -109,7 +109,6 @@ public class WebSocketServerHandshaker07 extends WebSocketServerHandshaker {
|
|||||||
* Upgrade: websocket
|
* Upgrade: websocket
|
||||||
* Connection: Upgrade
|
* Connection: Upgrade
|
||||||
* Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
|
* Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
|
||||||
* Sec-WebSocket-Origin: http://example.com
|
|
||||||
* Sec-WebSocket-Protocol: chat, superchat
|
* Sec-WebSocket-Protocol: chat, superchat
|
||||||
* Sec-WebSocket-Version: 7
|
* Sec-WebSocket-Version: 7
|
||||||
* </pre>
|
* </pre>
|
||||||
|
@ -116,7 +116,6 @@ public class WebSocketServerHandshaker08 extends WebSocketServerHandshaker {
|
|||||||
* Upgrade: websocket
|
* Upgrade: websocket
|
||||||
* Connection: Upgrade
|
* Connection: Upgrade
|
||||||
* Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
|
* Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
|
||||||
* Sec-WebSocket-Origin: http://example.com
|
|
||||||
* Sec-WebSocket-Protocol: chat, superchat
|
* Sec-WebSocket-Protocol: chat, superchat
|
||||||
* Sec-WebSocket-Version: 8
|
* Sec-WebSocket-Version: 8
|
||||||
* </pre>
|
* </pre>
|
||||||
|
@ -115,7 +115,6 @@ public class WebSocketServerHandshaker13 extends WebSocketServerHandshaker {
|
|||||||
* Upgrade: websocket
|
* Upgrade: websocket
|
||||||
* Connection: Upgrade
|
* Connection: Upgrade
|
||||||
* Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
|
* Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
|
||||||
* Origin: http://example.com
|
|
||||||
* Sec-WebSocket-Protocol: chat, superchat
|
* Sec-WebSocket-Protocol: chat, superchat
|
||||||
* Sec-WebSocket-Version: 13
|
* Sec-WebSocket-Version: 13
|
||||||
* </pre>
|
* </pre>
|
||||||
|
@ -31,19 +31,27 @@ import io.netty.handler.codec.http.HttpHeaders;
|
|||||||
import io.netty.handler.codec.http.HttpObjectAggregator;
|
import io.netty.handler.codec.http.HttpObjectAggregator;
|
||||||
import io.netty.handler.codec.http.HttpRequestEncoder;
|
import io.netty.handler.codec.http.HttpRequestEncoder;
|
||||||
import io.netty.handler.codec.http.HttpResponseDecoder;
|
import io.netty.handler.codec.http.HttpResponseDecoder;
|
||||||
|
import io.netty.handler.codec.http.HttpScheme;
|
||||||
import io.netty.util.CharsetUtil;
|
import io.netty.util.CharsetUtil;
|
||||||
|
import io.netty.util.NetUtil;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
public abstract class WebSocketClientHandshakerTest {
|
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,
|
protected abstract WebSocketClientHandshaker newHandshaker(URI uri, String subprotocol, HttpHeaders headers,
|
||||||
boolean absoluteUpgradeUrl);
|
boolean absoluteUpgradeUrl);
|
||||||
|
|
||||||
protected WebSocketClientHandshaker newHandshaker(URI uri) {
|
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();
|
protected abstract CharSequence getOriginHeaderName();
|
||||||
@ -360,4 +368,31 @@ public abstract class WebSocketClientHandshakerTest {
|
|||||||
|
|
||||||
request.release();
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -115,7 +115,7 @@ public class WebSocketHandshakeHandOverTest {
|
|||||||
assertTrue(serverReceivedHandshake);
|
assertTrue(serverReceivedHandshake);
|
||||||
assertNotNull(serverHandshakeComplete);
|
assertNotNull(serverHandshakeComplete);
|
||||||
assertEquals("/test", serverHandshakeComplete.requestUri());
|
assertEquals("/test", serverHandshakeComplete.requestUri());
|
||||||
assertEquals(8, serverHandshakeComplete.requestHeaders().size());
|
assertEquals(7, serverHandshakeComplete.requestHeaders().size());
|
||||||
assertEquals("test-proto-2", serverHandshakeComplete.selectedSubprotocol());
|
assertEquals("test-proto-2", serverHandshakeComplete.selectedSubprotocol());
|
||||||
|
|
||||||
// Transfer the handshake response and the websocket message to the client
|
// Transfer the handshake response and the websocket message to the client
|
||||||
|
Loading…
x
Reference in New Issue
Block a user