diff --git a/core/src/main/java/org/jclouds/Constants.java b/core/src/main/java/org/jclouds/Constants.java index 9204863fe7..110d74732d 100644 --- a/core/src/main/java/org/jclouds/Constants.java +++ b/core/src/main/java/org/jclouds/Constants.java @@ -145,6 +145,14 @@ public interface Constants { */ public static final String PROPERTY_PROXY_PASSWORD = "jclouds.proxy-password"; + /** + * Boolean property. Default true. + *

+ * If a proxy server is configured, it will be used for all types of schemes. + * Set to false to not use a proxy server for sockets (such as ssh access). + */ + public static final String PROPERTY_PROXY_FOR_SOCKETS = "jclouds.proxy-for-sockets"; + /** * Integer property. *

diff --git a/core/src/main/java/org/jclouds/proxy/ProxyForURI.java b/core/src/main/java/org/jclouds/proxy/ProxyForURI.java index 09e046429d..e2e4220233 100644 --- a/core/src/main/java/org/jclouds/proxy/ProxyForURI.java +++ b/core/src/main/java/org/jclouds/proxy/ProxyForURI.java @@ -20,6 +20,7 @@ package org.jclouds.proxy; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.collect.Iterables.getLast; +import static org.jclouds.Constants.PROPERTY_PROXY_FOR_SOCKETS; import java.net.Authenticator; import java.net.InetSocketAddress; @@ -29,6 +30,7 @@ import java.net.ProxySelector; import java.net.SocketAddress; import java.net.URI; +import javax.inject.Named; import javax.inject.Singleton; import org.jclouds.domain.Credentials; @@ -45,6 +47,10 @@ import com.google.inject.Inject; public class ProxyForURI implements Function { private final ProxyConfig config; + @Inject(optional = true) + @Named(PROPERTY_PROXY_FOR_SOCKETS) + private boolean useProxyForSockets = true; + @VisibleForTesting @Inject ProxyForURI(ProxyConfig config) { @@ -62,7 +68,9 @@ public class ProxyForURI implements Function { */ @Override public Proxy apply(URI endpoint) { - if (config.useSystem()) { + if (!useProxyForSockets && "socket".equals(endpoint.getScheme())) { + return Proxy.NO_PROXY; + } else if (config.useSystem()) { System.setProperty("java.net.useSystemProxies", "true"); Iterable proxies = ProxySelector.getDefault().select(endpoint); return getLast(proxies); diff --git a/core/src/test/java/org/jclouds/proxy/ProxyForURITest.java b/core/src/test/java/org/jclouds/proxy/ProxyForURITest.java new file mode 100644 index 0000000000..f6a0218615 --- /dev/null +++ b/core/src/test/java/org/jclouds/proxy/ProxyForURITest.java @@ -0,0 +1,153 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jclouds.proxy; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; + +import java.lang.reflect.Field; +import java.net.InetSocketAddress; +import java.net.Proxy; +import java.net.Proxy.Type; +import java.net.URI; +import java.net.URISyntaxException; + +import org.jclouds.domain.Credentials; +import org.testng.annotations.Test; + +import com.google.common.base.Optional; +import com.google.common.net.HostAndPort; + +public class ProxyForURITest { + + private Optional noHostAndPort = Optional.absent(); + private Optional noCreds = Optional.absent(); + private Optional hostAndPort = Optional.of(HostAndPort.fromParts("proxy.example.com", 8080)); + private Optional creds = Optional.of(new Credentials("user", "pwd")); + + private class MyProxyConfig implements ProxyConfig { + private boolean useSystem; + private Type type; + private Optional proxy; + private Optional credentials; + + MyProxyConfig(boolean useSystem, Type type, Optional proxy, Optional credentials) { + this.useSystem = useSystem; + this.type = type; + this.proxy = proxy; + this.credentials = credentials; + } + + @Override + public boolean useSystem() { + return useSystem; + } + + @Override + public Type getType() { + return type; + } + + @Override + public Optional getProxy() { + return proxy; + } + + @Override + public Optional getCredentials() { + return credentials; + } + } + + @Test + public void testDontUseProxyForSockets() throws Exception { + ProxyConfig config = new MyProxyConfig(false, Proxy.Type.HTTP, hostAndPort, creds); + ProxyForURI proxy = new ProxyForURI(config); + Field useProxyForSockets = proxy.getClass().getDeclaredField("useProxyForSockets"); + useProxyForSockets.setAccessible(true); + useProxyForSockets.setBoolean(proxy, false); + URI uri = new URI("socket://ssh.example.com:22"); + assertEquals(proxy.apply(uri), Proxy.NO_PROXY); + } + + @Test + public void testUseProxyForSockets() throws Exception { + ProxyConfig config = new MyProxyConfig(false, Proxy.Type.HTTP, hostAndPort, creds); + ProxyForURI proxy = new ProxyForURI(config); + URI uri = new URI("socket://ssh.example.com:22"); + assertEquals(proxy.apply(uri), new Proxy(Proxy.Type.HTTP, new InetSocketAddress("proxy.example.com", 8080))); + } + + @Test + public void testUseProxyForSocketsSettingShouldntAffectHTTP() throws Exception { + ProxyConfig config = new MyProxyConfig(false, Proxy.Type.HTTP, hostAndPort, creds); + ProxyForURI proxy = new ProxyForURI(config); + Field useProxyForSockets = proxy.getClass().getDeclaredField("useProxyForSockets"); + useProxyForSockets.setAccessible(true); + useProxyForSockets.setBoolean(proxy, false); + URI uri = new URI("http://example.com/file"); + assertEquals(proxy.apply(uri), new Proxy(Proxy.Type.HTTP, new InetSocketAddress("proxy.example.com", 8080))); + } + + @Test + public void testHTTPDirect() throws URISyntaxException { + ProxyConfig config = new MyProxyConfig(false, Proxy.Type.DIRECT, noHostAndPort, noCreds); + URI uri = new URI("http://example.com/file"); + assertEquals(new ProxyForURI(config).apply(uri), Proxy.NO_PROXY); + } + + @Test + public void testHTTPSDirect() throws URISyntaxException { + ProxyConfig config = new MyProxyConfig(false, Proxy.Type.DIRECT, noHostAndPort, noCreds); + URI uri = new URI("https://example.com/file"); + assertEquals(new ProxyForURI(config).apply(uri), Proxy.NO_PROXY); + } + + @Test + public void testFTPDirect() throws URISyntaxException { + ProxyConfig config = new MyProxyConfig(false, Proxy.Type.DIRECT, noHostAndPort, noCreds); + URI uri = new URI("ftp://ftp.example.com/file"); + assertEquals(new ProxyForURI(config).apply(uri), Proxy.NO_PROXY); + } + + @Test + public void testSocketDirect() throws URISyntaxException { + ProxyConfig config = new MyProxyConfig(false, Proxy.Type.DIRECT, noHostAndPort, noCreds); + URI uri = new URI("socket://ssh.example.com:22"); + assertEquals(new ProxyForURI(config).apply(uri), Proxy.NO_PROXY); + } + + @Test + public void testHTTPThroughHTTPProxy() throws URISyntaxException { + ProxyConfig config = new MyProxyConfig(false, Proxy.Type.HTTP, hostAndPort, creds); + URI uri = new URI("http://example.com/file"); + assertEquals(new ProxyForURI(config).apply(uri), new Proxy(Proxy.Type.HTTP, new InetSocketAddress( + "proxy.example.com", 8080))); + } + + @Test + public void testHTTPThroughSystemProxy() throws URISyntaxException { + ProxyConfig config = new MyProxyConfig(true, Proxy.Type.DIRECT, noHostAndPort, noCreds); + URI uri = new URI("http://example.com/file"); + // could return a proxy, could return NO_PROXY, depends on the tester's + // environment + assertNotNull(new ProxyForURI(config).apply(uri)); + } + +}