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

Johannes Herr reopened CXF-9057:
--------------------------------

I have tried version 3.5.10 and 3.6.5 and the problem does not seem to be 
fixed. One can try it with the reproducer project I attached. If you change the 
version in the pom to one of those two versions, the chunked encoding is still 
terminated with 0 indicating success and no exception is thrown in 
{{chunked.ServerMockTest#stream_with_error_and_cxf_client}}.

I have looked into why the test case 
{{org.apache.cxf.systest.jaxws.AttachmentChunkingTest}} included in the fix 
does not fail in contrast to my reproducer (on tag 3.5.10). The problem seems 
to be that the server sending the response does not use chunked encoding when 
sending data. The bug does not apply then.

This is the response sent by the server in the test case 
{{testChunkingPartialFailure}}:

{noformat}
HTTP/1.1 200 OK
Date: Tue, 21 Jan 2025 11:48:59 GMT
Content-Type: text/xml;charset=utf-8
Content-Length: 254
Server: Jetty(9.4.56.v20240826)

<soap:Envelope 
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/";><soap:Body><soap:Fault><faultcode>soap:Server</faultcode><faultstring>Marshalling
 Error: simulated error during stream 
processing</faultstring></soap:Fault></soap:Body></soap:Envelope>
{noformat}

One can see that a response length is used and no chunked encoding is used. 
That means the server has buffered the response and not started sending it 
before the exception occurred. So he could avoid sending a partial response and 
can return an error messages. (Note that this can not be a fix for the bug, 
because the application could have been sending 100 GB of data before the 
exception. So it has to be streamed and cannot be completely buffered.)

It seems to be sufficient to enable MTOM in the test server to make it use 
chunked encoding in the unit test. The response looks like this then:

{noformat}
HTTP/1.1 200 OK
Date: Tue, 21 Jan 2025 12:15:33 GMT
Content-Type: multipart/related; type="application/xop+xml"; 
boundary="uuid:8cf6e9c1-fc0f-4513-bd6d-8a2bf85406f0"; 
start="<root.mess...@cxf.apache.org>"; start-info="text/xml"
Transfer-Encoding: chunked
Server: Jetty(9.4.56.v20240826)

8000

--uuid:8cf6e9c1-fc0f-4513-bd6d-8a2bf85406f0
Content-Type: application/xop+xml; charset=UTF-8; type="text/xml"
Content-Transfer-Encoding: binary
Content-ID: <root.mess...@cxf.apache.org>

<soap:Envelope 
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/";><soap:Body><ns2:downloadNextResponse
 
xmlns:ns2="http://cxf.apache.org/";><ns2:downloadNextResponse><dataContent><xop:Include
 xmlns:xop="http://www.w3.org/2004/08/xop/include"; 
href="cid:488565d7-85b5-4550-b66c-9db03faa0458-1@cxf.apache.org"/></dataContent></ns2:downloadNextResponse></ns2:downloadNextResponse></soap:Body></soap:Envelope>
--uuid:8cf6e9c1-fc0f-4513-bd6d-8a2bf85406f0
Content-Type:
Content-Transfer-Encoding: binary
Content-ID: <488565d7-85b5-4550-b66c-9db03faa045...@cxf.apache.org>

xxxxx[...]xxxxxxxxxxxxxxxxxx
6301
xxxxxxxx[...]xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
0
{noformat}

The undesired closing 0 is included in the response and the test case fails 
with {{java.lang.AssertionError: expected javax.xml.ws.soap.SOAPFaultException 
to be thrown, but nothing was thrown}}.

I have attached a patch with my changes to the class to make it use chunked 
encoding. (The randomness of the length of the response seems also a bit 
dangerous here, because if the response is too small Jetty will probably not 
use chunked encoding, but sent a buffered response.)

> Chunked Stream is closed regularly when Exception is thrown
> -----------------------------------------------------------
>
>                 Key: CXF-9057
>                 URL: https://issues.apache.org/jira/browse/CXF-9057
>             Project: CXF
>          Issue Type: Bug
>    Affects Versions: 3.5.8
>            Reporter: Johannes Herr
>            Assignee: Andriy Redko
>            Priority: Major
>             Fix For: 4.1.0, 3.5.10, 3.6.5, 4.0.6
>
>         Attachments: chunked-reproducer.tar.gz
>
>
> In response to SOAP requests served by Apache CXF we send large datasets 
> streamed directly from a database. Because of the size of the data, chunked 
> encoding is used. Unfortunately when a database error occurs and an exception 
> is thrown while data is sent, the client will receive a regular ending to the 
> chunked data stream. That means he has no way to recognise that an error 
> occurred and that he has only received a partial file.
> To be more specific the response looks somewhat like this:
> {code:java}
> HTTP/1.1 200 OK
> Date: Tue, 10 Sep 2024 16:17:45 GMT
> Content-Type: multipart/related; type="application/xop+xml"; 
> boundary="uuid:49aa53f9-ec29-4f1a-bc07-a21256c2f940"; 
> start="<root.mess...@cxf.apache.org>"; start-info="text/xml"
> Transfer-Encoding: chunked
> Server: Jetty(10.0.21)
> 8000
> --uuid:49aa53f9-ec29-4f1a-bc07-a21256c2f940
> Content-Type: application/xop+xml; charset=UTF-8; type="text/xml"
> Content-Transfer-Encoding: binary
> Content-ID: <root.mess...@cxf.apache.org>
> <soap:Envelope 
> xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/";>[...]</soap:Envelope>
> --uuid:49aa53f9-ec29-4f1a-bc07-a21256c2f940
> Content-Type:
> Content-Transfer-Encoding: binary
> Content-ID: <03d4ea67-6e8b-4d1f-91b0-b63208989f9...@cxf.apache.org>
> xxxxxxxxxxxx[...]xxxxxxx
> 356
> xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
> 0
> {code}
> That means the response ends with the "0" entry, indicating that the transfer 
> is complete.
> What should happen instead is that the response should be closed without 
> sending the final 0 entry. ([https://stackoverflow.com/a/17203961/136247])
> For example when we use a Servlet to stream data to a client a throw an 
> exception the result will look something like this:
> {code:java}
> HTTP/1.1 200 OK
> Date: Fri, 13 Sep 2024 09:31:48 GMT
> Content-Type: text/plain;charset=utf-8
> Transfer-Encoding: chunked
> Server: Jetty(10.0.21)
> 8
> Chunk 1
> 8
> Chunk 2
> 8
> Chunk 3
> 8
> Chunk 4
> 8
> Chunk 5
> {code}
> Here there is no closing 0 marker. As a result clients can recognise the 
> error. (Curl will report "curl: (18) transfer closed with outstanding read 
> data remaining", Chrome "Failed to load resource: 
> net::ERR_INCOMPLETE_CHUNKED_ENCODING")
> CXF should do the same and not end the chunked stream regularly, when an 
> exception is thrown.
> I have tested with Tomcat and Jetty. Both show the same behaviour.
> To provide some detail, Exceptions are caught by CXF here:
> org/apache/cxf/phase/PhaseInterceptorChain.java:328
> {code:java}
>                 } catch (RuntimeException ex) {
>                     if (!faultOccurred) {
>                         faultOccurred = true;
>                         wrapExceptionAsFault(message, ex);
>                     }
>                     state = State.ABORTED;
>                 }
> {code}
> The exception is logged, but not rethrown.
> If the exception would be thrown, for instance Tomcats ErrorReportValve would 
> shut down the output and thereby prevent the end of the input and closing 0 
> to be written.
> org/apache/catalina/valves/ErrorReportValve.java:112
> {code:java}
>                     // Now close immediately to signal to the client that
>                     // something went wrong
>                     response.getCoyoteResponse().action(ActionCode.CLOSE_NOW,
>                             
> request.getAttribute(RequestDispatcher.ERROR_EXCEPTION));
> {code}
> Without an exception to prevent this, a regular end of the stream will be 
> written by
> org/apache/catalina/connector/CoyoteAdapter.java:371
> response.finishResponse();
> In Summary: CXF ends a chunked encoded stream in a regular way in spite of 
> exceptions occurring, which makes it impossible for clients to recognise that 
> they have downloaded partial and therefore corrupt data.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to