Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue #8329 - support wildcards in proxy exclusion hosts #10538

Open
wants to merge 3 commits into
base: jetty-10.0.x
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ The following is a typical configuration:
include::../../{doc_code}/org/eclipse/jetty/docs/programming/client/http/HTTPClientDocs.java[tag=proxy]
----

You specify the proxy host and proxy port, and optionally also the addresses that you do not want to be proxied, and then add the proxy configuration on the `ProxyConfiguration` instance.
You specify the proxy host and proxy port, and optionally also the addresses that you do not want to be proxied (with wildcard '*' supported at the start and end), and then add the proxy configuration on the `ProxyConfiguration` instance.

Configured in this way, `HttpClient` makes requests to the HTTP proxy (for plain-text HTTP requests) or establishes a tunnel via HTTP `CONNECT` (for encrypted HTTPS requests).

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -658,6 +658,8 @@ public void proxy() throws Exception

// Do not proxy requests for localhost:8080.
proxy.getExcludedAddresses().add("localhost:8080");
// Do not proxy requests for any address starting with "127.".
proxy.getExcludedAddresses().add("127.*");

// Add the new proxy to the list of proxies already registered.
ProxyConfiguration proxyConfig = httpClient.getProxyConfiguration();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,13 @@
package org.eclipse.jetty.client;

import java.net.URI;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.regex.Pattern;

import org.eclipse.jetty.http.HttpScheme;
import org.eclipse.jetty.io.ClientConnectionFactory;
Expand Down Expand Up @@ -95,6 +98,8 @@ public abstract static class Proxy
// TODO use InetAddressSet? Or IncludeExcludeSet?
private final Set<String> included = new HashSet<>();
private final Set<String> excluded = new HashSet<>();
private final Map<String, Pattern> _exludedPatterns = new HashMap<>();
private final Map<String, HostPort> _hostPorts = new HashMap<>();
private final Origin origin;
private final SslContextFactory.Client sslContextFactory;

Expand Down Expand Up @@ -198,7 +203,7 @@ public boolean matches(Origin origin)
}
for (String excluded : this.excluded)
{
if (matches(address, excluded))
if (matchesWithWildcards(address, excluded))
{
result = false;
break;
Expand All @@ -210,12 +215,47 @@ public boolean matches(Origin origin)
private boolean matches(Origin.Address address, String pattern)
{
// TODO: add support for CIDR notation like 192.168.0.0/24, see DoSFilter
HostPort hostPort = new HostPort(pattern);
HostPort hostPort = _hostPorts.computeIfAbsent(pattern, HostPort::new);
String host = hostPort.getHost();
int port = hostPort.getPort();
return host.equals(address.getHost()) && (port <= 0 || port == address.getPort());
}

private boolean matchesWithWildcards(Origin.Address address, String pattern)
{
HostPort hostPort = _hostPorts.computeIfAbsent(pattern, HostPort::new);
String host = hostPort.getHost();
int port = hostPort.getPort();
Pattern hostPattern = _exludedPatterns.computeIfAbsent(host, this::compileHostRegex);
return hostPattern.matcher(address.getHost()).matches() && (port <= 0 || port == address.getPort());
}

private Pattern compileHostRegex(String host)
{
return Pattern.compile(extractHostRegex(host));
}

private String extractHostRegex(String host)
{
if (host.equals("*"))
{
return ".*";
}
if (host.startsWith("*") && host.endsWith("*"))
{
return ".*" + Pattern.quote(host.substring(1, host.length() - 1)) + ".*";
}
if (host.startsWith("*"))
{
return ".*" + Pattern.quote(host.substring(1));
}
if (host.endsWith("*"))
{
return Pattern.quote(host.substring(0, host.length() - 1)) + ".*";
}
return Pattern.quote(host);
}

/**
* @param connectionFactory the nested {@link ClientConnectionFactory}
* @return a new {@link ClientConnectionFactory} for this Proxy
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,4 +75,56 @@ public void testProxyMatchesWithIncludesAndExcludesIPv6() throws Exception
assertTrue(proxy.matches(new Origin("http", "[1::2:3:4]", 0)));
assertFalse(proxy.matches(new Origin("http", "[1::2:3:4]", 5)));
}

@Test
public void testProxyMatchesWithExclusionsWithWildcardAtEnd()
{
HttpProxy proxy = new HttpProxy("host", 0);
proxy.getExcludedAddresses().add("1.2.*");

assertFalse(proxy.matches(new Origin("http", "1.2.3.4", 0)));
assertFalse(proxy.matches(new Origin("http", "1.2.3.5", 0)));
assertFalse(proxy.matches(new Origin("http", "1.2.4.4", 0)));
assertFalse(proxy.matches(new Origin("http", "1.2.4.5", 0)));
}

@Test
public void testProxyMatchesWithExclusionsWithWildcardAtStart()
{
HttpProxy proxy = new HttpProxy("host", 0);
proxy.getExcludedAddresses().add("*.localhost");

assertFalse(proxy.matches(new Origin("http", "local.localhost", 0)));
assertFalse(proxy.matches(new Origin("http", "local.test.localhost", 0)));
assertTrue(proxy.matches(new Origin("http", "1.2.4.5", 0)));
}

@Test
public void testProxyMatchesWithExclusionsWithWildcardAtStartAndEnd()
{
HttpProxy proxy = new HttpProxy("host", 0);
proxy.getExcludedAddresses().add("*.local*");

assertFalse(proxy.matches(new Origin("http", "local.localhost", 0)));
assertFalse(proxy.matches(new Origin("http", "local.test.localhost.test", 0)));
assertTrue(proxy.matches(new Origin("http", "1.2.4.5", 0)));
}

@Test
public void testProxyMatchesWithExclusionsWithWildcardAndPort()
{
HttpProxy proxy = new HttpProxy("host", 0);
proxy.getExcludedAddresses().add("1.2.3.*:5");

assertFalse(proxy.matches(new Origin("http", "1.2.3.4", 5)));
}

@Test
public void testProxyMatchesWithExclusionWithWildcardOnly()
{
HttpProxy proxy = new HttpProxy("host", 0);
proxy.getExcludedAddresses().add("*");

assertFalse(proxy.matches(new Origin("http", "1.2.3.4", 0)));
}
}