diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpClient.java b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpClient.java
index c9ce6f258ed1..e6e71096bd69 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpClient.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpClient.java
@@ -562,7 +562,13 @@ protected Origin createOrigin(String scheme, String host, int port, Object tag)
return new Origin(scheme, host, port, tag);
}
- protected HttpDestination resolveDestination(Origin origin)
+ /**
+ *
Returns, creating it if absent, the destination with the given origin.
+ *
+ * @param origin the origin that identifies the destination
+ * @return the destination for the given origin
+ */
+ public HttpDestination resolveDestination(Origin origin)
{
return destinations.computeIfAbsent(origin, o ->
{
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpConnection.java b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpConnection.java
index 6930ca19b6b7..8ab4f21e1f79 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpConnection.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpConnection.java
@@ -120,7 +120,13 @@ protected void normalizeRequest(Request request)
if (version.getVersion() <= 11)
{
if (!headers.containsKey(HttpHeader.HOST.asString()))
- headers.put(getHttpDestination().getHostField());
+ {
+ URI uri = request.getURI();
+ if (uri != null)
+ headers.put(HttpHeader.HOST, uri.getAuthority());
+ else
+ headers.put(getHttpDestination().getHostField());
+ }
}
// Add content headers
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpDestination.java b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpDestination.java
index fd8ae0bb52b5..c8866e6dc00e 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpDestination.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpDestination.java
@@ -253,15 +253,13 @@ public void failed(Throwable x)
abort(x);
}
+ public void send(Request request, Response.CompleteListener listener)
+ {
+ ((HttpRequest)request).sendAsync(this, listener);
+ }
+
protected void send(HttpRequest request, List listeners)
{
- if (!getScheme().equalsIgnoreCase(request.getScheme()))
- throw new IllegalArgumentException("Invalid request scheme " + request.getScheme() + " for destination " + this);
- if (!getHost().equalsIgnoreCase(request.getHost()))
- throw new IllegalArgumentException("Invalid request host " + request.getHost() + " for destination " + this);
- int port = request.getPort();
- if (port >= 0 && getPort() != port)
- throw new IllegalArgumentException("Invalid request port " + port + " for destination " + this);
send(new HttpExchange(this, request, listeners));
}
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpRequest.java b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpRequest.java
index 53750ad0f2a6..2a373e288b02 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpRequest.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpRequest.java
@@ -40,6 +40,7 @@
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicReference;
+import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.LongConsumer;
import java.util.function.Supplier;
@@ -722,7 +723,7 @@ public Request timeout(long timeout, TimeUnit unit)
public ContentResponse send() throws InterruptedException, TimeoutException, ExecutionException
{
FutureResponseListener listener = new FutureResponseListener(this);
- send(this, listener);
+ send(listener);
try
{
@@ -761,15 +762,20 @@ public ContentResponse send() throws InterruptedException, TimeoutException, Exe
@Override
public void send(Response.CompleteListener listener)
{
- send(this, listener);
+ sendAsync(client::send, listener);
}
- private void send(HttpRequest request, Response.CompleteListener listener)
+ void sendAsync(HttpDestination destination, Response.CompleteListener listener)
+ {
+ sendAsync(destination::send, listener);
+ }
+
+ private void sendAsync(BiConsumer> sender, Response.CompleteListener listener)
{
if (listener != null)
responseListeners.add(listener);
sent();
- client.send(request, responseListeners);
+ sender.accept(this, responseListeners);
}
void sent()
diff --git a/tests/test-http-client-transport/src/test/java/org/eclipse/jetty/http/client/HttpClientTest.java b/tests/test-http-client-transport/src/test/java/org/eclipse/jetty/http/client/HttpClientTest.java
index ccc977159cc9..7e58db34ce7e 100644
--- a/tests/test-http-client-transport/src/test/java/org/eclipse/jetty/http/client/HttpClientTest.java
+++ b/tests/test-http-client-transport/src/test/java/org/eclipse/jetty/http/client/HttpClientTest.java
@@ -36,6 +36,8 @@
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
+import org.eclipse.jetty.client.HttpDestination;
+import org.eclipse.jetty.client.Origin;
import org.eclipse.jetty.client.api.ContentResponse;
import org.eclipse.jetty.client.api.Destination;
import org.eclipse.jetty.client.api.Response;
@@ -44,7 +46,9 @@
import org.eclipse.jetty.client.util.InputStreamResponseListener;
import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpMethod;
+import org.eclipse.jetty.http.HttpScheme;
import org.eclipse.jetty.http.HttpStatus;
+import org.eclipse.jetty.http.HttpURI;
import org.eclipse.jetty.http2.FlowControlStrategy;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.handler.AbstractHandler;
@@ -733,6 +737,46 @@ protected void service(String target, Request jettyRequest, HttpServletRequest r
assertEquals(1, scenario.client.getDestinations().size());
}
+ @ParameterizedTest
+ @ArgumentsSource(TransportProvider.class)
+ public void testRequestWithDifferentDestination(Transport transport) throws Exception
+ {
+ init(transport);
+
+ String requestScheme = HttpScheme.HTTPS.is(scenario.getScheme()) ? "http" : "https";
+ String requestHost = "otherHost.com";
+ int requestPort = 8888;
+ scenario.start(new EmptyServerHandler()
+ {
+ @Override
+ protected void service(String target, Request jettyRequest, HttpServletRequest request, HttpServletResponse response)
+ {
+ HttpURI uri = jettyRequest.getHttpURI();
+ assertEquals(requestHost, uri.getHost());
+ assertEquals(requestPort, uri.getPort());
+ if (scenario.transport == Transport.H2C || scenario.transport == Transport.H2)
+ assertEquals(requestScheme, request.getScheme());
+ }
+ });
+
+ Origin origin = new Origin(scenario.getScheme(), "localhost", scenario.getNetworkConnectorLocalPortInt().get());
+ HttpDestination destination = scenario.client.resolveDestination(origin);
+
+ org.eclipse.jetty.client.api.Request request = scenario.client.newRequest(requestHost, requestPort)
+ .scheme(requestScheme)
+ .path("/path");
+
+ CountDownLatch resultLatch = new CountDownLatch(1);
+ destination.send(request, result ->
+ {
+ assertTrue(result.isSucceeded());
+ assertEquals(HttpStatus.OK_200, result.getResponse().getStatus());
+ resultLatch.countDown();
+ });
+
+ assertTrue(resultLatch.await(5, TimeUnit.SECONDS));
+ }
+
private void sleep(long time) throws IOException
{
try