[CXF-8926] replace PipedInputStream with TimedBlockingPipe to fix MTO…#3250
Open
ffang wants to merge 1 commit into
Open
[CXF-8926] replace PipedInputStream with TimedBlockingPipe to fix MTO…#3250ffang wants to merge 1 commit into
ffang wants to merge 1 commit into
Conversation
…M attachment stall
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
…M attachment stall
Summary
Fixes CXF-8926: a CXF client sending a large request body (e.g. a MTOM attachment) to a slow or stalled server hangs indefinitely with no way to recover.
Root cause
Two conduits are affected by the same underlying problem — the CXF writer thread can be permanently blocked on a request-body write with no effect from
receiveTimeout:HttpClientHTTPConduit— CXF serializes the request body into aPipedOutputStream; the JDKHttpClientdrains the connectedPipedInputStreamon a cached thread-pool thread. When the server reads slowly (or not at all), OS TCP send/receive buffers fill, the HttpClient thread stalls inside the pipe, andPipedOutputStream.write()blocks inawaitSpace()forever. Compounding this, after ~60 s of inactivity the JDK cached-pool idle-reaps the draining thread; the next write then throwsjava.io.IOException: Read end dead→Could not write attachmentseven though the server never closed the connection.URLConnectionHTTPConduit— writes directly toHttpURLConnection$StreamingOutputStream; when OS TCP buffers fill the socket write blocks indefinitely. No pipe or thread-reap is involved — it simply hangs.In both cases
receiveTimeouthas no effect because it only governs the HTTP response read timeout, not the request-body write path.Fix
HttpClientHTTPConduit: replacePipedInputStream/PipedOutputStreamwith a newTimedBlockingPipe— a purpose-built, lock-based circular byte buffer. Key differences from the JDK pipe:receiveTimeout > 0, writes fail with a boundedIOExceptioninstead of hanging forever; whenreceiveTimeout = 0, writes block indefinitely (same as before, but without theRead end deadrisk).URLConnectionHTTPConduit: interpose the sameTimedBlockingPipebetween the CXF writer and the socket output. A background daemon thread drains the pipe and pushes bytes to the socket;close()on the pipe side waits for the copier to finish beforehandleResponse()reads the reply.Tests added (
MTOMAttachmentStallTest)testMtomClientDoesNotHangWhenNetworkStallsServerSocketaccepts but never reads; OS TCP buffers saturateforceURLConnection)testMtomClientSucceedsWhenServerResumesAfterStallHttpClientHTTPConduittestMtomClientDoesNotHangWhenNetworkStallssetsreceiveTimeout = 5 sand asserts the client unblocks within 20 s.testMtomClientSucceedsWhenServerResumesAfterStallsetsreceiveTimeout = 0(infinite) and asserts the call succeeds once back-pressure releases — provingTimedBlockingPipesurvives the stall that previously causedRead end dead.