[
https://issues.apache.org/jira/browse/CXF-8926?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17840206#comment-17840206
]
Kai Zander commented on CXF-8926:
---------------------------------
I too am getting the exception [~wilfriedvandenberghe], posted. We're on CXF
4.0.4 and this doesn't necessarily have anything to do with uploading
attachments: Any large request (larger then the chunking threshold) will do,
_if_ the target server rejects a chunk with HTTP 413 and closes the connection.
In our case, we're calling an NGINX with {{client_max_body_size: 1MB}}. When
sending a request that's larger than this limit, _and_ CXF uses chunked
transfer encoding (which it does by default for requests larger than 4096
bytes), NGINX will reject the chunk that exceeds the request body limit and
close the connection.
The {{HttpClient}} used by {{HttpClientHttpConduit}} notices that and cancels
the read subscription, but CXF doesn't notice and it'll hang at
{{PipedOutputStream.write()}}.
The JDK {{HttpClient}} by default uses an {{Executors.newCachedThreadPool()}}
with an idle timeout of 60 seconds. In the best case, where no other requests
are being sent, the thread originally used for "our" request will die after 60
seconds. The {{PipedInputStream}} then finally notices that and we get the
{{"Read end dead"}} exception.
If the application is _not_ idle and the thread pool's threads are _not_
running into their idle timeout, "our" original request may hang indefinitely.
If we enable debug logs for the {{HttpClient}} with
{{-Djdk.httpclient.HttpClient.log=errors,requests,headers,frames:control:data:window,ssl,trace,channel}},
we can see the following:
{code:plain}
INFO 2024-04-22 18:25:23,614 HttpClient - MISC: Registering timer
ConnectTimerEvent, TimeoutEvent[id=6, duration=PT5S,
deadline=2024-04-22T16:25:28.614694400Z] - {} - HttpClient-3-Worker-3
INFO 2024-04-22 18:25:23,632 HttpClient - CHANNEL: Start reading from
java.nio.channels.SocketChannel[connected local=/REDACTED:64261
remote=REDACTED/REDACTED:443] - {} - HttpClient-3-SelectorManager
INFO 2024-04-22 18:25:23,632 HttpClient - CHANNEL: Start requesting bytes for
writing to channel: java.nio.channels.SocketChannel[connected
local=/REDACTED:64261 remote=REDACTED/REDACTED:443] - {} -
HttpClient-3-SelectorManager
INFO 2024-04-22 18:25:23,653 HttpClient - MISC: Canceling timer
ConnectTimerEvent, TimeoutEvent[id=6, duration=PT5S,
deadline=2024-04-22T16:25:28.614694400Z] - {} - HttpClient-3-Worker-3
INFO 2024-04-22 18:25:23,653 HttpClient - CHANNEL: HTTP/1 read subscriber got
subscription from https://REDACTED/REDACTED/REDACTED POST - {} -
HttpClient-3-Worker-3
// Start sending data, announcing chunked transfer encoding
INFO 2024-04-22 18:25:23,653 HttpClient - REQUEST:
https://REDACTED/REDACTED/REDACTED POST - {} - HttpClient-3-Worker-3
INFO 2024-04-22 18:25:23,653 HttpClient - HEADERS: REQUEST HEADERS:
POST /REDACTED HTTP/1.1
Host: REDACTED
Transfer-encoding: chunked
Accept: */*
Content-Type: application/soap+xml; action="REDACTED"; charset=UTF-8
User-Agent: Apache-CXF/4.0.4
- {} - HttpClient-3-Worker-3
// Got response ~200ms later --> Rejected with HTTP 413, connection closed
INFO 2024-04-22 18:25:23,846 HttpClient - HEADERS: RESPONSE HEADERS:
connection: close
content-length: 176
content-type: text/html; charset=utf-8
date: Mon, 22 Apr 2024 16:25:23 GMT
- {} - HttpClient-3-Worker-3
INFO 2024-04-22 18:25:23,846 HttpClient - RESPONSE: (POST
https://REDACTED/REDACTED/REDACTED) 413 HTTP_1_1 Local port: 64261 - {} -
HttpClient-3-Worker-3
INFO 2024-04-22 18:25:23,846 HttpClient - MISC: Applying response filters - {}
- HttpClient-3-Worker-3
INFO 2024-04-22 18:25:23,846 HttpClient - MISC: Applying
jdk.internal.net.http.RedirectFilter@40f5ba59 - {} - HttpClient-3-Worker-3
INFO 2024-04-22 18:25:23,846 HttpClient - MISC: Applying
jdk.internal.net.http.AuthenticationFilter@4e324def - {} -
HttpClient-3-Worker-3
INFO 2024-04-22 18:25:23,846 HttpClient - MISC: All filters applied - {} -
HttpClient-3-Worker-3
INFO 2024-04-22 18:25:23,846 HttpClient - MISC: Canceling timer
ResponseTimerEvent[TimeoutEvent[id=5, duration=PT10S,
deadline=2024-04-22T16:25:33.613191800Z]] - {} - HttpClient-3-Worker-3
INFO 2024-04-22 18:25:23,846 HttpClient - MISC: Attempting to return
connection to the pool: HttpConnection:
java.nio.channels.SocketChannel[connected local=/REDACTED:64261
remote=REDACTED/REDACTED:443] - {} - HttpClient-3-Worker-3
INFO 2024-04-22 18:25:23,846 HttpClient - MISC: Closing connection
(keepAlive=false, isOpen=true): HttpConnection:
java.nio.channels.SocketChannel[connected local=/REDACTED:64261
remote=REDACTED/REDACTED:443] - {} - HttpClient-3-Worker-3
INFO 2024-04-22 18:25:23,846 HttpClient - MISC: Closing: PlainHttpConnection:
HttpConnection: java.nio.channels.SocketChannel[connected local=/REDACTED:64261
remote=REDACTED/REDACTED:443] - {} - HttpClient-3-Worker-3
INFO 2024-04-22 18:25:23,846 HttpClient - MISC: Canceling timer
ConnectTimerEvent, TimeoutEvent[id=6, duration=PT5S,
deadline=2024-04-22T16:25:28.614694400Z] - {} - HttpClient-3-Worker-3
// --> Socket closed
INFO 2024-04-22 18:25:23,846 HttpClient - CHANNEL: Connection close signalled:
connection closed locally (java.nio.channels.SocketChannel[closed]) - {} -
HttpClient-3-Worker-3
INFO 2024-04-22 18:25:23,847 HttpClient - CHANNEL: Read error signalled on
channel java.nio.channels.SocketChannel[closed]: java.io.IOException:
connection closed locally - {} - HttpClient-3-Worker-3
INFO 2024-04-22 18:25:23,847 HttpClient - CHANNEL: Raising error with
subscriber for java.nio.channels.SocketChannel[closed]: java.io.IOException:
connection closed locally - {} - HttpClient-3-Worker-3
INFO 2024-04-22 18:25:23,847 HttpClient - MISC: HttpClient-3-SelectorManager:
java.io.IOException: Channel closed - {} - HttpClient-3-SelectorManager
INFO 2024-04-22 18:25:23,847 HttpClient - ERROR: HTTP/1 read subscriber
recorded error: <uri unavailable> - java.io.IOException: connection closed
locally - {} - HttpClient-3-Worker-3
INFO 2024-04-22 18:25:23,847 HttpClient - CHANNEL: Stopped reading from
channel java.nio.channels.SocketChannel[closed] - {} - HttpClient-3-Worker-3
INFO 2024-04-22 18:25:23,847 HttpClient - CHANNEL: Failed to write to channel
(java.nio.channels.SocketChannel[closed]:
java.nio.channels.ClosedChannelException) - {} - HttpClient-3-Worker-3
INFO 2024-04-22 18:25:23,847 HttpClient - CHANNEL: Cancelling write
subscription - {} - HttpClient-3-Worker-3
// One minute later, the thread "HttpClient-3-Worker-3" (the reading side/end)
is no longer alive and we get "Read end dead" when attempting to write more data
WARN 2024-04-22 18:26:23,879 PhaseInterceptorChain - Interceptor for REDACTED
has thrown exception, unwinding now - {} - message-consumer-pool-3-thread-2
org.apache.cxf.binding.soap.SoapFault: Problem writing SAAJ model to stream:
Read end dead
{code}
Notice how the {{HttpClient}} immediately notices the server rejecting the
chunk with HTTP 413, but it takes another full minute until the idle timeout
applies, the {{HttpClient}} worker thread dies and CXF notices.
> MTOM - Lock while processing attachment
> ---------------------------------------
>
> Key: CXF-8926
> URL: https://issues.apache.org/jira/browse/CXF-8926
> Project: CXF
> Issue Type: Bug
> Reporter: wilfried
> Priority: Major
>
> I'm currently implementing a SOAP client to send document with CXF 4.0.1 (the
> application is quarkus based).
> My client is working fine when firewall is open between my machine and the
> target server, but in case firewall is closed (for QA environment for
> example), I was expecting to get a timeout, but it's not the case. The SOAP
> client stops its execution to the interceptor *AttachmentOutEndingInterceptor
> *and waits indefinitely.
> After profiling the application, I found out a lock as shown by the below
> thread dump:
> {code:java}
> "executor-thread-2" #296 daemon prio=5 os_prio=0 cpu=31.25ms elapsed=201.04s
> tid=0x0000019f9cd475d0 nid=0x5cf8 in Object.wait() [0x0000009645dfe000]
> java.lang.Thread.State: TIMED_WAITING (on object monitor)
> at java.lang.Object.wait([email protected]/Native Method)
> - waiting on <no object reference available>
> at
> java.io.PipedInputStream.awaitSpace([email protected]/PipedInputStream.java:273)
> at
> java.io.PipedInputStream.receive([email protected]/PipedInputStream.java:231)
> - locked <0x0000000613854b08> (a java.io.PipedInputStream)
> at
> java.io.PipedOutputStream.write([email protected]/PipedOutputStream.java:150)
> at
> org.apache.cxf.io.AbstractWrappedOutputStream.write(AbstractWrappedOutputStream.java:51)
> at
> org.apache.cxf.io.AbstractThresholdOutputStream.write(AbstractThresholdOutputStream.java:69)
> at
> org.apache.cxf.io.CacheAndWriteOutputStream.write(CacheAndWriteOutputStream.java:81)
> at jakarta.activation.DataHandler.writeTo(DataHandler.java:283)
> at
> org.apache.cxf.attachment.AttachmentSerializer.writeAttachments(AttachmentSerializer.java:318)
> at
> org.apache.cxf.interceptor.AttachmentOutInterceptor$AttachmentOutEndingInterceptor.handleMessage(AttachmentOutInterceptor.java:126)
> at
> org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:307)
> - locked <0x0000000613856e30> (a
> org.apache.cxf.phase.PhaseInterceptorChain)
> at org.apache.cxf.endpoint.ClientImpl.doInvoke(ClientImpl.java:528)
> at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:439)
> at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:354)
> at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:312)
> at org.apache.cxf.frontend.ClientProxy.invokeSync(ClientProxy.java:96)
> at
> org.apache.cxf.jaxws.JaxWsClientProxy.invoke(JaxWsClientProxy.java:140)
> at jdk.proxy7.$Proxy235.addMessage(jdk.proxy7/Unknown Source)
> at
> lu.etat.ci.fwt.soap.SOAPTestController.callSaySomethingMtomSecuredCIDUT(SOAPTestController.java:138)
> at
> lu.etat.ci.fwt.soap.SOAPTestController$quarkusrestinvoker$callSaySomethingMtomSecuredCIDUT_1b14f2d5ed1a4d42c824e7582903a9f19063cae3.invoke(Unknown
> Source)
> at
> org.jboss.resteasy.reactive.server.handlers.InvocationHandler.handle(InvocationHandler.java:29)
> at
> io.quarkus.resteasy.reactive.server.runtime.QuarkusResteasyReactiveRequestContext.invokeHandler(QuarkusResteasyReactiveRequestContext.java:141)
> at
> org.jboss.resteasy.reactive.common.core.AbstractResteasyReactiveContext.run(AbstractResteasyReactiveContext.java:145)
> at
> io.quarkus.vertx.core.runtime.VertxCoreRecorder$14.runWith(VertxCoreRecorder.java:576)
> at
> org.jboss.threads.EnhancedQueueExecutor$Task.run(EnhancedQueueExecutor.java:2513)
> at
> org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1512)
> at
> org.jboss.threads.DelegatingRunnable.run(DelegatingRunnable.java:29)
> at
> org.jboss.threads.ThreadLocalResettingRunnable.run(ThreadLocalResettingRunnable.java:29)
> at
> io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
> at java.lang.Thread.run([email protected]/Thread.java:833)
> {code}
--
This message was sent by Atlassian Jira
(v8.20.10#820010)