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();

Reply via email to