|
34 | 34 | import java.util.concurrent.atomic.AtomicReference; |
35 | 35 |
|
36 | 36 | import org.apache.hc.client5.http.AuthenticationStrategy; |
| 37 | +import org.apache.hc.client5.http.ConnectAlpnProvider; |
37 | 38 | import org.apache.hc.client5.http.EndpointInfo; |
38 | 39 | import org.apache.hc.client5.http.HttpRoute; |
39 | 40 | import org.apache.hc.client5.http.RouteTracker; |
|
47 | 48 | import org.apache.hc.client5.http.auth.ChallengeType; |
48 | 49 | import org.apache.hc.client5.http.auth.MalformedChallengeException; |
49 | 50 | import org.apache.hc.client5.http.config.RequestConfig; |
| 51 | +import org.apache.hc.client5.http.impl.AlpnHeaderSupport; |
50 | 52 | import org.apache.hc.client5.http.impl.auth.AuthCacheKeeper; |
51 | 53 | import org.apache.hc.client5.http.impl.auth.AuthenticationHandler; |
52 | 54 | import org.apache.hc.client5.http.impl.routing.BasicRouteDirector; |
@@ -99,18 +101,31 @@ public final class AsyncConnectExec implements AsyncExecChainHandler { |
99 | 101 | private final AuthCacheKeeper authCacheKeeper; |
100 | 102 | private final HttpRouteDirector routeDirector; |
101 | 103 |
|
| 104 | + private final ConnectAlpnProvider alpnProvider; |
| 105 | + |
| 106 | + |
102 | 107 | public AsyncConnectExec( |
103 | 108 | final HttpProcessor proxyHttpProcessor, |
104 | 109 | final AuthenticationStrategy proxyAuthStrategy, |
105 | 110 | final SchemePortResolver schemePortResolver, |
106 | 111 | final boolean authCachingDisabled) { |
| 112 | + this(proxyHttpProcessor, proxyAuthStrategy, schemePortResolver, authCachingDisabled, null); |
| 113 | + } |
| 114 | + |
| 115 | + public AsyncConnectExec( |
| 116 | + final HttpProcessor proxyHttpProcessor, |
| 117 | + final AuthenticationStrategy proxyAuthStrategy, |
| 118 | + final SchemePortResolver schemePortResolver, |
| 119 | + final boolean authCachingDisabled, |
| 120 | + final ConnectAlpnProvider alpnProvider) { |
107 | 121 | Args.notNull(proxyHttpProcessor, "Proxy HTTP processor"); |
108 | 122 | Args.notNull(proxyAuthStrategy, "Proxy authentication strategy"); |
109 | 123 | this.proxyHttpProcessor = proxyHttpProcessor; |
110 | 124 | this.proxyAuthStrategy = proxyAuthStrategy; |
111 | 125 | this.authenticator = new AuthenticationHandler(); |
112 | 126 | this.authCacheKeeper = authCachingDisabled ? null : new AuthCacheKeeper(schemePortResolver); |
113 | 127 | this.routeDirector = BasicRouteDirector.INSTANCE; |
| 128 | + this.alpnProvider = alpnProvider; |
114 | 129 | } |
115 | 130 |
|
116 | 131 | static class State { |
@@ -275,7 +290,7 @@ public void cancelled() { |
275 | 290 | if (LOG.isDebugEnabled()) { |
276 | 291 | LOG.debug("{} create tunnel", exchangeId); |
277 | 292 | } |
278 | | - createTunnel(state, proxy, target, scope, new AsyncExecCallback() { |
| 293 | + createTunnel(state, proxy, target, route, scope, new AsyncExecCallback() { |
279 | 294 |
|
280 | 295 | @Override |
281 | 296 | public AsyncDataConsumer handleResponse(final HttpResponse response, final EntityDetails entityDetails) throws HttpException, IOException { |
@@ -380,6 +395,7 @@ private void createTunnel( |
380 | 395 | final State state, |
381 | 396 | final HttpHost proxy, |
382 | 397 | final HttpHost nextHop, |
| 398 | + final HttpRoute route, |
383 | 399 | final AsyncExecChain.Scope scope, |
384 | 400 | final AsyncExecCallback asyncExecCallback) { |
385 | 401 |
|
@@ -426,6 +442,13 @@ public void produceRequest(final RequestChannel requestChannel, |
426 | 442 | final HttpRequest connect = new BasicHttpRequest(Method.CONNECT, nextHop, nextHop.toHostString()); |
427 | 443 | connect.setVersion(HttpVersion.HTTP_1_1); |
428 | 444 |
|
| 445 | + // --- RFC 7639: inject ALPN header (if provided) ---------------- |
| 446 | + if (alpnProvider != null) { |
| 447 | + final List<String> alpn = alpnProvider.getAlpnForTunnel(nextHop, route); |
| 448 | + if (alpn != null && !alpn.isEmpty()) { |
| 449 | + connect.setHeader(AlpnHeaderSupport.formatValue(alpn)); |
| 450 | + } |
| 451 | + } |
429 | 452 | proxyHttpProcessor.process(connect, null, clientContext); |
430 | 453 | authenticator.addAuthResponse(proxy, ChallengeType.PROXY, connect, proxyAuthExchange, clientContext); |
431 | 454 |
|
|
0 commit comments