0

I'm using Apache httpclient 4.3.6 and httpcore 4.3.3 (bundled with opensaml 3.3.0). I'm attempting to fetch a web page through a proxy via HTTPS but get a SocketTimeoutException every time. HTTP connections work fine. The specific timeout doesn't matter; it just takes longer to fail with higher values.

Sample code:

public class TestGet {
    private static final int TIMEOUT = 7000;

    public static void main(String[] args) throws Exception {
        URL url   = new URL("https://www.google.com");
        URL proxy = new URL("https://myproxy:9090/");
        try {
            String s = get(url, proxy);
            System.out.println(s);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static String get(URL url, URL proxy) throws IOException, URISyntaxException {
        CloseableHttpClient client  = HttpClients.createDefault();
        HttpGet             request = new HttpGet(url.toURI());
        HttpHost            host    = null;

        if (proxy != null) {
            host = new HttpHost(proxy.getHost(), proxy.getPort(), proxy.getProtocol());
        }

        RequestConfig config = RequestConfig.custom()
            .setProxy(host)
            .setConnectionRequestTimeout(TIMEOUT)
            .setConnectTimeout(TIMEOUT)
            .setSocketTimeout(TIMEOUT)
            .build();
        request.setConfig(config);

        try {
            CloseableHttpResponse response = client.execute(request);
            try {
                System.out.println(response.getStatusLine());
                return EntityUtils.toString(response.getEntity());
            } finally {
                response.close();
            }
        } finally {
            client.close();
        }
    }
}

The exception is thrown when trying to connect to the proxy. The stack trace is

org.apache.http.conn.ConnectTimeoutException: Connect to <proxy> failed: Read timed out
    at org.apache.http.impl.conn.HttpClientConnectionOperator.connect(HttpClientConnectionOperator.java:134)
    at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.connect(PoolingHttpClientConnectionManager.java:319)
    at org.apache.http.impl.execchain.MainClientExec.establishRoute(MainClientExec.java:371)
    at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:219)
    at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:195)
    at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:86)
    at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:108)
    at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:184)
    at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:82)
    at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:106)
    at authentication.TestGet.get(TestGet.java:47)
    at authentication.TestGet.main(TestGet.java:22)
Caused by: java.net.SocketTimeoutException: Read timed out
    at java.net.SocketInputStream.socketRead0(Native Method)
    at java.net.SocketInputStream.socketRead(Unknown Source)
    at java.net.SocketInputStream.read(Unknown Source)
    at java.net.SocketInputStream.read(Unknown Source)
    at sun.security.ssl.InputRecord.readFully(Unknown Source)
    at sun.security.ssl.InputRecord.read(Unknown Source)
    at sun.security.ssl.SSLSocketImpl.readRecord(Unknown Source)
    at sun.security.ssl.SSLSocketImpl.performInitialHandshake(Unknown Source)
    at sun.security.ssl.SSLSocketImpl.startHandshake(Unknown Source)
    at sun.security.ssl.SSLSocketImpl.startHandshake(Unknown Source)
    at org.apache.http.conn.ssl.SSLConnectionSocketFactory.createLayeredSocket(SSLConnectionSocketFactory.java:290)
    at org.apache.http.conn.ssl.SSLConnectionSocketFactory.connectSocket(SSLConnectionSocketFactory.java:259)
    at org.apache.http.impl.conn.HttpClientConnectionOperator.connect(HttpClientConnectionOperator.java:125)
    ... 11 more

This looks a lot like Apache issue HTTPCLIENT-1478 which had to do with the socket timeout not being set. That bug was marked fixed in 4.3.4 (I'm using 4.3.6) and while some of the comments indicate that work-arounds are still necessary in later versions, they aren't working for me. More to the point, I've stepped into SSLConnectionSocketFactory.createConnection() and confirmed that the socket timeout is being set to a non-zero value.

I'm stuck. I don't know why the connection is failing and haven't been able to step any deeper than the call to SSLSocketImpl.startHandshake() to troubleshoot. What could be wrong, and how do I fix it?

Michael Carman
  • 30,628
  • 10
  • 74
  • 122
  • What happens if you set an infinite socket timeout? It can well be that the server side process gets stuck in a middle of SSL handshake and stops sending any data to the client. – ok2c Sep 21 '17 at 12:47

2 Answers2

4

Don't use .setConnectionRequestTimeout(TIMEOUT)

Alternatively, wait a long time and see what happens.

Read this for more information.

Scrambo
  • 579
  • 5
  • 17
White Druid
  • 295
  • 1
  • 12
1

[Answer by question author; may be of limited applicability to others]

Confirm that the proxy server supports HTTPS. It may expect plain HTTP even though HTTPS is used on the connection to the target server. If the proxy doesn't support HTTPS it won't respond to the client hello message; thus resulting in a socket timeout.

Setting the javax.net.debug system property to ssl will enable debug logging of SSL negotiation. If you see a ClientHello without a subsequent ServerHello the proxy server probably doesn't support HTTPS. Change the proxy from https:// to http:// and try again.

Michael Carman
  • 30,628
  • 10
  • 74
  • 122