Skip to content

Commit

Permalink
Non proxy hosts support
Browse files Browse the repository at this point in the history
  • Loading branch information
vietj committed May 12, 2021
1 parent 70e40dc commit 1df6d8a
Show file tree
Hide file tree
Showing 18 changed files with 481 additions and 90 deletions.
18 changes: 18 additions & 0 deletions src/main/asciidoc/http.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -1828,6 +1828,24 @@ For a SOCKS5 proxy:
The DNS resolution is always done on the proxy server, to achieve the functionality of a SOCKS4 client, it is necessary
to resolve the DNS address locally.

Proxy options can also be set per request:

[source,$lang]
----
{@link examples.HTTPExamples#perRequestProxyOptions}
----

NOTE: A given host should always use the same proxy options: as HTTP requests are pooled, per request proxy
options are used when establishing the connection

You can use {@link io.vertx.core.http.HttpClientOptions#setNonProxyHosts} to configure a list of host bypassing
the proxy. The lists accepts `*` wildcard for matching domains:

[source,$lang]
----
{@link examples.HTTPExamples#nonProxyHosts}
----

==== Handling of other protocols

The HTTP proxy implementation supports getting ftp:// urls if the proxy supports
Expand Down
8 changes: 8 additions & 0 deletions src/main/asciidoc/net.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -779,6 +779,14 @@ Here's an example:
The DNS resolution is always done on the proxy server, to achieve the functionality of a SOCKS4 client, it is necessary
to resolve the DNS address locally.

You can use {@link io.vertx.core.net.NetClientOptions#setNonProxyHosts} to configure a list of host bypassing
the proxy. The lists accepts `*` wildcard for matching domains:

[source,$lang]
----
{@link examples.NetExamples#nonProxyHosts}
----


=== Using HA PROXY protocol

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@ public static void fromJson(Iterable<java.util.Map.Entry<String, Object>> json,
obj.setPort(((Number)member.getValue()).intValue());
}
break;
case "proxyOptions":
if (member.getValue() instanceof JsonObject) {
obj.setProxyOptions(new io.vertx.core.net.ProxyOptions((io.vertx.core.json.JsonObject)member.getValue()));
}
break;
case "ssl":
if (member.getValue() instanceof Boolean) {
obj.setSsl((Boolean)member.getValue());
Expand Down Expand Up @@ -69,6 +74,9 @@ public static void toJson(RequestOptions obj, java.util.Map<String, Object> json
if (obj.getPort() != null) {
json.put("port", obj.getPort());
}
if (obj.getProxyOptions() != null) {
json.put("proxyOptions", obj.getProxyOptions().toJson());
}
if (obj.isSsl() != null) {
json.put("ssl", obj.isSsl());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,16 @@ static void fromJson(Iterable<java.util.Map.Entry<String, Object>> json, ClientO
obj.setMetricsName((String)member.getValue());
}
break;
case "nonProxyHosts":
if (member.getValue() instanceof JsonArray) {
java.util.ArrayList<java.lang.String> list = new java.util.ArrayList<>();
((Iterable<Object>)member.getValue()).forEach( item -> {
if (item instanceof String)
list.add((String)item);
});
obj.setNonProxyHosts(list);
}
break;
case "proxyOptions":
if (member.getValue() instanceof JsonObject) {
obj.setProxyOptions(new io.vertx.core.net.ProxyOptions((io.vertx.core.json.JsonObject)member.getValue()));
Expand All @@ -57,6 +67,11 @@ static void toJson(ClientOptionsBase obj, java.util.Map<String, Object> json) {
if (obj.getMetricsName() != null) {
json.put("metricsName", obj.getMetricsName());
}
if (obj.getNonProxyHosts() != null) {
JsonArray array = new JsonArray();
obj.getNonProxyHosts().forEach(item -> array.add(item));
json.put("nonProxyHosts", array);
}
if (obj.getProxyOptions() != null) {
json.put("proxyOptions", obj.getProxyOptions().toJson());
}
Expand Down
25 changes: 25 additions & 0 deletions src/main/java/examples/HTTPExamples.java
Original file line number Diff line number Diff line change
Expand Up @@ -1022,6 +1022,31 @@ public void example59(Vertx vertx) {

}

public void nonProxyHosts(Vertx vertx) {

HttpClientOptions options = new HttpClientOptions()
.setProxyOptions(new ProxyOptions().setType(ProxyType.SOCKS5)
.setHost("localhost").setPort(1080)
.setUsername("username").setPassword("secret"))
.addNonProxyHost("*.foo.com")
.addNonProxyHost("localhost");
HttpClient client = vertx.createHttpClient(options);

}

public void perRequestProxyOptions(HttpClient client, ProxyOptions proxyOptions) {

client.request(new RequestOptions()
.setHost("example.com")
.setProxyOptions(proxyOptions))
.compose(request -> request
.send()
.compose(HttpClientResponse::body))
.onSuccess(body -> {
System.out.println("Received response");
});
}

public void example60(Vertx vertx) {

HttpClientOptions options = new HttpClientOptions()
Expand Down
13 changes: 13 additions & 0 deletions src/main/java/examples/NetExamples.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
import io.vertx.core.Vertx;
import io.vertx.core.buffer.Buffer;
import io.vertx.core.http.ClientAuth;
import io.vertx.core.http.HttpClient;
import io.vertx.core.http.HttpClientOptions;
import io.vertx.core.http.HttpServerOptions;
import io.vertx.core.net.*;

Expand Down Expand Up @@ -564,6 +566,17 @@ public void example47(Vertx vertx) {
NetClient client = vertx.createNetClient(options);
}

public void nonProxyHosts(Vertx vertx) {

NetClientOptions options = new NetClientOptions()
.setProxyOptions(new ProxyOptions().setType(ProxyType.SOCKS5)
.setHost("localhost").setPort(1080)
.setUsername("username").setPassword("secret"))
.addNonProxyHost("*.foo.com")
.addNonProxyHost("localhost");
NetClient client = vertx.createNetClient(options);
}

public void example48(Vertx vertx) throws CertificateException {
SelfSignedCertificate certificate = SelfSignedCertificate.create();

Expand Down
2 changes: 2 additions & 0 deletions src/main/java/io/vertx/core/http/HttpClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,12 @@
import io.vertx.core.MultiMap;
import io.vertx.core.buffer.Buffer;
import io.vertx.core.metrics.Measured;
import io.vertx.core.net.SocketAddress;
import io.vertx.core.streams.ReadStream;

import java.util.List;
import java.util.function.Function;
import java.util.function.Predicate;

/**
* An asynchronous HTTP client.
Expand Down
10 changes: 10 additions & 0 deletions src/main/java/io/vertx/core/http/HttpClientOptions.java
Original file line number Diff line number Diff line change
Expand Up @@ -1138,6 +1138,16 @@ public HttpClientOptions setProxyOptions(ProxyOptions proxyOptions) {
return (HttpClientOptions) super.setProxyOptions(proxyOptions);
}

@Override
public HttpClientOptions setNonProxyHosts(List<String> nonProxyHosts) {
return (HttpClientOptions) super.setNonProxyHosts(nonProxyHosts);
}

@Override
public HttpClientOptions addNonProxyHost(String nonProxyHost) {
return (HttpClientOptions) super.addNonProxyHost(nonProxyHost);
}

@Override
public HttpClientOptions setLocalAddress(String localAddress) {
return (HttpClientOptions) super.setLocalAddress(localAddress);
Expand Down
29 changes: 29 additions & 0 deletions src/main/java/io/vertx/core/http/RequestOptions.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import io.vertx.core.MultiMap;
import io.vertx.core.VertxException;
import io.vertx.core.json.JsonObject;
import io.vertx.core.net.ProxyOptions;
import io.vertx.core.net.SocketAddress;

import java.net.MalformedURLException;
Expand All @@ -32,6 +33,11 @@
@DataObject(generateConverter = true)
public class RequestOptions {

/**
* The default value for proxy options = {@code null}
*/
public static final ProxyOptions DEFAULT_PROXY_OPTIONS = null;

/**
* The default value for server method = {@code null}
*/
Expand Down Expand Up @@ -72,6 +78,7 @@ public class RequestOptions {
*/
public static final long DEFAULT_TIMEOUT = 0;

private ProxyOptions proxyOptions;
private SocketAddress server;
private HttpMethod method;
private String host;
Expand All @@ -86,6 +93,7 @@ public class RequestOptions {
* Default constructor
*/
public RequestOptions() {
proxyOptions = DEFAULT_PROXY_OPTIONS;
server = DEFAULT_SERVER;
method = DEFAULT_HTTP_METHOD;
host = DEFAULT_HOST;
Expand Down Expand Up @@ -155,6 +163,27 @@ public RequestOptions(JsonObject json) {
}
}

/**
* Get the proxy options override for connections
*
* @return proxy options override
*/
public ProxyOptions getProxyOptions() {
return proxyOptions;
}

/**
* Override the {@link HttpClientOptions#setProxyOptions(ProxyOptions)} proxy options
* for connections.
*
* @param proxyOptions proxy options override object
* @return a reference to this, so the API can be used fluently
*/
public RequestOptions setProxyOptions(ProxyOptions proxyOptions) {
this.proxyOptions = proxyOptions;
return this;
}

/**
* Get the server address to be used by the client request.
*
Expand Down
5 changes: 4 additions & 1 deletion src/main/java/io/vertx/core/http/impl/EndpointKey.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,22 +10,25 @@
*/
package io.vertx.core.http.impl;

import io.vertx.core.net.ProxyOptions;
import io.vertx.core.net.SocketAddress;

final class EndpointKey {

final boolean ssl;
final SocketAddress serverAddr;
final SocketAddress peerAddr;
final ProxyOptions proxyOptions;

EndpointKey(boolean ssl, SocketAddress serverAddr, SocketAddress peerAddr) {
EndpointKey(boolean ssl, ProxyOptions proxyOptions, SocketAddress serverAddr, SocketAddress peerAddr) {
if (serverAddr == null) {
throw new NullPointerException("No null server address");
}
if (peerAddr == null) {
throw new NullPointerException("No null peer address");
}
this.ssl = ssl;
this.proxyOptions = proxyOptions;
this.peerAddr = peerAddr;
this.serverAddr = serverAddr;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
import io.vertx.core.impl.ContextInternal;
import io.vertx.core.net.NetSocket;
import io.vertx.core.net.ProxyOptions;
import io.vertx.core.net.ProxyType;
import io.vertx.core.net.SocketAddress;
import io.vertx.core.net.impl.NetClientImpl;
import io.vertx.core.net.impl.NetSocketInternal;
Expand All @@ -48,6 +47,7 @@ public class HttpChannelConnector {
private final HttpClientImpl client;
private final NetClientImpl netClient;
private final HttpClientOptions options;
private final ProxyOptions proxyOptions;
private final ClientMetrics metrics;
private final boolean ssl;
private final boolean useAlpn;
Expand All @@ -57,6 +57,7 @@ public class HttpChannelConnector {

public HttpChannelConnector(HttpClientImpl client,
NetClientImpl netClient,
ProxyOptions proxyOptions,
ClientMetrics metrics,
HttpVersion version,
boolean ssl,
Expand All @@ -67,6 +68,7 @@ public HttpChannelConnector(HttpClientImpl client,
this.netClient = netClient;
this.metrics = metrics;
this.options = client.getOptions();
this.proxyOptions = proxyOptions;
this.ssl = ssl;
this.useAlpn = useAlpn;
this.version = version;
Expand All @@ -79,11 +81,6 @@ public SocketAddress server() {
}

private void connect(EventLoopContext context, Promise<NetSocket> promise) {
ProxyOptions proxyOptions = this.options.getProxyOptions();
if (proxyOptions != null && !ssl && proxyOptions.getType()== ProxyType.HTTP) {
// http proxy requests are handled in HttpClientImpl, everything else can use netty proxy handler
proxyOptions = null;
}
netClient.connectInternal(proxyOptions, server, peerAddress, this.options.isForceSni() ? peerAddress.host() : null, ssl, useAlpn, promise, context, 0);
}

Expand Down
Loading

0 comments on commit 1df6d8a

Please sign in to comment.