4

I'm trying to understand how the ProxySelector class works. My current code looks like this:

    URI uri = new URI("http://google.com");
    proxySelector.select(uri);

I understand that when calling proxySelector.select(uri); this is suppose to return a list of proxies for the respective URI. But I don't see how to set the proxy for each URI.

I know I could set the default proxy using the setDefault() method but as far as I understand this will set the system wide proxy, not the proxy for a specific URI.

I might be missing some basic point here but how do I set one proxy for url A (such as http://google.com) and a different proxy for url B (such as http://ebay.com) and then have the system automatically select the correct proxy each time it connects to the corresponding url?

Michal Foksa
  • 11,225
  • 9
  • 50
  • 68
Amit Asaf
  • 155
  • 1
  • 11
  • See: https://stackoverflow.com/questions/34319679/using-proxy-with-httpcomponentsclienthttprequestfactory-for-resttemplate/34432952#34432952 – Michal Foksa Nov 07 '17 at 05:47
  • Thanks. So basically you need to implement the logic of which proxy is selected in the "select" method? How to you actually connect to the URL with the proxy by using System.setProperty()? – Amit Asaf Nov 07 '17 at 18:48

2 Answers2

5
  1. Override ProxySelector.select(URI uri) method where you implement custom logic to choose right proxy or list of proxies for the URI.

  2. either set the new, custom, ProxySelector as system wide by calling ProxySelector.setDefault(customProxySelector).

    Any subclass of URLConnection will use ProxySelector, e.g.:

    URLConnection conn = url.openConnection();
    
  3. or configure framework you are going to use to invoke remote URI, e.g Spring RestTemplate:

    HttpRoutePlanner routePlanner = new SystemDefaultRoutePlanner(new MyProxySelector());
    
    HttpComponentsClientHttpRequestFactory clientHttpRequestFactory 
        = new HttpComponentsClientHttpRequestFactory(
            HttpClientBuilder.create()
                .setRoutePlanner(routePlanner)
                .build());
    restTemplate = new RestTemplate(clientHttpRequestFactory);
    

It is good practice to fallback to default ProxySelector in custom select(URI uri) in case the custom logic does not determine suitable proxy for the uri.

See my other answer for ProxySelector example.

Networking and proxies is well explained in Java Networking and Proxies (paragraph 4 ProxySelector) and ProxySelector Java docs.

Community
  • 1
  • 1
Michal Foksa
  • 11,225
  • 9
  • 50
  • 68
  • I'm trying to use ProxySelector class in conjunction with ebay API sdk - if I set the proxy can I guarantee all calls to ebay will be routed through a proxy? – Amit Asaf Nov 08 '17 at 02:20
  • My guess is yes, but I do not have experience with ebay API. I am backing my opinion on http://developer.ebay.com/DevZone/javasdk-jaxb/docs/readme.htm#631 where they introduce custom `ProxySelector`. Which is (if I can trust following source code https://github.com/prestonvanloon/ebaysdkcore/blob/master/src/main/java/com/ebay/sdk/util/SdkProxySelector.java ) nothing just a selector leading to single proxy for each URL. – Michal Foksa Nov 08 '17 at 06:22
2

Actually, that works pretty well without any reflection, by just using an enhanced ProxySelector, that supports whitelisting for specific urls and passes the rest through to a delegate (aka the default) ProxySelector.

public class DelegatingProxySelector extends ProxySelector {

    private final Set<URI> allProxiedUri = new HashSet<>();

    private String proxyHost;
    private Integer proxyPort;

    private final ProxySelector delegate;

    public DelegatingProxySelector(
        String proxyHost, Integer proxyPort, ProxySelector delegate) {
        this.proxyHost = proxyHost;
        this.proxyPort = proxyPort;
        this.delegate = delegate;
    }

    @Override
    public List<Proxy> select(final URI uri) {
        if (allProxiedUri.contains(uri)) {
            final InetSocketAddress proxyAddress = InetSocketAddress
                .createUnresolved(proxyHost, proxyPort);
            return Collections.singletonList(new Proxy(Type.HTTP, proxyAddress));
        }
        return delegate.select(uri);
    }

    @Override
    public void connectFailed(final URI uri, final SocketAddress sa, final IOException ioe) {
        System.err.println("Unable to reach uri " + uri + " via proxy: " + ioe.getMessage());
    }
    
    public void addProxiedUri(URI uri) {
        allProxiedUri.add(uri);
    }
}

...

final DelegatingProxySelector delegatingProxySelector = new DelegatingProxySelector("localhost", 3128, ProxySelector.getDefault());
ProxySelector.setDefault(delegatingProxySelector);