[
https://issues.apache.org/jira/browse/HTTPCLIENT-2164?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17367984#comment-17367984
]
Oleg Kalnichevski commented on HTTPCLIENT-2164:
-----------------------------------------------
[~jared429] HttpClient releases the connection used to execute a message
exchange immediately after the final response has been fully consumed. This is
intentional and by design.
Response messages without an enclosed content body trigger automatic connection
release immediately upon receipt. This is also intentional. Consequently,
message interceptors are not guaranteed to have access to the underlying
connection.
There are two options:
1. Upgrade to HttpClient 5.x that provides access the SSL session through
the execution context
2. Manually stick SSLSession into the execution context from a custom
request executor
{code:java}
CloseableHttpClient httpclient = HttpClientBuilder.create()
.setRequestExecutor(new HttpRequestExecutor() {
@Override
public HttpResponse execute(HttpRequest request,
HttpClientConnection conn,
HttpContext context) throws
IOException, HttpException {
if (conn instanceof ManagedHttpClientConnection) {
context.setAttribute("ssl.session",
((ManagedHttpClientConnection) conn).getSSLSession());
}
return super.execute(request, conn, context);
}
})
.build();
try {
HttpGet httpget = new HttpGet("https://httpbin.org/");
System.out.println("Executing request " + httpget.getRequestLine());
HttpClientContext context = HttpClientContext.create();
CloseableHttpResponse response = httpclient.execute(httpget, context);
try {
HttpEntity entity = response.getEntity();
System.out.println("----------------------------------------");
System.out.println(response.getStatusLine());
EntityUtils.consume(entity);
} finally {
response.close();
}
SSLSession sslSession = context.getAttribute("ssl.session",
SSLSession.class);
System.out.println(sslSession);
} finally {
httpclient.close();
}
{code}
> HttpResponseInterceptor connection is closed 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://<redacted>.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 200 OK [Date: Tue, 22 Jun 2021 16:04:36
> GMT, Content-Type: application/json, Content-Length: 11, Connection:
> keep-alive, x-amzn-RequestId: 097b2037-62b1-48fd-b28e-95fb679ba696,
> x-amz-apigw-id: BVaDPHS6IAMFSfA=, X-Amzn-Trace-Id:
> Root=1-60d20a14-2e49fa58675b563e763acbc7;Sampled=0]
> ResponseEntityProxy{[Content-Type: application/json,Content-Length:
> 11,Chunked: false]}}
> Connection: CPoolProxy{10.95.216.212:51737<->52.200.70.32: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 <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 <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]