Skip to content

Commit 496a905

Browse files
committed
The HTTP client request path when resolving an address does not apply the default proxy options nor performs proxy filering.
Apply those after we resolve the address to a socket address before interracting with the HTTP connection manager.
1 parent 3642cb8 commit 496a905

File tree

2 files changed

+88
-20
lines changed

2 files changed

+88
-20
lines changed

src/main/java/io/vertx/core/http/impl/HttpClientImpl.java

Lines changed: 21 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -325,13 +325,13 @@ private Future<HttpClientRequest> doRequest(
325325
ContextInternal ctx = vertx.getOrCreateContext();
326326
ContextInternal connCtx = ctx.isEventLoopContext() ? ctx : vertx.createEventLoopContext(ctx.nettyEventLoop(), ctx.workerPool(), ctx.classLoader());
327327
Promise<HttpClientRequest> promise = ctx.promise();
328-
Future<HttpClientStream> future;
329-
ProxyOptions proxyOptions;
328+
Future<ConnectionObtainedResult> future;
330329
if (endpointResolver != null && endpointResolver.accepts(server) != null) {
331330
Future<EndpointLookup> fut = endpointResolver.lookupEndpoint(ctx, server);
332331
future = fut.compose(lookup -> {
333332
SocketAddress address = lookup.address();
334-
EndpointKey key = new EndpointKey(useSSL, sslOptions, proxyConfig, address, authority != null ? authority : HostAndPort.create(address.host(), address.port()));
333+
ProxyOptions proxyOptions = computeProxyOptions(proxyConfig, address);
334+
EndpointKey key = new EndpointKey(useSSL, sslOptions, proxyOptions, address, authority != null ? authority : HostAndPort.create(address.host(), address.port()));
335335
return httpCM.withEndpointAsync(key, httpEndpointProvider(), (endpoint, created) -> {
336336
Future<Lease<HttpClientConnection>> fut2 = endpoint.requestConnection(connCtx, connectTimeout);
337337
if (fut2 == null) {
@@ -347,19 +347,14 @@ private Future<HttpClientRequest> doRequest(
347347
return conn.createStream(ctx).map(stream -> {
348348
HttpClientStream wrapped = new StatisticsGatheringHttpClientStream(stream, endpointRequest);
349349
wrapped.closeHandler(v -> lease.recycle());
350-
return wrapped;
350+
return new ConnectionObtainedResult(proxyOptions, wrapped);
351351
});
352352
});
353353
}
354354
});
355355
});
356-
if (future != null) {
357-
proxyOptions = proxyConfig;
358-
} else {
359-
proxyOptions = null;
360-
}
361356
} else if (server instanceof SocketAddress) {
362-
proxyOptions = computeProxyOptions(proxyConfig, (SocketAddress) server);
357+
ProxyOptions proxyOptions = computeProxyOptions(proxyConfig, (SocketAddress) server);
363358
EndpointKey key = new EndpointKey(useSSL, sslOptions, proxyOptions, (SocketAddress) server, authority);
364359
future = httpCM.withEndpointAsync(key, httpEndpointProvider(), (endpoint, created) -> {
365360
Future<Lease<HttpClientConnection>> fut = endpoint.requestConnection(connCtx, connectTimeout);
@@ -368,13 +363,11 @@ private Future<HttpClientRequest> doRequest(
368363
} else {
369364
return fut.compose(lease -> {
370365
HttpClientConnection conn = lease.get();
371-
return conn.createStream(ctx).andThen(ar -> {
372-
if (ar.succeeded()) {
373-
HttpClientStream stream = ar.result();
374-
stream.closeHandler(v -> {
375-
lease.recycle();
376-
});
377-
}
366+
return conn.createStream(ctx).map(stream -> {
367+
stream.closeHandler(v -> {
368+
lease.recycle();
369+
});
370+
return new ConnectionObtainedResult(proxyOptions, stream);
378371
});
379372
});
380373
}
@@ -385,13 +378,22 @@ private Future<HttpClientRequest> doRequest(
385378
if (future == null) {
386379
return connCtx.failedFuture("Cannot resolve address " + server);
387380
} else {
388-
future.map(stream -> {
389-
return createRequest(stream, method, headers, requestURI, proxyOptions, useSSL, idleTimeout, followRedirects, traceOperation);
381+
future.map(res -> {
382+
return createRequest(res.stream, method, headers, requestURI, res.proxyOptions, useSSL, idleTimeout, followRedirects, traceOperation);
390383
}).onComplete(promise);
391384
return promise.future();
392385
}
393386
}
394387

388+
private static class ConnectionObtainedResult {
389+
private final ProxyOptions proxyOptions;
390+
private final HttpClientStream stream;
391+
public ConnectionObtainedResult(ProxyOptions proxyOptions, HttpClientStream stream) {
392+
this.proxyOptions = proxyOptions;
393+
this.stream = stream;
394+
}
395+
}
396+
395397
Future<HttpClientRequest> createRequest(HttpClientConnection conn, ContextInternal context) {
396398
return conn.createStream(context).map(this::createRequest);
397399
}

src/test/java/io/vertx/core/http/ResolvingHttpClientTest.java

Lines changed: 67 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
package io.vertx.core.http;
22

33
import io.vertx.core.Future;
4+
import io.vertx.core.VertxOptions;
45
import io.vertx.core.buffer.Buffer;
6+
import io.vertx.core.http.impl.CleanableHttpClient;
7+
import io.vertx.core.http.impl.HttpClientImpl;
58
import io.vertx.core.http.impl.HttpClientInternal;
69
import io.vertx.core.net.*;
710
import io.vertx.test.core.VertxTestBase;
@@ -26,6 +29,17 @@ public class ResolvingHttpClientTest extends VertxTestBase {
2629
private BiConsumer<Integer, HttpServerRequest> requestHandler;
2730
private List<HttpServer> servers;
2831

32+
@Override
33+
protected VertxOptions getOptions() {
34+
VertxOptions options = super.getOptions();
35+
options.getAddressResolverOptions().setHostsValue(Buffer.buffer("" +
36+
"127.0.0.1 localhost\n" +
37+
"127.0.0.1 s1.example.com\n" +
38+
"127.0.0.1 s2.example.com\n"
39+
));
40+
return options;
41+
}
42+
2943
private void startServers(int numServers) throws Exception {
3044
startServers(numServers, new HttpServerOptions());
3145
}
@@ -172,6 +186,59 @@ public void testResolveToSameSocketAddressWithProxy() throws Exception {
172186
assertNotNull(proxy.lastLocalAddress());
173187
}
174188

189+
@Test
190+
public void testAcceptProxyFilter() throws Exception {
191+
testFilter(true);
192+
}
193+
194+
@Test
195+
public void testRejectProxyFilter() throws Exception {
196+
testFilter(false);
197+
}
198+
199+
private void testFilter(boolean accept) throws Exception {
200+
HttpProxy proxy = new HttpProxy();
201+
proxy.start(vertx);
202+
try {
203+
int numServers = 2;
204+
waitFor(numServers * 2);
205+
startServers(numServers);
206+
requestHandler = (idx, req) -> {
207+
boolean proxied = idx == 0 && accept;
208+
SocketAddress remote = req.connection().remoteAddress();
209+
assertEquals(proxied, proxy.localAddresses().contains(remote.host() + ":" + remote.port()));
210+
req.response().end("server-" + idx);
211+
};
212+
FakeAddressResolver resolver = new FakeAddressResolver();
213+
resolver.registerAddress("example.com", Arrays.asList(
214+
SocketAddress.inetSocketAddress(HttpTestBase.DEFAULT_HTTP_PORT, "s1.example.com"),
215+
SocketAddress.inetSocketAddress(HttpTestBase.DEFAULT_HTTP_PORT + 1, "s2.example.com")));
216+
HttpClientInternal client = (HttpClientInternal) vertx.httpClientBuilder()
217+
.with(new HttpClientOptions()
218+
.setProxyOptions(new ProxyOptions().setType(ProxyType.HTTP).setHost("localhost").setPort(proxy.port())))
219+
.withAddressResolver(resolver)
220+
.build();
221+
((HttpClientImpl)((CleanableHttpClient)client).delegate).proxyFilter(so -> {
222+
return accept && so.host().equals("s1.example.com");
223+
});
224+
Set<String> responses = Collections.synchronizedSet(new HashSet<>());
225+
for (int i = 0;i < numServers * 2;i++) {
226+
client.request(new RequestOptions().setServer(new FakeAddress("example.com"))).compose(req -> req
227+
.send()
228+
.andThen(onSuccess(resp -> assertEquals(200, resp.statusCode())))
229+
.compose(HttpClientResponse::body)
230+
).onComplete(onSuccess(v -> {
231+
responses.add(v.toString());
232+
complete();
233+
}));
234+
}
235+
await();
236+
Assert.assertEquals(new HashSet<>(Arrays.asList("server-0", "server-1")), responses);
237+
} finally {
238+
proxy.stop();
239+
}
240+
}
241+
175242
@Test
176243
public void testResolveFailure() {
177244
Exception cause = new Exception("Not found");
@@ -539,5 +606,4 @@ private void testSSL(RequestOptions request, boolean expectFailure, boolean veri
539606
assertTrue(expectFailure);
540607
}
541608
}
542-
543609
}

0 commit comments

Comments
 (0)