Uploaded image for project: 'HttpComponents HttpClient'
  1. HttpComponents HttpClient
  2. HTTPCLIENT-2177

Unable to use HTTP Proxy with CloseableHttpAsyncClient

    XMLWordPrintableJSON

Details

    • Bug
    • Status: Resolved
    • Major
    • Resolution: Fixed
    • 5.0, 5.1
    • 5.1.1, 5.2-alpha1
    • HttpClient (async)
    • None
    • Windows 10.0.19041 Build 19041
      Java 11.0.11
      Gradle 6.8

    Description

      When executing a standard GET request with a configured proxy (authenticated or not) using an instance of CloseableHttpAsyncClient, the request fails with "IllegalStateException: No tunnel unless connected."

      Is making requests via proxies using an AsyncClient not supported? It is not entirely clear from the current release notes/examples.

      Minimal example to reproduce issue, although you will of course need to configure the proxy accordingly given your environment.

       

      import java.util.concurrent.Future;
      import javax.net.ssl.SSLEngine;
      import javax.net.ssl.SSLSession;
      import org.apache.hc.client5.http.async.methods.SimpleHttpRequest;
      import org.apache.hc.client5.http.async.methods.SimpleHttpResponse;
      import org.apache.hc.client5.http.async.methods.SimpleRequestBuilder;
      import org.apache.hc.client5.http.async.methods.SimpleRequestProducer;
      import org.apache.hc.client5.http.async.methods.SimpleResponseConsumer;
      import org.apache.hc.client5.http.config.RequestConfig;
      import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient;
      import org.apache.hc.client5.http.impl.async.HttpAsyncClients;
      import org.apache.hc.client5.http.impl.nio.PoolingAsyncClientConnectionManager;
      import org.apache.hc.client5.http.impl.nio.PoolingAsyncClientConnectionManagerBuilder;
      import org.apache.hc.client5.http.protocol.HttpClientContext;
      import org.apache.hc.client5.http.ssl.ClientTlsStrategyBuilder;
      import org.apache.hc.core5.concurrent.FutureCallback;
      import org.apache.hc.core5.function.Factory;
      import org.apache.hc.core5.http.HttpHost;
      import org.apache.hc.core5.http.message.StatusLine;
      import org.apache.hc.core5.http.nio.ssl.TlsStrategy;
      import org.apache.hc.core5.http2.HttpVersionPolicy;
      import org.apache.hc.core5.io.CloseMode;
      import org.apache.hc.core5.reactor.ssl.TlsDetails;
      
      public class AsyncMain {
      
        public static void main(final String[] args) throws Exception {
          final TlsStrategy tlsStrategy = ClientTlsStrategyBuilder.create()
              .useSystemProperties()
              .setTlsDetailsFactory(new Factory<SSLEngine, TlsDetails>() {
                @Override
                public TlsDetails create(final SSLEngine sslEngine) {
                  return new TlsDetails(sslEngine.getSession(), sslEngine.getApplicationProtocol());
                }
              }).build();
      
          final PoolingAsyncClientConnectionManager cm = PoolingAsyncClientConnectionManagerBuilder.create()
              .setTlsStrategy(tlsStrategy)
              .build();
      
          try (final CloseableHttpAsyncClient client = HttpAsyncClients.custom()
              .setVersionPolicy(HttpVersionPolicy.NEGOTIATE)
              .setConnectionManager(cm)
              .build()) {
      
            client.start();
      
            final HttpClientContext clientContext = HttpClientContext.create();
            final HttpHost target = new HttpHost("https", "nghttp2.org");
            final HttpHost proxy = new HttpHost("127.0.0.1", 8888);
            final RequestConfig config = RequestConfig.custom().setProxy(proxy).build();
            final SimpleHttpRequest request = SimpleRequestBuilder.get()
                .setHttpHost(target)
                .setRequestConfig(config)
                .setPath("/httpbin/")
                .build();
      
            System.out.println("Executing request " + request);
            final Future<SimpleHttpResponse> future = client.execute(
                SimpleRequestProducer.create(request),
                SimpleResponseConsumer.create(),
                clientContext,
                new FutureCallback<SimpleHttpResponse>() {
                  @Override
                  public void completed(final SimpleHttpResponse response) {
                    System.out.println(request + "->" + new StatusLine(response));
                    final SSLSession sslSession = clientContext.getSSLSession();
                    if (sslSession != null) {
                      System.out.println("SSL protocol " + sslSession.getProtocol());
                      System.out.println("SSL cipher suite " + sslSession.getCipherSuite());
                    }
                    System.out.println(response.getBody());
                  }
      
                  @Override
                  public void failed(final Exception ex) {
                    System.out.println(request + "->" + ex);
                  }
      
                  @Override
                  public void cancelled() {
                    System.out.println(request + " cancelled");
                  }
                });
            future.get();
            System.out.println("Shutting down");
            client.close(CloseMode.GRACEFUL);
          }
        }
      }
      

       

      The resulting stack trace :

      Exception in thread "main" java.util.concurrent.ExecutionException: java.lang.IllegalStateException: No tunnel unless connected at org.apache.hc.core5.concurrent.BasicFuture.getResult(BasicFuture.java:72) at org.apache.hc.core5.concurrent.BasicFuture.get(BasicFuture.java:85) at AsyncMain.main(AsyncMain.java:86)Caused by: java.lang.IllegalStateException: No tunnel unless connected at org.apache.hc.core5.util.Asserts.check(Asserts.java:38) at org.apache.hc.client5.http.RouteTracker.tunnelTarget(RouteTracker.java:143) at org.apache.hc.client5.http.impl.async.AsyncConnectExec$4.completed(AsyncConnectExec.java:270) at org.apache.hc.client5.http.impl.async.AsyncConnectExec$5.completed(AsyncConnectExec.java:388) at org.apache.hc.client5.http.impl.async.HttpAsyncMainClientExec$1.consumeResponse(HttpAsyncMainClientExec.java:206) at org.apache.hc.core5.http.impl.nio.ClientHttp1StreamHandler.consumeHeader(ClientHttp1StreamHandler.java:253) at org.apache.hc.core5.http.impl.nio.ClientHttp1StreamDuplexer.consumeHeader(ClientHttp1StreamDuplexer.java:348) at org.apache.hc.core5.http.impl.nio.ClientHttp1StreamDuplexer.consumeHeader(ClientHttp1StreamDuplexer.java:80)Caused by: java.lang.IllegalStateException: No tunnel unless connected
       at org.apache.hc.core5.http.impl.nio.AbstractHttp1StreamDuplexer.onInput(AbstractHttp1StreamDuplexer.java:288) at org.apache.hc.core5.http.impl.nio.AbstractHttp1IOEventHandler.inputReady(AbstractHttp1IOEventHandler.java:64) at org.apache.hc.core5.http.impl.nio.ClientHttp1IOEventHandler.inputReady(ClientHttp1IOEventHandler.java:39) at org.apache.hc.core5.reactor.InternalDataChannel.onIOEvent(InternalDataChannel.java:131) at org.apache.hc.core5.reactor.InternalChannel.handleIOEvent(InternalChannel.java:51) at org.apache.hc.core5.reactor.SingleCoreIOReactor.processEvents(SingleCoreIOReactor.java:178) at org.apache.hc.core5.reactor.SingleCoreIOReactor.doExecute(SingleCoreIOReactor.java:127) at org.apache.hc.core5.reactor.AbstractSingleCoreIOReactor.execute(AbstractSingleCoreIOReactor.java:85) at org.apache.hc.core5.reactor.IOReactorWorker.run(IOReactorWorker.java:44) at java.base/java.lang.Thread.run(Thread.java:829)
      

      Attachments

        1. auth-proxy-context-wire-HTTPCLIENT-2177.log
          26 kB
          Andrei Vasilev
        2. context-wire.log
          13 kB
          Andrei Vasilev
        3. protocol-exception-context-wire.log
          36 kB
          Andrei Vasilev
        4. unauth-proxy-context-wire-HTTPCLIENT-2177.log
          92 kB
          Andrei Vasilev

        Activity

          People

            Unassigned Unassigned
            avasilev Andrei Vasilev
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved: