You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cxf.apache.org by re...@apache.org on 2025/02/16 16:55:06 UTC

(cxf) branch 3.6.x-fixes updated (468b31b165 -> 63fe05703e)

This is an automated email from the ASF dual-hosted git repository.

reta pushed a change to branch 3.6.x-fixes
in repository https://gitbox.apache.org/repos/asf/cxf.git


    from 468b31b165 Recording .gitmergeinfo Changes
     new 07b6af3eb3 CXF-9057: Chunked Stream is closed regularly when Exception is thrown (MTOM) (#2234)
     new a365545d00 Recording .gitmergeinfo Changes
     new 63fe05703e Recording .gitmergeinfo Changes

The 3 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .gitmergeinfo                                      |   4 +
 .../AbortedInvocationException.java}               |   8 +-
 .../apache/cxf/phase/PhaseInterceptorChain.java    |   3 +
 .../interceptor/Soap11FaultOutInterceptor.java     |   8 +-
 .../interceptor/Soap12FaultOutInterceptor.java     |   8 +-
 .../transport/http/AbstractHTTPDestination.java    |  29 +++++-
 ...st.java => AbstractAttachmentChunkingTest.java} |  75 +++-----------
 .../cxf/systest/jaxws/AttachmentChunkingTest.java  | 101 ++-----------------
 ...ngTest.java => AttachmentMtomChunkingTest.java} | 108 +++++----------------
 .../src/test/resources/attachments/cxf9057.wsdl    |   1 +
 10 files changed, 97 insertions(+), 248 deletions(-)
 copy core/src/main/java/org/apache/cxf/{continuations/SuspendedInvocationException.java => phase/AbortedInvocationException.java} (87%)
 copy systests/jaxws/src/test/java/org/apache/cxf/systest/jaxws/{AttachmentChunkingTest.java => AbstractAttachmentChunkingTest.java} (59%)
 copy systests/jaxws/src/test/java/org/apache/cxf/systest/jaxws/{AttachmentChunkingTest.java => AttachmentMtomChunkingTest.java} (54%)


(cxf) 01/03: CXF-9057: Chunked Stream is closed regularly when Exception is thrown (MTOM) (#2234)

Posted by re...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

reta pushed a commit to branch 3.6.x-fixes
in repository https://gitbox.apache.org/repos/asf/cxf.git

commit 07b6af3eb368e691a85e15ad77e07aedfc6a9d33
Author: Andriy Redko <dr...@gmail.com>
AuthorDate: Sat Feb 15 10:42:30 2025 -0500

    CXF-9057: Chunked Stream is closed regularly when Exception is thrown (MTOM) (#2234)
    
    (cherry picked from commit e28d4a77a7ee59d03219ff4767eae1d7bedeb207)
    (cherry picked from commit 7f14b6284f14e4ebe18e4f8411687d5120e91f55)
    
    # Conflicts:
    #       systests/jaxws/src/test/java/org/apache/cxf/systest/jaxws/AttachmentChunkingTest.java
---
 .../cxf/phase/AbortedInvocationException.java      |  48 +++++++++
 .../apache/cxf/phase/PhaseInterceptorChain.java    |   3 +
 .../interceptor/Soap11FaultOutInterceptor.java     |   8 +-
 .../interceptor/Soap12FaultOutInterceptor.java     |   8 +-
 .../transport/http/AbstractHTTPDestination.java    |  29 +++++-
 ...st.java => AbstractAttachmentChunkingTest.java} |  75 +++-----------
 .../cxf/systest/jaxws/AttachmentChunkingTest.java  | 101 ++-----------------
 ...ngTest.java => AttachmentMtomChunkingTest.java} | 108 +++++----------------
 .../src/test/resources/attachments/cxf9057.wsdl    |   1 +
 9 files changed, 137 insertions(+), 244 deletions(-)

diff --git a/core/src/main/java/org/apache/cxf/phase/AbortedInvocationException.java b/core/src/main/java/org/apache/cxf/phase/AbortedInvocationException.java
new file mode 100644
index 0000000000..ee2553d1af
--- /dev/null
+++ b/core/src/main/java/org/apache/cxf/phase/AbortedInvocationException.java
@@ -0,0 +1,48 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.cxf.phase;
+
+/**
+ * Represents transport-specific exceptions which are used to indicate that
+ * a given invocation was suspended
+ */
+public class AbortedInvocationException extends RuntimeException {
+
+    private static final long serialVersionUID = 6889545463301144757L;
+
+
+    public AbortedInvocationException(Throwable cause) {
+        super(cause);
+    }
+
+    public AbortedInvocationException() {
+    }
+
+
+    /**
+     * Returns a transport-specific runtime exception
+     * @return RuntimeException the transport-specific runtime exception,
+     *         can be null for asynchronous transports
+     */
+    public RuntimeException getRuntimeException() {
+        Throwable ex = getCause();
+        return ex instanceof RuntimeException ? (RuntimeException)ex : null;
+    }
+}
diff --git a/core/src/main/java/org/apache/cxf/phase/PhaseInterceptorChain.java b/core/src/main/java/org/apache/cxf/phase/PhaseInterceptorChain.java
index c8a52a8e95..316e58d26f 100644
--- a/core/src/main/java/org/apache/cxf/phase/PhaseInterceptorChain.java
+++ b/core/src/main/java/org/apache/cxf/phase/PhaseInterceptorChain.java
@@ -325,6 +325,9 @@ public class PhaseInterceptorChain implements InterceptorChain {
                     }
                     pause();
                     throw ex;
+                } catch (AbortedInvocationException ex) {
+                    abort();
+                    throw ex;
                 } catch (RuntimeException ex) {
                     if (!faultOccurred) {
                         faultOccurred = true;
diff --git a/rt/bindings/soap/src/main/java/org/apache/cxf/binding/soap/interceptor/Soap11FaultOutInterceptor.java b/rt/bindings/soap/src/main/java/org/apache/cxf/binding/soap/interceptor/Soap11FaultOutInterceptor.java
index 5e612a5932..95ebee9f7c 100644
--- a/rt/bindings/soap/src/main/java/org/apache/cxf/binding/soap/interceptor/Soap11FaultOutInterceptor.java
+++ b/rt/bindings/soap/src/main/java/org/apache/cxf/binding/soap/interceptor/Soap11FaultOutInterceptor.java
@@ -37,6 +37,7 @@ import org.apache.cxf.common.util.StringUtils;
 import org.apache.cxf.interceptor.Fault;
 import org.apache.cxf.message.Message;
 import org.apache.cxf.message.MessageUtils;
+import org.apache.cxf.phase.AbortedInvocationException;
 import org.apache.cxf.phase.Phase;
 import org.apache.cxf.staxutils.StaxUtils;
 
@@ -69,7 +70,12 @@ public class Soap11FaultOutInterceptor extends AbstractSoapInterceptor {
             // have been streaming some data already and may not be able to inject a fault in the middle 
             // of the data transfer.
             if (MessageUtils.getContextualBoolean(message, Message.PARTIAL_ATTACHMENTS_MESSAGE, false)) {
-                throw f;
+                // Signal that response has to be aborted midway
+                if (MessageUtils.getContextualBoolean(message, Message.MTOM_ENABLED, false)) {
+                    throw new AbortedInvocationException(f);
+                } else {
+                    throw f;
+                }
             }
 
             XMLStreamWriter writer = message.getContent(XMLStreamWriter.class);
diff --git a/rt/bindings/soap/src/main/java/org/apache/cxf/binding/soap/interceptor/Soap12FaultOutInterceptor.java b/rt/bindings/soap/src/main/java/org/apache/cxf/binding/soap/interceptor/Soap12FaultOutInterceptor.java
index 35cd7498a6..e766282c02 100644
--- a/rt/bindings/soap/src/main/java/org/apache/cxf/binding/soap/interceptor/Soap12FaultOutInterceptor.java
+++ b/rt/bindings/soap/src/main/java/org/apache/cxf/binding/soap/interceptor/Soap12FaultOutInterceptor.java
@@ -38,6 +38,7 @@ import org.apache.cxf.common.util.StringUtils;
 import org.apache.cxf.interceptor.Fault;
 import org.apache.cxf.message.Message;
 import org.apache.cxf.message.MessageUtils;
+import org.apache.cxf.phase.AbortedInvocationException;
 import org.apache.cxf.phase.Phase;
 import org.apache.cxf.staxutils.StaxUtils;
 
@@ -71,7 +72,12 @@ public class Soap12FaultOutInterceptor extends AbstractSoapInterceptor {
             // have been streaming some data already and may not be able to inject a fault in the middle 
             // of the data transfer.
             if (MessageUtils.getContextualBoolean(message, Message.PARTIAL_ATTACHMENTS_MESSAGE, false)) {
-                throw f;
+                // Signal that response has to be aborted midway
+                if (MessageUtils.getContextualBoolean(message, Message.MTOM_ENABLED, false)) {
+                    throw new AbortedInvocationException(f);
+                } else {
+                    throw f;
+                }
             }
 
             XMLStreamWriter writer = message.getContent(XMLStreamWriter.class);
diff --git a/rt/transports/http/src/main/java/org/apache/cxf/transport/http/AbstractHTTPDestination.java b/rt/transports/http/src/main/java/org/apache/cxf/transport/http/AbstractHTTPDestination.java
index 2a7d558730..18aaeedb47 100644
--- a/rt/transports/http/src/main/java/org/apache/cxf/transport/http/AbstractHTTPDestination.java
+++ b/rt/transports/http/src/main/java/org/apache/cxf/transport/http/AbstractHTTPDestination.java
@@ -63,6 +63,7 @@ import org.apache.cxf.message.ExchangeImpl;
 import org.apache.cxf.message.Message;
 import org.apache.cxf.message.MessageImpl;
 import org.apache.cxf.message.MessageUtils;
+import org.apache.cxf.phase.AbortedInvocationException;
 import org.apache.cxf.policy.PolicyDataEngine;
 import org.apache.cxf.security.SecurityContext;
 import org.apache.cxf.security.transport.TLSSessionInfo;
@@ -262,8 +263,17 @@ public abstract class AbstractHTTPDestination
         copyKnownRequestAttributes(req, inMessage);
 
         try {
-            incomingObserver.onMessage(inMessage);
-            invokeComplete(context, req, resp, inMessage);
+            try {
+                incomingObserver.onMessage(inMessage);
+                invokeComplete(context, req, resp, inMessage);
+            } catch (AbortedInvocationException ex) {
+                maybeResetAndCloseResponseOutputStream(resp);
+                if (ex.getRuntimeException() != null) {
+                    throw ex.getRuntimeException();
+                } else {
+                    throw ex;
+                }
+            } 
         } catch (SuspendedInvocationException ex) {
             if (ex.getRuntimeException() != null) {
                 throw ex.getRuntimeException();
@@ -678,6 +688,21 @@ public abstract class AbstractHTTPDestination
         return responseStream;
     }
 
+    private void maybeResetAndCloseResponseOutputStream(HttpServletResponse response) throws IOException {
+        try {
+            // The Servlet API does not provide means to abort the response, the best
+            // we could do is reset buffers (only partial data is going to be sent) and close
+            // the connection.
+            if (!response.isCommitted()) {
+                response.setHeader(HttpHeaderHelper.CONNECTION, HttpHeaderHelper.CLOSE);
+                response.resetBuffer();
+                response.getOutputStream().close();
+            }
+        } catch (IllegalStateException ex) {
+            // response.getWriter() has already been called
+        }
+    }
+
     private void closeResponseOutputStream(HttpServletResponse response) throws IOException {
         try {
             response.getOutputStream().close();
diff --git a/systests/jaxws/src/test/java/org/apache/cxf/systest/jaxws/AttachmentChunkingTest.java b/systests/jaxws/src/test/java/org/apache/cxf/systest/jaxws/AbstractAttachmentChunkingTest.java
similarity index 59%
copy from systests/jaxws/src/test/java/org/apache/cxf/systest/jaxws/AttachmentChunkingTest.java
copy to systests/jaxws/src/test/java/org/apache/cxf/systest/jaxws/AbstractAttachmentChunkingTest.java
index 6112fbe207..86562b0ddc 100644
--- a/systests/jaxws/src/test/java/org/apache/cxf/systest/jaxws/AttachmentChunkingTest.java
+++ b/systests/jaxws/src/test/java/org/apache/cxf/systest/jaxws/AbstractAttachmentChunkingTest.java
@@ -25,46 +25,34 @@ import java.io.InputStream;
 import java.io.OutputStream;
 import java.util.Arrays;
 import java.util.concurrent.ThreadLocalRandom;
-import java.util.logging.Logger;
 
 import javax.activation.DataHandler;
 import javax.activation.DataSource;
 import javax.xml.ws.Binding;
 import javax.xml.ws.BindingProvider;
-import javax.xml.ws.Endpoint;
 import javax.xml.ws.soap.SOAPBinding;
-import javax.xml.ws.soap.SOAPFaultException;
 
 import org.apache.cxf.Download;
 import org.apache.cxf.DownloadFault_Exception;
 import org.apache.cxf.DownloadNextResponseType;
-import org.apache.cxf.common.logging.LogUtils;
 import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
 import org.apache.cxf.testutil.common.AbstractBusClientServerTestBase;
-import org.apache.cxf.testutil.common.AbstractBusTestServerBase;
 
-import org.junit.BeforeClass;
 import org.junit.Test;
 
-import static org.hamcrest.CoreMatchers.containsString;
 import static org.hamcrest.CoreMatchers.equalTo;
 import static org.hamcrest.MatcherAssert.assertThat;
-import static org.junit.Assert.assertThrows;
-import static org.junit.Assert.assertTrue;
 
-public class AttachmentChunkingTest extends AbstractBusClientServerTestBase {
-    private static final String PORT = allocatePort(DownloadServer.class);
-    private static final Logger LOG = LogUtils.getLogger(AttachmentChunkingTest.class);
-
-    private static final class DownloadImpl implements Download {
+abstract class AbstractAttachmentChunkingTest extends AbstractBusClientServerTestBase {
+    protected static final class DownloadImpl implements Download {
         @Override
-        public DownloadNextResponseType downloadNext(Boolean simulate) {
+        public DownloadNextResponseType downloadNext(Integer minNumberOfChunks, Boolean simulate) {
             final DownloadNextResponseType responseType = new DownloadNextResponseType();
             responseType.setDataContent(new DataHandler(new DataSource() {
                 @Override
                 public InputStream getInputStream() {
                     if (simulate) {
-                        return simulate();
+                        return simulate((minNumberOfChunks == null) ? 1 : minNumberOfChunks);
                     } else {
                         return generate(100000);
                     }
@@ -89,49 +77,6 @@ public class AttachmentChunkingTest extends AbstractBusClientServerTestBase {
             return responseType;
         }
     }
-
-    public static class DownloadServer extends AbstractBusTestServerBase {
-        protected void run() {
-            Object implementor = new DownloadImpl();
-            String address = "http://localhost:" + PORT + "/SoapContext/SoapPort";
-            Endpoint.publish(address, implementor);
-        }
-
-        public static void main(String[] args) {
-            try {
-                DownloadServer s = new DownloadServer();
-                s.start();
-            } catch (Exception ex) {
-                ex.printStackTrace();
-                System.exit(-1);
-            } finally {
-                LOG.info("done!");
-            }
-        }
-    }
-
-    @BeforeClass
-    public static void startServers() throws Exception {
-        assertTrue("server did not launch correctly", launchServer(DownloadServer.class, true));
-    }
-
-    @Test
-    public void testChunkingPartialFailure() {
-        final JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
-        factory.setServiceClass(Download.class);
-
-        final Download client = (Download) factory.create();
-        final BindingProvider bindingProvider = (BindingProvider) client;
-        final Binding binding = bindingProvider.getBinding();
-
-        final String address = String.format("http://localhost:%s/SoapContext/SoapPort/DownloadPort", PORT);
-        bindingProvider.getRequestContext().put("javax.xml.ws.service.endpoint.address", address);
-        ((SOAPBinding) binding).setMTOMEnabled(true);
-
-        // See please https://issues.apache.org/jira/browse/CXF-9057
-        SOAPFaultException ex = assertThrows(SOAPFaultException.class, () -> client.downloadNext(true));
-        assertThat(ex.getMessage(), containsString("simulated error during stream processing"));
-    }
     
     @Test
     public void testChunking() throws IOException, DownloadFault_Exception {
@@ -142,22 +87,26 @@ public class AttachmentChunkingTest extends AbstractBusClientServerTestBase {
         final BindingProvider bindingProvider = (BindingProvider) client;
         final Binding binding = bindingProvider.getBinding();
 
-        final String address = String.format("http://localhost:%s/SoapContext/SoapPort/DownloadPort", PORT);
+        final String address = String.format("http://localhost:%s/SoapContext/SoapPort/DownloadPort", getPort());
         bindingProvider.getRequestContext().put("javax.xml.ws.service.endpoint.address", address);
         ((SOAPBinding) binding).setMTOMEnabled(true);
 
-        final DownloadNextResponseType response = client.downloadNext(false);
+        final DownloadNextResponseType response = client.downloadNext(1, false);
         assertThat(response.getDataContent().getInputStream().readAllBytes().length, equalTo(100000));
     }
     
+    protected abstract String getPort();
+    
     private static InputStream generate(int size) {
         final byte[] buf = new byte[size];
         Arrays.fill(buf, (byte) 'x');
         return new ByteArrayInputStream(buf);
     }
     
-    private static InputStream simulate() {
+    private static InputStream simulate(final int minNumberOfChunks) {
         return new InputStream() {
+            private int chunk;
+
             @Override
             public int read() {
                 return (byte) 'x';
@@ -165,7 +114,7 @@ public class AttachmentChunkingTest extends AbstractBusClientServerTestBase {
 
             @Override
             public int read(byte[] b, int off, int len) {
-                if (ThreadLocalRandom.current().nextBoolean()) {
+                if (chunk++ >= minNumberOfChunks && ThreadLocalRandom.current().nextBoolean()) {
                     throw new IllegalArgumentException("simulated error during stream processing");
                 }
 
diff --git a/systests/jaxws/src/test/java/org/apache/cxf/systest/jaxws/AttachmentChunkingTest.java b/systests/jaxws/src/test/java/org/apache/cxf/systest/jaxws/AttachmentChunkingTest.java
index 6112fbe207..1fe25ea21e 100644
--- a/systests/jaxws/src/test/java/org/apache/cxf/systest/jaxws/AttachmentChunkingTest.java
+++ b/systests/jaxws/src/test/java/org/apache/cxf/systest/jaxws/AttachmentChunkingTest.java
@@ -19,16 +19,9 @@
 
 package org.apache.cxf.systest.jaxws;
 
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.Arrays;
-import java.util.concurrent.ThreadLocalRandom;
+import java.util.List;
 import java.util.logging.Logger;
 
-import javax.activation.DataHandler;
-import javax.activation.DataSource;
 import javax.xml.ws.Binding;
 import javax.xml.ws.BindingProvider;
 import javax.xml.ws.Endpoint;
@@ -36,60 +29,23 @@ import javax.xml.ws.soap.SOAPBinding;
 import javax.xml.ws.soap.SOAPFaultException;
 
 import org.apache.cxf.Download;
-import org.apache.cxf.DownloadFault_Exception;
-import org.apache.cxf.DownloadNextResponseType;
 import org.apache.cxf.common.logging.LogUtils;
+import org.apache.cxf.ext.logging.LoggingFeature;
 import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
-import org.apache.cxf.testutil.common.AbstractBusClientServerTestBase;
 import org.apache.cxf.testutil.common.AbstractBusTestServerBase;
 
 import org.junit.BeforeClass;
 import org.junit.Test;
 
 import static org.hamcrest.CoreMatchers.containsString;
-import static org.hamcrest.CoreMatchers.equalTo;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.assertThrows;
 import static org.junit.Assert.assertTrue;
 
-public class AttachmentChunkingTest extends AbstractBusClientServerTestBase {
+public class AttachmentChunkingTest extends AbstractAttachmentChunkingTest {
     private static final String PORT = allocatePort(DownloadServer.class);
     private static final Logger LOG = LogUtils.getLogger(AttachmentChunkingTest.class);
 
-    private static final class DownloadImpl implements Download {
-        @Override
-        public DownloadNextResponseType downloadNext(Boolean simulate) {
-            final DownloadNextResponseType responseType = new DownloadNextResponseType();
-            responseType.setDataContent(new DataHandler(new DataSource() {
-                @Override
-                public InputStream getInputStream() {
-                    if (simulate) {
-                        return simulate();
-                    } else {
-                        return generate(100000);
-                    }
-                }
-
-                @Override
-                public OutputStream getOutputStream() {
-                    return null;
-                }
-
-                @Override
-                public String getContentType() {
-                    return "";
-                }
-
-                @Override
-                public String getName() {
-                    return "";
-                }
-            }));
-
-            return responseType;
-        }
-    }
-
     public static class DownloadServer extends AbstractBusTestServerBase {
         protected void run() {
             Object implementor = new DownloadImpl();
@@ -118,63 +74,24 @@ public class AttachmentChunkingTest extends AbstractBusClientServerTestBase {
     @Test
     public void testChunkingPartialFailure() {
         final JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
+        factory.setFeatures(List.of(new LoggingFeature()));
         factory.setServiceClass(Download.class);
 
         final Download client = (Download) factory.create();
         final BindingProvider bindingProvider = (BindingProvider) client;
         final Binding binding = bindingProvider.getBinding();
 
-        final String address = String.format("http://localhost:%s/SoapContext/SoapPort/DownloadPort", PORT);
+        final String address = String.format("http://localhost:%s/SoapContext/SoapPort/DownloadPort", getPort());
         bindingProvider.getRequestContext().put("javax.xml.ws.service.endpoint.address", address);
         ((SOAPBinding) binding).setMTOMEnabled(true);
 
         // See please https://issues.apache.org/jira/browse/CXF-9057
-        SOAPFaultException ex = assertThrows(SOAPFaultException.class, () -> client.downloadNext(true));
+        SOAPFaultException ex = assertThrows(SOAPFaultException.class, () -> client.downloadNext(1, true));
         assertThat(ex.getMessage(), containsString("simulated error during stream processing"));
     }
-    
-    @Test
-    public void testChunking() throws IOException, DownloadFault_Exception {
-        final JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
-        factory.setServiceClass(Download.class);
-
-        final Download client = (Download) factory.create();
-        final BindingProvider bindingProvider = (BindingProvider) client;
-        final Binding binding = bindingProvider.getBinding();
-
-        final String address = String.format("http://localhost:%s/SoapContext/SoapPort/DownloadPort", PORT);
-        bindingProvider.getRequestContext().put("javax.xml.ws.service.endpoint.address", address);
-        ((SOAPBinding) binding).setMTOMEnabled(true);
-
-        final DownloadNextResponseType response = client.downloadNext(false);
-        assertThat(response.getDataContent().getInputStream().readAllBytes().length, equalTo(100000));
-    }
-    
-    private static InputStream generate(int size) {
-        final byte[] buf = new byte[size];
-        Arrays.fill(buf, (byte) 'x');
-        return new ByteArrayInputStream(buf);
-    }
-    
-    private static InputStream simulate() {
-        return new InputStream() {
-            @Override
-            public int read() {
-                return (byte) 'x';
-            }
 
-            @Override
-            public int read(byte[] b, int off, int len) {
-                if (ThreadLocalRandom.current().nextBoolean()) {
-                    throw new IllegalArgumentException("simulated error during stream processing");
-                }
-
-                for (int i = off; i < off + len; i++) {
-                    b[i] = (byte) 'x';
-                }
-
-                return len;
-            }
-        };
+    @Override
+    protected String getPort() {
+        return PORT;
     }
 }
diff --git a/systests/jaxws/src/test/java/org/apache/cxf/systest/jaxws/AttachmentChunkingTest.java b/systests/jaxws/src/test/java/org/apache/cxf/systest/jaxws/AttachmentMtomChunkingTest.java
similarity index 54%
copy from systests/jaxws/src/test/java/org/apache/cxf/systest/jaxws/AttachmentChunkingTest.java
copy to systests/jaxws/src/test/java/org/apache/cxf/systest/jaxws/AttachmentMtomChunkingTest.java
index 6112fbe207..ce4cf5c718 100644
--- a/systests/jaxws/src/test/java/org/apache/cxf/systest/jaxws/AttachmentChunkingTest.java
+++ b/systests/jaxws/src/test/java/org/apache/cxf/systest/jaxws/AttachmentMtomChunkingTest.java
@@ -19,82 +19,41 @@
 
 package org.apache.cxf.systest.jaxws;
 
-import java.io.ByteArrayInputStream;
 import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.Arrays;
-import java.util.concurrent.ThreadLocalRandom;
+import java.util.List;
 import java.util.logging.Logger;
 
-import javax.activation.DataHandler;
-import javax.activation.DataSource;
 import javax.xml.ws.Binding;
 import javax.xml.ws.BindingProvider;
 import javax.xml.ws.Endpoint;
+import javax.xml.ws.WebServiceException;
 import javax.xml.ws.soap.SOAPBinding;
-import javax.xml.ws.soap.SOAPFaultException;
 
 import org.apache.cxf.Download;
 import org.apache.cxf.DownloadFault_Exception;
 import org.apache.cxf.DownloadNextResponseType;
 import org.apache.cxf.common.logging.LogUtils;
+import org.apache.cxf.ext.logging.LoggingFeature;
+import org.apache.cxf.helpers.IOUtils;
 import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
-import org.apache.cxf.testutil.common.AbstractBusClientServerTestBase;
 import org.apache.cxf.testutil.common.AbstractBusTestServerBase;
 
 import org.junit.BeforeClass;
 import org.junit.Test;
 
-import static org.hamcrest.CoreMatchers.containsString;
-import static org.hamcrest.CoreMatchers.equalTo;
-import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.assertThrows;
 import static org.junit.Assert.assertTrue;
 
-public class AttachmentChunkingTest extends AbstractBusClientServerTestBase {
+public class AttachmentMtomChunkingTest extends AbstractAttachmentChunkingTest {
     private static final String PORT = allocatePort(DownloadServer.class);
-    private static final Logger LOG = LogUtils.getLogger(AttachmentChunkingTest.class);
-
-    private static final class DownloadImpl implements Download {
-        @Override
-        public DownloadNextResponseType downloadNext(Boolean simulate) {
-            final DownloadNextResponseType responseType = new DownloadNextResponseType();
-            responseType.setDataContent(new DataHandler(new DataSource() {
-                @Override
-                public InputStream getInputStream() {
-                    if (simulate) {
-                        return simulate();
-                    } else {
-                        return generate(100000);
-                    }
-                }
-
-                @Override
-                public OutputStream getOutputStream() {
-                    return null;
-                }
-
-                @Override
-                public String getContentType() {
-                    return "";
-                }
-
-                @Override
-                public String getName() {
-                    return "";
-                }
-            }));
-
-            return responseType;
-        }
-    }
+    private static final Logger LOG = LogUtils.getLogger(AttachmentMtomChunkingTest.class);
 
     public static class DownloadServer extends AbstractBusTestServerBase {
         protected void run() {
             Object implementor = new DownloadImpl();
             String address = "http://localhost:" + PORT + "/SoapContext/SoapPort";
-            Endpoint.publish(address, implementor);
+            final Endpoint endpoint = Endpoint.publish(address, implementor, new LoggingFeature());
+            ((SOAPBinding)endpoint.getBinding()).setMTOMEnabled(true);
         }
 
         public static void main(String[] args) {
@@ -114,67 +73,46 @@ public class AttachmentChunkingTest extends AbstractBusClientServerTestBase {
     public static void startServers() throws Exception {
         assertTrue("server did not launch correctly", launchServer(DownloadServer.class, true));
     }
-
+    
     @Test
-    public void testChunkingPartialFailure() {
+    public void testChunkingPartialEarlyFailure() throws IOException, DownloadFault_Exception {
         final JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
+        factory.setFeatures(List.of(new LoggingFeature()));
         factory.setServiceClass(Download.class);
 
         final Download client = (Download) factory.create();
         final BindingProvider bindingProvider = (BindingProvider) client;
         final Binding binding = bindingProvider.getBinding();
 
-        final String address = String.format("http://localhost:%s/SoapContext/SoapPort/DownloadPort", PORT);
+        final String address = String.format("http://localhost:%s/SoapContext/SoapPort/DownloadPort", getPort());
         bindingProvider.getRequestContext().put("javax.xml.ws.service.endpoint.address", address);
         ((SOAPBinding) binding).setMTOMEnabled(true);
 
         // See please https://issues.apache.org/jira/browse/CXF-9057
-        SOAPFaultException ex = assertThrows(SOAPFaultException.class, () -> client.downloadNext(true));
-        assertThat(ex.getMessage(), containsString("simulated error during stream processing"));
+        assertThrows(WebServiceException.class, () -> client.downloadNext(1, true));
     }
-    
+
     @Test
-    public void testChunking() throws IOException, DownloadFault_Exception {
+    public void testChunkingPartialLateFailure() throws IOException, DownloadFault_Exception {
         final JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
+        factory.setFeatures(List.of(new LoggingFeature()));
         factory.setServiceClass(Download.class);
 
         final Download client = (Download) factory.create();
         final BindingProvider bindingProvider = (BindingProvider) client;
         final Binding binding = bindingProvider.getBinding();
 
-        final String address = String.format("http://localhost:%s/SoapContext/SoapPort/DownloadPort", PORT);
+        final String address = String.format("http://localhost:%s/SoapContext/SoapPort/DownloadPort", getPort());
         bindingProvider.getRequestContext().put("javax.xml.ws.service.endpoint.address", address);
         ((SOAPBinding) binding).setMTOMEnabled(true);
 
-        final DownloadNextResponseType response = client.downloadNext(false);
-        assertThat(response.getDataContent().getInputStream().readAllBytes().length, equalTo(100000));
-    }
-    
-    private static InputStream generate(int size) {
-        final byte[] buf = new byte[size];
-        Arrays.fill(buf, (byte) 'x');
-        return new ByteArrayInputStream(buf);
+        // See please https://issues.apache.org/jira/browse/CXF-9057
+        final DownloadNextResponseType response = client.downloadNext(10, true);
+        assertThrows(IOException.class, () -> IOUtils.readBytesFromStream(response.getDataContent().getInputStream()));
     }
-    
-    private static InputStream simulate() {
-        return new InputStream() {
-            @Override
-            public int read() {
-                return (byte) 'x';
-            }
 
-            @Override
-            public int read(byte[] b, int off, int len) {
-                if (ThreadLocalRandom.current().nextBoolean()) {
-                    throw new IllegalArgumentException("simulated error during stream processing");
-                }
-
-                for (int i = off; i < off + len; i++) {
-                    b[i] = (byte) 'x';
-                }
-
-                return len;
-            }
-        };
+    @Override
+    protected String getPort() {
+        return PORT;
     }
 }
diff --git a/systests/jaxws/src/test/resources/attachments/cxf9057.wsdl b/systests/jaxws/src/test/resources/attachments/cxf9057.wsdl
index 721fa08bb4..9a83f31a96 100644
--- a/systests/jaxws/src/test/resources/attachments/cxf9057.wsdl
+++ b/systests/jaxws/src/test/resources/attachments/cxf9057.wsdl
@@ -21,6 +21,7 @@
             </xs:complexType>
             <xs:complexType name="downloadNext">
                 <xs:sequence>
+                    <xs:element minOccurs="0" name="minNumberOfChunks" type="xs:int"/>
                     <xs:element minOccurs="0" name="simulate" type="xs:boolean"/>
                 </xs:sequence>
             </xs:complexType>


(cxf) 03/03: Recording .gitmergeinfo Changes

Posted by re...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

reta pushed a commit to branch 3.6.x-fixes
in repository https://gitbox.apache.org/repos/asf/cxf.git

commit 63fe05703e9c7a14a46914077a552680c133a123
Author: Andriy Redko <dr...@gmail.com>
AuthorDate: Sun Feb 16 11:29:42 2025 -0500

    Recording .gitmergeinfo Changes
---
 .gitmergeinfo | 1 +
 1 file changed, 1 insertion(+)

diff --git a/.gitmergeinfo b/.gitmergeinfo
index fb11af5195..52005bff91 100644
--- a/.gitmergeinfo
+++ b/.gitmergeinfo
@@ -1422,6 +1422,7 @@ M f3bfb4f76e83ca3bd58c8d934ecbaea4f98d3284
 M f3e2e6fc360d3c26ae489e552f60da6357479811
 M f3ff0735a7e0d8816bf0b43f5d97b54d5f034ff5
 M f422bd4caf99c59083cf336f350ec666eeebad26
+M f43e8b0116d7e0ec93c7de271dbb5b9b038ca333
 M f45825a7241a7e04e70b67ebec71c0a37e145200
 M f48dc57d5bb4a8848f3b4f9ef5cedcfd9d8ab1b7
 M f491429e1f238114e840238d154009cba487c7fc


(cxf) 02/03: Recording .gitmergeinfo Changes

Posted by re...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

reta pushed a commit to branch 3.6.x-fixes
in repository https://gitbox.apache.org/repos/asf/cxf.git

commit a365545d00a68aa8ff4e6f6bec3e504be107693c
Author: Andriy Redko <dr...@gmail.com>
AuthorDate: Sun Feb 16 11:29:28 2025 -0500

    Recording .gitmergeinfo Changes
---
 .gitmergeinfo | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/.gitmergeinfo b/.gitmergeinfo
index cf2d367d68..fb11af5195 100644
--- a/.gitmergeinfo
+++ b/.gitmergeinfo
@@ -1,5 +1,6 @@
 origin/4.0.x-fixes
 
+B 004f60c7e1554f5ab4e984eebd33866207fc54cf
 B 00b1c007eef119337217c9dde8de598d88c6544a
 B 00bbab65e59b8f27366335aec19e50129b7759f0
 B 0194b82a60d9db30c858121af8e70f7d7fa1e5d9
@@ -274,6 +275,7 @@ B eee70693019e46e52c8128482ea04676365716df
 B f03c3b0f9dccf7ebec8e1016247091cb363344ea
 B f0b038e685c03e3834aac2d6e56c625e4ba0ff1a
 B f16a87bdd0cedd82af9d62729c0d7418aa0e81a0
+B f1936015b9f6f3f1a81ca828103c5ceb03cd82ab
 B f34885c323e4c8f7f09b568a60afd03ccf0b5893
 B f35d8ae18b51088f7238a0af6b9caaca4da8ef95
 B f3e15e52c7d27d5734d3716dc3beb9a19f879387
@@ -881,6 +883,7 @@ M 7dc87bce5436a7aee3899c2bc67629cc56fc4623
 M 7e088f4aa5ddc849411f70635ed50859bfa236f8
 M 7e317f44903968cba5a81ad6942372ac52332e79
 M 7e97f2635497e8258685f2eb1cd388e06bc668fe
+M 7f14b6284f14e4ebe18e4f8411687d5120e91f55
 M 7f1be08ff328406c07fca362cf91b096bad37289
 M 7f33a57480f7377bc1c7be9f281e9905a2df9792
 M 7f884b94781defc5b17d47d427b689529fdbcf16