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

dkulp pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/cxf.git

commit ed102a26c22b5376ace2951d508485457f1f606b
Author: Andriy Redko <drr...@gmail.com>
AuthorDate: Sun Nov 27 11:13:55 2022 -0500

    CXF-8799: Unxepected URLEncode in MTOM Content-Id
---
 .../cxf/attachment/AttachmentSerializer.java       | 19 ++++++-
 .../org/apache/cxf/attachment/AttachmentUtil.java  | 63 +++++++---------------
 .../cxf/attachment/AttachmentSerializerTest.java   |  6 +++
 .../apache/cxf/attachment/AttachmentUtilTest.java  | 27 ++++------
 4 files changed, 55 insertions(+), 60 deletions(-)

diff --git 
a/core/src/main/java/org/apache/cxf/attachment/AttachmentSerializer.java 
b/core/src/main/java/org/apache/cxf/attachment/AttachmentSerializer.java
index 2d9676b970..9b6922c347 100644
--- a/core/src/main/java/org/apache/cxf/attachment/AttachmentSerializer.java
+++ b/core/src/main/java/org/apache/cxf/attachment/AttachmentSerializer.java
@@ -237,7 +237,14 @@ public class AttachmentSerializer {
                 //
                 String[] address = attachmentId.split("@", 2);
                 if (address.length == 2) {
-                    writer.write(attachmentId);
+                    // See please AttachmentUtil::createContentID, the domain 
part is URL encoded
+                    final String decoded = tryDecode(address[1], 
StandardCharsets.UTF_8);
+                    // If the domain part is encoded, decode it 
+                    if (!decoded.equalsIgnoreCase(address[1])) {
+                        writer.write(address[0] + "@" + decoded);
+                    } else {
+                        writer.write(attachmentId);
+                    }
                 } else {
                     writer.write(URLEncoder.encode(attachmentId, 
StandardCharsets.UTF_8.name()));
                 }
@@ -373,4 +380,14 @@ public class AttachmentSerializer {
     private static String decode(String s, Charset charset) {
         return URLDecoder.decode(s.replaceAll("([^%])[+]", "$1%2B"), charset);
     }
+
+    // Try to decode the string assuming the decoding may fail, the original 
string is going to
+    // be returned in this case.
+    private static String tryDecode(String s, Charset charset) {
+        try { 
+            return decode(s, charset);
+        } catch (IllegalArgumentException ex) {
+            return s;
+        }
+    }
 }
diff --git a/core/src/main/java/org/apache/cxf/attachment/AttachmentUtil.java 
b/core/src/main/java/org/apache/cxf/attachment/AttachmentUtil.java
index 747bf54454..e585d26ca1 100644
--- a/core/src/main/java/org/apache/cxf/attachment/AttachmentUtil.java
+++ b/core/src/main/java/org/apache/cxf/attachment/AttachmentUtil.java
@@ -45,7 +45,6 @@ import java.util.Set;
 import java.util.UUID;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.logging.Logger;
-import java.util.regex.Pattern;
 
 import jakarta.activation.CommandInfo;
 import jakarta.activation.CommandMap;
@@ -81,15 +80,8 @@ public final class AttachmentUtil {
     private static final Random BOUND_RANDOM = new Random();
     private static final CommandMap DEFAULT_COMMAND_MAP = 
CommandMap.getDefaultCommandMap();
     private static final MailcapCommandMap COMMAND_MAP = new 
EnhancedMailcapCommandMap();
-
-    /**
-     * Yet <a 
href="https://datatracker.ietf.org/doc/html/rfc822#appendix-D";>RFC-822 Appendix 
D (ALPHABETICAL LISTING OF SYNTAX RULES)</a>
-     * allows more characters in domain-literal,
-     * this regex is valid to check that the parsed domain is compliant,
-     * although it is stricter
-     */
-    private static final Pattern ALPHA_NUMERIC_DOMAIN_PATTERN = 
Pattern.compile("^\\w+(\\.\\w+)*$");
-
+    
+    
     static final class EnhancedMailcapCommandMap extends MailcapCommandMap {
         @Override
         public synchronized DataContentHandler createDataContentHandler(
@@ -239,49 +231,24 @@ public final class AttachmentUtil {
         }
     }
 
-    /**
-     * Creates Content ID from {@link #ATT_UUID} and given namespace
-     * <p>
-     * Example:
-     * <pre>6976d00d-740c-48ed-b63d-8c56707544f...@example.com</pre>
-     * <p>
-     * <a 
href="https://datatracker.ietf.org/doc/html/rfc2392#section-2";>RFC-2392 Section 
2 (The MID and CID URL Schemes)</a>
-     * specifies Content ID as:
-     * <pre>
-     *   content-id = url-addr-spec
-     *   url-addr-spec = addr-spec ; URL encoding of RFC 822 addr-spec
-     * </pre>
-     * <a 
href="https://datatracker.ietf.org/doc/html/rfc822#appendix-D";>RFC-822 Appendix 
D (ALPHABETICAL LISTING OF SYNTAX RULES)</a>:
-     * <pre>
-     *   addr-spec = local-part "@" domain ; global address
-     * </pre>
-     *
-     * @param ns namespace. If null, falls back to "cxf.apache.org"
-     * @return Content ID
-     */
-    public static String createContentID(String ns) {
+    public static String createContentID(String ns) throws 
UnsupportedEncodingException {
         // tend to change
         String cid = "cxf.apache.org";
         if (ns != null && !ns.isEmpty()) {
-            if (isAlphaNumericDomain(ns)) {
-                cid = ns;
-            }
             try {
                 URI uri = new URI(ns);
                 String host = uri.getHost();
-                if (host != null && isAlphaNumericDomain(host)) {
+                if (host != null) {
                     cid = host;
+                } else {
+                    cid = ns;
                 }
             } catch (Exception e) {
-                // Could not parse domain => use fallback value
+                cid = ns;
             }
         }
         return ATT_UUID + '-' + Integer.toString(COUNTER.incrementAndGet()) + 
'@'
-            + URLEncoder.encode(cid, StandardCharsets.UTF_8);
-    }
-
-    private static boolean isAlphaNumericDomain(String string) {
-        return ALPHA_NUMERIC_DOMAIN_PATTERN.matcher(string).matches();
+            + URLEncoder.encode(cid, StandardCharsets.UTF_8.name());
     }
 
     public static String getUniqueBoundaryValue() {
@@ -521,7 +488,12 @@ public final class AttachmentUtil {
         source.setContentType(mimeType);
         DataHandler handler = new DataHandler(source);
 
-        String id = AttachmentUtil.createContentID(elementNS);
+        String id;
+        try {
+            id = AttachmentUtil.createContentID(elementNS);
+        } catch (UnsupportedEncodingException e) {
+            throw new Fault(e);
+        }
         AttachmentImpl att = new AttachmentImpl(id, handler);
         att.setXOP(isXop);
         return att;
@@ -556,7 +528,12 @@ public final class AttachmentUtil {
         //      ignore, just do the normal attachment thing
         }
 
-        String id = AttachmentUtil.createContentID(elementNS);
+        String id;
+        try {
+            id = AttachmentUtil.createContentID(elementNS);
+        } catch (UnsupportedEncodingException e) {
+            throw new Fault(e);
+        }
         AttachmentImpl att = new AttachmentImpl(id, handler);
         if (!StringUtils.isEmpty(handler.getName())) {
             //set Content-Disposition attachment header if filename isn't null
diff --git 
a/core/src/test/java/org/apache/cxf/attachment/AttachmentSerializerTest.java 
b/core/src/test/java/org/apache/cxf/attachment/AttachmentSerializerTest.java
index e6a7640edb..13f4793dee 100644
--- a/core/src/test/java/org/apache/cxf/attachment/AttachmentSerializerTest.java
+++ b/core/src/test/java/org/apache/cxf/attachment/AttachmentSerializerTest.java
@@ -182,6 +182,12 @@ public class AttachmentSerializerTest {
         doTestMessageMTOM("cid:http%3A%2F%2Fcxf.apache.org%2F", 
"<http://cxf.apache.org/>");
     }
 
+    @Test
+    public void testMessageMTOMCidEncoded() throws Exception {
+        
doTestMessageMTOM("cid:cxf@[2001%3A0db8%3A11a3%3A09d7%3A1f34%3A8a2e%3A07a0%3A765d]",
+            "<cxf@[2001:0db8:11a3:09d7:1f34:8a2e:07a0:765d]>");
+    }
+
     @Test
     public void testMessageMTOMUrlDecoded() throws Exception {
         doTestMessageMTOM("test+me.xml", "<test%2Bme.xml>");
diff --git 
a/core/src/test/java/org/apache/cxf/attachment/AttachmentUtilTest.java 
b/core/src/test/java/org/apache/cxf/attachment/AttachmentUtilTest.java
index eeebc24e2e..6b3285c810 100644
--- a/core/src/test/java/org/apache/cxf/attachment/AttachmentUtilTest.java
+++ b/core/src/test/java/org/apache/cxf/attachment/AttachmentUtilTest.java
@@ -20,13 +20,15 @@ package org.apache.cxf.attachment;
 
 import java.io.File;
 import java.io.IOException;
+import java.io.UnsupportedEncodingException;
 import java.math.BigInteger;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
 
 import org.apache.cxf.io.CachedOutputStream;
 import org.apache.cxf.message.Message;
 import org.apache.cxf.message.MessageImpl;
 
-import org.junit.Ignore;
 import org.junit.Test;
 
 import static org.easymock.EasyMock.createMock;
@@ -34,16 +36,10 @@ import static org.easymock.EasyMock.replay;
 import static org.easymock.EasyMock.verify;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.endsWith;
-import static org.hamcrest.Matchers.matchesPattern;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotEquals;
 
 public class AttachmentUtilTest {
-
-    // Yet RFC822 allows more characters in domain-literal,
-    // this regex is enough to check that the fallback domain is compliant
-    public static final String CONTENT_ID_WITH_ALPHA_NUMERIC_DOMAIN_PATTERN = 
".+@\\w+(\\.\\w+)*";
-
     @Test
     public void testContendDispositionFileNameNoQuotes() {
         assertEquals("a.txt",
@@ -141,15 +137,15 @@ public class AttachmentUtilTest {
         assertNotEquals(AttachmentUtil.createContentID(null), 
AttachmentUtil.createContentID(null));
     }
 
+
     @Test
-    public void testCreateContentIDWithNullDomainNamePassed() {
+    public void testCreateContentIDWithNullDomainNamePassed() throws 
UnsupportedEncodingException {
         String actual = AttachmentUtil.createContentID(null);
-
-        assertThat(actual, 
matchesPattern(CONTENT_ID_WITH_ALPHA_NUMERIC_DOMAIN_PATTERN));
+        assertThat(actual, endsWith("@cxf.apache.org"));
     }
 
     @Test
-    public void testCreateContentIDWithDomainNamePassed() {
+    public void testCreateContentIDWithDomainNamePassed() throws 
UnsupportedEncodingException {
         String domain = "subdomain.example.com";
 
         String actual = AttachmentUtil.createContentID(domain);
@@ -158,7 +154,7 @@ public class AttachmentUtilTest {
     }
 
     @Test
-    public void testCreateContentIDWithUrlPassed() {
+    public void testCreateContentIDWithUrlPassed() throws 
UnsupportedEncodingException {
         String domain = "subdomain.example.com";
         String url = "https://"; + domain + "/a/b/c";
 
@@ -168,7 +164,7 @@ public class AttachmentUtilTest {
     }
 
     @Test
-    public void testCreateContentIDWithIPv4BasedUrlPassed() {
+    public void testCreateContentIDWithIPv4BasedUrlPassed() throws 
UnsupportedEncodingException {
         String domain = "127.0.0.1";
         String url = "https://"; + domain + "/a/b/c";
 
@@ -178,13 +174,12 @@ public class AttachmentUtilTest {
     }
 
     @Test
-    public void testCreateContentIDWithIPv6BasedUrlPassed() {
+    public void testCreateContentIDWithIPv6BasedUrlPassed() throws 
UnsupportedEncodingException {
         String domain = "[2001:0db8:11a3:09d7:1f34:8a2e:07a0:765d]";
         String url = "http://"; + domain + "/a/b/c";
 
         String actual = AttachmentUtil.createContentID(url);
-
-        assertThat(actual, 
matchesPattern(CONTENT_ID_WITH_ALPHA_NUMERIC_DOMAIN_PATTERN));
+        assertThat(actual, endsWith("@" + URLEncoder.encode(domain, 
StandardCharsets.UTF_8)));
     }
 
     private CachedOutputStream testSetStreamedAttachmentProperties(final 
String property, final Object value)

Reply via email to