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

chibenwa pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-mime4j.git

commit c8ff400ceb7d28ee2cedb7c87fc190ff400bb9b3
Author: Benoit TELLIER <[email protected]>
AuthorDate: Mon Nov 2 15:24:38 2026 +0000

    [FIX] StructuredFieldParser: a quoted pair escapes one character, also in a 
comment
    
    The outermost comment had no quoted pair rule, so "\)" ended it:
    "http://example.com/(a\) b)c" was read as "http://example.com/b)c".
    
    A quoted pair also matched the backslash and the whole rest of the
    value, as ANY was one character or more: a quoted pair in a quoted
    string or a nested comment swallowed the closing quote, and the value
    read as null.
---
 .../field/structured/StructuredFieldParser.jj      |  9 ++++++++-
 .../mime4j/field/ContentLocationFieldTest.java     | 22 ++++++++++++++++++++++
 2 files changed, 30 insertions(+), 1 deletion(-)

diff --git 
a/dom/src/main/javacc/org/apache/james/mime4j/field/structured/StructuredFieldParser.jj
 
b/dom/src/main/javacc/org/apache/james/mime4j/field/structured/StructuredFieldParser.jj
index 71f2060f..6ba407de 100644
--- 
a/dom/src/main/javacc/org/apache/james/mime4j/field/structured/StructuredFieldParser.jj
+++ 
b/dom/src/main/javacc/org/apache/james/mime4j/field/structured/StructuredFieldParser.jj
@@ -152,6 +152,12 @@ SKIP :
        "(" : INCOMMENT
 }
 
+<INCOMMENT> SKIP :
+{
+       // a quoted pair such as "\)" does not end the comment
+       < <QUOTEDPAIR> >
+}
+
 <INCOMMENT> SKIP :
 {
        // ends a comment
@@ -222,6 +228,7 @@ TOKEN :
 <*>
 TOKEN :
 {
+       // a quoted pair escapes a single character
        < #QUOTEDPAIR: "\\" <ANY> >
-|      < #ANY: (~[])+ >
+|      < #ANY: ~[] >
 }
\ No newline at end of file
diff --git 
a/dom/src/test/java/org/apache/james/mime4j/field/ContentLocationFieldTest.java 
b/dom/src/test/java/org/apache/james/mime4j/field/ContentLocationFieldTest.java
index 2d7bed6d..f2b67879 100644
--- 
a/dom/src/test/java/org/apache/james/mime4j/field/ContentLocationFieldTest.java
+++ 
b/dom/src/test/java/org/apache/james/mime4j/field/ContentLocationFieldTest.java
@@ -60,4 +60,26 @@ public class ContentLocationFieldTest extends TestCase {
         assertEquals("this/that/whatnot", location);
     }
 
+    public void testQuotedPairInComment() throws Exception {
+        ContentLocationField f = parse("Content-Location: 
http://example.com/(a\\) b)c");
+        assertEquals("http://example.com/c";, f.getLocation());
+        assertNull(f.getParseException());
+    }
+
+    public void testQuotedPairInCommentShouldAgreeWithTheLenientParser() 
throws Exception {
+        String[] values = {"http://example.com/(a\\) b)c", "a(\\()b", 
"a(x\\\\)b", "a(\\))b", "a((\\)))b"};
+        for (String value : values) {
+            ContentLocationField strict = parse("Content-Location: " + value);
+            ContentLocationField lenient = 
LenientContentLocationFieldTest.parse("Content-Location: " + value);
+            assertEquals(value, lenient.getLocation(), strict.getLocation());
+        }
+    }
+
+    public void testQuotedPairShouldNotSwallowTheRestOfTheValue() throws 
Exception {
+        // a quoted pair escapes one character: the closing quote and what 
follows are still read
+        ContentLocationField f = parse("Content-Location: \"a\\\"b\" (c\\) d) 
e");
+        assertNotNull(f.getLocation());
+        assertTrue(f.getLocation(), f.getLocation().endsWith("e"));
+        assertNull(f.getParseException());
+    }
 }


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to