[ 
https://issues.apache.org/jira/browse/HTTPCLIENT-2164?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Jared S updated HTTPCLIENT-2164:
--------------------------------
    Description: 
I am trying to use an HttpResponseInterceptor to view server certificates 
returned during the TLS handshake. The following code snippet works fine - 
unless the server response has an empty body. Then, it fails with a 
ConnectionShutdownException. This feels like a bug - an empty response body 
(i.e. a 204) is valid, so I don't see why it should behave so differently from 
a 200 with content.

 
{code:java}
public class Run {
public static void main(String[] args) throws URISyntaxException, IOException {
    HttpClientBuilder httpClientBuilder = HttpClients.custom();
    httpClientBuilder.addInterceptorLast((HttpResponseInterceptor) (response, 
context) -> {
        ManagedHttpClientConnection connection =
                (ManagedHttpClientConnection) 
context.getAttribute(HttpCoreContext.HTTP_CONNECTION);
        System.out.println("Response: " + response);
        System.out.println("Connection: " + connection);
        SSLSession sslSession = connection.getSSLSession();
        if (sslSession != null) {
            context.setAttribute("certificateChain", 
sslSession.getPeerCertificates());
        }
    });
    CloseableHttpClient httpClient = httpClientBuilder.build();
    final HttpContext context = new BasicHttpContext();
    final HttpPut put = new HttpPut();
    put.setURI(new 
URI("https://ussyy51xji.execute-api.us-east-1.amazonaws.com/Prod";));
    httpClient.execute(put, context);
    for (X509Certificate cert : (X509Certificate[]) 
context.getAttribute("certificateChain")) {
        System.out.println(cert.getSubjectX500Principal());
    }
}
{code}
I used AWS API Gateway to set up a minimal server. When the backend is set to

 
{code:java}
def lambda_handler(event, context):
    # TODO implement
    return {
        'statusCode': 200,
        'body': "hello world",
        'isBase64Encoded': False
    }
{code}
then the client works fine:
{code:java}
Response: HttpResponseProxy{HTTP/1.1 502 Bad Gateway [Date: Tue, 22 Jun 2021 
15:46:54 GMT, Content-Type: application/json, Content-Length: 36, Connection: 
keep-alive, x-amzn-RequestId: 70c74c10-453f-4d34-8bd9-27d7974a46b1, 
x-amzn-ErrorType: InternalServerErrorException, x-amz-apigw-id: 
BVXdQGbVoAMFrIw=] ResponseEntityProxy{[Content-Type: 
application/json,Content-Length: 36,Chunked: false]}}
Connection: CPoolProxy{10.95.216.212:51100<->54.197.25.122:443}
CN=*.execute-api.us-east-1.amazonaws.com
CN=Amazon, OU=Server CA 1B, O=Amazon, C=US
CN=Amazon Root CA 1, O=Amazon, C=US
CN=Starfield Services Root Certificate Authority - G2, O="Starfield 
Technologies, Inc.", L=Scottsdale, ST=Arizona, C=US
{code}
However, if I set the backend to instead be:
{code:java}
def lambda_handler(event, context):
    # TODO implement
    return {
        'statusCode': 204,
        'body': None,
        'isBase64Encoded': False
    }
{code}
 

then it fails with
{code:java}
Exception in thread "main" org.apache.http.impl.conn.ConnectionShutdownException
        at 
org.apache.http.impl.conn.CPoolProxy.getValidConnection(CPoolProxy.java:77)
        at 
org.apache.http.impl.conn.CPoolProxy.getSSLSession(CPoolProxy.java:137)
        at com.amazonaws.<redacted>.client.Run.lambda$main$0(Run.java:33)
        at 
org.apache.http.protocol.ImmutableHttpProcessor.process(ImmutableHttpProcessor.java:142)
        at 
org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:191)
        at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:89)
        at 
org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:110)
        at 
org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:185)
        at 
org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:83)
        at com.amazonaws.<redacted>.client.Run.main(Run.java:42)
{code}
The same happens if I return a 200 (as opposed to a 204) with an empty body.

Note CPoolProxy\{detached} when it fails versus 
CPoolProxy\{10.95.216.212:65140<->54.197.189.189:443} when it works.

I don't know of any other way to get the certificates, so I'm marking this as a 
major loss in functionality.

There is an old ticket relating to a closed connection from a 204, but this is 
so old I can't imagine it could be the cause: 
https://issues.apache.org/jira/browse/HTTPCLIENT-464

  was:
I am trying to use an HttpResponseInterceptor to view server certificates 
returned during the TLS handshake. The following code snippet works fine - 
unless the server response has an empty body. Then, it fails with a 
ConnectionShutdownException. This feels like a bug - an empty response body 
(i.e. a 204) is valid, so I don't see why it should behave so differently from 
a 200 with content.

 
{code:java}
public class Run {
    public static void main(String[] args) throws URISyntaxException, 
IOException {
        HttpClientBuilder httpClientBuilder = HttpClients.custom();
        httpClientBuilder.addInterceptorLast((HttpResponseInterceptor) 
(response, context) -> {
            ManagedHttpClientConnection connection =
                    (ManagedHttpClientConnection) 
context.getAttribute(HttpCoreContext.HTTP_CONNECTION);
            System.out.println("Response: " + response);
            System.out.println("Connection: " + connection);
            SSLSession sslSession = connection.getSSLSession();
            if (sslSession != null) {
                context.setAttribute("certificateChain", 
sslSession.getPeerCertificates());
            }
        });
        CloseableHttpClient httpClient = httpClientBuilder.build();
        final HttpContext context = new BasicHttpContext();
        final HttpPut put = new HttpPut();
        put.setURI(new 
URI("https://<redacted>.execute-api.us-east-1.amazonaws.com/Prod"));
        httpClient.execute(put, context);
        System.out.println((Certificate[]) 
context.getAttribute("certificateChain"));
    }
}
{code}
I used AWS API Gateway to set up a minimal server. When the backend is set to

 
{code:java}
def lambda_handler(event, context):
    # TODO implement
    return {
        'statusCode': 200,
        'body': "hello world",
        'isBase64Encoded': False
    }
{code}
then the client works fine:
{code:java}
Response: HttpResponseProxy{HTTP/1.1 502 Bad Gateway [Date: Tue, 22 Jun 2021 
15:46:54 GMT, Content-Type: application/json, Content-Length: 36, Connection: 
keep-alive, x-amzn-RequestId: 70c74c10-453f-4d34-8bd9-27d7974a46b1, 
x-amzn-ErrorType: InternalServerErrorException, x-amz-apigw-id: 
BVXdQGbVoAMFrIw=] ResponseEntityProxy{[Content-Type: 
application/json,Content-Length: 36,Chunked: false]}}
Connection: CPoolProxy{10.95.216.212:51100<->54.197.25.122:443}
CN=*.execute-api.us-east-1.amazonaws.com
CN=Amazon, OU=Server CA 1B, O=Amazon, C=US
CN=Amazon Root CA 1, O=Amazon, C=US
CN=Starfield Services Root Certificate Authority - G2, O="Starfield 
Technologies, Inc.", L=Scottsdale, ST=Arizona, C=US
{code}
However, if I set the backend to instead be:
{code:java}
def lambda_handler(event, context):
    # TODO implement
    return {
        'statusCode': 204,
        'body': None,
        'isBase64Encoded': False
    }
{code}
 

then it fails with
{code:java}
Exception in thread "main" org.apache.http.impl.conn.ConnectionShutdownException
        at 
org.apache.http.impl.conn.CPoolProxy.getValidConnection(CPoolProxy.java:77)
        at 
org.apache.http.impl.conn.CPoolProxy.getSSLSession(CPoolProxy.java:137)
        at com.amazonaws.<redacted>.client.Run.lambda$main$0(Run.java:33)
        at 
org.apache.http.protocol.ImmutableHttpProcessor.process(ImmutableHttpProcessor.java:142)
        at 
org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:191)
        at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:89)
        at 
org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:110)
        at 
org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:185)
        at 
org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:83)
        at com.amazonaws.<redacted>.client.Run.main(Run.java:42)
{code}
The same happens if I return a 200 (as opposed to a 204) with an empty body.

Note CPoolProxy\{detached} when it fails versus 
CPoolProxy\{10.95.216.212:65140<->54.197.189.189:443} when it works.

I don't know of any other way to get the certificates, so I'm marking this as a 
major loss in functionality. 

There is an old ticket relating to a closed connection from a 204, but this is 
so old I can't imagine it could be the cause: 
https://issues.apache.org/jira/browse/HTTPCLIENT-464


> HttpResponseInterceptor connection is null when response body is empty
> ----------------------------------------------------------------------
>
>                 Key: HTTPCLIENT-2164
>                 URL: https://issues.apache.org/jira/browse/HTTPCLIENT-2164
>             Project: HttpComponents HttpClient
>          Issue Type: Bug
>          Components: HttpClient (classic)
>    Affects Versions: 4.5.13
>         Environment: MacOS/Linux
>            Reporter: Jared S
>            Priority: Major
>
> I am trying to use an HttpResponseInterceptor to view server certificates 
> returned during the TLS handshake. The following code snippet works fine - 
> unless the server response has an empty body. Then, it fails with a 
> ConnectionShutdownException. This feels like a bug - an empty response body 
> (i.e. a 204) is valid, so I don't see why it should behave so differently 
> from a 200 with content.
>  
> {code:java}
> public class Run {
> public static void main(String[] args) throws URISyntaxException, IOException 
> {
>     HttpClientBuilder httpClientBuilder = HttpClients.custom();
>     httpClientBuilder.addInterceptorLast((HttpResponseInterceptor) (response, 
> context) -> {
>         ManagedHttpClientConnection connection =
>                 (ManagedHttpClientConnection) 
> context.getAttribute(HttpCoreContext.HTTP_CONNECTION);
>         System.out.println("Response: " + response);
>         System.out.println("Connection: " + connection);
>         SSLSession sslSession = connection.getSSLSession();
>         if (sslSession != null) {
>             context.setAttribute("certificateChain", 
> sslSession.getPeerCertificates());
>         }
>     });
>     CloseableHttpClient httpClient = httpClientBuilder.build();
>     final HttpContext context = new BasicHttpContext();
>     final HttpPut put = new HttpPut();
>     put.setURI(new 
> URI("https://ussyy51xji.execute-api.us-east-1.amazonaws.com/Prod";));
>     httpClient.execute(put, context);
>     for (X509Certificate cert : (X509Certificate[]) 
> context.getAttribute("certificateChain")) {
>         System.out.println(cert.getSubjectX500Principal());
>     }
> }
> {code}
> I used AWS API Gateway to set up a minimal server. When the backend is set to
>  
> {code:java}
> def lambda_handler(event, context):
>     # TODO implement
>     return {
>         'statusCode': 200,
>         'body': "hello world",
>         'isBase64Encoded': False
>     }
> {code}
> then the client works fine:
> {code:java}
> Response: HttpResponseProxy{HTTP/1.1 502 Bad Gateway [Date: Tue, 22 Jun 2021 
> 15:46:54 GMT, Content-Type: application/json, Content-Length: 36, Connection: 
> keep-alive, x-amzn-RequestId: 70c74c10-453f-4d34-8bd9-27d7974a46b1, 
> x-amzn-ErrorType: InternalServerErrorException, x-amz-apigw-id: 
> BVXdQGbVoAMFrIw=] ResponseEntityProxy{[Content-Type: 
> application/json,Content-Length: 36,Chunked: false]}}
> Connection: CPoolProxy{10.95.216.212:51100<->54.197.25.122:443}
> CN=*.execute-api.us-east-1.amazonaws.com
> CN=Amazon, OU=Server CA 1B, O=Amazon, C=US
> CN=Amazon Root CA 1, O=Amazon, C=US
> CN=Starfield Services Root Certificate Authority - G2, O="Starfield 
> Technologies, Inc.", L=Scottsdale, ST=Arizona, C=US
> {code}
> However, if I set the backend to instead be:
> {code:java}
> def lambda_handler(event, context):
>     # TODO implement
>     return {
>         'statusCode': 204,
>         'body': None,
>         'isBase64Encoded': False
>     }
> {code}
>  
> then it fails with
> {code:java}
> Exception in thread "main" 
> org.apache.http.impl.conn.ConnectionShutdownException
>       at 
> org.apache.http.impl.conn.CPoolProxy.getValidConnection(CPoolProxy.java:77)
>       at 
> org.apache.http.impl.conn.CPoolProxy.getSSLSession(CPoolProxy.java:137)
>       at com.amazonaws.<redacted>.client.Run.lambda$main$0(Run.java:33)
>       at 
> org.apache.http.protocol.ImmutableHttpProcessor.process(ImmutableHttpProcessor.java:142)
>       at 
> org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:191)
>       at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:89)
>       at 
> org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:110)
>       at 
> org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:185)
>       at 
> org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:83)
>       at com.amazonaws.<redacted>.client.Run.main(Run.java:42)
> {code}
> The same happens if I return a 200 (as opposed to a 204) with an empty body.
> Note CPoolProxy\{detached} when it fails versus 
> CPoolProxy\{10.95.216.212:65140<->54.197.189.189:443} when it works.
> I don't know of any other way to get the certificates, so I'm marking this as 
> a major loss in functionality.
> There is an old ticket relating to a closed connection from a 204, but this 
> is so old I can't imagine it could be the cause: 
> https://issues.apache.org/jira/browse/HTTPCLIENT-464



--
This message was sent by Atlassian Jira
(v8.3.4#803005)

---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to