Skip to content

Commit

Permalink
Support ClientProperties.PROXY_URI & al in HttpUrlConnector (#5091)
Browse files Browse the repository at this point in the history
* Support for proxy in HttpUrlConnector

Signed-off-by: Jorge Bescos Gascon <[email protected]>
  • Loading branch information
jbescos committed Jul 1, 2022
1 parent e114d5e commit a83d288
Show file tree
Hide file tree
Showing 9 changed files with 116 additions and 35 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2021 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
Expand Down Expand Up @@ -520,4 +520,19 @@ public static <T> T getValue(final Map<String, ?> properties, final String key,
public static <T> T getValue(final Map<String, ?> properties, final String key, final Class<T> type) {
return PropertiesHelper.getValue(properties, key, type, null);
}

/**
* Get the value of the specified property. If null, it will obtain it from System property.
* <p/>
* If the property is not set the method will return {@code null}.
*
* @param properties Map of properties to get the property value from.
* @param key Name of the property.
* @param systemKey Name of the System property.
* @return Value of the property or {@code null}.
* @since 2.37
*/
public static String getValue(Map<String, ?> properties, String key, String systemKey) {
return PropertiesHelper.getValue(properties, key, System.getProperty(systemKey), String.class, null);
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, 2019 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2013, 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
Expand All @@ -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;
Expand Down Expand Up @@ -267,6 +268,23 @@ public interface ConnectionFactory {
* @throws java.io.IOException in case the connection cannot be provided.
*/
public HttpURLConnection getConnection(URL url) throws IOException;

/**
* Get a {@link java.net.HttpURLConnection} for a given URL.
* <p>
* Implementation of the method MUST be thread-safe and MUST ensure that
* a dedicated {@link java.net.HttpURLConnection} instance is returned for concurrent
* requests.
* </p>
*
* @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.
*/
default HttpURLConnection getConnection(URL url, Proxy proxy) throws IOException {
return (proxy == null) ? getConnection(url) : (HttpURLConnection) url.openConnection(proxy);
}
}

private static class DefaultConnectionFactory implements ConnectionFactory {
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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;
Expand All @@ -37,17 +42,19 @@
import java.util.concurrent.Future;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Pattern;
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.ExternalProperties;
import org.glassfish.jersey.client.ClientProperties;
import org.glassfish.jersey.client.ClientRequest;
import org.glassfish.jersey.client.ClientResponse;
Expand Down Expand Up @@ -314,10 +321,37 @@ protected void secureConnection(final JerseyClient client, final HttpURLConnecti
}
}

private static URI getProxyUriValue(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 ClientResponse _apply(final ClientRequest request) throws IOException {
final HttpURLConnection uc;

uc = this.connectionFactory.getConnection(request.getUri().toURL());
Proxy proxy = null;
Object proxyUri = request.getConfiguration().getProperties().get(ClientProperties.PROXY_URI);
if (proxyUri != null) {
URI uri = getProxyUriValue(proxyUri);
String username = ClientProperties.getValue(request.getConfiguration().getProperties(),
ClientProperties.PROXY_USERNAME, ExternalProperties.HTTP_PROXY_USER);
String password = ClientProperties.getValue(request.getConfiguration().getProperties(),
ClientProperties.PROXY_PASSWORD, ExternalProperties.HTTP_PROXY_PASSWORD);
if (username != null) {
StringBuilder auth = new StringBuilder().append(username).append(":");
if (password != null) {
auth.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(uri.getHost(), uri.getPort()));
}
uc = this.connectionFactory.getConnection(request.getUri().toURL(), proxy);
uc.setDoInput(true);

final String httpMethod = request.getMethod();
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, 2018 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2013, 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
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2020 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2020, 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
Expand Down Expand Up @@ -32,11 +32,21 @@ public final class ExternalProperties {
public static final String HTTP_PROXY_PORT = "http.proxyPort";

/**
* Property used to indicates the hosts that should be accessed
* Property used to indicate the hosts that should be accessed
* without going through the proxy.
*/
public static final String HTTP_NON_PROXY_HOSTS = "http.nonProxyHosts";

/**
* Property used to specify the user name to authenticate with the proxy.
*/
public static final String HTTP_PROXY_USER = "http.proxyUser";

/**
* Property used to specify the password to authenticate with the proxy.
*/
public static final String HTTP_PROXY_PASSWORD = "http.proxyPassword";

/**
* Prevent instantiation.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
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;
Expand Down Expand Up @@ -72,6 +73,7 @@ public static List<Object[]> testData() {
{Apache5ConnectorProvider.class},
{JettyConnectorProvider.class},
{NettyConnectorProvider.class},
{HttpUrlConnectorProvider.class},
});
}

Expand Down Expand Up @@ -110,7 +112,8 @@ public void testGetSuccess() {
client().property(ClientProperties.PROXY_USERNAME, ProxyTest.PROXY_USERNAME);
client().property(ClientProperties.PROXY_PASSWORD, ProxyTest.PROXY_PASSWORD);
Response response = target("proxyTest").request().get();
assertEquals(200, response.getStatus());
response.bufferEntity();
assertEquals(response.readEntity(String.class), 200, response.getStatus());
}

private static Server server;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2020 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2020, 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
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2020 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2020, 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
Expand All @@ -16,28 +16,11 @@

package org.glassfish.jersey.tests.integration.jersey4003;

import org.glassfish.jersey.client.ClientConfig;
import org.glassfish.jersey.client.HttpUrlConnectorProvider;
import org.glassfish.jersey.client.JerseyClientBuilder;
import org.glassfish.jersey.client.JerseyCompletionStageRxInvoker;

import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;

import org.mockito.Mockito;

import javax.ws.rs.client.Client;
import javax.ws.rs.client.Entity;
import javax.ws.rs.client.InvocationCallback;
import javax.ws.rs.client.ResponseProcessingException;
import javax.ws.rs.core.GenericType;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.Proxy;
import java.net.URL;
import java.util.concurrent.CompletionStage;
import java.util.concurrent.CountDownLatch;
Expand All @@ -46,6 +29,23 @@
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;

import javax.ws.rs.client.Client;
import javax.ws.rs.client.Entity;
import javax.ws.rs.client.InvocationCallback;
import javax.ws.rs.client.ResponseProcessingException;
import javax.ws.rs.core.GenericType;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

import org.glassfish.jersey.client.ClientConfig;
import org.glassfish.jersey.client.HttpUrlConnectorProvider;
import org.glassfish.jersey.client.JerseyClientBuilder;
import org.glassfish.jersey.client.JerseyCompletionStageRxInvoker;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mockito;

public class LostResponseTest {

private static final String DUMMY_URL = "http://foo";
Expand All @@ -59,7 +59,7 @@ public void setup() throws IOException {
HttpUrlConnectorProvider.ConnectionFactory connectionFactory =
Mockito.mock(HttpUrlConnectorProvider.ConnectionFactory.class);
HttpURLConnection connection = Mockito.mock(HttpURLConnection.class);
Mockito.when(connectionFactory.getConnection(Mockito.any(URL.class))).thenReturn(connection);
Mockito.when(connectionFactory.getConnection(Mockito.any(URL.class), Mockito.any())).thenReturn(connection);

OutputStream outputStream = Mockito.mock(OutputStream.class);
Mockito.when(connection.getOutputStream()).thenReturn(outputStream);
Expand Down

0 comments on commit a83d288

Please sign in to comment.