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-jdkim.git

commit 7659c43fcc82ffbb505d7c14e8855e493bd0002f
Author: Benoit TELLIER <[email protected]>
AuthorDate: Wed Nov 4 21:51:34 2026 +0100

    [FIX] Message: strip the WSP after a field name in linear time
    
    rawName removed the trailing WSP with replaceAll("[ \t]+$", ""). On a
    run of WSP inside the name, the regex retried from each position of the
    run and backed off one character at a time: quadratic, seconds of CPU
    for an 8 KB field and hours for a 1 MB one, on every message parsed,
    signed or not, before any signature is examined.
    
    The name now ends after a backward scan from the colon. This also keeps
    the WSP before a final \x85 or \r, which "$" treated as the end of the
    name.
---
 .../java/org/apache/james/jdkim/impl/Message.java  |  6 +++-
 .../apache/james/jdkim/impl/MessageLimitsTest.java | 32 ++++++++++++++++++++++
 2 files changed, 37 insertions(+), 1 deletion(-)

diff --git a/main/src/main/java/org/apache/james/jdkim/impl/Message.java 
b/main/src/main/java/org/apache/james/jdkim/impl/Message.java
index 687e669..91a89e0 100644
--- a/main/src/main/java/org/apache/james/jdkim/impl/Message.java
+++ b/main/src/main/java/org/apache/james/jdkim/impl/Message.java
@@ -144,7 +144,11 @@ public class Message implements Headers {
      * without trailing WSP.
      */
     private static String rawName(String field) {
-        return field.substring(0, field.indexOf(':')).replaceAll("[ \t]+$", 
"").toLowerCase(Locale.US);
+        int end = field.indexOf(':');
+        while (end > 0 && (field.charAt(end - 1) == ' ' || field.charAt(end - 
1) == '\t')) {
+            end--;
+        }
+        return field.substring(0, end).toLowerCase(Locale.US);
     }
 
     public InputStream getBodyInputStream() {
diff --git 
a/main/src/test/java/org/apache/james/jdkim/impl/MessageLimitsTest.java 
b/main/src/test/java/org/apache/james/jdkim/impl/MessageLimitsTest.java
index b2945f0..a90d76d 100644
--- a/main/src/test/java/org/apache/james/jdkim/impl/MessageLimitsTest.java
+++ b/main/src/test/java/org/apache/james/jdkim/impl/MessageLimitsTest.java
@@ -62,6 +62,38 @@ public class MessageLimitsTest {
         assertThat(message.getFields("To")).hasSize(1);
     }
 
+    @Test(timeout = 10_000)
+    public void shouldParseFieldNameWithLongWspRunInLinearTime() throws 
Exception {
+        StringBuilder sb = new StringBuilder("From: [email protected]\r\nx");
+        for (int i = 0; i < 200_000; i++) {
+            sb.append(' ');
+        }
+        sb.append("y: v\r\n\r\nbody\r\n");
+
+        Message message = new Message(stream(sb));
+
+        assertThat(message.getFields()).hasSize(2);
+    }
+
+    @Test
+    public void shouldStillMatchFieldNameWithoutItsTrailingWsp() throws 
Exception {
+        StringBuilder sb = new StringBuilder("From: [email protected]\r\nX-Long 
\t : v\r\n\r\nbody\r\n");
+
+        Message message = new Message(stream(sb));
+
+        assertThat(message.getFields("X-Long")).hasSize(1);
+    }
+
+    @Test
+    public void shouldKeepWspBeforeLineTerminatorLikeCharInFieldName() throws 
Exception {
+        byte[] bytes = ("From: [email protected]\r\nx " + (char) 0x85 + ": 
v\r\n\r\nbody\r\n")
+                .getBytes(StandardCharsets.ISO_8859_1);
+
+        Message message = new Message(new ByteArrayInputStream(bytes));
+
+        assertThat(message.getFields("x " + (char) 0x85)).hasSize(1);
+    }
+
     @Test
     public void shouldParseLongLine() throws Exception {
         StringBuilder sb = new StringBuilder("From: 
[email protected]\r\nX-Long: ");


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

Reply via email to