You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@james.apache.org by bt...@apache.org on 2022/09/23 01:45:04 UTC

[james-project] branch 3.7.x updated (ed7660c8b1 -> ef062ac821)

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

btellier pushed a change to branch 3.7.x
in repository https://gitbox.apache.org/repos/asf/james-project.git


    from ed7660c8b1 task/task-distributed - fixing NullPointerException when executeTask
     new 7664606b0a JAMES-3803 RemoteDelivery uses different scheduler for dequeuing (#1121)
     new 3f5e779516 JAMES-3431 Stricter validation for DSN ENVID (#1002)
     new a29d2db243 JAMES-343 Mail: Fix resetting DSN parameters
     new 7a2e6fac03 JAMES-3753 Fix FlowedMessageUtils.deflow() (#972)
     new ef062ac821 JAMES-3744 remove redundant hashmaps which lead to OOM

The 5 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:
 .../main/java/org/apache/mailet/DsnParameters.java | 101 ++++++++++
 .../api/src/main/java/org/apache/mailet/Mail.java  |   1 +
 .../java/org/apache/mailet/DsnParametersTest.java  |  68 ++++++-
 .../org/apache/mailet/base/FlowedMessageUtils.java |   8 +-
 .../apache/mailet/base/FlowedMessageUtilsTest.java | 205 +++++++++++++++++++++
 .../org/apache/james/server/core/MailImplTest.java |  25 +++
 .../mailets/remote/delivery/DeliveryRunnable.java  |  13 +-
 .../transport/matchers/DSNDelayRequestedTest.java  |   2 -
 .../org/apache/james/jmap/UriPathTemplate.java     |  23 +--
 9 files changed, 405 insertions(+), 41 deletions(-)
 create mode 100644 mailet/base/src/test/java/org/apache/mailet/base/FlowedMessageUtilsTest.java


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@james.apache.org
For additional commands, e-mail: notifications-help@james.apache.org


[james-project] 03/05: JAMES-343 Mail: Fix resetting DSN parameters

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

btellier pushed a commit to branch 3.7.x
in repository https://gitbox.apache.org/repos/asf/james-project.git

commit a29d2db2436dbf3a80c52a20cd9a8158670c811e
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Thu Jun 2 10:34:08 2022 +0700

    JAMES-343 Mail: Fix resetting DSN parameters
    
    Updating from DSN_PARAMETERS_1 to DSN_PARAMETERS_2 where
    DSN_PARAMETERS_2 misses some parameters present in
    DSN_PARAMETERS_1 causes those parameters to still be present
    in DSN_PARAMETERS_2.
    
    (cherry picked from commit 6003ecb236b4a2cab38ba73056e9babbaac15fc7)
---
 .../main/java/org/apache/mailet/DsnParameters.java |  8 +++++++
 .../api/src/main/java/org/apache/mailet/Mail.java  |  1 +
 .../org/apache/james/server/core/MailImplTest.java | 25 ++++++++++++++++++++++
 3 files changed, 34 insertions(+)

diff --git a/mailet/api/src/main/java/org/apache/mailet/DsnParameters.java b/mailet/api/src/main/java/org/apache/mailet/DsnParameters.java
index a426dceb01..9919da4dea 100644
--- a/mailet/api/src/main/java/org/apache/mailet/DsnParameters.java
+++ b/mailet/api/src/main/java/org/apache/mailet/DsnParameters.java
@@ -25,6 +25,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Optional;
+import java.util.function.Consumer;
 
 import javax.mail.internet.AddressException;
 
@@ -388,6 +389,13 @@ public class DsnParameters {
             return new DsnAttributeValues(notify, orcpt, envId, ret);
         }
 
+        public static void forEachDsnAttributeName(Consumer<AttributeName> action) {
+            action.accept(ENVID_ATTRIBUTE_NAME);
+            action.accept(RET_ATTRIBUTE_NAME);
+            action.accept(NOTIFY_ATTRIBUTE_NAME);
+            action.accept(ORCPT_ATTRIBUTE_NAME);
+        }
+
         private final Optional<AttributeValue<Map<String, AttributeValue<String>>>> notifyAttributeValue;
         private final Optional<AttributeValue<Map<String, AttributeValue<String>>>> orcptAttributeValue;
         private final Optional<AttributeValue<String>> envIdAttributeValue;
diff --git a/mailet/api/src/main/java/org/apache/mailet/Mail.java b/mailet/api/src/main/java/org/apache/mailet/Mail.java
index fe7ca1ab6d..5d918ffb3f 100644
--- a/mailet/api/src/main/java/org/apache/mailet/Mail.java
+++ b/mailet/api/src/main/java/org/apache/mailet/Mail.java
@@ -444,6 +444,7 @@ public interface Mail extends Serializable, Cloneable {
     }
 
     default void setDsnParameters(DsnParameters dsnParameters) {
+        DsnParameters.DsnAttributeValues.forEachDsnAttributeName(this::removeAttribute);
         dsnParameters.toAttributes()
             .asAttributes()
             .forEach(this::setAttribute);
diff --git a/server/container/core/src/test/java/org/apache/james/server/core/MailImplTest.java b/server/container/core/src/test/java/org/apache/james/server/core/MailImplTest.java
index 390879be9c..cca06ce2f0 100644
--- a/server/container/core/src/test/java/org/apache/james/server/core/MailImplTest.java
+++ b/server/container/core/src/test/java/org/apache/james/server/core/MailImplTest.java
@@ -404,6 +404,31 @@ public class MailImplTest extends ContractMailTest {
             .contains(dsnParameters);
     }
 
+    @Test
+    void setDsnParametersShouldUpdateStoredValue() throws Exception {
+        DsnParameters dsnParameters1 = DsnParameters.builder()
+            .envId(DsnParameters.EnvId.of("434554-55445-33443"))
+            .ret(DsnParameters.Ret.FULL)
+            .addRcptParameter(new MailAddress("bob@apache.org"), DsnParameters.RecipientDsnParameters.of(new MailAddress("andy@apache.org")))
+            .addRcptParameter(new MailAddress("cedric@apache.org"), DsnParameters.RecipientDsnParameters.of(EnumSet.of(DsnParameters.Notify.SUCCESS)))
+            .addRcptParameter(new MailAddress("domi@apache.org"), DsnParameters.RecipientDsnParameters.of(EnumSet.of(DsnParameters.Notify.FAILURE), new MailAddress("eric@apache.org")))
+            .build().get();
+        DsnParameters dsnParameters2 = DsnParameters.builder()
+            .envId(DsnParameters.EnvId.of("434554-55445-33434ee4"))
+            .addRcptParameter(new MailAddress("domi@apache.org"), DsnParameters.RecipientDsnParameters.of(EnumSet.of(DsnParameters.Notify.FAILURE), new MailAddress("eric@apache.org")))
+            .build().get();
+
+        MailImpl mail = MailImpl.builder()
+            .name("mail-id")
+            .build();
+
+        mail.setDsnParameters(dsnParameters1);
+        mail.setDsnParameters(dsnParameters2);
+
+        assertThat(mail.dsnParameters())
+            .contains(dsnParameters2);
+    }
+
     @Test
     void dsnParametersShouldBeEmptyByDefault() {
         MailImpl mail = MailImpl.builder()


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@james.apache.org
For additional commands, e-mail: notifications-help@james.apache.org


[james-project] 02/05: JAMES-3431 Stricter validation for DSN ENVID (#1002)

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

btellier pushed a commit to branch 3.7.x
in repository https://gitbox.apache.org/repos/asf/james-project.git

commit 3f5e7795162112e203b918ea6ef46d6d61833451
Author: Benoit TELLIER <bt...@linagora.com>
AuthorDate: Tue May 24 08:55:35 2022 +0700

    JAMES-3431 Stricter validation for DSN ENVID (#1002)
    
    Setting an invalid EndId leads to emails not being
    transmissible to third party systems. Stricter validation
    fixes this.
    
    We need to match the XText syntax. Provides a utility to
    check, encode and decode XText.
    
    See https://datatracker.ietf.org/doc/html/rfc3461#section-4
    
    (cherry picked from commit 5ad5cb6a4e07432502350f4ee1dee9a50fae9d01)
---
 .../main/java/org/apache/mailet/DsnParameters.java | 93 ++++++++++++++++++++++
 .../java/org/apache/mailet/DsnParametersTest.java  | 68 +++++++++++++---
 .../transport/matchers/DSNDelayRequestedTest.java  |  2 -
 3 files changed, 152 insertions(+), 11 deletions(-)

diff --git a/mailet/api/src/main/java/org/apache/mailet/DsnParameters.java b/mailet/api/src/main/java/org/apache/mailet/DsnParameters.java
index 5d23938d6e..a426dceb01 100644
--- a/mailet/api/src/main/java/org/apache/mailet/DsnParameters.java
+++ b/mailet/api/src/main/java/org/apache/mailet/DsnParameters.java
@@ -32,6 +32,7 @@ import org.apache.commons.lang3.tuple.Pair;
 import org.apache.james.core.MailAddress;
 
 import com.github.fge.lambdas.Throwing;
+import com.google.common.base.CharMatcher;
 import com.google.common.base.Joiner;
 import com.google.common.base.MoreObjects;
 import com.google.common.base.Preconditions;
@@ -52,6 +53,96 @@ public class DsnParameters {
     public static final String ENVID_PARAMETER = "ENVID";
     public static final String RET_PARAMETER = "RET";
 
+    public static class XText {
+        private static final CharMatcher ESCAPE_CHAR = CharMatcher.isNot('+');
+        // https://datatracker.ietf.org/doc/html/rfc3461#section-4
+        private static CharMatcher XCHAR_VALIDATOR = CharMatcher.inRange('!', '~')
+            .and(CharMatcher.isNot('='))
+            .and(ESCAPE_CHAR);
+        private static CharMatcher HEX_VALIDATOR = CharMatcher.inRange('0', '9')
+            .or(CharMatcher.inRange('A', 'F'));
+
+        static String encode(String text) {
+            if (isOnlyXChar(text)) {
+                return text;
+            }
+            StringBuilder result = new StringBuilder();
+            text.chars()
+                .forEach(i -> encode(i, result));
+            return result.toString();
+        }
+
+        private static StringBuilder encode(int i, StringBuilder result) {
+            if (i < 33 || i > 126 || i == 43 || i == 61) {
+                return result.append('+')
+                    .append(String.format("%02X", i));
+            }
+            return result.append((char) i);
+        }
+
+        static String decode(String text) {
+            Preconditions.checkArgument(isValid(text), "Decoding invalid xtext '%s'", text);
+            if (XCHAR_VALIDATOR.matchesAllOf(text)) {
+                return text;
+            }
+            char[] chars = text.toCharArray();
+            StringBuilder result = new StringBuilder();
+            int i = 0;
+            while (i < chars.length) {
+                char c = chars[i];
+                if (c == 43) {
+                    // + escape sequence
+                    char hex1 = chars[i + 1];
+                    char hex2 = chars[i + 2];
+                    char hexChar = (char) Integer.parseInt("" + hex1 + hex2, 16);
+                    result.append(hexChar);
+                    i += 3;
+                } else {
+                    result.append(c);
+                    i++;
+                }
+            }
+            return result.toString();
+        }
+
+        static boolean isValid(String text) {
+            if (isOnlyXChar(text)) {
+                return true;
+            }
+            char[] chars = text.toCharArray();
+            int i = 0;
+            while (i < chars.length) {
+                char c = chars[i];
+                if (!XCHAR_VALIDATOR.matches(c)) {
+                    if (c == 43) {
+                        // + escape sequence
+                        if (!isValidEscapeSequence(chars, i)) {
+                            return false;
+                        }
+                        i += 3;
+                    } else {
+                        return false;
+                    }
+                } else {
+                    i++;
+                }
+            }
+            return true;
+        }
+
+        private static boolean isValidEscapeSequence(char[] chars, int i) {
+            if (i + 3 > chars.length) {
+                return false;
+            }
+            return HEX_VALIDATOR.matches(chars[i + 1])
+                && HEX_VALIDATOR.matches(chars[i + 2]);
+        }
+
+        private static boolean isOnlyXChar(String text) {
+            return XCHAR_VALIDATOR.matchesAllOf(text);
+        }
+    }
+
     /**
      * RET parameter allow the sender to control which part of the bounced message should be returned to the sender.
      *
@@ -104,6 +195,8 @@ public class DsnParameters {
 
         public static EnvId of(String value) {
             Preconditions.checkNotNull(value);
+            Preconditions.checkArgument(XText.isValid(value), "According to RFC-3461 EnvId should be a valid xtext" +
+                ", thus composed of CHARs between \"!\" (33) and \"~\" (126) inclusive, except for \"+\" and \"=\" or follow the hexadecimal escape sequence.");
 
             return new EnvId(value);
         }
diff --git a/mailet/api/src/test/java/org/apache/mailet/DsnParametersTest.java b/mailet/api/src/test/java/org/apache/mailet/DsnParametersTest.java
index ff0e6c3ee6..ba0c0c8b93 100644
--- a/mailet/api/src/test/java/org/apache/mailet/DsnParametersTest.java
+++ b/mailet/api/src/test/java/org/apache/mailet/DsnParametersTest.java
@@ -29,8 +29,11 @@ import org.apache.mailet.DsnParameters.EnvId;
 import org.apache.mailet.DsnParameters.Notify;
 import org.apache.mailet.DsnParameters.RecipientDsnParameters;
 import org.apache.mailet.DsnParameters.Ret;
+import org.apache.mailet.DsnParameters.XText;
 import org.junit.jupiter.api.Nested;
 import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
 
 import com.google.common.collect.ImmutableMap;
 
@@ -113,19 +116,23 @@ class DsnParametersTest {
     @Nested
     class EnvIdTest {
         @Test
-        void parseShouldReturnEmptyOnUnknownValue() {
-            assertThat(Ret.parse("unknown")).isEmpty();
+        void ofShouldThrowOnNullValue() {
+            assertThatThrownBy(() -> EnvId.of(null))
+                .isInstanceOf(NullPointerException.class);
         }
 
-        @Test
-        void parseShouldReturnEmptyOnEmptyValue() {
-            assertThat(EnvId.of("").asString()).isEqualTo("");
+        @ParameterizedTest
+        @ValueSource(strings = {"bad envid", "bad=envid", "Bad+envId", "Bad+"})
+        void ofShouldThrowOnBadValue(String badValue) {
+            assertThatThrownBy(() -> EnvId.of(badValue))
+                .isInstanceOf(IllegalArgumentException.class);
         }
 
-        @Test
-        void ofShouldThrowOnNullValue() {
-            assertThatThrownBy(() -> EnvId.of(null))
-                .isInstanceOf(NullPointerException.class);
+        @ParameterizedTest
+        @ValueSource(strings = {"good", "000023", "good+32space", "+32", "", "+61", "+43"})
+        void ofShouldAcceptGoodValue(String value) {
+            assertThat(EnvId.of(value).asString())
+                .isEqualTo(value);
         }
 
         @Test
@@ -147,6 +154,49 @@ class DsnParametersTest {
         }
     }
 
+    @Nested
+    class XTextTest {
+        @ParameterizedTest
+        @ValueSource(strings = {"bad envid", "bad=envid", "Bad+envId", "Bad+", "Bad+2"})
+        void isValidShouldReturnFalseOnBadValue(String badValue) {
+            assertThat(XText.isValid(badValue))
+                .isFalse();
+        }
+
+        @ParameterizedTest
+        @ValueSource(strings = {"bad envid", "bad=envid", "Bad+envId", "Bad+", "Bad+0o", "Bad+2"})
+        void decodeShouldThrowWhenInvalid(String badValue) {
+            assertThatThrownBy(() -> XText.decode(badValue))
+                .isInstanceOf(IllegalArgumentException.class);
+        }
+
+        @ParameterizedTest
+        @ValueSource(strings = {"good", "000023", "", "good+32space", "+32", "+61", "+43"})
+        void isValidShouldReturnTrueOnGoodValue(String value) {
+            assertThat(XText.isValid(value))
+                .isTrue();
+        }
+
+        @ParameterizedTest
+        @ValueSource(strings = {"abc", "a+32bc", "", " &*^%$@#%^&#%%kefbvvule89623r757'\"\\/?<>=+-_", "0123"})
+        void encodeDecodeShouldNoop(String value) {
+            assertThat(XText.decode(XText.encode(value)))
+                .isEqualTo(value);
+        }
+
+        @Test
+        void encodeShouldReturnTheGoodValue() {
+            assertThat(XText.encode("abc def+0123=gdef"))
+                .isEqualTo("abc+20def+2B0123+3Dgdef");
+        }
+
+        @Test
+        void decodeShouldReturnTheGoodValue() {
+            assertThat(XText.decode("abc+20def+2B0123+3Dgdef"))
+                .isEqualTo("abc def+0123=gdef");
+        }
+    }
+
     @Nested
     class NotifyTest {
         @Test
diff --git a/server/mailet/mailets/src/test/java/org/apache/james/transport/matchers/DSNDelayRequestedTest.java b/server/mailet/mailets/src/test/java/org/apache/james/transport/matchers/DSNDelayRequestedTest.java
index 7a6f714729..62fe867e18 100644
--- a/server/mailet/mailets/src/test/java/org/apache/james/transport/matchers/DSNDelayRequestedTest.java
+++ b/server/mailet/mailets/src/test/java/org/apache/james/transport/matchers/DSNDelayRequestedTest.java
@@ -27,13 +27,11 @@ import static org.apache.mailet.base.MailAddressFixture.RECIPIENT1;
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.assertThatCode;
 import static org.assertj.core.api.Assertions.assertThatThrownBy;
-import static org.junit.jupiter.api.Assertions.*;
 
 import java.util.EnumSet;
 
 import org.apache.james.server.core.MailImpl;
 import org.apache.mailet.DsnParameters;
-import org.apache.mailet.base.MailAddressFixture;
 import org.apache.mailet.base.test.FakeMatcherConfig;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Nested;


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@james.apache.org
For additional commands, e-mail: notifications-help@james.apache.org


[james-project] 05/05: JAMES-3744 remove redundant hashmaps which lead to OOM

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

btellier pushed a commit to branch 3.7.x
in repository https://gitbox.apache.org/repos/asf/james-project.git

commit ef062ac82187f886d7eabc6b9bca902109f78448
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Fri Apr 8 21:08:46 2022 +0700

    JAMES-3744 remove redundant hashmaps which lead to OOM
    
    Upstream https://github.com/reactor/reactor-netty/commit/fe6653fac44df16664bdd0628ad56cd142175bca
    
    (cherry picked from commit 06260220051a42522ff501e75f689d59f640744d)
---
 .../org/apache/james/jmap/UriPathTemplate.java     | 23 ++--------------------
 1 file changed, 2 insertions(+), 21 deletions(-)

diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/UriPathTemplate.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/UriPathTemplate.java
index 6c158a9951..902cdb27cc 100644
--- a/server/protocols/jmap/src/main/java/org/apache/james/jmap/UriPathTemplate.java
+++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/UriPathTemplate.java
@@ -52,10 +52,6 @@ public class UriPathTemplate {
 
     private final List<String> pathVariables =
         new ArrayList<>();
-    private final HashMap<String, Matcher> matchers =
-        new HashMap<>();
-    private final HashMap<String, Map<String, String>> vars =
-        new HashMap<>();
 
     private final Pattern uriPattern;
 
@@ -126,14 +122,7 @@ public class UriPathTemplate {
 
     private Matcher matcher(String uri) {
         uri = filterQueryParams(uri);
-        Matcher m = matchers.get(uri);
-        if (null == m) {
-            m = uriPattern.matcher(uri);
-            synchronized (matchers) {
-                matchers.put(uri, m);
-            }
-        }
-        return m;
+        return uriPattern.matcher(uri);
     }
 
     /**
@@ -146,12 +135,7 @@ public class UriPathTemplate {
      * @return the path parameters from the uri. Never {@code null}.
      */
     final Map<String, String> match(String uri) {
-        Map<String, String> pathParameters = vars.get(uri);
-        if (null != pathParameters) {
-            return pathParameters;
-        }
-
-        pathParameters = new HashMap<>();
+        Map<String, String> pathParameters = new HashMap<>();
         Matcher m = matcher(uri);
         if (m.matches()) {
             int i = 1;
@@ -160,9 +144,6 @@ public class UriPathTemplate {
                 pathParameters.put(name, val);
             }
         }
-        synchronized (vars) {
-            vars.put(uri, pathParameters);
-        }
 
         return pathParameters;
     }


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@james.apache.org
For additional commands, e-mail: notifications-help@james.apache.org


[james-project] 04/05: JAMES-3753 Fix FlowedMessageUtils.deflow() (#972)

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

btellier pushed a commit to branch 3.7.x
in repository https://gitbox.apache.org/repos/asf/james-project.git

commit 7a2e6fac030cfb9ed26cc142e26b20e0a81c41ac
Author: cketti <ck...@cketti.de>
AuthorDate: Fri Apr 22 07:03:30 2022 +0200

    JAMES-3753 Fix FlowedMessageUtils.deflow() (#972)
    
    (cherry picked from commit d38a35996d693ac927331cfa1238ce5768c0719f)
---
 .../org/apache/mailet/base/FlowedMessageUtils.java |   8 +-
 .../apache/mailet/base/FlowedMessageUtilsTest.java | 205 +++++++++++++++++++++
 2 files changed, 209 insertions(+), 4 deletions(-)

diff --git a/mailet/base/src/main/java/org/apache/mailet/base/FlowedMessageUtils.java b/mailet/base/src/main/java/org/apache/mailet/base/FlowedMessageUtils.java
index 45689081c3..36ee5c49c1 100644
--- a/mailet/base/src/main/java/org/apache/mailet/base/FlowedMessageUtils.java
+++ b/mailet/base/src/main/java/org/apache/mailet/base/FlowedMessageUtils.java
@@ -78,11 +78,11 @@ public final class FlowedMessageUtils {
             String line = i < lines.length ? lines[i] : null;
             int actualQuoteDepth = 0;
             
-            if (line != null && line.length() > 0) {
+            if (line != null) {
                 if (line.equals(RFC2646_SIGNATURE)) {
                     // signature handling (the previous line is not flowed)
                     resultLineFlowed = false;
-                } else if (line.charAt(0) == RFC2646_QUOTE) {
+                } else if (line.length() > 0 && line.charAt(0) == RFC2646_QUOTE) {
                     // Quote
                     actualQuoteDepth = 1;
                     while (actualQuoteDepth < line.length() && line.charAt(actualQuoteDepth) == RFC2646_QUOTE) {
@@ -95,7 +95,7 @@ public final class FlowedMessageUtils {
                     line = line.substring(actualQuoteDepth);
                     
                 } else {
-                    // id quote-depth changes wrt the first line then this is not flowed
+                    // if quote-depth changes wrt the first line then this is not flowed
                     if (resultLineQuoteDepth > 0) {
                         resultLineFlowed = false;
                     }
@@ -107,7 +107,7 @@ public final class FlowedMessageUtils {
                 }
                 
             // if the previous was the last then it was not flowed
-            } else if (line == null) {
+            } else {
                 resultLineFlowed = false;
             }
 
diff --git a/mailet/base/src/test/java/org/apache/mailet/base/FlowedMessageUtilsTest.java b/mailet/base/src/test/java/org/apache/mailet/base/FlowedMessageUtilsTest.java
new file mode 100644
index 0000000000..61987bd030
--- /dev/null
+++ b/mailet/base/src/test/java/org/apache/mailet/base/FlowedMessageUtilsTest.java
@@ -0,0 +1,205 @@
+/****************************************************************
+ * 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.mailet.base;
+
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class FlowedMessageUtilsTest {
+    private static final boolean DEL_SP_NO = false;
+    private static final boolean DEL_SP_YES = true;
+
+    @Test
+    void deflowWithSimpleText() {
+        String input = "Text that should be \r\n" +
+            "displayed on one line";
+
+        String result = FlowedMessageUtils.deflow(input, DEL_SP_NO);
+
+        assertThat(result).isEqualTo("Text that should be displayed on one line");
+    }
+
+    @Test
+    void deflowWithOnlySomeLinesEndingInSpace() {
+        String input = "Text that \r\n" +
+            "should be \r\n" +
+            "displayed on \r\n" +
+            "one line.\r\n" +
+            "Text that should retain\r\n" +
+            "its line break.";
+
+        String result = FlowedMessageUtils.deflow(input, DEL_SP_NO);
+
+        assertThat(result).isEqualTo(
+            "Text that should be displayed on one line.\r\n" +
+                "Text that should retain\r\n" +
+                "its line break.");
+    }
+
+    @Test
+    void deflowWithNothingToDo() {
+        String input = "Line one\r\nLine two\r\n";
+
+        String result = FlowedMessageUtils.deflow(input, DEL_SP_NO);
+
+        assertThat(result).isEqualTo(input);
+    }
+
+    @Test
+    void deflowWithQuotedText() {
+        String input = "On [date], [user] wrote:\r\n" +
+            "> Text that should be displayed \r\n" +
+            "> on one line\r\n" +
+            "\r\n" +
+            "Some more text that should be \r\n" +
+            "displayed on one line.\r\n";
+
+        String result = FlowedMessageUtils.deflow(input, DEL_SP_NO);
+
+        assertThat(result).isEqualTo(
+            "On [date], [user] wrote:\r\n" +
+                "> Text that should be displayed on one line\r\n" +
+                "\r\n" +
+                "Some more text that should be displayed on one line.\r\n");
+    }
+
+    @Test
+    void deflowWithQuotedTextEndingInSpace() {
+        String input = "> Quoted text \r\n" +
+            "Some other text";
+
+        String result = FlowedMessageUtils.deflow(input, DEL_SP_NO);
+
+        assertThat(result).isEqualTo("> Quoted text \r\nSome other text");
+    }
+
+    @Test
+    void deflowWithQuotedTextEndingInSpaceBeforeQuotedTextOfDifferentQuoteDepth() {
+        String input = ">> Depth 2 \r\n" +
+            "> Depth 1 \r\n" +
+            "> is here\r\n" +
+            "Some other text";
+
+        String result = FlowedMessageUtils.deflow(input, DEL_SP_NO);
+
+        assertThat(result).isEqualTo(
+            ">> Depth 2 \r\n" +
+                "> Depth 1 is here\r\n" +
+                "Some other text");
+    }
+
+    @Test
+    void deflowWithQuotedTextEndingInSpaceFollowedByEmptyLine() {
+        String input = "> Quoted \r\n" +
+            "\r\n" +
+            "Text";
+
+        String result = FlowedMessageUtils.deflow(input, DEL_SP_NO);
+
+        assertThat(result).isEqualTo(input);
+    }
+
+    @Test
+    void deflowWithDelSp() {
+        String input = "Text that is wrapped mid wo \r\nrd";
+
+        String result = FlowedMessageUtils.deflow(input, DEL_SP_YES);
+
+        assertThat(result).isEqualTo("Text that is wrapped mid word");
+    }
+
+    @Test
+    void deflowWithQuotedTextAndSpaceStuffingAndDelSp() {
+        String input = "> Quoted te \r\n" +
+            "> xt";
+
+        String result = FlowedMessageUtils.deflow(input, DEL_SP_YES);
+
+        assertThat(result).isEqualTo("> Quoted text");
+    }
+
+    @Test
+    void deflowWithSpaceStuffedSecondLine() {
+        String input = "Text that should be \r\n" +
+            " displayed on one line";
+
+        String result = FlowedMessageUtils.deflow(input, DEL_SP_NO);
+
+        assertThat(result).isEqualTo("Text that should be displayed on one line");
+    }
+
+    @Test
+    void deflowWithOnlySpaceStuffing() {
+        String input = "Line 1\r\n" +
+            " Line 2\r\n" +
+            " Line 3\r\n";
+
+        String result = FlowedMessageUtils.deflow(input, DEL_SP_NO);
+
+        assertThat(result).isEqualTo("Line 1\r\nLine 2\r\nLine 3\r\n");
+    }
+
+    @Test
+    void deflowWithQuotedSpaceStuffedSecondLine() {
+        String input = "> Text that should be \r\n" +
+            "> displayed on one line";
+
+        String result = FlowedMessageUtils.deflow(input, DEL_SP_NO);
+
+        assertThat(result).isEqualTo("> Text that should be displayed on one line");
+    }
+
+    @Test
+    void deflowWithTextContainingSignature() {
+        String input = "Text that should be \r\n" +
+            "displayed on one line.\r\n" +
+            "\r\n" +
+            "-- \r\n" +
+            "Signature \r\n" +
+            "text";
+
+        String result = FlowedMessageUtils.deflow(input, DEL_SP_NO);
+
+        assertThat(result).isEqualTo(
+            "Text that should be displayed on one line.\r\n" +
+                "\r\n" +
+                "-- \r\n" +
+                "Signature text");
+    }
+
+    @Test
+    void deflowWithQuotedTextContainingSignature() {
+        String input = "> Text that should be \r\n" +
+            "> displayed on one line.\r\n" +
+            "> \r\n" +
+            "> -- \r\n" +
+            "> Signature \r\n" +
+            "> text";
+
+        String result = FlowedMessageUtils.deflow(input, DEL_SP_NO);
+
+        assertThat(result).isEqualTo(
+            "> Text that should be displayed on one line.\r\n" +
+                "> \r\n" +
+                "> -- \r\n" +
+                "> Signature text");
+    }
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@james.apache.org
For additional commands, e-mail: notifications-help@james.apache.org


[james-project] 01/05: JAMES-3803 RemoteDelivery uses different scheduler for dequeuing (#1121)

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

btellier pushed a commit to branch 3.7.x
in repository https://gitbox.apache.org/repos/asf/james-project.git

commit 7664606b0a6325bec14ade623c095e230218b13e
Author: AdBuch <41...@users.noreply.github.com>
AuthorDate: Fri Aug 19 11:18:35 2022 +0200

    JAMES-3803 RemoteDelivery uses different scheduler for dequeuing (#1121)
    
    This is necessary as else in high load a delivery-task can queue in the same thread as the never ending dequeuing-task and stay there forever
    
    (cherry picked from commit c57bf62155843f2577d2c62a205d5e064b2ea5d8)
---
 .../transport/mailets/remote/delivery/DeliveryRunnable.java | 13 ++++++++-----
 1 file changed, 8 insertions(+), 5 deletions(-)

diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remote/delivery/DeliveryRunnable.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remote/delivery/DeliveryRunnable.java
index 1c771f9920..25d3a2d549 100644
--- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remote/delivery/DeliveryRunnable.java
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remote/delivery/DeliveryRunnable.java
@@ -68,7 +68,8 @@ public class DeliveryRunnable implements Disposable {
     private final Supplier<Date> dateSupplier;
     private final MailetContext mailetContext;
     private Disposable disposable;
-    private Scheduler remoteDeliveryScheduler;
+    private Scheduler remoteDeliveryProcessScheduler;
+    private Scheduler remoteDeliveryDequeueScheduler;
 
     public DeliveryRunnable(MailQueue queue, RemoteDeliveryConfiguration configuration, DNSService dnsServer, MetricFactory metricFactory,
                             MailetContext mailetContext, Bouncer bouncer) {
@@ -91,11 +92,12 @@ public class DeliveryRunnable implements Disposable {
     }
 
     public void start() {
-        remoteDeliveryScheduler = Schedulers.newBoundedElastic(Schedulers.DEFAULT_BOUNDED_ELASTIC_SIZE, Schedulers.DEFAULT_BOUNDED_ELASTIC_QUEUESIZE, "RemoteDelivery");
+        remoteDeliveryProcessScheduler = Schedulers.newBoundedElastic(Schedulers.DEFAULT_BOUNDED_ELASTIC_SIZE, Schedulers.DEFAULT_BOUNDED_ELASTIC_QUEUESIZE, "RemoteDelivery-Process");
+        remoteDeliveryDequeueScheduler = Schedulers.newSingle("RemoteDelivery-Dequeue");
         disposable = Flux.from(queue.deQueue())
-            .flatMap(queueItem -> runStep(queueItem).subscribeOn(remoteDeliveryScheduler), Queues.SMALL_BUFFER_SIZE)
+            .flatMap(queueItem -> runStep(queueItem).subscribeOn(remoteDeliveryProcessScheduler), Queues.SMALL_BUFFER_SIZE)
             .onErrorContinue(((throwable, nothing) -> LOGGER.error("Exception caught in RemoteDelivery", throwable)))
-            .subscribeOn(remoteDeliveryScheduler)
+            .subscribeOn(remoteDeliveryDequeueScheduler)
             .subscribe();
     }
 
@@ -202,6 +204,7 @@ public class DeliveryRunnable implements Disposable {
     @Override
     public void dispose() {
         disposable.dispose();
-        remoteDeliveryScheduler.dispose();
+        remoteDeliveryProcessScheduler.dispose();
+        remoteDeliveryDequeueScheduler.dispose();
     }
 }


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@james.apache.org
For additional commands, e-mail: notifications-help@james.apache.org