[ https://issues.apache.org/jira/browse/HTTPCLIENT-2373?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17956310#comment-17956310 ]
Oleg Kalnichevski commented on HTTPCLIENT-2373: ----------------------------------------------- [~beth4soptim] Basically what code does is this: it creates a connection to the proxy for `https` scheme, fails to correctly set up the tunnel and then returns the connection back to the pool as _valid_ and {_}re-usable{_}. The next request grans the same connection from the pool, hits the proxy with a request intended for the target, not the proxy, and predictably gets 400 back. Oleg > HTTP proxy returns 400 when connection was established before > ------------------------------------------------------------- > > Key: HTTPCLIENT-2373 > URL: https://issues.apache.org/jira/browse/HTTPCLIENT-2373 > Project: HttpComponents HttpClient > Issue Type: Bug > Components: HttpClient (classic) > Affects Versions: 5.4.4 > Reporter: Thomas Beckers > Priority: Major > > The following code makes a HTTP request that returns 400 from the proxy > (Squid). > There is no issue when no connection is established before > (DO_SOCKET_CONNECT_BEFORE = false). The socket connection is done to perform > some sort of connection test before making the actual HTTP request. > Equivalent code is working in Http Client 4. > {code:java} > import org.apache.hc.client5.http.HttpRoute; > import org.apache.hc.client5.http.classic.methods.HttpGet; > import org.apache.hc.client5.http.config.ConnectionConfig; > import org.apache.hc.client5.http.config.RequestConfig; > import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; > import org.apache.hc.client5.http.impl.classic.HttpClientBuilder; > import org.apache.hc.client5.http.impl.classic.HttpClients; > import org.apache.hc.client5.http.impl.io.BasicHttpClientConnectionManager; > import org.apache.hc.client5.http.impl.io.ManagedHttpClientConnectionFactory; > import org.apache.hc.client5.http.impl.routing.DefaultProxyRoutePlanner; > import org.apache.hc.client5.http.io.ConnectionEndpoint; > import org.apache.hc.client5.http.io.HttpClientConnectionManager; > import org.apache.hc.client5.http.io.LeaseRequest; > import org.apache.hc.client5.http.protocol.HttpClientContext; > import org.apache.hc.client5.http.routing.HttpRoutePlanner; > import org.apache.hc.client5.http.ssl.DefaultClientTlsStrategy; > import org.apache.hc.client5.http.ssl.TlsSocketStrategy; > import org.apache.hc.core5.http.HttpException; > import org.apache.hc.core5.http.HttpHost; > import org.apache.hc.core5.http.HttpVersion; > import org.apache.hc.core5.http.config.Http1Config; > import org.apache.hc.core5.http.config.Registry; > import org.apache.hc.core5.http.config.RegistryBuilder; > import org.apache.hc.core5.http.io.SocketConfig; > import org.apache.hc.core5.http.protocol.HttpContext; > import org.apache.hc.core5.util.TimeValue; > import org.apache.hc.core5.util.Timeout; > import java.io.IOException; > import java.net.URI; > import java.util.concurrent.ExecutionException; > import java.util.concurrent.TimeUnit; > import java.util.concurrent.TimeoutException; > public class HttpClientIssue { > private static final String PROXY_HOST = "<SQUID_HOST>"; > private static final int PROXY_PORT = 3128; > private static final URI TARGET_URI = > URI.create("https://workspace.google.com:443/intl/de/gmail/"); > private static boolean DO_SOCKET_CONNECT_BEFORE = true; > public static void main(String[] args) throws IOException, > ExecutionException, InterruptedException, TimeoutException { > Client client = createHttpClient(); > if (DO_SOCKET_CONNECT_BEFORE) { > ConnectionEndpoint connectionEndpoint = null; > try { > HttpHost targetHost = new HttpHost(TARGET_URI.getScheme(), > TARGET_URI.getHost(), TARGET_URI.getPort()); > HttpRoute route = determineRouteViaHttpProxy(targetHost); > LeaseRequest connectionRequest = > client.connectionManager().lease(null, route, Timeout.ofMilliseconds(15_000), > null); > connectionEndpoint = > connectionRequest.get(Timeout.ofMilliseconds(15_000)); > HttpClientContext context = HttpClientContext.create(); > context.setRoute(route); > client.connectionManager().connect(connectionEndpoint, > Timeout.ofMilliseconds(15_000), context); > if (!connectionEndpoint.isConnected()) { > throw new RuntimeException(); > } > } finally { > client.connectionManager().release(connectionEndpoint, null, > TimeValue.of(0, TimeUnit.SECONDS)); > } > } > HttpGet request = new HttpGet(TARGET_URI); > String result = client.client() > .execute(request, response -> new > String(response.getEntity().getContent().readAllBytes())); > System.out.println(result); > } > private record Client(CloseableHttpClient client, > HttpClientConnectionManager connectionManager) { > } > private static class HttpProxyRoutePlanner implements HttpRoutePlanner { > @Override > public HttpRoute determineRoute(HttpHost targetHost, HttpContext > context) { > HttpHost proxyHost = new HttpHost(PROXY_HOST, PROXY_PORT); > boolean isSecure = > "https".equalsIgnoreCase(targetHost.getSchemeName()); > return new HttpRoute(targetHost, null, proxyHost, isSecure); > } > } > private static HttpRoute determineRouteViaHttpProxy(HttpHost targetHost) { > HttpRoutePlanner routePlanner = new HttpProxyRoutePlanner(); > HttpRoute httpRoute; > try { > httpRoute = routePlanner.determineRoute(targetHost, null, null); > } catch (HttpException e) { > throw new RuntimeException(e.getMessage(), e); > } > return httpRoute; > } > private static Client createHttpClient() { > Http1Config http1Config = Http1Config.custom() > .setVersion(HttpVersion.HTTP_1_1) > .build(); > ManagedHttpClientConnectionFactory managedHttpClientConnectionFactory > = ManagedHttpClientConnectionFactory.builder() > > .http1Config(http1Config) > > .build(); > ConnectionConfig connectionConfig = ConnectionConfig.custom() > > .setConnectTimeout(15_000, TimeUnit.MILLISECONDS) > > .setSocketTimeout(15_000, TimeUnit.MILLISECONDS) > .build(); > RequestConfig requestConfig = RequestConfig.custom() > > .setExpectContinueEnabled(false) > .build(); > BasicHttpClientConnectionManager connectionManager = > BasicHttpClientConnectionManager.create(createSchemeRegistry(), > > managedHttpClientConnectionFactory); > connectionManager.setConnectionConfig(connectionConfig); > > connectionManager.setSocketConfig(SocketConfig.custom().setSoTimeout(15_000, > TimeUnit.MILLISECONDS).build()); > HttpClientBuilder clientBuilder = HttpClients.custom() > > .setConnectionManager(connectionManager) > > .setDefaultRequestConfig(requestConfig) > .setRoutePlanner( > new > DefaultProxyRoutePlanner(new HttpHost(PROXY_HOST, PROXY_PORT))); > return new Client(clientBuilder.build(), connectionManager); > } > private static Registry<TlsSocketStrategy> createSchemeRegistry() { > RegistryBuilder<TlsSocketStrategy> registryBuilder = > RegistryBuilder.create(); > registryBuilder.register("https", > DefaultClientTlsStrategy.createSystemDefault()); > return registryBuilder.build(); > } > } > {code} > (This code is a boiled down version of the real code in our application) > Is this a bug or are we misusing Http Client? -- This message was sent by Atlassian Jira (v8.20.10#820010) --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@hc.apache.org For additional commands, e-mail: dev-h...@hc.apache.org