From f850e5e1be272ca977561a25b4b75c8d1d496d84 Mon Sep 17 00:00:00 2001
From: Jorge Bescos Gascon
Date: Wed, 22 Jun 2022 08:44:00 +0200
Subject: [PATCH] Support for proxy in HttpUrlConnector
Signed-off-by: Jorge Bescos Gascon
---
.../client/HttpUrlConnectorProvider.java | 8 ++-
.../client/internal/HttpUrlConnector.java | 63 ++++++++++++++++---
.../client/internal/localization.properties | 3 +-
.../jersey/client/HttpUrlConnectorTest.java | 18 +++---
.../connector/proxy/ProxySelectorTest.java | 46 ++++++++++++++
.../e2e/client/connector/proxy/ProxyTest.java | 5 +-
.../ssl/SslHttpUrlConnectorTest.java | 16 ++---
7 files changed, 130 insertions(+), 29 deletions(-)
diff --git a/core-client/src/main/java/org/glassfish/jersey/client/HttpUrlConnectorProvider.java b/core-client/src/main/java/org/glassfish/jersey/client/HttpUrlConnectorProvider.java
index 7389781ece..0dab495299 100644
--- a/core-client/src/main/java/org/glassfish/jersey/client/HttpUrlConnectorProvider.java
+++ b/core-client/src/main/java/org/glassfish/jersey/client/HttpUrlConnectorProvider.java
@@ -18,6 +18,7 @@
import java.io.IOException;
import java.net.HttpURLConnection;
+import java.net.Proxy;
import java.net.URL;
import java.util.Map;
import java.util.logging.Logger;
@@ -263,17 +264,18 @@ public interface ConnectionFactory {
*
*
* @param url the endpoint URL.
+ * @param proxy the configured proxy or null.
* @return the {@link java.net.HttpURLConnection}.
* @throws java.io.IOException in case the connection cannot be provided.
*/
- public HttpURLConnection getConnection(URL url) throws IOException;
+ public HttpURLConnection getConnection(URL url, Proxy proxy) throws IOException;
}
private static class DefaultConnectionFactory implements ConnectionFactory {
@Override
- public HttpURLConnection getConnection(final URL url) throws IOException {
- return (HttpURLConnection) url.openConnection();
+ public HttpURLConnection getConnection(URL url, Proxy proxy) throws IOException {
+ return (HttpURLConnection) (proxy != null ? url.openConnection(proxy) : url.openConnection());
}
}
diff --git a/core-client/src/main/java/org/glassfish/jersey/client/internal/HttpUrlConnector.java b/core-client/src/main/java/org/glassfish/jersey/client/internal/HttpUrlConnector.java
index 443c8573ed..21d2cae3ba 100644
--- a/core-client/src/main/java/org/glassfish/jersey/client/internal/HttpUrlConnector.java
+++ b/core-client/src/main/java/org/glassfish/jersey/client/internal/HttpUrlConnector.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, 2021 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2022 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
@@ -21,13 +21,18 @@
import java.io.InputStream;
import java.lang.reflect.Field;
import java.net.HttpURLConnection;
+import java.net.InetSocketAddress;
import java.net.ProtocolException;
+import java.net.Proxy;
+import java.net.Proxy.Type;
import java.net.SocketTimeoutException;
import java.net.URI;
import java.net.URISyntaxException;
import java.security.AccessController;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
+import java.util.Arrays;
+import java.util.Base64;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
@@ -39,15 +44,15 @@
import java.util.logging.Logger;
import java.util.stream.Collectors;
+import javax.net.ssl.HostnameVerifier;
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.SSLSocketFactory;
import javax.ws.rs.ProcessingException;
import javax.ws.rs.client.Client;
+import javax.ws.rs.core.Configuration;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;
-import javax.net.ssl.HostnameVerifier;
-import javax.net.ssl.HttpsURLConnection;
-import javax.net.ssl.SSLSocketFactory;
-
import org.glassfish.jersey.client.ClientProperties;
import org.glassfish.jersey.client.ClientRequest;
import org.glassfish.jersey.client.ClientResponse;
@@ -314,10 +319,54 @@ protected void secureConnection(final JerseyClient client, final HttpURLConnecti
}
}
+ private URI getProxyUri(Object proxy) {
+ if (proxy instanceof URI) {
+ return (URI) proxy;
+ } else if (proxy instanceof String) {
+ return URI.create((String) proxy);
+ } else {
+ throw new ProcessingException(LocalizationMessages.WRONG_PROXY_URI_TYPE(ClientProperties.PROXY_URI));
+ }
+ }
+
+ private String getFromConfigOrSystem(ClientRequest request, String clientProperty, String systemProperty) {
+ String result = request.resolveProperty(clientProperty, String.class);
+ if (result == null) {
+ result = System.getProperty(systemProperty);
+ }
+ return result;
+ }
+
+ private URI getProxyUri(ClientRequest request) {
+ Configuration config = request.getConfiguration();
+ Object proxyUri = config.getProperty(ClientProperties.PROXY_URI);
+ if (proxyUri == null) {
+ String proxyHost = System.getProperty("http.proxyHost");
+ String proxyPort = System.getProperty("http.proxyPort");
+ if (proxyHost != null && proxyPort != null) {
+ return URI.create(proxyHost + ":" + proxyPort);
+ }
+ } else {
+ return getProxyUri(proxyUri);
+ }
+ return null;
+ }
+
private ClientResponse _apply(final ClientRequest request) throws IOException {
final HttpURLConnection uc;
-
- uc = this.connectionFactory.getConnection(request.getUri().toURL());
+ Proxy proxy = null;
+ URI proxyUri = getProxyUri(request);
+ if (proxyUri != null) {
+ String username = getFromConfigOrSystem(request, ClientProperties.PROXY_USERNAME, "http.proxyUser");
+ String password = getFromConfigOrSystem(request, ClientProperties.PROXY_PASSWORD, "http.proxyPassword");
+ if (username != null && password != null) {
+ StringBuilder auth = new StringBuilder().append(username).append(":").append(password);
+ String encoded = "Basic " + Base64.getEncoder().encodeToString(auth.toString().getBytes());
+ request.getHeaders().put("Proxy-Authorization", Arrays.asList(encoded));
+ }
+ proxy = new Proxy(Type.HTTP, new InetSocketAddress(proxyUri.getHost(), proxyUri.getPort()));
+ }
+ uc = this.connectionFactory.getConnection(request.getUri().toURL(), proxy);
uc.setDoInput(true);
final String httpMethod = request.getMethod();
diff --git a/core-client/src/main/resources/org/glassfish/jersey/client/internal/localization.properties b/core-client/src/main/resources/org/glassfish/jersey/client/internal/localization.properties
index 4bc0ae8e30..8e3823cde3 100644
--- a/core-client/src/main/resources/org/glassfish/jersey/client/internal/localization.properties
+++ b/core-client/src/main/resources/org/glassfish/jersey/client/internal/localization.properties
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2012, 2019 Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2012, 2022 Oracle and/or its affiliates. All rights reserved.
#
# This program and the accompanying materials are made available under the
# terms of the Eclipse Public License v. 2.0, which is available at
@@ -84,3 +84,4 @@ error.request.cancelled=Request cancelled by the client call.
error.listener.init=ClientLifecycleListener {0} failed to initialize properly.
error.listener.close=ClientLifecycleListener {0} failed to close properly.
error.shutdownhook.close=Client shutdown hook {0} failed.
+wrong.proxy.uri.type=The proxy URI ("{0}") property MUST be an instance of String or URI.
diff --git a/core-client/src/test/java/org/glassfish/jersey/client/HttpUrlConnectorTest.java b/core-client/src/test/java/org/glassfish/jersey/client/HttpUrlConnectorTest.java
index 7cd91213bd..b7a7616b65 100644
--- a/core-client/src/test/java/org/glassfish/jersey/client/HttpUrlConnectorTest.java
+++ b/core-client/src/test/java/org/glassfish/jersey/client/HttpUrlConnectorTest.java
@@ -16,11 +16,14 @@
package org.glassfish.jersey.client;
+import static org.junit.Assert.assertEquals;
+
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.ProtocolException;
+import java.net.Proxy;
import java.net.SocketTimeoutException;
import java.net.URI;
import java.net.URL;
@@ -30,6 +33,10 @@
import java.util.List;
import java.util.Map;
+import javax.net.ssl.HostnameVerifier;
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.SSLPeerUnverifiedException;
+import javax.net.ssl.SSLSocketFactory;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Entity;
@@ -39,17 +46,10 @@
import javax.ws.rs.core.Link;
import javax.ws.rs.core.Response;
-import javax.net.ssl.HostnameVerifier;
-import javax.net.ssl.HttpsURLConnection;
-import javax.net.ssl.SSLPeerUnverifiedException;
-import javax.net.ssl.SSLSocketFactory;
-
import org.glassfish.jersey.client.internal.HttpUrlConnector;
-
import org.junit.Assert;
import org.junit.Ignore;
import org.junit.Test;
-import static org.junit.Assert.assertEquals;
/**
* Various tests for the default client connector.
@@ -91,7 +91,7 @@ public void testConnectionTimeoutNoEntity() {
public void testResolvedRequestUri() {
HttpUrlConnectorProvider.ConnectionFactory factory = new HttpUrlConnectorProvider.ConnectionFactory() {
@Override
- public HttpURLConnection getConnection(URL endpointUrl) throws IOException {
+ public HttpURLConnection getConnection(URL endpointUrl, Proxy proxy) throws IOException {
HttpURLConnection result = (HttpURLConnection) endpointUrl.openConnection();
return wrapRedirectedHttp(result);
}
@@ -435,7 +435,7 @@ public void testSSLConnection() {
ClientRequest request = client.target("https://localhost:8080").request().buildGet().request();
HttpUrlConnectorProvider.ConnectionFactory factory = new HttpUrlConnectorProvider.ConnectionFactory() {
@Override
- public HttpURLConnection getConnection(URL endpointUrl) throws IOException {
+ public HttpURLConnection getConnection(URL endpointUrl, Proxy proxy) throws IOException {
HttpURLConnection result = (HttpURLConnection) endpointUrl.openConnection();
return wrapNoContentHttps(result);
}
diff --git a/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/connector/proxy/ProxySelectorTest.java b/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/connector/proxy/ProxySelectorTest.java
index 4580facf24..facbcf5f58 100644
--- a/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/connector/proxy/ProxySelectorTest.java
+++ b/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/connector/proxy/ProxySelectorTest.java
@@ -24,6 +24,8 @@
import org.glassfish.jersey.apache.connector.ApacheConnectorProvider;
import org.glassfish.jersey.apache5.connector.Apache5ConnectorProvider;
import org.glassfish.jersey.client.ClientConfig;
+import org.glassfish.jersey.client.ClientProperties;
+import org.glassfish.jersey.client.HttpUrlConnectorProvider;
import org.glassfish.jersey.client.spi.ConnectorProvider;
import org.glassfish.jersey.jetty.connector.JettyConnectorProvider;
import org.glassfish.jersey.netty.connector.NettyConnectorProvider;
@@ -44,6 +46,7 @@
import javax.ws.rs.core.Response;
import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
+import java.util.Base64;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@@ -57,6 +60,8 @@
@RunWith(Parameterized.class)
public class ProxySelectorTest {
private static final String NO_PASS = "no-pass";
+ private static final String PROXY_USERNAME = "proxy-user";
+ private static final String PROXY_PASSWORD = "proxy-password";
@Parameterized.Parameters(name = "{index}: {0}")
public static List