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 005f0fe79767da149b346ee5784b7e8b107a2d96
Author: Benoit TELLIER <[email protected]>
AuthorDate: Wed Nov 4 15:06:32 2026 +0100

    [FIX] StructuredFieldParser: drop the backslash of a quoted pair followed 
by text in a quoted string
    
    The quoted pair is a MORE rule whose action removes the backslash from
    the token manager's image. STRING_CONTENT and FOLD had no action, so
    JavaCC built their image from the raw input, MORE prefix included: the
    backslash came back ("a\"b" read as a\"b, the lenient parser gives a"b),
    and a quoted pair just before a fold was dropped. Both tokens now take
    their image from the edited buffer, the fold keeping only the text before
    the line break.
    
    Fixes #106
---
 .../mime4j/field/structured/StructuredFieldParser.jj  | 10 +++++++---
 .../james/mime4j/field/ContentLocationFieldTest.java  | 19 +++++++++++++++++++
 .../field/structured/StructuredFieldParserTest.java   |  8 ++++++++
 3 files changed, 34 insertions(+), 3 deletions(-)

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 6ba407de..dd4a0dc9 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
@@ -123,6 +123,7 @@ private String doParse() :
                |
                t = <FOLD>
                        {
+                               buffer.append(t.image);
                                if (preserveFolding) buffer.append("\r\n");
                        }
                |
@@ -207,9 +208,12 @@ SKIP :
 
 <INQUOTEDSTRING> TOKEN :
 {
-       < STRING_CONTENT : (~["\"", "\\", "\r"])+ >
-       // Preserve line break within quotes but not trailing white space
-|      < FOLD: "\r\n" ( [" ", "\t"] )* >
+       // a token after a quoted pair (MORE) takes its image from image, where 
the
+       // quoted pair action removed the backslash, not from the raw input
+       < STRING_CONTENT : (~["\"", "\\", "\r"])+ > { matchedToken.image = 
image.toString(); }
+       // Preserve line break within quotes but not trailing white space:
+       // the image keeps only the quoted pairs before the fold
+|      < FOLD: "\r\n" ( [" ", "\t"] )* > { matchedToken.image = 
image.substring(0, image.length() - lengthOfMatch); }
 |      < QUOTEDSTRING: "\"" > { matchedToken.image = image.substring(0, 
image.length() - 1); } : DEFAULT
 }
 
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 f2b67879..85f18c7a 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
@@ -82,4 +82,23 @@ public class ContentLocationFieldTest extends TestCase {
         assertTrue(f.getLocation(), f.getLocation().endsWith("e"));
         assertNull(f.getParseException());
     }
+
+    public void testQuotedPairFollowedByTextInQuotedString() throws Exception {
+        ContentLocationField f = parse("Content-Location: \"a\\\"b\"");
+        assertNull(f.getParseException());
+        assertEquals("a\"b", f.getLocation());
+
+        f = parse("Content-Location: \"http://example.com/a\\\\b.html\"";);
+        assertNull(f.getParseException());
+        assertEquals("http://example.com/a\\b.html";, f.getLocation());
+    }
+
+    public void testQuotedPairInQuotedStringShouldAgreeWithTheLenientParser() 
throws Exception {
+        String[] values = {"\"a\\\"b\"", "\"http://example.com/a\\\\b.html\"";, 
"\"ab\\\"\""};
+        for (String value : values) {
+            ContentLocationField strict = parse("Content-Location: " + value);
+            ContentLocationField lenient = 
LenientContentLocationFieldTest.parse("Content-Location: " + value);
+            assertEquals(value, lenient.getLocation(), strict.getLocation());
+        }
+    }
 }
diff --git 
a/dom/src/test/java/org/apache/james/mime4j/field/structured/StructuredFieldParserTest.java
 
b/dom/src/test/java/org/apache/james/mime4j/field/structured/StructuredFieldParserTest.java
index cd8775dc..1bd807f4 100644
--- 
a/dom/src/test/java/org/apache/james/mime4j/field/structured/StructuredFieldParserTest.java
+++ 
b/dom/src/test/java/org/apache/james/mime4j/field/structured/StructuredFieldParserTest.java
@@ -63,6 +63,14 @@ public class StructuredFieldParserTest {
         Assert.assertEquals("Field Value", parse("Fi(This is a comment)eld (A 
(very (nested) )comment)Value"));
     }
 
+    @Test
+    public void testQuotedPairInQuotedString() throws Exception {
+        Assert.assertEquals("a\"b", parse("\"a\\\"b\""));
+        Assert.assertEquals("a\\b", parse("\"a\\\\b\""));
+        Assert.assertEquals("ab\"", parse("\"ab\\\"\""));
+        Assert.assertEquals("a\"\r\nb", parse("\"a\\\"\r\n b\""));
+    }
+
     private String parse(String in) throws Exception {
         StructuredFieldParser parser = new StructuredFieldParser(new 
StringReader(in));
         parser.setFoldingPreserved(true);


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

Reply via email to