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 <[email protected]> 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("[email protected]"), "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("[email protected]"), "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: <[email protected]>\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: <[email protected]>\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("[email protected]"), "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: <[email protected]>\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: [email protected] For additional commands, e-mail: [email protected]
