Skip to content

Commit

Permalink
#245: Proxy Support (#338)
Browse files Browse the repository at this point in the history
  • Loading branch information
mvomiero authored May 21, 2024
1 parent b2754e9 commit 430fff0
Show file tree
Hide file tree
Showing 9 changed files with 370 additions and 6 deletions.
2 changes: 1 addition & 1 deletion cli/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@
</agent>
<imageName>${imageName}</imageName>
<buildArgs>
<arg>--enable-url-protocols=https</arg>
<arg>--enable-url-protocols=http,https</arg>
<arg>-H:IncludeResources="nls/.*"</arg>
<arg>--initialize-at-build-time=org.apache.commons.compress</arg>
</buildArgs>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import com.devonfw.tools.ide.log.IdeSubLogger;
import com.devonfw.tools.ide.log.IdeSubLoggerNone;
import com.devonfw.tools.ide.merge.DirectoryMerger;
import com.devonfw.tools.ide.network.ProxyContext;
import com.devonfw.tools.ide.os.SystemInfo;
import com.devonfw.tools.ide.os.SystemInfoImpl;
import com.devonfw.tools.ide.process.ProcessContext;
Expand Down Expand Up @@ -645,6 +646,12 @@ public void setDefaultExecutionDirectory(Path defaultExecutionDirectory) {
}
}

@Override
public ProxyContext getProxyContext() {

return new ProxyContext(this);
}

@Override
public GitContext getGitContext() {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import com.devonfw.tools.ide.io.IdeProgressBar;
import com.devonfw.tools.ide.log.IdeLogger;
import com.devonfw.tools.ide.merge.DirectoryMerger;
import com.devonfw.tools.ide.network.ProxyContext;
import com.devonfw.tools.ide.os.SystemInfo;
import com.devonfw.tools.ide.process.ProcessContext;
import com.devonfw.tools.ide.repo.CustomToolRepository;
Expand Down Expand Up @@ -422,6 +423,8 @@ default void requireOnline(String purpose) {
*/
Path getDefaultExecutionDirectory();

ProxyContext getProxyContext();

/**
* @return the {@link GitContext} used to run several git commands.
*/
Expand Down
22 changes: 17 additions & 5 deletions cli/src/main/java/com/devonfw/tools/ide/io/FileAccessImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.ProxySelector;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpClient.Redirect;
Expand Down Expand Up @@ -53,9 +56,6 @@ public class FileAccessImpl implements FileAccess {

private final IdeContext context;

/** The {@link HttpClient} for HTTP requests. */
private final HttpClient client;

/**
* The constructor.
*
Expand All @@ -65,7 +65,18 @@ public FileAccessImpl(IdeContext context) {

super();
this.context = context;
this.client = HttpClient.newBuilder().followRedirects(Redirect.ALWAYS).build();
}

private HttpClient createHttpClient(String url) {

HttpClient.Builder builder = HttpClient.newBuilder().followRedirects(Redirect.ALWAYS);
Proxy proxy = this.context.getProxyContext().getProxy(url);
if (proxy != Proxy.NO_PROXY) {
this.context.info("Downloading through proxy: " + proxy);
InetSocketAddress proxyAddress = (InetSocketAddress) proxy.address();
builder.proxy(ProxySelector.of(proxyAddress));
}
return builder.build();
}

@Override
Expand All @@ -77,7 +88,8 @@ public void download(String url, Path target) {
if (url.startsWith("http")) {

HttpRequest request = HttpRequest.newBuilder().uri(URI.create(url)).GET().build();
HttpResponse<InputStream> response = this.client.send(request, HttpResponse.BodyHandlers.ofInputStream());
HttpClient client = createHttpClient(url);
HttpResponse<InputStream> response = client.send(request, HttpResponse.BodyHandlers.ofInputStream());

if (response.statusCode() == 200) {
downloadFileWithProgressBar(url, target, response);
Expand Down
47 changes: 47 additions & 0 deletions cli/src/main/java/com/devonfw/tools/ide/network/ProxyConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package com.devonfw.tools.ide.network;

import com.devonfw.tools.ide.context.IdeContext;

import java.net.MalformedURLException;
import java.net.URL;

/**
* Class responsible for parsing and storing the host and port information from a given proxy URL.
*/
public class ProxyConfig {

private final IdeContext context;

private String host;

private int port;

ProxyConfig(String proxyUrl, IdeContext context) {

this.context = context;

try {
URL url = new URL(proxyUrl);
host = url.getHost();
port = url.getPort();
} catch (MalformedURLException e) {
this.context.warning(ProxyContext.PROXY_FORMAT_WARNING_MESSAGE);
}
}

/**
* @return a {@link String} representing the host of the proxy
*/
public String getHost() {

return host;
}

/**
* @return an {@code int} representing the port of the proxy
*/
public int getPort() {

return port;
}
}
96 changes: 96 additions & 0 deletions cli/src/main/java/com/devonfw/tools/ide/network/ProxyContext.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
package com.devonfw.tools.ide.network;

import com.devonfw.tools.ide.context.IdeContext;

import java.net.InetSocketAddress;
import java.net.Proxy;

/**
* Class for handling system proxy settings. This class is responsible for detecting and managing the proxy configurations for HTTP and HTTPS protocols based on
* the system's environment variables.
*/
public class ProxyContext {

private final IdeContext context;

private static final String HTTP_PROXY = "http_proxy";

private static final String HTTPS_PROXY = "https_proxy";

private static final String PROXY_DOCUMENTATION_PAGE = "https://github.com/devonfw/IDEasy/blob/main/documentation/proxy-support.adoc";

static final String PROXY_FORMAT_WARNING_MESSAGE =
"Proxy configuration detected, but the formatting appears to be incorrect. Proxy configuration will be skipped.\n"
+ "Please note that IDEasy can detect a proxy only if the corresponding environmental variables are properly formatted. "
+ "For further details, see " + PROXY_DOCUMENTATION_PAGE;

final private ProxyConfig httpProxyConfig;

final private ProxyConfig httpsProxyConfig;

/**
* Class to detect system proxy configurations
*
* @param context the {@link IdeContext}
*/
public ProxyContext(IdeContext context) {

this.context = context;
this.httpProxyConfig = initializeProxyConfig(HTTP_PROXY);
this.httpsProxyConfig = initializeProxyConfig(HTTPS_PROXY);
}

private ProxyConfig initializeProxyConfig(String proxyEnvVariable) {

String proxyUrl = System.getenv(proxyEnvVariable);
if (proxyUrl == null) {
proxyUrl = System.getenv(proxyEnvVariable.toUpperCase());
}
return (proxyUrl != null && !proxyUrl.isEmpty()) ? new ProxyConfig(proxyUrl, context) : null;
}

/**
* Retrieves the system proxy for a given URL.
*
* @param url The URL of the request for which to detect a proxy. This is used to determine the corresponding proxy based on the protocol.
* @return A {@link Proxy} object representing the system proxy for the given URL, or {@link Proxy#NO_PROXY} if no valid proxy is found or if the proxy
* configuration is invalid.
*/
public Proxy getProxy(String url) {

ProxyConfig proxyConfig = getProxyConfig(url);
if (proxyConfig != null) {
String proxyHost = proxyConfig.getHost();
int proxyPort = proxyConfig.getPort();

if (proxyHost != null && !proxyHost.isEmpty() && proxyPort > 0 && proxyPort <= 65535) {
InetSocketAddress proxyAddress = new InetSocketAddress(proxyHost, proxyPort);
if (proxyAddress.isUnresolved()) {
this.context.warning(ProxyContext.PROXY_FORMAT_WARNING_MESSAGE);
return Proxy.NO_PROXY;
}
return new Proxy(Proxy.Type.HTTP, proxyAddress);
}
}
return Proxy.NO_PROXY;
}

/**
* Retrieves the appropriate {@link ProxyConfig} object based on the given request URL.
*
* @param url a {@link String} representing the URL for which the related proxy is to be determined
* @return a {@link ProxyConfig} object with the correct settings, or {@code null} if the URL is malformed
*/
public ProxyConfig getProxyConfig(String url) {

if (url.startsWith("http://")) {
return httpProxyConfig;
} else if (url.startsWith("https://")) {
return httpsProxyConfig;
} else {
this.context.warning("Download URL wrongly formatted: " + url);
return null;
}
}
}

Loading

0 comments on commit 430fff0

Please sign in to comment.