Prematurely interrupting HTTP POST chunked transfer if size limit exceeded

249 views Asked by At

There is HTTP REST service (java, spring boot) it consumes POST requests. It should respond with error code if file larger than specified is transferred. Problem is that client uses Transfer-Encoding: chunked and size of file is unknown ahead of request body transfer has been completed.

Service keeps counting bytes received. If counter exceeds a limit. It responds with 413/Request Entity Too Large and closes conection. But client keeps transferring data.

Request wireshark dump

Prematurely response dump

It leads to the IOException on the client side:

java.net.SocketException: Broken pipe
    at java.base/sun.nio.ch.NioSocketImpl.implWrite(NioSocketImpl.java:420)
    at java.base/sun.nio.ch.NioSocketImpl.write(NioSocketImpl.java:440)
    at java.base/sun.nio.ch.NioSocketImpl$2.write(NioSocketImpl.java:826)
    at java.base/java.net.Socket$SocketOutputStream.write(Socket.java:1035)
    at org.apache.hc.core5.http.impl.io.DefaultBHttpClientConnection$1.write(DefaultBHttpClientConnection.java:231)
    at org.apache.hc.core5.http.impl.io.SessionOutputBufferImpl.flushBuffer(SessionOutputBufferImpl.java:117)
    at org.apache.hc.core5.http.impl.io.SessionOutputBufferImpl.write(SessionOutputBufferImpl.java:150)
    at org.apache.hc.core5.http.impl.io.ChunkedOutputStream.flushCache(ChunkedOutputStream.java:127)
    at org.apache.hc.core5.http.impl.io.ChunkedOutputStream.flush(ChunkedOutputStream.java:234)
    at org.apache.hc.client5.http.entity.mime.InputStreamBody.writeTo(InputStreamBody.java:92)
    at org.apache.hc.client5.http.entity.mime.AbstractMultipartFormat.doWriteTo(AbstractMultipartFormat.java:165)
    at org.apache.hc.client5.http.entity.mime.AbstractMultipartFormat.writeTo(AbstractMultipartFormat.java:188)
    at org.apache.hc.client5.http.entity.mime.MultipartFormEntity.writeTo(MultipartFormEntity.java:109)
    at org.apache.hc.client5.http.impl.classic.RequestEntityProxy.writeTo(RequestEntityProxy.java:106)
    at org.apache.hc.core5.http.impl.io.DefaultBHttpClientConnection.sendRequestEntity(DefaultBHttpClientConnection.java:252)
    at org.apache.hc.core5.http.impl.io.HttpRequestExecutor.execute(HttpRequestExecutor.java:141)
    at org.apache.hc.core5.http.impl.io.HttpRequestExecutor.execute(HttpRequestExecutor.java:218)
    at org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager$InternalConnectionEndpoint.execute(PoolingHttpClientConnectionManager.java:712)
    at org.apache.hc.client5.http.impl.classic.InternalExecRuntime.execute(InternalExecRuntime.java:216)
    at org.apache.hc.client5.http.impl.classic.MainClientExec.execute(MainClientExec.java:116)
    at org.apache.hc.client5.http.impl.classic.ExecChainElement.execute(ExecChainElement.java:51)
    at org.apache.hc.client5.http.impl.classic.ConnectExec.execute(ConnectExec.java:188)
    at org.apache.hc.client5.http.impl.classic.ExecChainElement.execute(ExecChainElement.java:51)
    at org.apache.hc.client5.http.impl.classic.ProtocolExec.execute(ProtocolExec.java:192)
    at org.apache.hc.client5.http.impl.classic.ExecChainElement.execute(ExecChainElement.java:51)
    at org.apache.hc.client5.http.impl.classic.HttpRequestRetryExec.execute(HttpRequestRetryExec.java:96)
    at org.apache.hc.client5.http.impl.classic.ExecChainElement.execute(ExecChainElement.java:51)
    at org.apache.hc.client5.http.impl.classic.ContentCompressionExec.execute(ContentCompressionExec.java:152)
    at org.apache.hc.client5.http.impl.classic.ExecChainElement.execute(ExecChainElement.java:51)
    at org.apache.hc.client5.http.impl.classic.RedirectExec.execute(RedirectExec.java:115)
    at org.apache.hc.client5.http.impl.classic.ExecChainElement.execute(ExecChainElement.java:51)
    at org.apache.hc.client5.http.impl.classic.InternalHttpClient.doExecute(InternalHttpClient.java:170)
    at org.apache.hc.client5.http.impl.classic.CloseableHttpClient.execute(CloseableHttpClient.java:245)
    at org.apache.hc.client5.http.impl.classic.CloseableHttpClient.execute(CloseableHttpClient.java:188)
    at org.apache.hc.client5.http.impl.classic.CloseableHttpClient.execute(CloseableHttpClient.java:162)
...
    Suppressed: java.net.SocketException: Broken pipe
        at java.base/sun.nio.ch.NioSocketImpl.implWrite(NioSocketImpl.java:420)
        at java.base/sun.nio.ch.NioSocketImpl.write(NioSocketImpl.java:440)
        at java.base/sun.nio.ch.NioSocketImpl$2.write(NioSocketImpl.java:826)
        at java.base/java.net.Socket$SocketOutputStream.write(Socket.java:1035)
        at org.apache.hc.core5.http.impl.io.DefaultBHttpClientConnection$1.write(DefaultBHttpClientConnection.java:231)
        at org.apache.hc.core5.http.impl.io.SessionOutputBufferImpl.flushBuffer(SessionOutputBufferImpl.java:117)
        at org.apache.hc.core5.http.impl.io.SessionOutputBufferImpl.write(SessionOutputBufferImpl.java:150)
        at org.apache.hc.core5.http.impl.io.ChunkedOutputStream.flushCache(ChunkedOutputStream.java:127)
        at org.apache.hc.core5.http.impl.io.ChunkedOutputStream.finish(ChunkedOutputStream.java:184)
        at org.apache.hc.core5.http.impl.io.ChunkedOutputStream.close(ChunkedOutputStream.java:245)
        at org.apache.hc.core5.http.impl.io.DefaultBHttpClientConnection.sendRequestEntity(DefaultBHttpClientConnection.java:253)
        ... 23 more

i tried both java.net.http and org.apache.hc.client5.http client. And it seems there is no way to get response in case of IOException.

Is it possible to get response error code if IOException? OR more general, what is the correct way of prematurely interrupting POST requests with Transfer-Encoding: chunked ?

0

There are 0 answers