httpclientapache-httpclient-5.x

Migrate http client 4 & 5 using SOCKS


I'd like to migrate from HTTP Client 4 to 5 using SOCKS. Here's my code with HTTP Client 4:

                    InetSocketAddress socksaddr = new InetSocketAddress((String) call.props.get(PROXY_HOST_NAME),
                        Integer.parseInt((String) call.props.get(PROXY_PORT)));

                Lookup<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder
                        .<ConnectionSocketFactory>create()
                        .register(HTTP, new SocksCompatibleConnectionSocketFactory(socksaddr))
                        .register(HTTPS, new SocksCompatibleSSLConnectionSocketFactory(socksaddr,
                                (javax.net.ssl.SSLSocketFactory) SSLSocketFactory.getDefault()))
                        .build();
                BasicHttpClientConnectionManager basicmgr = new BasicHttpClientConnectionManager(
                        socketFactoryRegistry);
                final CloseableHttpClient client = HttpClientBuilder.create().setConnectionManager(basicmgr)
                        .setDefaultRequestConfig(RequestConfig.custom()
                                .setConnectTimeout(MxParam.getIntWithDefaultValueNoException(WSTIMEOUT, 30000))
                                .setSocketTimeout(MxParam.getIntWithDefaultValueNoException(WSTIMEOUT, 30000))
                                .build())
                        .setConnectionManagerShared(true)
                        .useSystemProperties()
                        .setMaxConnPerRoute(MxParam.getIntWithDefaultValueNoException(MAXCONECTIONPERHOST, 20))
                        .setMaxConnTotal(MxParam.getIntWithDefaultValueNoException(MAXTOTALCONNECTION, 20))
                        .build();

With the 2 following classes:

static class SocksCompatibleConnectionSocketFactory extends PlainConnectionSocketFactory {

    private final InetSocketAddress socksAddress;

    public SocksCompatibleConnectionSocketFactory(InetSocketAddress socksAddress) {
        super();
        this.socksAddress = socksAddress;
    }

    @Override
    public Socket createSocket(HttpContext context) throws IOException {
        return new Socket(new Proxy(Proxy.Type.SOCKS, socksAddress));
    }
}

static class SocksCompatibleSSLConnectionSocketFactory extends SSLConnectionSocketFactory {
    final InetSocketAddress socksAddress;

    public SocksCompatibleSSLConnectionSocketFactory(final InetSocketAddress socksAddress,
            final SSLSocketFactory sslSocketFactory) {
        super(sslSocketFactory, split(System.getProperty("https.protocols")),
                split(System.getProperty("https.cipherSuites")), getDefaultHostnameVerifier());
        this.socksAddress = socksAddress;
    }

    @Override
    public Socket createSocket(final HttpContext context) throws IOException {
        return new Socket(new Proxy(Proxy.Type.SOCKS, socksAddress));
    }

    private static String[] split(final String s) {
        if (TextUtils.isBlank(s)) {
            return null;
        }
        return s.split(" *, *");
    }
}

I don't see what to do in order to use my SOCKS compatible socket factories, could you please help me ?


Solution

  • One no longer needs to do any of these. One can configure connection tunneling through a SOCKS proxy using SocketConfig

    
    final InetSocketAddress socksaddr = new InetSocketAddress("localhost", 1080);
    final PoolingHttpClientConnectionManager cm = PoolingHttpClientConnectionManagerBuilder.create()
            .setDefaultSocketConfig(SocketConfig.custom()
                    .setSocksProxyAddress(socksaddr)
                    .build())
            .build();
    try (final CloseableHttpClient httpclient = HttpClients.custom()
            .setConnectionManager(cm)
            .build()) {
    
        final HttpHost target = new HttpHost("http", "httpbin.org", 80);
        final HttpGet request = new HttpGet("/get");
    
        System.out.println("Executing request " + request.getMethod() + " " + request.getUri() +
                " via SOCKS proxy " + socksaddr);
        httpclient.execute(target, request, response -> {
            System.out.println("----------------------------------------");
            System.out.println(request + "->" + new StatusLine(response));
            EntityUtils.consume(response.getEntity());
            return null;
        });
    }