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

Johannes Herr commented on CXF-9057:
------------------------------------

I have included the 3.5.11-SNAPSHOT version in two of our projects and ran the 
test suites against it. No problems have surfaced.

My producer behave as intended as desired with 3.5.11-SNAPSHOT. It now throws 
an exception where it would have silently returned partial data before.

The included unit test seems to always produce too little data to actually use 
chunked encoding. It always sends an empty response. (Which of course is also 
one of the cases one would want to test.)

{noformat}
HTTP/1.1 200 OK
Date: Thu, 06 Feb 2025 11:57:27 GMT
Content-Type: multipart/related; type="application/xop+xml"; 
boundary="uuid:691cbcb3-ae72-453a-bfa1-be85d1546ce3"; 
start="<[email protected]>"; start-info="text/xml"
Connection: close
Content-Length: 0
Server: Jetty(9.4.56.v20240826)
{noformat}

To actually use chunked encoding, I replaced:
{code}
                if (ThreadLocalRandom.current().nextBoolean()) {
                    throw new IllegalArgumentException("simulated error during 
stream processing");
                }
{code}

With:
{code}
                if (ThreadLocalRandom.current().nextDouble() < 0.01) {
                    throw new IllegalArgumentException("simulated error during 
stream processing");
                }
{code}

Note that the unit test will fail, when chunked encoding is used, because the 
exception is only thrown when the returned input stream is read.

{code}
ByteStreams.toByteArray(downloadNextResponseType.getDataContent().getInputStream())
{code}

The tests contain the string:

{code}
"jakarta.xml.ws.service.endpoint.address"
{code}

in
org.apache.cxf.systest.jaxws.AbstractAttachmentChunkingTest#testChunking
org.apache.cxf.systest.jaxws.AttachmentMtomChunkingTest#testChunkingPartialFailure

instead of:

{code}
"javax.xml.ws.service.endpoint.address"
{code}

(In "testChunkingPartialFailure" this is not noticeable, because it expects an 
exception, which it will get of the string instead of the network problems:\)

{noformat}
javax.xml.ws.soap.SOAPFaultException: Cannot invoke 
"org.apache.cxf.transport.http.Address.getURL()" because "address" is null
{noformat}

I have looked at the diff. Unfortunately I do not know the cxf source code 
enough to be able to assess it.

So your changes seem to fix the problem very well. Thank you for taking the 
time to look into the problem!


> 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: 3.5.11, 3.6.6, 4.0.7, 4.1.1
>
>         Attachments: activate-chunked-in-unit-text.patch, 
> 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="<[email protected]>"; 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: <[email protected]>
> <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: <[email protected]>
> 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