Search code examples
javaspringspring-bootapache-httpclient-4.xresttemplate

Connection Timeout for Rest Template with HTTP Client 4.5 under Proxy


How can I set timeout? I have set almost all timeout configurations. Normally without proxy it works fine. The problem happens when I am connecting with Proxy connection details. Log show that it is getting connected and no reply is received.

2020-03-04 19:53:39,751 DEBUG [main] org.springframework.core.log.CompositeLog: HTTP POST https://destinationurl.io/api/agentmanagement/v3/oauth/token
2020-03-04 19:53:39,803 DEBUG [main] org.springframework.core.log.CompositeLog: Accept=[application/json, application/*+json]
2020-03-04 19:53:39,807 DEBUG [main] org.springframework.core.log.CompositeLog: Writing [grant_type=client_credentials&client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer&client_assertion=token--cjKRDhVI0OuYo] as "application/x-www-form-urlencoded"
2020-03-04 19:53:39,821 DEBUG [main] org.apache.http.client.protocol.RequestAuthCache: Auth cache not set in the context
2020-03-04 19:53:39,823 DEBUG [main] org.apache.http.impl.conn.PoolingHttpClientConnectionManager: Connection request: [route: {tls}->http://proxyurl:3128->https://destinationurl.io:443][total kept alive: 0; route allocated: 0 of 20; total allocated: 0 of 100]
2020-03-04 19:53:39,838 DEBUG [main] org.apache.http.impl.conn.PoolingHttpClientConnectionManager: Connection leased: [id: 0][route: {tls}->http://proxyurl:3128->https://destinationurl.io:443][total kept alive: 0; route allocated: 1 of 20; total allocated: 1 of 100]
2020-03-04 19:53:39,839 DEBUG [main] org.apache.http.impl.execchain.MainClientExec: Opening connection {tls}->http://proxyurl:3128->https://destinationurl.io:443
2020-03-04 19:53:40,047 DEBUG [main] org.apache.http.impl.conn.DefaultHttpClientConnectionOperator: Connecting to proxyurl/35.158.73.29:3128
2020-03-04 19:53:40,420 DEBUG [main] org.apache.http.impl.conn.DefaultHttpClientConnectionOperator: Connection established 132.186.74.92:65173<->35.158.73.29:3128
2020-03-04 19:53:40,423 DEBUG [main] org.apache.http.impl.conn.LoggingManagedHttpClientConnection: http-outgoing-0 >> CONNECT destinationurl.io:443 HTTP/1.1
2020-03-04 19:53:40,424 DEBUG [main] org.apache.http.impl.conn.LoggingManagedHttpClientConnection: http-outgoing-0 >> Host: destinationurl.io
2020-03-04 19:53:40,424 DEBUG [main] org.apache.http.impl.conn.LoggingManagedHttpClientConnection: http-outgoing-0 >> User-Agent: Apache-HttpClient/4.5.10 (Java/1.8.0_201)
2020-03-04 19:53:40,424 DEBUG [main] org.apache.http.impl.conn.Wire: http-outgoing-0 >> "CONNECT destinationurl.io:443 HTTP/1.1[\r][\n]"
2020-03-04 19:53:40,424 DEBUG [main] org.apache.http.impl.conn.Wire: http-outgoing-0 >> "Host: destinationurl.io[\r][\n]"
2020-03-04 19:53:40,424 DEBUG [main] org.apache.http.impl.conn.Wire: http-outgoing-0 >> "User-Agent: Apache-HttpClient/4.5.10 (Java/1.8.0_201)[\r][\n]"
2020-03-04 19:53:40,424 DEBUG [main] org.apache.http.impl.conn.Wire: http-outgoing-0 >> "[\r][\n]"

Log is attached.

    <dependency>
        <groupId>org.apache.httpcomponents</groupId>
        <artifactId>httpclient</artifactId>
        <version>4.5.11</version>
    </dependency>

Here is my config. I'm using spring boot 2.2.

PoolingHttpClientConnectionManager connectionManager;
if (properties.isAllCertificateAllowed()) {
  connectionManager =
          new PoolingHttpClientConnectionManager(
                  buildSocketFactoryRegistry(trustAllSslConnectionSocketFactory(trustAllSslContext())));
} else {
  connectionManager = new PoolingHttpClientConnectionManager();
}

RequestConfig config = RequestConfig.custom()
        .setSocketTimeout(properties.getConnectTimeout())
        .setConnectTimeout(properties.getConnectTimeout())
        .setConnectionRequestTimeout(properties.getConnectTimeout())
        .build();

/* HttpClientBuilder using http client connection connectionManager */
HttpClientBuilder httpClientBuilder =
        HttpClientBuilder.create()
                .setConnectionManager(connectionManager)
                .useSystemProperties()
                .disableCookieManagement()
                .setDefaultRequestConfig(config);

HttpComponentsClientHttpRequestFactory httpRequestFactory = new HttpComponentsClientHttpRequestFactory();
httpRequestFactory.setConnectTimeout(properties.getConnectTimeout()) ;
httpRequestFactory.setReadTimeout(properties.getReadTimeout());
httpRequestFactory.setConnectionRequestTimeout(properties.getConnectionRequestTimeout());

if (properties.isProxyEnabled()) {
  log.info(properties.toString());

  /* proxy username ,password name setting */
  CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
  credentialsProvider.setCredentials(
          new AuthScope(properties.getProxyAddress(), properties.getProxyPort()),
          new UsernamePasswordCredentials(
                  properties.getProxyUsername(), properties.getProxyPassword()));

  httpClientBuilder.setProxy(
          new HttpHost(properties.getProxyAddress(), properties.getProxyPort())); //TODO,"https"
  httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider);

  CloseableHttpClient httpClient = httpClientBuilder.build();
  httpRequestFactory.setHttpClient(httpClient);
}
RestTemplate restTemplate = new RestTemplate(httpRequestFactory);

Solution

  • Looks like its a proxy problem. HTTP/HTTPS schema of proxy configuration should be checked with your given proxy details. You can give the option to trust all the certificates while creating the restTemplate. Please see the sample below for trusting all the certificates :-

    Reference: Spring RestTemplate Connection Timeout is not working

    Sample code :-

    @Bean
    public RestTemplate restTemplate(AgentManagementProperties properties) {
        PoolingHttpClientConnectionManager connectionManager;
        if (properties.isAllCertificateAllowed()) {
          connectionManager =
              new PoolingHttpClientConnectionManager(
                  buildSocketFactoryRegistry(trustAllSslConnectionSocketFactory(trustAllSslContext())));
        } else {
          connectionManager = new PoolingHttpClientConnectionManager();
        }
        connectionManager.setMaxTotal(properties.getMaxPooledHttpConnections());
        connectionManager.setDefaultMaxPerRoute(properties.getMaxHttpConnectionsPerRoute());
    
        RequestConfig config =
            RequestConfig.custom()
                .setSocketTimeout(properties.getConnectTimeout())
                .setConnectTimeout(properties.getConnectTimeout())
                .setConnectionRequestTimeout(properties.getConnectTimeout())
                .build();
    
        /* HttpClientBuilder using http client connection connectionManager */
        HttpClientBuilder httpClientBuilder =
            HttpClientBuilder.create()
                .setConnectionManager(connectionManager)
                .useSystemProperties()
                .disableCookieManagement()
                .setDefaultRequestConfig(config);
    
        HttpComponentsClientHttpRequestFactory httpRequestFactory =
            new HttpComponentsClientHttpRequestFactory();
        httpRequestFactory.setConnectTimeout(properties.getConnectTimeout());
        httpRequestFactory.setReadTimeout(properties.getReadTimeout());
        httpRequestFactory.setConnectionRequestTimeout(properties.getConnectionRequestTimeout());
    
        if (properties.isProxyEnabled()) {
          // proxy username and password setting
          CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
          credentialsProvider.setCredentials(
              new AuthScope(properties.getProxyAddress(), properties.getProxyPort()),
              new UsernamePasswordCredentials(
                  properties.getProxyUsername(), properties.getProxyPassword()));
          // proxy url, port and schema setting
          httpClientBuilder.setProxy(
              new HttpHost(
                  properties.getProxyAddress(),
                  properties.getProxyPort(),
                  properties.getProxySchema()));
          httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider);
    
          CloseableHttpClient httpClient = httpClientBuilder.build();
          httpRequestFactory.setHttpClient(httpClient);
        }
        return new RestTemplate(httpRequestFactory);
      }
    
      private static Registry<ConnectionSocketFactory> buildSocketFactoryRegistry(
          SSLConnectionSocketFactory sslConnectionSocketFactory) {
        return RegistryBuilder.<ConnectionSocketFactory>create()
            .register("http", new PlainConnectionSocketFactory())
            .register("https", sslConnectionSocketFactory)
            .build();
      }
    
      private static SSLConnectionSocketFactory trustAllSslConnectionSocketFactory(
          SSLContext sslContext) {
        return new SSLConnectionSocketFactory(sslContext);
      }
    
      private static SSLContext trustAllSslContext() {
        SSLContext sslContext = null;
        try {
          sslContext = SSLContext.getInstance("TLS");
          sslContext.init(
              null,
              new TrustManager[] {
                new X509TrustManager() {
                  public void checkClientTrusted(X509Certificate[] arg0, String arg1) {
                    // NOT IMPLEMENTED Please refer SDK Core
                  }
    
                  public void checkServerTrusted(X509Certificate[] arg0, String arg1) {
                    // NOT IMPLEMENTED Please refer SDK Core
                  }
    
                  public X509Certificate[] getAcceptedIssuers() {
                    return new X509Certificate[0];
                  }
                }
              },
              new SecureRandom());
        } catch (KeyManagementException | NoSuchAlgorithmException e) {
          String errorMessage = "An error occured while configuring ssl context: {}";
          log.error(errorMessage, e);
        }
        return sslContext;
      }