Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 14 additions & 4 deletions vertx-core/src/main/java/io/vertx/core/http/HttpClientRequest.java
Original file line number Diff line number Diff line change
Expand Up @@ -65,18 +65,28 @@ public interface HttpClientRequest extends WriteStream<Buffer> {
HttpClientRequest drainHandler(Handler<Void> handler);

/**
* Override the request authority, when using HTTP/1.x this overrides the request {@code host} header, when using
* HTTP/2 this sets the {@code authority} pseudo header. When the port is a negative value, the default
* scheme port will be used.
* Override the request authority initially set by the client.
*
* <p>The default request authority is the server host and port when connecting to the server.
* <ul>
* <li>when using HTTP/1.x this overrides the request {@code host} header</li>
* <li>when using HTTP/2 this sets the {@code authority} pseudo header</li>
*
* When the port is a negative value, the default scheme port will be used.
*
* <p>According to the protocol, it can set to {@code null} (although it is not common), e.g. an HTTP/2 request
* can have a null authority when it carries an {@code host} header.</p>
*
* @param authority override the request authority
* @return a reference to this, so the API can be used fluently
*/
@Fluent
HttpClientRequest authority(HostAndPort authority);

/**
* @return the current request authority
*/
HostAndPort authority();

/**
* Set the request to follow HTTP redirects up to {@link HttpClientOptions#getMaxRedirects()}.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -527,7 +527,7 @@ private Future<HttpClientRequest> doRequestDirectly(
});
});
});
return wrap(httpMethod, requestURI, headers, traceOperation, idleTimeout, followRedirects, proxyOptions, fut2);
return wrap(authority, httpMethod, requestURI, headers, traceOperation, idleTimeout, followRedirects, proxyOptions, fut2);
}

private Future<HttpClientRequest> doRequest(
Expand Down Expand Up @@ -698,7 +698,7 @@ public Future<ConnectionObtainedResult> apply(SharedHttpClientConnectionGroup po
// I think this is not possible - so remove it
return streamCtx.failedFuture("Cannot resolve address " + server);
} else {
return wrap(method, requestURI, headers, traceOperation, idleTimeout, followRedirects, null, future);
return wrap(authority, method, requestURI, headers, traceOperation, idleTimeout, followRedirects, null, future);
}
}

Expand Down Expand Up @@ -738,7 +738,8 @@ <T> Future<T> getPool(boolean resolveOrigin,
return resourceManager.withResourceAsync(key, provider, (group, created) -> function.apply(group));
}

private Future<HttpClientRequest> wrap(HttpMethod method,
private Future<HttpClientRequest> wrap(HostAndPort authority,
HttpMethod method,
String requestURI,
MultiMap headers,
String traceOperation,
Expand All @@ -756,7 +757,7 @@ private Future<HttpClientRequest> wrap(HttpMethod method,
options.setFollowRedirects(followRedirects);
options.setTraceOperation(traceOperation);
HttpClientStream stream = res.stream;
HttpClientRequestImpl request = createRequest(stream.connection(), stream, options);
HttpClientRequestImpl request = createRequest(authority, stream.connection(), stream, options);
if (res.alternative != null) {
String altUsedValue;
int defaultPort = stream.connection().isSsl() ? 443 : 80;
Expand Down Expand Up @@ -787,8 +788,8 @@ public ConnectionObtainedResult(HttpClientStream stream, Lease<HttpClientConnect
}
}

HttpClientRequestImpl createRequest(HttpConnection connection, HttpClientStream stream, RequestOptions options) {
HttpClientRequestImpl request = new HttpClientRequestImpl(connection, stream);
HttpClientRequestImpl createRequest(HostAndPort authority, HttpConnection connection, HttpClientStream stream, RequestOptions options) {
HttpClientRequestImpl request = new HttpClientRequestImpl(authority, connection, stream);
request.init(options);
Function<HttpClientResponse, Future<RequestOptions>> rHandler = redirectHandler;
if (rHandler != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@ public HttpClientStream stream() {
return stream;
}

public HostAndPort authority() {
return authority;
}

@Override
public long id() {
return stream.id();
Expand Down Expand Up @@ -82,5 +86,4 @@ public String uri() {
public HttpMethod method() {
return method;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -45,14 +45,14 @@ public abstract class HttpClientRequestBase implements HttpClientRequestInternal
private long lastDataReceived;
protected Throwable reset;

HttpClientRequestBase(HttpConnection connection, HttpClientStream stream, PromiseInternal<HttpClientResponse> responsePromise, HttpMethod method, String uri) {
HttpClientRequestBase(HostAndPort authority, HttpConnection connection, HttpClientStream stream, PromiseInternal<HttpClientResponse> responsePromise, HttpMethod method, String uri) {
this.connection = connection;
this.stream = stream;
this.responsePromise = responsePromise;
this.context = responsePromise.context();
this.uri = uri;
this.method = method;
this.authority = stream.connection().authority();
this.authority = authority;
this.ssl = stream.connection().isSsl();

//
Expand All @@ -70,7 +70,7 @@ public abstract class HttpClientRequestBase implements HttpClientRequestInternal
});
}

protected HostAndPort authority() {
public HostAndPort authority() {
return authority;
}

Expand Down Expand Up @@ -171,7 +171,12 @@ void fail(Throwable t) {
}

void handlePush(HttpClientPush push) {
HttpClientRequestPushPromise pushReq = new HttpClientRequestPushPromise(connection, push.stream(), push.method(), push.uri(), push.headers());
HttpClientRequestPushPromise pushReq = new HttpClientRequestPushPromise(connection,
push.stream(),
push.authority(),
push.method(),
push.uri(),
push.headers());
if (pushHandler != null) {
pushHandler.handle(pushReq);
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,8 @@ public class HttpClientRequestImpl extends HttpClientRequestBase implements Http
private boolean isConnect;
private String traceOperation;

public HttpClientRequestImpl(HttpConnection connection, HttpClientStream stream) {
super(connection, stream, stream.context().promise(), HttpMethod.GET, "/");
public HttpClientRequestImpl(HostAndPort authority, HttpConnection connection, HttpClientStream stream) {
super(authority, connection, stream, stream.context().promise(), HttpMethod.GET, "/");
this.chunked = false;
this.endPromise = context.promise();
this.endFuture = endPromise.future();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import io.vertx.core.Promise;
import io.vertx.core.buffer.Buffer;
import io.vertx.core.http.*;
import io.vertx.core.net.HostAndPort;

import java.util.function.Function;

Expand All @@ -32,10 +33,11 @@ class HttpClientRequestPushPromise extends HttpClientRequestBase {
public HttpClientRequestPushPromise(
HttpConnection connection,
HttpClientStream stream,
HostAndPort authority,
HttpMethod method,
String uri,
MultiMap headers) {
super(connection, stream, stream.connection().context().promise(), method, uri);
super(authority, connection, stream, stream.connection().context().promise(), method, uri);
this.stream = stream;
this.headers = headers;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import io.vertx.core.http.*;
import io.vertx.core.internal.ContextInternal;
import io.vertx.core.internal.PromiseInternal;
import io.vertx.core.net.HostAndPort;
import io.vertx.core.net.SocketAddress;

import javax.net.ssl.SSLSession;
Expand Down Expand Up @@ -231,8 +232,16 @@ public Future<HttpClientRequest> request(ContextInternal context, RequestOptions
future = actual.createStream(context);
}
}
String host = options.getHost();
Integer port = options.getPort();
HostAndPort authority;
if (host != null && port != null) {
authority = HostAndPort.authority(host, port);
} else {
authority = actual.authority();
}
return future.map(stream -> {
HttpClientRequestImpl request = new HttpClientRequestImpl(this, stream);
HttpClientRequestImpl request = new HttpClientRequestImpl(authority, this, stream);
stream.closeHandler(this::checkPending);
if (options != null) {
request.init(options);
Expand Down
38 changes: 38 additions & 0 deletions vertx-core/src/test/java/io/vertx/tests/http/HttpTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
import io.vertx.tests.http.http3.Http3Test;
import org.assertj.core.api.AbstractThrowableAssert;
import org.junit.Assert;
import org.junit.Assume;
import org.junit.Test;

import java.io.*;
Expand Down Expand Up @@ -3771,6 +3772,7 @@ class MockReq implements HttpClientRequest {
public HttpClientRequest setChunked(boolean chunked) { throw new UnsupportedOperationException(); }
public boolean isChunked() { return false; }
public HttpClientRequest authority(HostAndPort authority) { throw new UnsupportedOperationException(); }
public HostAndPort authority() { throw new UnsupportedOperationException(); }
public HttpMethod getMethod() { return method; }
public String absoluteURI() { return baseURI; }
public HttpVersion version() { return HttpVersion.HTTP_1_1; }
Expand Down Expand Up @@ -6124,4 +6126,40 @@ public void testResolverKeepAlive() throws Exception {
assertTrue(delta >= 500);
assertTrue(delta <= 1000);
}

@Test
public void testNoAuthority() throws Exception {
Assume.assumeTrue(testAddress.isInetSocket());
assertEquals(testAddress.toString(), testNoAuthority(false).toString());
}

@Test
public void testForceNoAuthority() throws Exception {
Assume.assumeTrue(testAddress.isInetSocket() && config.version() != HttpVersion.HTTP_3);
assertEquals("null", testNoAuthority(true).toString());
}

public Buffer testNoAuthority(boolean force) throws Exception {
server.requestHandler(request -> {
request
.response()
.end("" + request.authority());
});

startServer(testAddress);

return client
.request(new RequestOptions().setServer(testAddress))
.compose(request -> {
assertEquals(testAddress.toString(), request.authority().toString());
if (force) {
request.authority(null);
}
return request
.send()
.expecting(HttpResponseExpectation.SC_OK)
.compose(HttpClientResponse::body);
})
.await();
}
}
Loading