You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@hc.apache.org by "jan (Jira)" <ji...@apache.org> on 2019/11/24 21:49:00 UTC

[jira] [Comment Edited] (HTTPCORE-614) ChunkedInputStream makes connection unclosable?

    [ https://issues.apache.org/jira/browse/HTTPCORE-614?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=16981191#comment-16981191 ] 

jan edited comment on HTTPCORE-614 at 11/24/19 9:48 PM:
--------------------------------------------------------

This is for closing entity stream first: Suppose the server side sends chunks, but it does not close the chunk stream, yet. On the client side, the connection can not be closed, since the underlying SocketInputStream does not return -1. The situation can be mocked as follows (SocketInputStream is not public):
{code:java}
String content = "1\r\nA\r\n";
ByteArrayInputStream bais = new ByteArrayInputStream(content.getBytes());
FilterInputStream socketInputStream = new FilterInputStream(bais) {
    public int read(byte b[], int off, int length) throws IOException {
        int i = super.read(b, off, length);
        if (i == -1) {
            // SocketInputStream#socketRead(fd, b, off, length, timeout) reads forever
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        return i;
    }
};
HttpTransportMetricsImpl metrics = new HttpTransportMetricsImpl(); 
SessionInputBufferImpl sessionInputBuffer = new SessionInputBufferImpl(metrics, 8192);
sessionInputBuffer.bind(socketInputStream);
ChunkedInputStream cis = new ChunkedInputStream(sessionInputBuffer, null);
Assert.assertEquals('A', cis.read()); // this is ok
cis.close(); // this hangs{code}
Do I miss something?


was (Author: supol):
This is for closing entity stream first: Suppose the server side sends chunks, but it does not close the chunk stream, yet. On the client side, the connection can not be closed, since the underlying SocketInputStream does not return -1. The situation can be mocked as follows (SocketInputStream is not public):
{code:java}
String content = "1\r\nA\r\n";
ByteArrayInputStream bais = new ByteArrayInputStream(content.getBytes());
FilterInputStream socketInputStream = new FilterInputStream(bais) {
    public int read(byte b[], int off, int length) throws IOException {
        int i = super.read(b, off, length);
        if (i == -1) {
            // SocketInputStream#socketRead(fd, b, off, length, timeout) reads forever
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        return i;
    }
};
HttpTransportMetricsImpl metrics = new HttpTransportMetricsImpl(); 
SessionInputBufferImpl sessionInputBuffer = new SessionInputBufferImpl(metrics, 8192);
sessionInputBuffer.bind(socketInputStream);
ChunkedInputStream cis = new ChunkedInputStream(sessionInputBuffer, null);
Assert.assertEquals('A', cis.read());
cis.close();{code}

Do I miss something?

> ChunkedInputStream makes connection unclosable?
> -----------------------------------------------
>
>                 Key: HTTPCORE-614
>                 URL: https://issues.apache.org/jira/browse/HTTPCORE-614
>             Project: HttpComponents HttpCore
>          Issue Type: Bug
>          Components: HttpCore
>            Reporter: jan
>            Priority: Major
>
> Suppose the following code:
>  
> {code:java}
> CloseableHttpResponse response =...
> InputStream i = response.getEntity().getContent();
> {code}
> With Apache httpclient 4.5, it was possible to do 
>  
> {code:java}
> response.close();
> i.close();
> {code}
>  
> With Apache 4.5.1+ it is no longer possible. For instance, with 4.5.9, it throws:
>  
> {noformat}
> Caused by: org.apache.http.MalformedChunkCodingException: CRLF expected at end of chunkCaused by:
>  org.apache.http.MalformedChunkCodingException: CRLF expected at end of chunk 
> at org.apache.http.impl.io.ChunkedInputStream.getChunkSize(ChunkedInputStream.java:250) 
> at org.apache.http.impl.io.ChunkedInputStream.nextChunk(ChunkedInputStream.java:222) 
> at org.apache.http.impl.io.ChunkedInputStream.read(ChunkedInputStream.java:183) 
> at org.apache.http.impl.io.ChunkedInputStream.read(ChunkedInputStream.java:210) 
> at org.apache.http.impl.io.ChunkedInputStream.close(ChunkedInputStream.java:312) 
> at org.apache.http.impl.execchain.ResponseEntityProxy.streamClosed(ResponseEntityProxy.java:142) 
> at org.apache.http.conn.EofSensorInputStream.checkClose(EofSensorInputStream.java:228) 
> at org.apache.http.conn.EofSensorInputStream.close(EofSensorInputStream.java:172) 
> at java.io.BufferedInputStream.close(BufferedInputStream.java:483) 
> at java.io.FilterInputStream.close(FilterInputStream.java:181){noformat}
>  
> The underlying connection is closed and ChunkedInputStream is unhappy.
> The advised solution was to switch the close order to:
>  
> {code:java}
> i.close()
> response.close().
> {code}
>  
> But in this case, when i.close() is called, the thread is stuck on reading from the connection since the ChunkedInputStream tries to read from the socket:
> {noformat}
>  java.lang.Thread.State: RUNNABLE
>  at java.net.SocketInputStream.socketRead0(Native Method)
>  at java.net.SocketInputStream.socketRead(SocketInputStream.java:116)
>  at java.net.SocketInputStream.read(SocketInputStream.java:171)
>  at java.net.SocketInputStream.read(SocketInputStream.java:141)
>  at org.apache.http.impl.io.SessionInputBufferImpl.streamRead(SessionInputBufferImpl.java:137)
>  at org.apache.http.impl.io.SessionInputBufferImpl.fillBuffer(SessionInputBufferImpl.java:153)
>  at org.apache.http.impl.io.SessionInputBufferImpl.readLine(SessionInputBufferImpl.java:280)
>  at org.apache.http.impl.io.ChunkedInputStream.getChunkSize(ChunkedInputStream.java:261)
>  at org.apache.http.impl.io.ChunkedInputStream.nextChunk(ChunkedInputStream.java:222)
>  at org.apache.http.impl.io.ChunkedInputStream.read(ChunkedInputStream.java:183)
>  at org.apache.http.impl.io.ChunkedInputStream.read(ChunkedInputStream.java:210)
>  at org.apache.http.impl.io.ChunkedInputStream.close(ChunkedInputStream.java:312)
>  at org.apache.http.impl.execchain.ResponseEntityProxy.streamClosed(ResponseEntityProxy.java:142)
>  at org.apache.http.conn.EofSensorInputStream.checkClose(EofSensorInputStream.java:228)
>  at org.apache.http.conn.EofSensorInputStream.close(EofSensorInputStream.java:172)
>  at java.io.BufferedInputStream.close(BufferedInputStream.java:483)
>  at java.io.FilterInputStream.close(FilterInputStream.java:181)
> {noformat}
> What would be the correct solution to close the connection?
> The brief history of the issue is at https://github.com/eclipse-ee4j/jersey/issues/4321.
>  
>  
>  
>  



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

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@hc.apache.org
For additional commands, e-mail: dev-help@hc.apache.org