[
https://issues.apache.org/jira/browse/HTTPCLIENT-2177?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17416746#comment-17416746
]
Oleg Kalnichevski commented on HTTPCLIENT-2177:
-----------------------------------------------
My apologies, [~avasilev] You were right and I was wrong. There was another
defect in the async connect executor. The async connecting route tracking code
did not track routing state correctly in case of the proxy not keeping the
tunnel connection alive during the authetication challenge exchange and as a
result could not re-establish the tunnel in case of an authentication failure.
Please re-test the fix [1]. Please note there are two relevant commits in the
branch.
Oleg
[1] https://github.com/apache/httpcomponents-client/tree/HTTPCLIENT-2177
> Unable to use HTTP Proxy with CloseableHttpAsyncClient
> ------------------------------------------------------
>
> Key: HTTPCLIENT-2177
> URL: https://issues.apache.org/jira/browse/HTTPCLIENT-2177
> Project: HttpComponents HttpClient
> Issue Type: Improvement
> Components: HttpClient (async)
> Affects Versions: 5.0, 5.1
> Environment: Windows 10.0.19041 Build 19041
> Java 11.0.11
> Gradle 6.8
> Reporter: Andrei Vasilev
> Priority: Minor
> Fix For: 5.2-alpha1
>
> Attachments: auth-proxy-context-wire-HTTPCLIENT-2177.log,
> context-wire.log, unauth-proxy-context-wire-HTTPCLIENT-2177.log
>
>
> 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.
>
> {code:java}
> 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);
> }
> }
> }
> {code}
>
> The resulting stack trace :
> {code:java}
> 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)
> {code}
--
This message was sent by Atlassian Jira
(v8.3.4#803005)
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]