This is an automated email from the ASF dual-hosted git repository. reta pushed a commit to branch 4.1.x-fixes in repository https://gitbox.apache.org/repos/asf/cxf.git
commit a74d3aff61086d5c7851e5a7e42f45dd1535a37a Author: Andriy Redko <[email protected]> AuthorDate: Thu Oct 8 11:37:16 2026 -0400 CXF-9251: Thrown exception trying to write into closed stream (#3555) * CXF-9251: Thrown exception trying to write into closed stream * Address code review comments (cherry picked from commit cb99c360800551a5594ea9de2a4f159a16c62734) --- .../apache/cxf/ext/logging/LoggingOutputStream.java | 19 +++++++------------ .../cxf/ext/logging/LoggingOutInterceptorTest.java | 6 ++---- 2 files changed, 9 insertions(+), 16 deletions(-) diff --git a/rt/features/logging/src/main/java/org/apache/cxf/ext/logging/LoggingOutputStream.java b/rt/features/logging/src/main/java/org/apache/cxf/ext/logging/LoggingOutputStream.java index ac24ac1a528..ab3a3b072fb 100644 --- a/rt/features/logging/src/main/java/org/apache/cxf/ext/logging/LoggingOutputStream.java +++ b/rt/features/logging/src/main/java/org/apache/cxf/ext/logging/LoggingOutputStream.java @@ -82,16 +82,15 @@ public class LoggingOutputStream extends CacheAndWriteOutputStream { * This caused ghost/delayed OUT log and possible memory-leak due to DelayedCachedOutputStreamCleaner * * Once closed (and logged), any late write (for example the fault chain writing the closing tags - * through a writer still wrapping this stream) is only passed through to the flow-through stream and - * is not cached anymore: some containers (e.g. Tomcat 10.1) silently accept writes after close, and - * caching them would spill into a new temp file that close() (now a no-op) could never delete. + * through a writer still wrapping this stream) is leading to {@code IOException} since all underlying + * stream are closed: some containers (e.g. Tomcat 10.1) silently accept writes after close, and + * caching them (by letting writes to go through) would spill into a new temp file that close() + * (now a no-op) could never delete. */ @Override public void write(byte[] b) throws IOException { if (closed.get()) { - // already closed and logged: pass through only, do not cache again - getFlowThroughStream().write(b); - return; + throw new IOException("The channel has been closed already"); } try { super.write(b); @@ -104,9 +103,7 @@ public class LoggingOutputStream extends CacheAndWriteOutputStream { @Override public void write(byte[] b, int off, int len) throws IOException { if (closed.get()) { - // already closed and logged: pass through only, do not cache again - getFlowThroughStream().write(b, off, len); - return; + throw new IOException("The channel has been closed already"); } try { super.write(b, off, len); @@ -119,9 +116,7 @@ public class LoggingOutputStream extends CacheAndWriteOutputStream { @Override public void write(int b) throws IOException { if (closed.get()) { - // already closed and logged: pass through only, do not cache again - getFlowThroughStream().write(b); - return; + throw new IOException("The channel has been closed already"); } try { super.write(b); diff --git a/rt/features/logging/src/test/java/org/apache/cxf/ext/logging/LoggingOutInterceptorTest.java b/rt/features/logging/src/test/java/org/apache/cxf/ext/logging/LoggingOutInterceptorTest.java index e94f726432f..bc415a21484 100644 --- a/rt/features/logging/src/test/java/org/apache/cxf/ext/logging/LoggingOutInterceptorTest.java +++ b/rt/features/logging/src/test/java/org/apache/cxf/ext/logging/LoggingOutInterceptorTest.java @@ -336,8 +336,7 @@ public class LoggingOutInterceptorTest { // A late writer still holding the old stream reference, with a flow-through stream that // accepts writes after close: it must not be cached (and spilled to a new temp file) again - cached.write(bytes, 0, bytes.length); - assertThat(((ByteArrayOutputStream) os).size(), equalTo(2 * bytes.length)); + assertThrows(IOException.class, () -> cached.write(bytes, 0, bytes.length)); final File tempFile = ((CachedOutputStream) cached).getTempFile(); cleaner.forceClean(); @@ -385,8 +384,7 @@ public class LoggingOutInterceptorTest { // e.g. the fault chain (SoapOutEndingInterceptor) writing the closing tags through the // XMLStreamWriter that still wraps this stream, with a flow-through stream that accepts writes // after close (as Tomcat 10.1 does): it must not be cached (and spilled to a new temp file) again - cached.write(bytes, 0, bytes.length); - assertThat(((ByteArrayOutputStream) os).size(), equalTo(2 * bytes.length)); + assertThrows(IOException.class, () -> cached.write(bytes, 0, bytes.length)); final File tempFile = ((CachedOutputStream) cached).getTempFile(); cleaner.forceClean();
