Skip to content

Commit

Permalink
Include system proxy
Browse files Browse the repository at this point in the history
Signed-off-by: Jorge Bescos Gascon <[email protected]>
  • Loading branch information
jbescos committed Jun 29, 2023
1 parent 5c36c47 commit d58a42c
Show file tree
Hide file tree
Showing 5 changed files with 136 additions and 80 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;

import java.net.InetSocketAddress;
import java.net.ProxySelector;

import io.helidon.common.http.Http;
import io.helidon.nima.testing.junit5.webserver.ServerTest;
import io.helidon.nima.testing.junit5.webserver.SetUpRoute;
Expand Down Expand Up @@ -65,12 +68,12 @@ public void after() {

@Test
void testNoProxy() {
try (Http1ClientResponse response = client.get("/get").request()) {
assertThat(response.status(), is(Http.Status.OK_200));
String entity = response.entity().as(String.class);
assertThat(entity, is("Hello"));
}
assertThat(httpProxy.counter(), is(0));
noProxyChecks();
}

@Test
void testNoProxyTypeDefaultsToNone() {
noProxyChecks();
}

@Test
Expand All @@ -85,17 +88,35 @@ void testNoHosts() {
}

@Test
void testNoProxyType() {
void testNoProxyTypeButHasHost() {
Proxy proxy = Proxy.builder().host(PROXY_HOST).port(proxyPort).build();
successVerify(proxy);
}

@Test
void testProxyNoneTypeButHasHost() {
Proxy proxy = Proxy.builder().type(ProxyType.NONE).host(PROXY_HOST).port(proxyPort).build();
successVerify(proxy);
}

@Test
void testSimpleProxy() {
Proxy proxy = Proxy.builder().type(ProxyType.HTTP).host(PROXY_HOST).port(proxyPort).build();
successVerify(proxy);
}

@Test
void testSystemProxy() {
ProxySelector original = ProxySelector.getDefault();
try {
ProxySelector.setDefault(ProxySelector.of(new InetSocketAddress(PROXY_HOST, proxyPort)));
Proxy proxy = Proxy.create();
successVerify(proxy);
} finally {
ProxySelector.setDefault(original);
}
}

private void successVerify(Proxy proxy) {
try (Http1ClientResponse response = client.get("/get").proxy(proxy).request()) {
assertThat(response.status(), is(Http.Status.OK_200));
Expand All @@ -105,6 +126,15 @@ private void successVerify(Proxy proxy) {
assertThat(httpProxy.counter(), is(1));
}

private void noProxyChecks() {
try (Http1ClientResponse response = client.get("/get").request()) {
assertThat(response.status(), is(Http.Status.OK_200));
String entity = response.entity().as(String.class);
assertThat(entity, is("Hello"));
}
assertThat(httpProxy.counter(), is(0));
}

private static class Routes {
private static String get() {
return "Hello";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
import static org.hamcrest.MatcherAssert.assertThat;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ProxySelector;

import io.helidon.common.configurable.Resource;
import io.helidon.common.http.Http;
Expand Down Expand Up @@ -102,25 +104,44 @@ public static void afterAll() {

@Test
void testNoProxy() {
try (Http1ClientResponse response = client.get("/get").request()) {
assertThat(response.status(), is(Http.Status.OK_200));
String entity = response.entity().as(String.class);
assertThat(entity, is("Hello"));
}
noProxyChecks();
}

@Test
void testNoProxyTypeDefaultsToNone() {
noProxyChecks();
}

@Test
void testNoProxyType() {
void testNoProxyTypeButHasHost() {
Proxy proxy = Proxy.builder().host(PROXY_HOST).port(PROXY_PORT).build();
successVerify(proxy);
}

@Test
void testProxyNoneTypeButHasHost() {
Proxy proxy = Proxy.builder().type(ProxyType.NONE).host(PROXY_HOST).port(PROXY_PORT).build();
successVerify(proxy);
}

@Test
void testSimpleProxy() {
Proxy proxy = Proxy.builder().type(ProxyType.HTTP).host(PROXY_HOST).port(PROXY_PORT).build();
successVerify(proxy);
}

@Test
void testSystemProxy() {
ProxySelector original = ProxySelector.getDefault();
try {
ProxySelector.setDefault(ProxySelector.of(new InetSocketAddress(PROXY_HOST, PROXY_PORT)));
Proxy proxy = Proxy.create();
successVerify(proxy);
} finally {
ProxySelector.setDefault(original);
}
}

private void successVerify(Proxy proxy) {
try (Http1ClientResponse response = client.get("/get").proxy(proxy).request()) {
assertThat(response.status(), is(Http.Status.OK_200));
Expand All @@ -129,6 +150,14 @@ private void successVerify(Proxy proxy) {
}
}

private void noProxyChecks() {
try (Http1ClientResponse response = client.get("/get").request()) {
assertThat(response.status(), is(Http.Status.OK_200));
String entity = response.entity().as(String.class);
assertThat(entity, is("Hello"));
}
}

private static class Routes {
private static String get() {
return "Hello";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import io.helidon.common.configurable.LruCache;
import io.helidon.common.config.Config;
import io.helidon.common.configurable.LruCache;
import io.helidon.config.metadata.Configured;
import io.helidon.config.metadata.ConfiguredOption;

Expand All @@ -46,6 +46,7 @@ public class Proxy {
* No proxy instance.
*/
private static final Proxy NO_PROXY = new Proxy(builder().type(ProxyType.NONE));
private static final Proxy SYSTEM_PROXY = new Proxy(builder().type(ProxyType.SYSTEM));

private static final Pattern PORT_PATTERN = Pattern.compile(".*:(\\d+)");
private static final Pattern IP_V4 = Pattern.compile("^(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)(\\."
Expand All @@ -70,20 +71,20 @@ public class Proxy {
private final Function<UriHelper, Boolean> noProxy;
private final Optional<String> username;
private final Optional<char[]> password;
private final ProxySelector systemSelector;
private final boolean useSystemSelector;

private Proxy(Proxy.Builder builder) {
this.type = builder.type();
this.systemSelector = builder.systemSelector();
this.host = builder.host();
this.useSystemSelector = ((null == host) && (null != systemSelector));
if (this.host != null) {
this.type = ProxyType.HTTP;
} else {
this.type = builder.type();
}

this.port = builder.port();
this.username = builder.username();
this.password = builder.password();

if (useSystemSelector) {
if (type == ProxyType.SYSTEM) {
this.noProxy = inetSocketAddress -> true;
} else {
this.noProxy = prepareNoProxy(builder.noProxyHosts());
Expand Down Expand Up @@ -134,9 +135,7 @@ public static Proxy create(Config config) {
* @return a proxy instance configured based on this system settings
*/
public static Proxy create() {
return builder()
.useSystemSelector(true)
.build();
return SYSTEM_PROXY;
}

static Function<UriHelper, Boolean> prepareNoProxy(Set<String> noProxyHosts) {
Expand Down Expand Up @@ -279,11 +278,11 @@ private static Optional<Boolean> isIpV6HostRegExp(String host) {
}

/**
* Get proxy type. For testing purposes.
* Get proxy type.
*
* @return the proxy type
*/
ProxyType type() {
public ProxyType type() {
return type;
}

Expand All @@ -302,11 +301,23 @@ public boolean isNoHosts(UriHelper uri) {
}

/**
* Creates an InetSocketAddress from a host:port.
* Creates an Optional with the InetSocketAddress of the server proxy for the specified uri.
* @param uri the uri
* @return the InetSocketAddress
*/
public InetSocketAddress address() {
return new InetSocketAddress(host, port);
public Optional<InetSocketAddress> address(UriHelper uri) {
if (type == null || type == ProxyType.NONE) {
return Optional.empty();
} else if (type == ProxyType.SYSTEM) {
for (java.net.Proxy netProxy : ProxySelector.getDefault().select(uri.toUri())) {
if (netProxy.type() == java.net.Proxy.Type.HTTP) {
return Optional.of((InetSocketAddress) netProxy.address());
}
}
return Optional.empty();
} else {
return Optional.of(new InetSocketAddress(host, port));
}
}

/**
Expand Down Expand Up @@ -335,18 +346,16 @@ public boolean equals(Object o) {
}
Proxy proxy = (Proxy) o;
return port == proxy.port
&& useSystemSelector == proxy.useSystemSelector
&& type == proxy.type
&& Objects.equals(host, proxy.host)
&& Objects.equals(noProxy, proxy.noProxy)
&& Objects.equals(username, proxy.username)
&& Objects.equals(password, proxy.password)
&& Objects.equals(systemSelector, proxy.systemSelector);
&& Objects.equals(password, proxy.password);
}

@Override
public int hashCode() {
return Objects.hash(type, host, port, noProxy, username, password, systemSelector, useSystemSelector);
return Objects.hash(type, host, port, noProxy, username, password);
}

/**
Expand All @@ -356,20 +365,22 @@ public int hashCode() {
public static class Builder implements io.helidon.common.Builder<Builder, Proxy> {
private final Set<String> noProxyHosts = new HashSet<>();

// Defaults to system
private ProxyType type;
private String host;
private int port = 80;
private String username;
private char[] password;
private ProxySelector systemSelector;

private Builder() {
}

@Override
public Proxy build() {
if ((null == host) || (host.isEmpty() && (null == systemSelector))) {
if ((null == host) || (host.isEmpty())) {
return NO_PROXY;
} else if (type == ProxyType.SYSTEM) {
return SYSTEM_PROXY;
}
return new Proxy(this);
}
Expand All @@ -385,11 +396,6 @@ public Proxy build() {
* <th>description</th>
* </tr>
* <tr>
* <td>use-system-selector</td>
* <td>{@code false}</td>
* <td>Whether system proxy selector should be used</td>
* </tr>
* <tr>
* <td>type</td>
* <td>{@code no default}</td>
* <td>Sets which type is this proxy. See {@link Proxy.ProxyType}</td>
Expand Down Expand Up @@ -425,7 +431,6 @@ public Proxy build() {
* @return updated builder instance
*/
public Builder config(Config config) {
config.get("use-system-selector").asBoolean().ifPresent(this::useSystemSelector);
if (this.type != ProxyType.SYSTEM) {
config.get("type").asString().map(ProxyType::valueOf).ifPresentOrElse(this::type, () -> type(ProxyType.HTTP));
config.get("host").asString().ifPresent(this::host);
Expand All @@ -442,10 +447,11 @@ public Builder config(Config config) {
*
* @param type proxy type
* @return updated builder instance
* @throws NullPointerException when type is null
*/
@ConfiguredOption("HTTP")
public Builder type(ProxyType type) {
this.type = type;
this.type = Objects.requireNonNull(type);
return this;
}

Expand All @@ -454,10 +460,11 @@ public Builder type(ProxyType type) {
*
* @param host host
* @return updated builder instance
* @throws NullPointerException when host is null
*/
@ConfiguredOption
public Builder host(String host) {
this.host = host;
this.host = Objects.requireNonNull(host);
return this;
}

Expand Down Expand Up @@ -519,27 +526,6 @@ public Builder addNoProxy(String noProxyHost) {
return this;
}

/**
* Configure proxy from environment variables and system properties.
*
* @param useIt use system selector
* @return updated builder instance
*/
@ConfiguredOption("false")
public Builder useSystemSelector(boolean useIt) {
if (useIt) {
this.type = ProxyType.SYSTEM;
this.systemSelector = ProxySelector.getDefault();
} else {
if (this.type == ProxyType.SYSTEM) {
this.type = ProxyType.NONE;
}
this.systemSelector = null;
}

return this;
}

ProxyType type() {
return type;
}
Expand All @@ -563,10 +549,6 @@ Optional<String> username() {
Optional<char[]> password() {
return Optional.ofNullable(password);
}

ProxySelector systemSelector() {
return systemSelector;
}
}

/**
Expand Down
Loading

0 comments on commit d58a42c

Please sign in to comment.