Introduce WebSocketClientHandshaker::absoluteUpgradeUrl, close #9205 (#9206)

Motivation:

When connecting through an HTTP proxy over clear HTTP, user agents must send requests with an absolute url. This hold true for WebSocket Upgrade request.

WebSocketClientHandshaker and subclasses currently always send requests with a relative url, which causes proxies to crash as request is malformed.

Modification:

Introduce a new parameter `absoluteUpgradeUrl` and expose it in constructors and WebSocketClientHandshakerFactory.

Result:

It's now possible to configure WebSocketClientHandshaker so it works properly with HTTP proxies over clear HTTP.
This commit is contained in:
Stephane Landelle 2019-06-08 01:01:10 +02:00 committed by Norman Maurer
parent ac95ff8b63
commit 3c36ce6b5c
11 changed files with 278 additions and 30 deletions

View File

@ -75,6 +75,8 @@ public abstract class WebSocketClientHandshaker {
private final int maxFramePayloadLength; private final int maxFramePayloadLength;
private final boolean absoluteUpgradeUrl;
/** /**
* Base constructor * Base constructor
* *
@ -115,12 +117,39 @@ public abstract class WebSocketClientHandshaker {
protected WebSocketClientHandshaker(URI uri, WebSocketVersion version, String subprotocol, protected WebSocketClientHandshaker(URI uri, WebSocketVersion version, String subprotocol,
HttpHeaders customHeaders, int maxFramePayloadLength, HttpHeaders customHeaders, int maxFramePayloadLength,
long forceCloseTimeoutMillis) { long forceCloseTimeoutMillis) {
this(uri, version, subprotocol, customHeaders, maxFramePayloadLength, forceCloseTimeoutMillis, false);
}
/**
* Base constructor
*
* @param uri
* URL for web socket communications. e.g "ws://myhost.com/mypath". Subsequent web socket frames will be
* sent to this URL.
* @param version
* Version of web socket specification to use to connect to the server
* @param subprotocol
* Sub protocol request sent to the server.
* @param customHeaders
* Map of custom headers to add to the client request
* @param maxFramePayloadLength
* Maximum length of a frame's payload
* @param forceCloseTimeoutMillis
* Close the connection if it was not closed by the server after timeout specified
* @param absoluteUpgradeUrl
* Use an absolute url for the Upgrade request, typically when connecting through an HTTP proxy over
* clear HTTP
*/
protected WebSocketClientHandshaker(URI uri, WebSocketVersion version, String subprotocol,
HttpHeaders customHeaders, int maxFramePayloadLength,
long forceCloseTimeoutMillis, boolean absoluteUpgradeUrl) {
this.uri = uri; this.uri = uri;
this.version = version; this.version = version;
expectedSubprotocol = subprotocol; expectedSubprotocol = subprotocol;
this.customHeaders = customHeaders; this.customHeaders = customHeaders;
this.maxFramePayloadLength = maxFramePayloadLength; this.maxFramePayloadLength = maxFramePayloadLength;
this.forceCloseTimeoutMillis = forceCloseTimeoutMillis; this.forceCloseTimeoutMillis = forceCloseTimeoutMillis;
this.absoluteUpgradeUrl = absoluteUpgradeUrl;
} }
/** /**
@ -535,7 +564,11 @@ public abstract class WebSocketClientHandshaker {
/** /**
* Return the constructed raw path for the give {@link URI}. * Return the constructed raw path for the give {@link URI}.
*/ */
static String rawPath(URI wsURL) { protected String upgradeUrl(URI wsURL) {
if (absoluteUpgradeUrl) {
return wsURL.toString();
}
String path = wsURL.getRawPath(); String path = wsURL.getRawPath();
String query = wsURL.getRawQuery(); String query = wsURL.getRawQuery();
if (query != null && !query.isEmpty()) { if (query != null && !query.isEmpty()) {

View File

@ -88,7 +88,34 @@ public class WebSocketClientHandshaker00 extends WebSocketClientHandshaker {
public WebSocketClientHandshaker00(URI webSocketURL, WebSocketVersion version, String subprotocol, public WebSocketClientHandshaker00(URI webSocketURL, WebSocketVersion version, String subprotocol,
HttpHeaders customHeaders, int maxFramePayloadLength, HttpHeaders customHeaders, int maxFramePayloadLength,
long forceCloseTimeoutMillis) { long forceCloseTimeoutMillis) {
super(webSocketURL, version, subprotocol, customHeaders, maxFramePayloadLength, forceCloseTimeoutMillis); this(webSocketURL, version, subprotocol, customHeaders, maxFramePayloadLength, forceCloseTimeoutMillis, false);
}
/**
* Creates a new instance with the specified destination WebSocket location and version to initiate.
*
* @param webSocketURL
* URL for web socket communications. e.g "ws://myhost.com/mypath". Subsequent web socket frames will be
* sent to this URL.
* @param version
* Version of web socket specification to use to connect to the server
* @param subprotocol
* Sub protocol request sent to the server.
* @param customHeaders
* Map of custom headers to add to the client request
* @param maxFramePayloadLength
* Maximum length of a frame's payload
* @param forceCloseTimeoutMillis
* Close the connection if it was not closed by the server after timeout specified
* @param absoluteUpgradeUrl
* Use an absolute url for the Upgrade request, typically when connecting through an HTTP proxy over
* clear HTTP
*/
WebSocketClientHandshaker00(URI webSocketURL, WebSocketVersion version, String subprotocol,
HttpHeaders customHeaders, int maxFramePayloadLength,
long forceCloseTimeoutMillis, boolean absoluteUpgradeUrl) {
super(webSocketURL, version, subprotocol, customHeaders, maxFramePayloadLength, forceCloseTimeoutMillis,
absoluteUpgradeUrl);
} }
/** /**
@ -148,12 +175,10 @@ public class WebSocketClientHandshaker00 extends WebSocketClientHandshaker {
System.arraycopy(key3, 0, challenge, 8, 8); System.arraycopy(key3, 0, challenge, 8, 8);
expectedChallengeResponseBytes = Unpooled.wrappedBuffer(WebSocketUtil.md5(challenge)); expectedChallengeResponseBytes = Unpooled.wrappedBuffer(WebSocketUtil.md5(challenge));
// Get path
URI wsURL = uri(); URI wsURL = uri();
String path = rawPath(wsURL);
// Format request // Format request
FullHttpRequest request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, path); FullHttpRequest request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, upgradeUrl(wsURL));
HttpHeaders headers = request.headers(); HttpHeaders headers = request.headers();
if (customHeaders != null) { if (customHeaders != null) {

View File

@ -130,7 +130,45 @@ public class WebSocketClientHandshaker07 extends WebSocketClientHandshaker {
public WebSocketClientHandshaker07(URI webSocketURL, WebSocketVersion version, String subprotocol, public WebSocketClientHandshaker07(URI webSocketURL, WebSocketVersion version, String subprotocol,
boolean allowExtensions, HttpHeaders customHeaders, int maxFramePayloadLength, boolean allowExtensions, HttpHeaders customHeaders, int maxFramePayloadLength,
boolean performMasking, boolean allowMaskMismatch, long forceCloseTimeoutMillis) { boolean performMasking, boolean allowMaskMismatch, long forceCloseTimeoutMillis) {
super(webSocketURL, version, subprotocol, customHeaders, maxFramePayloadLength, forceCloseTimeoutMillis); this(webSocketURL, version, subprotocol, allowExtensions, customHeaders, maxFramePayloadLength, performMasking,
allowMaskMismatch, forceCloseTimeoutMillis, false);
}
/**
* Creates a new instance.
*
* @param webSocketURL
* URL for web socket communications. e.g "ws://myhost.com/mypath". Subsequent web socket frames will be
* sent to this URL.
* @param version
* Version of web socket specification to use to connect to the server
* @param subprotocol
* Sub protocol request sent to the server.
* @param allowExtensions
* Allow extensions to be used in the reserved bits of the web socket frame
* @param customHeaders
* Map of custom headers to add to the client request
* @param maxFramePayloadLength
* Maximum length of a frame's payload
* @param performMasking
* Whether to mask all written websocket frames. This must be set to true in order to be fully compatible
* with the websocket specifications. Client applications that communicate with a non-standard server
* which doesn't require masking might set this to false to achieve a higher performance.
* @param allowMaskMismatch
* When set to true, frames which are not masked properly according to the standard will still be
* accepted
* @param forceCloseTimeoutMillis
* Close the connection if it was not closed by the server after timeout specified.
* @param absoluteUpgradeUrl
* Use an absolute url for the Upgrade request, typically when connecting through an HTTP proxy over
* clear HTTP
*/
WebSocketClientHandshaker07(URI webSocketURL, WebSocketVersion version, String subprotocol,
boolean allowExtensions, HttpHeaders customHeaders, int maxFramePayloadLength,
boolean performMasking, boolean allowMaskMismatch, long forceCloseTimeoutMillis,
boolean absoluteUpgradeUrl) {
super(webSocketURL, version, subprotocol, customHeaders, maxFramePayloadLength, forceCloseTimeoutMillis,
absoluteUpgradeUrl);
this.allowExtensions = allowExtensions; this.allowExtensions = allowExtensions;
this.performMasking = performMasking; this.performMasking = performMasking;
this.allowMaskMismatch = allowMaskMismatch; this.allowMaskMismatch = allowMaskMismatch;
@ -156,9 +194,7 @@ public class WebSocketClientHandshaker07 extends WebSocketClientHandshaker {
*/ */
@Override @Override
protected FullHttpRequest newHandshakeRequest() { protected FullHttpRequest newHandshakeRequest() {
// Get path
URI wsURL = uri(); URI wsURL = uri();
String path = rawPath(wsURL);
// Get 16 bit nonce and base 64 encode it // Get 16 bit nonce and base 64 encode it
byte[] nonce = WebSocketUtil.randomBytes(16); byte[] nonce = WebSocketUtil.randomBytes(16);
@ -175,7 +211,7 @@ public class WebSocketClientHandshaker07 extends WebSocketClientHandshaker {
} }
// Format request // Format request
FullHttpRequest request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, path); FullHttpRequest request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, upgradeUrl(wsURL));
HttpHeaders headers = request.headers(); HttpHeaders headers = request.headers();
if (customHeaders != null) { if (customHeaders != null) {

View File

@ -132,7 +132,45 @@ public class WebSocketClientHandshaker08 extends WebSocketClientHandshaker {
public WebSocketClientHandshaker08(URI webSocketURL, WebSocketVersion version, String subprotocol, public WebSocketClientHandshaker08(URI webSocketURL, WebSocketVersion version, String subprotocol,
boolean allowExtensions, HttpHeaders customHeaders, int maxFramePayloadLength, boolean allowExtensions, HttpHeaders customHeaders, int maxFramePayloadLength,
boolean performMasking, boolean allowMaskMismatch, long forceCloseTimeoutMillis) { boolean performMasking, boolean allowMaskMismatch, long forceCloseTimeoutMillis) {
super(webSocketURL, version, subprotocol, customHeaders, maxFramePayloadLength, forceCloseTimeoutMillis); this(webSocketURL, version, subprotocol, allowExtensions, customHeaders, maxFramePayloadLength, performMasking,
allowMaskMismatch, forceCloseTimeoutMillis, false);
}
/**
* Creates a new instance.
*
* @param webSocketURL
* URL for web socket communications. e.g "ws://myhost.com/mypath". Subsequent web socket frames will be
* sent to this URL.
* @param version
* Version of web socket specification to use to connect to the server
* @param subprotocol
* Sub protocol request sent to the server.
* @param allowExtensions
* Allow extensions to be used in the reserved bits of the web socket frame
* @param customHeaders
* Map of custom headers to add to the client request
* @param maxFramePayloadLength
* Maximum length of a frame's payload
* @param performMasking
* Whether to mask all written websocket frames. This must be set to true in order to be fully compatible
* with the websocket specifications. Client applications that communicate with a non-standard server
* which doesn't require masking might set this to false to achieve a higher performance.
* @param allowMaskMismatch
* When set to true, frames which are not masked properly according to the standard will still be
* accepted
* @param forceCloseTimeoutMillis
* Close the connection if it was not closed by the server after timeout specified.
* @param absoluteUpgradeUrl
* Use an absolute url for the Upgrade request, typically when connecting through an HTTP proxy over
* clear HTTP
*/
WebSocketClientHandshaker08(URI webSocketURL, WebSocketVersion version, String subprotocol,
boolean allowExtensions, HttpHeaders customHeaders, int maxFramePayloadLength,
boolean performMasking, boolean allowMaskMismatch, long forceCloseTimeoutMillis,
boolean absoluteUpgradeUrl) {
super(webSocketURL, version, subprotocol, customHeaders, maxFramePayloadLength, forceCloseTimeoutMillis,
absoluteUpgradeUrl);
this.allowExtensions = allowExtensions; this.allowExtensions = allowExtensions;
this.performMasking = performMasking; this.performMasking = performMasking;
this.allowMaskMismatch = allowMaskMismatch; this.allowMaskMismatch = allowMaskMismatch;
@ -158,9 +196,7 @@ public class WebSocketClientHandshaker08 extends WebSocketClientHandshaker {
*/ */
@Override @Override
protected FullHttpRequest newHandshakeRequest() { protected FullHttpRequest newHandshakeRequest() {
// Get path
URI wsURL = uri(); URI wsURL = uri();
String path = rawPath(wsURL);
// Get 16 bit nonce and base 64 encode it // Get 16 bit nonce and base 64 encode it
byte[] nonce = WebSocketUtil.randomBytes(16); byte[] nonce = WebSocketUtil.randomBytes(16);
@ -177,7 +213,7 @@ public class WebSocketClientHandshaker08 extends WebSocketClientHandshaker {
} }
// Format request // Format request
FullHttpRequest request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, path); FullHttpRequest request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, upgradeUrl(wsURL));
HttpHeaders headers = request.headers(); HttpHeaders headers = request.headers();
if (customHeaders != null) { if (customHeaders != null) {

View File

@ -133,7 +133,45 @@ public class WebSocketClientHandshaker13 extends WebSocketClientHandshaker {
boolean allowExtensions, HttpHeaders customHeaders, int maxFramePayloadLength, boolean allowExtensions, HttpHeaders customHeaders, int maxFramePayloadLength,
boolean performMasking, boolean allowMaskMismatch, boolean performMasking, boolean allowMaskMismatch,
long forceCloseTimeoutMillis) { long forceCloseTimeoutMillis) {
super(webSocketURL, version, subprotocol, customHeaders, maxFramePayloadLength, forceCloseTimeoutMillis); this(webSocketURL, version, subprotocol, allowExtensions, customHeaders, maxFramePayloadLength, performMasking,
allowMaskMismatch, forceCloseTimeoutMillis, false);
}
/**
* Creates a new instance.
*
* @param webSocketURL
* URL for web socket communications. e.g "ws://myhost.com/mypath". Subsequent web socket frames will be
* sent to this URL.
* @param version
* Version of web socket specification to use to connect to the server
* @param subprotocol
* Sub protocol request sent to the server.
* @param allowExtensions
* Allow extensions to be used in the reserved bits of the web socket frame
* @param customHeaders
* Map of custom headers to add to the client request
* @param maxFramePayloadLength
* Maximum length of a frame's payload
* @param performMasking
* Whether to mask all written websocket frames. This must be set to true in order to be fully compatible
* with the websocket specifications. Client applications that communicate with a non-standard server
* which doesn't require masking might set this to false to achieve a higher performance.
* @param allowMaskMismatch
* When set to true, frames which are not masked properly according to the standard will still be
* accepted
* @param forceCloseTimeoutMillis
* Close the connection if it was not closed by the server after timeout specified.
* @param absoluteUpgradeUrl
* Use an absolute url for the Upgrade request, typically when connecting through an HTTP proxy over
* clear HTTP
*/
WebSocketClientHandshaker13(URI webSocketURL, WebSocketVersion version, String subprotocol,
boolean allowExtensions, HttpHeaders customHeaders, int maxFramePayloadLength,
boolean performMasking, boolean allowMaskMismatch,
long forceCloseTimeoutMillis, boolean absoluteUpgradeUrl) {
super(webSocketURL, version, subprotocol, customHeaders, maxFramePayloadLength, forceCloseTimeoutMillis,
absoluteUpgradeUrl);
this.allowExtensions = allowExtensions; this.allowExtensions = allowExtensions;
this.performMasking = performMasking; this.performMasking = performMasking;
this.allowMaskMismatch = allowMaskMismatch; this.allowMaskMismatch = allowMaskMismatch;
@ -159,9 +197,7 @@ public class WebSocketClientHandshaker13 extends WebSocketClientHandshaker {
*/ */
@Override @Override
protected FullHttpRequest newHandshakeRequest() { protected FullHttpRequest newHandshakeRequest() {
// Get path
URI wsURL = uri(); URI wsURL = uri();
String path = rawPath(wsURL);
// Get 16 bit nonce and base 64 encode it // Get 16 bit nonce and base 64 encode it
byte[] nonce = WebSocketUtil.randomBytes(16); byte[] nonce = WebSocketUtil.randomBytes(16);
@ -178,7 +214,7 @@ public class WebSocketClientHandshaker13 extends WebSocketClientHandshaker {
} }
// Format request // Format request
FullHttpRequest request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, path); FullHttpRequest request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, upgradeUrl(wsURL));
HttpHeaders headers = request.headers(); HttpHeaders headers = request.headers();
if (customHeaders != null) { if (customHeaders != null) {

View File

@ -164,4 +164,62 @@ public final class WebSocketClientHandshakerFactory {
throw new WebSocketHandshakeException("Protocol version " + version + " not supported."); throw new WebSocketHandshakeException("Protocol version " + version + " not supported.");
} }
/**
* Creates a new handshaker.
*
* @param webSocketURL
* URL for web socket communications. e.g "ws://myhost.com/mypath".
* Subsequent web socket frames will be sent to this URL.
* @param version
* Version of web socket specification to use to connect to the server
* @param subprotocol
* Sub protocol request sent to the server. Null if no sub-protocol support is required.
* @param allowExtensions
* Allow extensions to be used in the reserved bits of the web socket frame
* @param customHeaders
* Custom HTTP headers to send during the handshake
* @param maxFramePayloadLength
* Maximum allowable frame payload length. Setting this value to your application's
* requirement may reduce denial of service attacks using long data frames.
* @param performMasking
* Whether to mask all written websocket frames. This must be set to true in order to be fully compatible
* with the websocket specifications. Client applications that communicate with a non-standard server
* which doesn't require masking might set this to false to achieve a higher performance.
* @param allowMaskMismatch
* When set to true, frames which are not masked properly according to the standard will still be
* accepted.
* @param forceCloseTimeoutMillis
* Close the connection if it was not closed by the server after timeout specified
* @param absoluteUpgradeUrl
* Use an absolute url for the Upgrade request, typically when connecting through an HTTP proxy over
* clear HTTP
*/
public static WebSocketClientHandshaker newHandshaker(
URI webSocketURL, WebSocketVersion version, String subprotocol,
boolean allowExtensions, HttpHeaders customHeaders, int maxFramePayloadLength,
boolean performMasking, boolean allowMaskMismatch, long forceCloseTimeoutMillis, boolean absoluteUpgradeUrl) {
if (version == V13) {
return new WebSocketClientHandshaker13(
webSocketURL, V13, subprotocol, allowExtensions, customHeaders,
maxFramePayloadLength, performMasking, allowMaskMismatch, forceCloseTimeoutMillis, absoluteUpgradeUrl);
}
if (version == V08) {
return new WebSocketClientHandshaker08(
webSocketURL, V08, subprotocol, allowExtensions, customHeaders,
maxFramePayloadLength, performMasking, allowMaskMismatch, forceCloseTimeoutMillis, absoluteUpgradeUrl);
}
if (version == V07) {
return new WebSocketClientHandshaker07(
webSocketURL, V07, subprotocol, allowExtensions, customHeaders,
maxFramePayloadLength, performMasking, allowMaskMismatch, forceCloseTimeoutMillis, absoluteUpgradeUrl);
}
if (version == V00) {
return new WebSocketClientHandshaker00(
webSocketURL, V00, subprotocol, customHeaders,
maxFramePayloadLength, forceCloseTimeoutMillis, absoluteUpgradeUrl);
}
throw new WebSocketHandshakeException("Protocol version " + version + " not supported.");
}
} }

View File

@ -22,8 +22,10 @@ import java.net.URI;
public class WebSocketClientHandshaker00Test extends WebSocketClientHandshakerTest { public class WebSocketClientHandshaker00Test extends WebSocketClientHandshakerTest {
@Override @Override
protected WebSocketClientHandshaker newHandshaker(URI uri, String subprotocol, HttpHeaders headers) { protected WebSocketClientHandshaker newHandshaker(URI uri, String subprotocol, HttpHeaders headers,
return new WebSocketClientHandshaker00(uri, WebSocketVersion.V00, subprotocol, headers, 1024); boolean absoluteUpgradeUrl) {
return new WebSocketClientHandshaker00(uri, WebSocketVersion.V00, subprotocol, headers,
1024, 10000, absoluteUpgradeUrl);
} }
@Override @Override

View File

@ -22,8 +22,11 @@ import java.net.URI;
public class WebSocketClientHandshaker07Test extends WebSocketClientHandshakerTest { public class WebSocketClientHandshaker07Test extends WebSocketClientHandshakerTest {
@Override @Override
protected WebSocketClientHandshaker newHandshaker(URI uri, String subprotocol, HttpHeaders headers) { protected WebSocketClientHandshaker newHandshaker(URI uri, String subprotocol, HttpHeaders headers,
return new WebSocketClientHandshaker07(uri, WebSocketVersion.V07, subprotocol, false, headers, 1024); boolean absoluteUpgradeUrl) {
return new WebSocketClientHandshaker07(uri, WebSocketVersion.V07, subprotocol, false, headers,
1024, true, false, 10000,
absoluteUpgradeUrl);
} }
@Override @Override

View File

@ -21,7 +21,10 @@ import java.net.URI;
public class WebSocketClientHandshaker08Test extends WebSocketClientHandshaker07Test { public class WebSocketClientHandshaker08Test extends WebSocketClientHandshaker07Test {
@Override @Override
protected WebSocketClientHandshaker newHandshaker(URI uri, String subprotocol, HttpHeaders headers) { protected WebSocketClientHandshaker newHandshaker(URI uri, String subprotocol, HttpHeaders headers,
return new WebSocketClientHandshaker08(uri, WebSocketVersion.V08, subprotocol, false, headers, 1024); boolean absoluteUpgradeUrl) {
return new WebSocketClientHandshaker08(uri, WebSocketVersion.V08, subprotocol, false, headers,
1024, true, true, 10000,
absoluteUpgradeUrl);
} }
} }

View File

@ -21,7 +21,10 @@ import java.net.URI;
public class WebSocketClientHandshaker13Test extends WebSocketClientHandshaker07Test { public class WebSocketClientHandshaker13Test extends WebSocketClientHandshaker07Test {
@Override @Override
protected WebSocketClientHandshaker newHandshaker(URI uri, String subprotocol, HttpHeaders headers) { protected WebSocketClientHandshaker newHandshaker(URI uri, String subprotocol, HttpHeaders headers,
return new WebSocketClientHandshaker13(uri, WebSocketVersion.V13, subprotocol, false, headers, 1024); boolean absoluteUpgradeUrl) {
return new WebSocketClientHandshaker13(uri, WebSocketVersion.V13, subprotocol, false, headers,
1024, true, true, 10000,
absoluteUpgradeUrl);
} }
} }

View File

@ -40,10 +40,11 @@ import java.net.URI;
import static org.junit.Assert.*; import static org.junit.Assert.*;
public abstract class WebSocketClientHandshakerTest { public abstract class WebSocketClientHandshakerTest {
protected abstract WebSocketClientHandshaker newHandshaker(URI uri, String subprotocol, HttpHeaders headers); protected abstract WebSocketClientHandshaker newHandshaker(URI uri, String subprotocol, HttpHeaders headers,
boolean absoluteUpgradeUrl);
protected WebSocketClientHandshaker newHandshaker(URI uri) { protected WebSocketClientHandshaker newHandshaker(URI uri) {
return newHandshaker(uri, null, null); return newHandshaker(uri, null, null, false);
} }
protected abstract CharSequence getOriginHeaderName(); protected abstract CharSequence getOriginHeaderName();
@ -180,7 +181,7 @@ public abstract class WebSocketClientHandshakerTest {
@Test @Test
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
public void testRawPath() { public void testUpgradeUrl() {
URI uri = URI.create("ws://localhost:9999/path%20with%20ws"); URI uri = URI.create("ws://localhost:9999/path%20with%20ws");
WebSocketClientHandshaker handshaker = newHandshaker(uri); WebSocketClientHandshaker handshaker = newHandshaker(uri);
FullHttpRequest request = handshaker.newHandshakeRequest(); FullHttpRequest request = handshaker.newHandshakeRequest();
@ -192,7 +193,7 @@ public abstract class WebSocketClientHandshakerTest {
} }
@Test @Test
public void testRawPathWithQuery() { public void testUpgradeUrlWithQuery() {
URI uri = URI.create("ws://localhost:9999/path%20with%20ws?a=b%20c"); URI uri = URI.create("ws://localhost:9999/path%20with%20ws?a=b%20c");
WebSocketClientHandshaker handshaker = newHandshaker(uri); WebSocketClientHandshaker handshaker = newHandshaker(uri);
FullHttpRequest request = handshaker.newHandshakeRequest(); FullHttpRequest request = handshaker.newHandshakeRequest();
@ -203,6 +204,18 @@ public abstract class WebSocketClientHandshakerTest {
} }
} }
@Test
public void testAbsoluteUpgradeUrlWithQuery() {
URI uri = URI.create("ws://localhost:9999/path%20with%20ws?a=b%20c");
WebSocketClientHandshaker handshaker = newHandshaker(uri, null, null, true);
FullHttpRequest request = handshaker.newHandshakeRequest();
try {
assertEquals("ws://localhost:9999/path%20with%20ws?a=b%20c", request.uri());
} finally {
request.release();
}
}
@Test(timeout = 3000) @Test(timeout = 3000)
public void testHttpResponseAndFrameInSameBuffer() { public void testHttpResponseAndFrameInSameBuffer() {
testHttpResponseAndFrameInSameBuffer(false); testHttpResponseAndFrameInSameBuffer(false);
@ -317,7 +330,7 @@ public abstract class WebSocketClientHandshakerTest {
inputHeaders.add(getProtocolHeaderName(), bogusSubProtocol); inputHeaders.add(getProtocolHeaderName(), bogusSubProtocol);
String realSubProtocol = "realSubProtocol"; String realSubProtocol = "realSubProtocol";
WebSocketClientHandshaker handshaker = newHandshaker(uri, realSubProtocol, inputHeaders); WebSocketClientHandshaker handshaker = newHandshaker(uri, realSubProtocol, inputHeaders, false);
FullHttpRequest request = handshaker.newHandshakeRequest(); FullHttpRequest request = handshaker.newHandshakeRequest();
HttpHeaders outputHeaders = request.headers(); HttpHeaders outputHeaders = request.headers();