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 2021/05/14 02:04:36 UTC

[james-project] 01/09: JAMES-3574 LMTP DATA processing errors should be propagated upstream

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

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

commit d56357762b53c649fc4ef569342fcec3cf226725
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Wed May 12 10:29:55 2021 +0700

    JAMES-3574 LMTP DATA processing errors should be propagated upstream
---
 .../james/lmtpserver/MailetContainerHandler.java   |   4 +-
 .../lmtpserver/MailetContainerHandlerTest.java     | 246 +++++++++++++++------
 2 files changed, 178 insertions(+), 72 deletions(-)

diff --git a/server/protocols/protocols-lmtp/src/main/java/org/apache/james/lmtpserver/MailetContainerHandler.java b/server/protocols/protocols-lmtp/src/main/java/org/apache/james/lmtpserver/MailetContainerHandler.java
index fcb58c0..3f7d18d 100644
--- a/server/protocols/protocols-lmtp/src/main/java/org/apache/james/lmtpserver/MailetContainerHandler.java
+++ b/server/protocols/protocols-lmtp/src/main/java/org/apache/james/lmtpserver/MailetContainerHandler.java
@@ -52,8 +52,8 @@ public class MailetContainerHandler extends DataLineJamesMessageHookHandler {
                 .smtpReturnCode(SMTPRetCode.MAIL_OK)
                 .smtpDescription(DSNStatus.getStatus(DSNStatus.SUCCESS, DSNStatus.CONTENT_OTHER) + " Message received")
                 .build());
-        } catch (MessagingException e) {
-            return new SMTPResponse(SMTPRetCode.LOCAL_ERROR, DSNStatus.getStatus(DSNStatus.TRANSIENT, DSNStatus.UNDEFINED_STATUS) + "Temporary error deliver message");
+        } catch (Exception e) {
+            return new SMTPResponse(SMTPRetCode.LOCAL_ERROR, DSNStatus.getStatus(DSNStatus.TRANSIENT, DSNStatus.UNDEFINED_STATUS) + " Temporary error deliver message");
         }
     }
 }
diff --git a/server/protocols/protocols-lmtp/src/test/java/org/apache/james/lmtpserver/MailetContainerHandlerTest.java b/server/protocols/protocols-lmtp/src/test/java/org/apache/james/lmtpserver/MailetContainerHandlerTest.java
index 98ecfb9..39d5a98 100644
--- a/server/protocols/protocols-lmtp/src/test/java/org/apache/james/lmtpserver/MailetContainerHandlerTest.java
+++ b/server/protocols/protocols-lmtp/src/test/java/org/apache/james/lmtpserver/MailetContainerHandlerTest.java
@@ -60,6 +60,7 @@ import org.awaitility.Awaitility;
 import org.jboss.netty.util.HashedWheelTimer;
 import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Nested;
 import org.junit.jupiter.api.Test;
 
 class MailetContainerHandlerTest {
@@ -76,81 +77,186 @@ class MailetContainerHandlerTest {
         }
     }
 
-    private RecordingMailProcessor recordingMailProcessor;
-    private LMTPServerFactory lmtpServerFactory;
-
-    @BeforeEach
-    void setUp()  throws Exception {
-        InMemoryDNSService dnsService = new InMemoryDNSService()
-            .registerMxRecord(Domain.LOCALHOST.asString(), "127.0.0.1")
-            .registerMxRecord("examplebis.local", "127.0.0.1")
-            .registerMxRecord("127.0.0.1", "127.0.0.1");
-        MemoryDomainList domainList = new MemoryDomainList(dnsService);
-        domainList.configure(DomainListConfiguration.builder()
-            .autoDetect(false)
-            .autoDetectIp(false)
-            .build());
-        recordingMailProcessor = new RecordingMailProcessor();
-
-        domainList.addDomain(Domain.of("examplebis.local"));
-        MemoryUsersRepository usersRepository = MemoryUsersRepository.withVirtualHosting(domainList);
-
-        usersRepository.addUser(Username.of("bob@examplebis.local"), "pwd");
-
-        FileSystem fileSystem = new FileSystemImpl(Configuration.builder()
-            .workingDirectory("../")
-            .configurationFromClasspath()
-            .build().directories());
-        MemoryRecipientRewriteTable rewriteTable = new MemoryRecipientRewriteTable();
-        rewriteTable.setConfiguration(RecipientRewriteTableConfiguration.DEFAULT_ENABLED);
-        AliasReverseResolver aliasReverseResolver = new AliasReverseResolverImpl(rewriteTable);
-        CanSendFrom canSendFrom = new CanSendFromImpl(rewriteTable, aliasReverseResolver);
-        MockProtocolHandlerLoader loader = MockProtocolHandlerLoader.builder()
-            .put(binder -> binder.bind(DomainList.class).toInstance(domainList))
-            .put(binder -> binder.bind(RecipientRewriteTable.class).toInstance(rewriteTable))
-            .put(binder -> binder.bind(CanSendFrom.class).toInstance(canSendFrom))
-            .put(binder -> binder.bind(MailProcessor.class).toInstance(recordingMailProcessor))
-            .put(binder -> binder.bind(FileSystem.class).toInstance(fileSystem))
-            .put(binder -> binder.bind(DNSService.class).toInstance(dnsService))
-            .put(binder -> binder.bind(UsersRepository.class).toInstance(usersRepository))
-            .put(binder -> binder.bind(MetricFactory.class).to(RecordingMetricFactory.class))
-            .build();
-        lmtpServerFactory = new LMTPServerFactory(loader, fileSystem, new RecordingMetricFactory(), new HashedWheelTimer());
-
-        lmtpServerFactory.configure(ConfigLoader.getConfig(ClassLoader.getSystemResourceAsStream("lmtpmailet.xml")));
-        lmtpServerFactory.init();
+    static class ThrowingMailProcessor implements MailProcessor {
+        @Override
+        public void service(Mail mail) {
+            throw new RuntimeException("Oups");
+        }
     }
 
-    @AfterEach
-    void tearDown() {
-        lmtpServerFactory.destroy();
+    @Nested
+    class Normal {
+
+        private RecordingMailProcessor recordingMailProcessor;
+        private LMTPServerFactory lmtpServerFactory;
+
+        @BeforeEach
+        void setUp()  throws Exception {
+            InMemoryDNSService dnsService = new InMemoryDNSService()
+                .registerMxRecord(Domain.LOCALHOST.asString(), "127.0.0.1")
+                .registerMxRecord("examplebis.local", "127.0.0.1")
+                .registerMxRecord("127.0.0.1", "127.0.0.1");
+            MemoryDomainList domainList = new MemoryDomainList(dnsService);
+            domainList.configure(DomainListConfiguration.builder()
+                .autoDetect(false)
+                .autoDetectIp(false)
+                .build());
+            recordingMailProcessor = new RecordingMailProcessor();
+
+            domainList.addDomain(Domain.of("examplebis.local"));
+            MemoryUsersRepository usersRepository = MemoryUsersRepository.withVirtualHosting(domainList);
+
+            usersRepository.addUser(Username.of("bob@examplebis.local"), "pwd");
+
+            FileSystem fileSystem = new FileSystemImpl(Configuration.builder()
+                .workingDirectory("../")
+                .configurationFromClasspath()
+                .build().directories());
+            MemoryRecipientRewriteTable rewriteTable = new MemoryRecipientRewriteTable();
+            rewriteTable.setConfiguration(RecipientRewriteTableConfiguration.DEFAULT_ENABLED);
+            AliasReverseResolver aliasReverseResolver = new AliasReverseResolverImpl(rewriteTable);
+            CanSendFrom canSendFrom = new CanSendFromImpl(rewriteTable, aliasReverseResolver);
+            MockProtocolHandlerLoader loader = MockProtocolHandlerLoader.builder()
+                .put(binder -> binder.bind(DomainList.class).toInstance(domainList))
+                .put(binder -> binder.bind(RecipientRewriteTable.class).toInstance(rewriteTable))
+                .put(binder -> binder.bind(CanSendFrom.class).toInstance(canSendFrom))
+                .put(binder -> binder.bind(MailProcessor.class).toInstance(recordingMailProcessor))
+                .put(binder -> binder.bind(FileSystem.class).toInstance(fileSystem))
+                .put(binder -> binder.bind(DNSService.class).toInstance(dnsService))
+                .put(binder -> binder.bind(UsersRepository.class).toInstance(usersRepository))
+                .put(binder -> binder.bind(MetricFactory.class).to(RecordingMetricFactory.class))
+                .build();
+            lmtpServerFactory = new LMTPServerFactory(loader, fileSystem, new RecordingMetricFactory(), new HashedWheelTimer());
+
+            lmtpServerFactory.configure(ConfigLoader.getConfig(ClassLoader.getSystemResourceAsStream("lmtpmailet.xml")));
+            lmtpServerFactory.init();
+        }
+
+        @AfterEach
+        void tearDown() {
+            lmtpServerFactory.destroy();
+        }
+
+        @Test
+        void emailShouldTriggerTheMailProcessing() throws Exception {
+            SocketChannel server = SocketChannel.open();
+            server.connect(new InetSocketAddress(LOCALHOST_IP, getLmtpPort()));
+
+            server.write(ByteBuffer.wrap(("LHLO <" + DOMAIN + ">\r\n").getBytes(StandardCharsets.UTF_8)));
+            server.write(ByteBuffer.wrap(("MAIL FROM: <bob@" + DOMAIN + ">\r\n").getBytes(StandardCharsets.UTF_8)));
+            server.write(ByteBuffer.wrap(("RCPT TO: <bo...@examplebis.local>\r\n").getBytes(StandardCharsets.UTF_8)));
+            server.write(ByteBuffer.wrap(("DATA\r\n").getBytes(StandardCharsets.UTF_8)));
+            server.read(ByteBuffer.allocate(1024)); // needed to synchronize
+            server.write(ByteBuffer.wrap(("header:value\r\n\r\nbody").getBytes(StandardCharsets.UTF_8)));
+            server.write(ByteBuffer.wrap(("\r\n").getBytes(StandardCharsets.UTF_8)));
+            server.write(ByteBuffer.wrap((".").getBytes(StandardCharsets.UTF_8)));
+            server.write(ByteBuffer.wrap(("\r\n").getBytes(StandardCharsets.UTF_8)));
+            server.write(ByteBuffer.wrap(("QUIT\r\n").getBytes(StandardCharsets.UTF_8)));
+
+            Awaitility.await()
+                .untilAsserted(() -> assertThat(recordingMailProcessor.getMails()).hasSize(1));
+        }
+
+        public int getLmtpPort() {
+            return lmtpServerFactory.getServers().stream()
+                .findFirst()
+                .flatMap(server -> server.getListenAddresses().stream().findFirst())
+                .map(InetSocketAddress::getPort)
+                .orElseThrow(() -> new IllegalStateException("LMTP server not defined"));
+        }
     }
 
-    @Test
-    void emailShouldTriggerTheMailProcessing() throws Exception {
-        SocketChannel server = SocketChannel.open();
-        server.connect(new InetSocketAddress(LOCALHOST_IP, getLmtpPort()));
-
-        server.write(ByteBuffer.wrap(("LHLO <" + DOMAIN + ">\r\n").getBytes(StandardCharsets.UTF_8)));
-        server.write(ByteBuffer.wrap(("MAIL FROM: <bob@" + DOMAIN + ">\r\n").getBytes(StandardCharsets.UTF_8)));
-        server.write(ByteBuffer.wrap(("RCPT TO: <bo...@examplebis.local>\r\n").getBytes(StandardCharsets.UTF_8)));
-        server.write(ByteBuffer.wrap(("DATA\r\n").getBytes(StandardCharsets.UTF_8)));
-        server.read(ByteBuffer.allocate(1024)); // needed to synchronize
-        server.write(ByteBuffer.wrap(("header:value\r\n\r\nbody").getBytes(StandardCharsets.UTF_8)));
-        server.write(ByteBuffer.wrap(("\r\n").getBytes(StandardCharsets.UTF_8)));
-        server.write(ByteBuffer.wrap((".").getBytes(StandardCharsets.UTF_8)));
-        server.write(ByteBuffer.wrap(("\r\n").getBytes(StandardCharsets.UTF_8)));
-        server.write(ByteBuffer.wrap(("QUIT\r\n").getBytes(StandardCharsets.UTF_8)));
-
-        Awaitility.await()
-            .untilAsserted(() -> assertThat(recordingMailProcessor.getMails()).hasSize(1));
+    @Nested
+    class Throwing {
+        private LMTPServerFactory lmtpServerFactory;
+
+        @BeforeEach
+        void setUp()  throws Exception {
+            InMemoryDNSService dnsService = new InMemoryDNSService()
+                .registerMxRecord(Domain.LOCALHOST.asString(), "127.0.0.1")
+                .registerMxRecord("examplebis.local", "127.0.0.1")
+                .registerMxRecord("127.0.0.1", "127.0.0.1");
+            MemoryDomainList domainList = new MemoryDomainList(dnsService);
+            domainList.configure(DomainListConfiguration.builder()
+                .autoDetect(false)
+                .autoDetectIp(false)
+                .build());
+
+            domainList.addDomain(Domain.of("examplebis.local"));
+            MemoryUsersRepository usersRepository = MemoryUsersRepository.withVirtualHosting(domainList);
+
+            usersRepository.addUser(Username.of("bob@examplebis.local"), "pwd");
+
+            FileSystem fileSystem = new FileSystemImpl(Configuration.builder()
+                .workingDirectory("../")
+                .configurationFromClasspath()
+                .build().directories());
+            MemoryRecipientRewriteTable rewriteTable = new MemoryRecipientRewriteTable();
+            rewriteTable.setConfiguration(RecipientRewriteTableConfiguration.DEFAULT_ENABLED);
+            AliasReverseResolver aliasReverseResolver = new AliasReverseResolverImpl(rewriteTable);
+            CanSendFrom canSendFrom = new CanSendFromImpl(rewriteTable, aliasReverseResolver);
+            MockProtocolHandlerLoader loader = MockProtocolHandlerLoader.builder()
+                .put(binder -> binder.bind(DomainList.class).toInstance(domainList))
+                .put(binder -> binder.bind(RecipientRewriteTable.class).toInstance(rewriteTable))
+                .put(binder -> binder.bind(CanSendFrom.class).toInstance(canSendFrom))
+                .put(binder -> binder.bind(MailProcessor.class).toInstance(new ThrowingMailProcessor()))
+                .put(binder -> binder.bind(FileSystem.class).toInstance(fileSystem))
+                .put(binder -> binder.bind(DNSService.class).toInstance(dnsService))
+                .put(binder -> binder.bind(UsersRepository.class).toInstance(usersRepository))
+                .put(binder -> binder.bind(MetricFactory.class).to(RecordingMetricFactory.class))
+                .build();
+            lmtpServerFactory = new LMTPServerFactory(loader, fileSystem, new RecordingMetricFactory(), new HashedWheelTimer());
+
+            lmtpServerFactory.configure(ConfigLoader.getConfig(ClassLoader.getSystemResourceAsStream("lmtpmailet.xml")));
+            lmtpServerFactory.init();
+        }
+
+        @AfterEach
+        void tearDown() {
+            lmtpServerFactory.destroy();
+        }
+
+        @Test
+        void emailShouldTriggerTheMailProcessing() throws Exception {
+            SocketChannel server = SocketChannel.open();
+            server.connect(new InetSocketAddress(LOCALHOST_IP, getLmtpPort()));
+
+            server.write(ByteBuffer.wrap(("LHLO <" + DOMAIN + ">\r\n").getBytes(StandardCharsets.UTF_8)));
+            server.write(ByteBuffer.wrap(("MAIL FROM: <bob@" + DOMAIN + ">\r\n").getBytes(StandardCharsets.UTF_8)));
+            server.write(ByteBuffer.wrap(("RCPT TO: <bo...@examplebis.local>\r\n").getBytes(StandardCharsets.UTF_8)));
+            server.write(ByteBuffer.wrap(("DATA\r\n").getBytes(StandardCharsets.UTF_8)));
+            server.read(ByteBuffer.allocate(1024)); // Read Welcome message
+            server.write(ByteBuffer.wrap(("header:value\r\n\r\nbody").getBytes(StandardCharsets.UTF_8)));
+            server.write(ByteBuffer.wrap(("\r\n").getBytes(StandardCharsets.UTF_8)));
+            server.write(ByteBuffer.wrap((".").getBytes(StandardCharsets.UTF_8)));
+            server.write(ByteBuffer.wrap(("\r\n").getBytes(StandardCharsets.UTF_8)));
+            server.write(ByteBuffer.wrap(("QUIT\r\n").getBytes(StandardCharsets.UTF_8)));
+
+            server.read(ByteBuffer.allocate(1024)); // Read Capabilities
+            server.read(ByteBuffer.allocate(1024)); // Read LHLO reply string
+            server.read(ByteBuffer.allocate(1024)); // Read MAIL reply string
+            server.read(ByteBuffer.allocate(1024)); // Read RCPT reply string
+
+            ByteBuffer buffer = ByteBuffer.allocate(1024);
+            server.read(buffer); // Read DATA reply string
+            assertThat(new String(readBytes(buffer), StandardCharsets.UTF_8))
+                .startsWith("451 4.0.0 Temporary error deliver message");
+        }
+
+        public int getLmtpPort() {
+            return lmtpServerFactory.getServers().stream()
+                .findFirst()
+                .flatMap(server -> server.getListenAddresses().stream().findFirst())
+                .map(InetSocketAddress::getPort)
+                .orElseThrow(() -> new IllegalStateException("LMTP server not defined"));
+        }
     }
 
-    public int getLmtpPort() {
-        return lmtpServerFactory.getServers().stream()
-            .findFirst()
-            .flatMap(server -> server.getListenAddresses().stream().findFirst())
-            .map(InetSocketAddress::getPort)
-            .orElseThrow(() -> new IllegalStateException("LMTP server not defined"));
+    private byte[] readBytes(ByteBuffer line) {
+        line.rewind();
+        byte[] bline = new byte[line.remaining()];
+        line.get(bline);
+        return bline;
     }
+
 }
\ No newline at end of file

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