From 9b2cfc4483c7174accca413ae0db841e8af4b069 Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Fri, 5 Jan 2024 11:42:11 +0100 Subject: [PATCH] Fixes #11223 - WebSocketClient.connect with URI including query parameters don't work for HTTP2 connector Fixed concatenation of path and query for HTTP/2 and HTTP/3 when creating `MetaData.ConnectRequest` to "tunnel" the WebSocket upgrade. Signed-off-by: Simone Bordet --- .../java/org/eclipse/jetty/http/MetaData.java | 29 ++++++++++++------- .../client/http/HttpSenderOverHTTP2.java | 4 ++- .../http/internal/HttpSenderOverHTTP3.java | 4 ++- .../tests/WebSocketOverHTTP2Test.java | 7 ++++- 4 files changed, 31 insertions(+), 13 deletions(-) diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/MetaData.java b/jetty-http/src/main/java/org/eclipse/jetty/http/MetaData.java index 8721ce3522a..d0c37a4cd42 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/MetaData.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/MetaData.java @@ -224,26 +224,35 @@ public class MetaData implements Iterable { private final String _protocol; - public ConnectRequest(HttpScheme scheme, HostPortHttpField authority, String path, HttpFields fields, String protocol) + public ConnectRequest(HttpScheme scheme, HostPortHttpField authority, String pathQuery, HttpFields fields, String protocol) { - this(scheme == null ? null : scheme.asString(), authority, path, fields, protocol); + this(scheme == null ? null : scheme.asString(), authority, pathQuery, fields, protocol); } - public ConnectRequest(long beginNanoTime, HttpScheme scheme, HostPortHttpField authority, String path, HttpFields fields, String protocol) + public ConnectRequest(long beginNanoTime, HttpScheme scheme, HostPortHttpField authority, String pathQuery, HttpFields fields, String protocol) { - this(beginNanoTime, scheme == null ? null : scheme.asString(), authority, path, fields, protocol); + this(beginNanoTime, scheme == null ? null : scheme.asString(), authority, pathQuery, fields, protocol); } - public ConnectRequest(String scheme, HostPortHttpField authority, String path, HttpFields fields, String protocol) + public ConnectRequest(String scheme, HostPortHttpField authority, String pathQuery, HttpFields fields, String protocol) { - this(NanoTime.now(), scheme, authority, path, fields, protocol); + this(NanoTime.now(), scheme, authority, pathQuery, fields, protocol); } - public ConnectRequest(long beginNanoTime, String scheme, HostPortHttpField authority, String path, HttpFields fields, String protocol) + public ConnectRequest(long beginNanoTime, String scheme, HostPortHttpField authority, String pathQuery, HttpFields fields, String protocol) { - super(beginNanoTime, HttpMethod.CONNECT.asString(), - HttpURI.build().scheme(scheme).host(authority == null ? null : authority.getHost()).port(authority == null ? -1 : authority.getPort()).pathQuery(path), - HttpVersion.HTTP_2, fields, Long.MIN_VALUE, null); + super(beginNanoTime, + HttpMethod.CONNECT.asString(), + HttpURI.build() + .scheme(scheme) + .host(authority == null ? null : authority.getHost()) + .port(authority == null ? -1 : authority.getPort()) + .pathQuery(pathQuery), + HttpVersion.HTTP_2, + fields, + Long.MIN_VALUE, + null + ); _protocol = protocol; } diff --git a/jetty-http2/http2-http-client-transport/src/main/java/org/eclipse/jetty/http2/client/http/HttpSenderOverHTTP2.java b/jetty-http2/http2-http-client-transport/src/main/java/org/eclipse/jetty/http2/client/http/HttpSenderOverHTTP2.java index 45b4961e937..e3846efe5dc 100644 --- a/jetty-http2/http2-http-client-transport/src/main/java/org/eclipse/jetty/http2/client/http/HttpSenderOverHTTP2.java +++ b/jetty-http2/http2-http-client-transport/src/main/java/org/eclipse/jetty/http2/client/http/HttpSenderOverHTTP2.java @@ -33,6 +33,7 @@ import org.eclipse.jetty.http2.frames.HeadersFrame; import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.Promise; +import org.eclipse.jetty.util.URIUtil; public class HttpSenderOverHTTP2 extends HttpSender { @@ -63,7 +64,8 @@ public class HttpSenderOverHTTP2 extends HttpSender else { HostPortHttpField authority = new HostPortHttpField(request.getHost(), request.getPort()); - metaData = new MetaData.ConnectRequest(request.getScheme(), authority, request.getPath(), request.getHeaders(), upgradeProtocol); + String pathQuery = URIUtil.addPathQuery(request.getPath(), request.getQuery()); + metaData = new MetaData.ConnectRequest(request.getScheme(), authority, pathQuery, request.getHeaders(), upgradeProtocol); } } else diff --git a/jetty-http3/http3-http-client-transport/src/main/java/org/eclipse/jetty/http3/client/http/internal/HttpSenderOverHTTP3.java b/jetty-http3/http3-http-client-transport/src/main/java/org/eclipse/jetty/http3/client/http/internal/HttpSenderOverHTTP3.java index f5fa7dd1e23..8a254516849 100644 --- a/jetty-http3/http3-http-client-transport/src/main/java/org/eclipse/jetty/http3/client/http/internal/HttpSenderOverHTTP3.java +++ b/jetty-http3/http3-http-client-transport/src/main/java/org/eclipse/jetty/http3/client/http/internal/HttpSenderOverHTTP3.java @@ -33,6 +33,7 @@ import org.eclipse.jetty.http3.frames.HeadersFrame; import org.eclipse.jetty.http3.internal.HTTP3Stream; import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.Callback; +import org.eclipse.jetty.util.URIUtil; public class HttpSenderOverHTTP3 extends HttpSender { @@ -63,7 +64,8 @@ public class HttpSenderOverHTTP3 extends HttpSender else { HostPortHttpField authority = new HostPortHttpField(request.getHost(), request.getPort()); - metaData = new MetaData.ConnectRequest(request.getScheme(), authority, request.getPath(), request.getHeaders(), upgradeProtocol); + String pathQuery = URIUtil.addPathQuery(request.getPath(), request.getQuery()); + metaData = new MetaData.ConnectRequest(request.getScheme(), authority, pathQuery, request.getHeaders(), upgradeProtocol); } } else diff --git a/jetty-websocket/websocket-jetty-tests/src/test/java/org/eclipse/jetty/websocket/tests/WebSocketOverHTTP2Test.java b/jetty-websocket/websocket-jetty-tests/src/test/java/org/eclipse/jetty/websocket/tests/WebSocketOverHTTP2Test.java index 7037a8ab418..e73521d4a80 100644 --- a/jetty-websocket/websocket-jetty-tests/src/test/java/org/eclipse/jetty/websocket/tests/WebSocketOverHTTP2Test.java +++ b/jetty-websocket/websocket-jetty-tests/src/test/java/org/eclipse/jetty/websocket/tests/WebSocketOverHTTP2Test.java @@ -162,7 +162,7 @@ public class WebSocketOverHTTP2Test startClient(protocolFn); EventSocket wsEndPoint = new EventSocket(); - URI uri = URI.create("ws://localhost:" + connector.getLocalPort() + "/ws/echo"); + URI uri = URI.create("ws://localhost:" + connector.getLocalPort() + "/ws/echo/query?param=value"); Session session = wsClient.connect(wsEndPoint, uri).get(5, TimeUnit.SECONDS); String text = "websocket"; @@ -382,6 +382,11 @@ public class WebSocketOverHTTP2Test protected void configure(JettyWebSocketServletFactory factory) { factory.addMapping("/ws/echo", (request, response) -> new EchoSocket()); + factory.addMapping("/ws/echo/query", (request, response) -> + { + assertNotNull(request.getQueryString()); + return new EchoSocket(); + }); factory.addMapping("/ws/null", (request, response) -> null); factory.addMapping("/ws/throw", (request, response) -> {