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

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

Hi Andriy, thanks for looking into this.

I think it really matters if the response uses chunked encoding or not. My bug 
report only concerns chunked encoding. When chunked encoding is not used, the 
servlet container can return whatever it wants to. That means it can return a 
soap error messages as it is the case right now:
{noformat}
HTTP/1.1 200 OK
Date: Mon, 27 Jan 2025 08:05:32 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}
(formatted for readability)

It could also return an error status 500 and the html error page you posted in 
your comment. Both are fine, since both indicate to the caller that something 
went wrong. (Of course the structured soap error contains more relevant 
information.)

However, when chunked encoding is used, the server has already sent the http 
success status and has already transferred parts of the response data. This has 
already been received and processed by the client, when the error occurs. That 
means it cannot go back and change the http status or change the data it sent. 
I therefore doubt, that jetty would try to send the html error page you 
describe in this case. Thats also not the behaviour my servlet test in the 
reproducer shows. As far as I have been able to determine, the only thing the 
webserver can do at this point is close the connection without the final "0" to 
indicate that the data transfer was not complete.

CXF sends the final "0" in case of errors at the moment and therefore the 
client can not distinguish between incomplete and successful downloads:
{noformat}
HTTP/1.1 200 OK
Date: Mon, 27 Jan 2025 08:03:13 GMT
Content-Type: multipart/related; type="application/xop+xml"; 
boundary="uuid:43c5ed92-e223-4dca-842b-933b7abd32e4"; 
start="<[email protected]>"; start-info="text/xml"
Transfer-Encoding: chunked
Server: Jetty(9.4.56.v20240826)

301

--uuid:43c5ed92-e223-4dca-842b-933b7abd32e4
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: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:[email protected]"/>
                </dataContent>
            </ns2:downloadNextResponse>
        </ns2:downloadNextResponse>
    </soap:Body>
</soap:Envelope>
--uuid:43c5ed92-e223-4dca-842b-933b7abd32e4
Content-Type:
Content-Transfer-Encoding: binary
Content-ID: <[email protected]>


0  <-- this should be missing in case of errors
{noformat}
I guess you are saying a fix for the chunked encoding case (throwing the 
exception to the servlet container) would break the behaviour when a fixed size 
response is sent?
Unfortunately I do not know enough about the cxf implementation to say if one 
can distinguish between these cases. Could cxf throw the exception only if 
chunked encoding is used to send the 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: 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