[ 
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

Reply via email to