[ https://issues.apache.org/jira/browse/HTTPCLIENT-2373?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]
Thomas Beckers updated HTTPCLIENT-2373: --------------------------------------- Description: 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? was: 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 misuning Http Client? > 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