diff --git a/src/main/java/com/glean/proxy/ChainedProxyConfiguration.java b/src/main/java/com/glean/proxy/ChainedProxyConfiguration.java new file mode 100644 index 0000000..0d7d11e --- /dev/null +++ b/src/main/java/com/glean/proxy/ChainedProxyConfiguration.java @@ -0,0 +1,62 @@ +package com.glean.proxy; + +import java.net.InetSocketAddress; +import java.util.Queue; +import java.util.Set; +import org.littleshoot.proxy.ChainedProxy; +import org.littleshoot.proxy.ChainedProxyAdapter; +import org.littleshoot.proxy.impl.ClientDetails; +import java.util.logging.Logger; +import org.littleshoot.proxy.ChainedProxyManager; +import io.netty.handler.codec.http.HttpRequest; + + +public class ChainedProxyConfiguration { + private static final Logger logger = Logger.getLogger(ChainedProxyConfiguration.class.getName()); + + public static ChainedProxyManager fromEnvironment() { + if (System.getenv("FORWARD_PROXY_HOST") == null || System.getenv("FORWARD_PROXY_PORT") == null || System.getenv("FORWARD_PROXY_DATA_SOURCE_HOSTS") == null) { + return (HttpRequest httpRequest, + Queue chainedProxies, + ClientDetails clientDetails) -> { + chainedProxies.add(ChainedProxyAdapter.FALLBACK_TO_DIRECT_CONNECTION); + }; + } + InetSocketAddress forwardProxy = new InetSocketAddress(System.getenv("FORWARD_PROXY_HOST"), Integer.parseInt(System.getenv("FORWARD_PROXY_PORT"))); + Set dataSourceHosts = Set.of(System.getenv("FORWARD_PROXY_DATA_SOURCE_HOSTS").split(",")); + + ChainedProxyManager chainedProxyManager = (HttpRequest httpRequest, + Queue chainedProxies, + ClientDetails clientDetails) -> { + String hostHeader = httpRequest.headers().get("Host"); + if (hostHeader == null) { + chainedProxies.add(ChainedProxyAdapter.FALLBACK_TO_DIRECT_CONNECTION); + logger.severe("No host header found, falling back to direct connection"); + return; + } + String host = hostHeader.split(":")[0]; + + if (dataSourceHosts.contains(host)) { + chainedProxies.add(new ChainedProxyAdapter() { + @Override + public InetSocketAddress getChainedProxyAddress() { + return forwardProxy; + } + + @Override + public String getUsername() { + return System.getenv("FORWARD_PROXY_USERNAME"); + } + + @Override + public String getPassword() { + return System.getenv("FORWARD_PROXY_PASSWORD"); + } + }); + } else { + chainedProxies.add(ChainedProxyAdapter.FALLBACK_TO_DIRECT_CONNECTION); + } + }; + return chainedProxyManager; + } +} diff --git a/src/main/java/com/glean/proxy/ProxyNetworking.java b/src/main/java/com/glean/proxy/ProxyNetworking.java index b36d864..2caa748 100644 --- a/src/main/java/com/glean/proxy/ProxyNetworking.java +++ b/src/main/java/com/glean/proxy/ProxyNetworking.java @@ -2,6 +2,7 @@ import java.net.InetSocketAddress; import java.util.logging.Logger; +import org.littleshoot.proxy.ChainedProxyManager; import org.littleshoot.proxy.HttpProxyServer; import org.littleshoot.proxy.impl.DefaultHttpProxyServer; import org.littleshoot.proxy.impl.ThreadPoolConfiguration; @@ -11,6 +12,7 @@ public class ProxyNetworking { protected final ThreadPoolConfiguration threadPoolConfiguration; protected final FilterConfiguration filterConfiguration; + protected final ChainedProxyManager chainedProxyManager; public void run(int port) { DynamicHttpFiltersSourceAdapter filtersSource = @@ -23,6 +25,7 @@ public void run(int port) { .withIdleConnectionTimeout(1200) // seconds .withThreadPoolConfiguration(threadPoolConfiguration) .withFiltersSource(filtersSource) + .withChainProxyManager(chainedProxyManager) .start(); try { Thread.sleep(Long.MAX_VALUE); @@ -35,6 +38,7 @@ public void run(int port) { private ProxyNetworking(Builder builder) { threadPoolConfiguration = builder.threadPoolConfiguration; filterConfiguration = builder.filterConfiguration; + chainedProxyManager = builder.chainedProxyManager; } public static Builder builder() { @@ -44,7 +48,8 @@ public static Builder builder() { public static class Builder { private ThreadPoolConfiguration threadPoolConfiguration; private FilterConfiguration filterConfiguration; - + private ChainedProxyManager chainedProxyManager; + public Builder withThreadPoolConfiguration(ThreadPoolConfiguration threadPoolConfiguration) { this.threadPoolConfiguration = threadPoolConfiguration; return this; @@ -55,6 +60,11 @@ public Builder withFilterConfiguration(FilterConfiguration filterConfiguration) return this; } + public Builder withChainedProxyManager(ChainedProxyManager chainedProxyManager) { + this.chainedProxyManager = chainedProxyManager; + return this; + } + public ProxyNetworking build() { if (threadPoolConfiguration == null) { threadPoolConfiguration = createThreadPoolConfigurationFromEnvironment(); @@ -62,6 +72,9 @@ public ProxyNetworking build() { if (filterConfiguration == null) { filterConfiguration = FilterConfiguration.fromEnvironment(); } + if (chainedProxyManager == null) { + chainedProxyManager = ChainedProxyConfiguration.fromEnvironment(); + } return new ProxyNetworking(this); } }