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/08/02 01:24:41 UTC

[james-project] branch master updated: JAMES-3775 Simplify and generify RSpamDHttpClient API

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


The following commit(s) were added to refs/heads/master by this push:
     new 173844abfa JAMES-3775 Simplify and generify RSpamDHttpClient API
173844abfa is described below

commit 173844abfab35d59804f8c5c9ac2c790b4891db0
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Mon Aug 1 11:06:43 2022 +0700

    JAMES-3775 Simplify and generify RSpamDHttpClient API
    
     - Avoid the javax.mail dependency: this undesired
      dependency should likely not be relied upon.
      This also enables callers to not parse the
      resulting mime message at all.
     - Upon reporting spam/ham do not split header/content. Reports can be done on the full message. Avoid pushing such a constraint to the caller.
---
 .../CombinedHeaderAndContentInputStreamHelper.java | 44 -----------------
 .../james/rspamd/client/RSpamDHttpClient.java      | 33 +++++--------
 .../james/rspamd/client/RSpamDHttpClientTest.java  | 57 ++++++++++------------
 3 files changed, 39 insertions(+), 95 deletions(-)

diff --git a/third-party/rspamd/src/main/java/org/apache/james/rspamd/client/CombinedHeaderAndContentInputStreamHelper.java b/third-party/rspamd/src/main/java/org/apache/james/rspamd/client/CombinedHeaderAndContentInputStreamHelper.java
deleted file mode 100644
index ee8929ed42..0000000000
--- a/third-party/rspamd/src/main/java/org/apache/james/rspamd/client/CombinedHeaderAndContentInputStreamHelper.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/****************************************************************
- * 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.james.rspamd.client;
-
-import java.io.ByteArrayInputStream;
-import java.io.InputStream;
-import java.io.SequenceInputStream;
-import java.nio.charset.StandardCharsets;
-import java.util.Enumeration;
-
-import javax.mail.MessagingException;
-import javax.mail.internet.MimeMessage;
-
-public class CombinedHeaderAndContentInputStreamHelper {
-    public static InputStream mergeHeaderAndContentInputStream(InputStream headerInputStream, InputStream contentInputStream) {
-        return new SequenceInputStream(new SequenceInputStream(headerInputStream, new ByteArrayInputStream("\r\n".getBytes())), contentInputStream);
-    }
-
-    public static InputStream getInputStreamOfMessageHeaders(MimeMessage message) throws MessagingException {
-        Enumeration<String> heads = message.getAllHeaderLines();
-        StringBuilder headBuffer = new StringBuilder();
-        while (heads.hasMoreElements()) {
-            headBuffer.append(heads.nextElement()).append("\n");
-        }
-        return new ByteArrayInputStream(headBuffer.toString().getBytes(StandardCharsets.UTF_8));
-    }
-}
diff --git a/third-party/rspamd/src/main/java/org/apache/james/rspamd/client/RSpamDHttpClient.java b/third-party/rspamd/src/main/java/org/apache/james/rspamd/client/RSpamDHttpClient.java
index 36c2d268da..57f78e5362 100644
--- a/third-party/rspamd/src/main/java/org/apache/james/rspamd/client/RSpamDHttpClient.java
+++ b/third-party/rspamd/src/main/java/org/apache/james/rspamd/client/RSpamDHttpClient.java
@@ -19,18 +19,12 @@
 
 package org.apache.james.rspamd.client;
 
-import static org.apache.james.rspamd.client.CombinedHeaderAndContentInputStreamHelper.getInputStreamOfMessageHeaders;
-import static org.apache.james.rspamd.client.CombinedHeaderAndContentInputStreamHelper.mergeHeaderAndContentInputStream;
 import static org.apache.james.rspamd.client.RSpamDClientConfiguration.DEFAULT_TIMEOUT_IN_SECONDS;
 
-import java.io.IOException;
 import java.io.InputStream;
 import java.nio.charset.StandardCharsets;
 import java.time.Duration;
 
-import javax.mail.MessagingException;
-import javax.mail.internet.MimeMessage;
-
 import org.apache.james.rspamd.exception.RSpamDUnexpectedException;
 import org.apache.james.rspamd.exception.UnauthorizedException;
 import org.apache.james.rspamd.model.AnalysisResult;
@@ -42,7 +36,6 @@ import com.fasterxml.jackson.datatype.jdk8.Jdk8Module;
 import com.github.fge.lambdas.Throwing;
 
 import io.netty.buffer.Unpooled;
-import reactor.core.publisher.Flux;
 import reactor.core.publisher.Mono;
 import reactor.netty.ByteBufMono;
 import reactor.netty.http.client.HttpClient;
@@ -64,23 +57,21 @@ public class RSpamDHttpClient {
         this.objectMapper = new ObjectMapper().registerModule(new Jdk8Module());
     }
 
-    public Mono<AnalysisResult> checkV2(MimeMessage mimeMessage) throws MessagingException, IOException {
-        return Flux.just(getInputStreamOfMessageHeaders(mimeMessage), mimeMessage.getInputStream())
-            .reduce(CombinedHeaderAndContentInputStreamHelper::mergeHeaderAndContentInputStream)
-            .flatMap(inputStream -> httpClient.post()
-                .uri(CHECK_V2_ENDPOINT)
-                .send(ReactorUtils.toChunks(inputStream, BUFFER_SIZE)
-                    .map(Unpooled::wrappedBuffer))
-                .responseSingle(this::checkMailHttpResponseHandler))
+    public Mono<AnalysisResult> checkV2(InputStream mimeMessage) {
+        return httpClient.post()
+            .uri(CHECK_V2_ENDPOINT)
+            .send(ReactorUtils.toChunks(mimeMessage, BUFFER_SIZE)
+                .map(Unpooled::wrappedBuffer))
+            .responseSingle(this::checkMailHttpResponseHandler)
             .subscribeOn(ReactorUtils.BLOCKING_CALL_WRAPPER);
     }
 
-    public Mono<Void> reportAsSpam(InputStream headerInputStream, InputStream contentInputStream) {
-        return reportMail(headerInputStream, contentInputStream, LEARN_SPAM_ENDPOINT);
+    public Mono<Void> reportAsSpam(InputStream content) {
+        return reportMail(content, LEARN_SPAM_ENDPOINT);
     }
 
-    public Mono<Void> reportAsHam(InputStream headerInputStream, InputStream contentInputStream) {
-        return reportMail(headerInputStream, contentInputStream, LEARN_HAM_ENDPOINT);
+    public Mono<Void> reportAsHam(InputStream content) {
+        return reportMail(content, LEARN_HAM_ENDPOINT);
     }
 
     private HttpClient buildReactorNettyHttpClient(RSpamDClientConfiguration configuration) {
@@ -91,10 +82,10 @@ public class RSpamDHttpClient {
             .headers(headers -> headers.add("Password", configuration.getPassword()));
     }
 
-    private Mono<Void> reportMail(InputStream headerInputStream, InputStream contentInputStream, String endpoint) {
+    private Mono<Void> reportMail(InputStream content, String endpoint) {
         return httpClient.post()
             .uri(endpoint)
-            .send(ReactorUtils.toChunks(mergeHeaderAndContentInputStream(headerInputStream, contentInputStream), BUFFER_SIZE)
+            .send(ReactorUtils.toChunks(content, BUFFER_SIZE)
                 .map(Unpooled::wrappedBuffer)
                 .subscribeOn(ReactorUtils.BLOCKING_CALL_WRAPPER))
             .responseSingle(this::reportMailHttpResponseHandler);
diff --git a/third-party/rspamd/src/test/java/org/apache/james/rspamd/client/RSpamDHttpClientTest.java b/third-party/rspamd/src/test/java/org/apache/james/rspamd/client/RSpamDHttpClientTest.java
index a77902ec9d..3b75928a14 100644
--- a/third-party/rspamd/src/test/java/org/apache/james/rspamd/client/RSpamDHttpClientTest.java
+++ b/third-party/rspamd/src/test/java/org/apache/james/rspamd/client/RSpamDHttpClientTest.java
@@ -20,23 +20,20 @@
 package org.apache.james.rspamd.client;
 
 import static org.apache.james.rspamd.DockerRSpamD.PASSWORD;
-import static org.apache.james.rspamd.client.CombinedHeaderAndContentInputStreamHelper.getInputStreamOfMessageHeaders;
 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.hamcrest.Matchers.nullValue;
 import static org.hamcrest.core.Is.is;
 
-import java.io.IOException;
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
 import java.util.Optional;
 
-import javax.mail.MessagingException;
-import javax.mail.internet.MimeMessage;
-
 import org.apache.james.rspamd.DockerRSpamDExtension;
 import org.apache.james.rspamd.exception.UnauthorizedException;
 import org.apache.james.rspamd.model.AnalysisResult;
-import org.apache.james.util.MimeMessageUtil;
+import org.apache.james.util.ClassLoaderUtils;
 import org.apache.james.util.Port;
 import org.apache.james.webadmin.WebAdminUtils;
 import org.eclipse.jetty.http.HttpStatus;
@@ -47,58 +44,58 @@ import org.junit.jupiter.api.extension.RegisterExtension;
 import io.restassured.http.Header;
 import io.restassured.specification.RequestSpecification;
 
-public class RSpamDHttpClientTest {
+class RSpamDHttpClientTest {
     private final static String SPAM_MESSAGE_PATH = "mail/spam/spam8.eml";
     private final static String HAM_MESSAGE_PATH = "mail/ham/ham1.eml";
 
     @RegisterExtension
     static DockerRSpamDExtension rSpamDExtension = new DockerRSpamDExtension();
 
-    private MimeMessage spamMessage;
-    private MimeMessage hamMessage;
+    private byte[] spamMessage;
+    private byte[] hamMessage;
 
     @BeforeEach
-    void setup() throws MessagingException {
-        spamMessage = MimeMessageUtil.mimeMessageFromStream(ClassLoader.getSystemResourceAsStream(SPAM_MESSAGE_PATH));
-        hamMessage = MimeMessageUtil.mimeMessageFromStream(ClassLoader.getSystemResourceAsStream(HAM_MESSAGE_PATH));
+    void setup() {
+        spamMessage = ClassLoaderUtils.getSystemResourceAsByteArray(SPAM_MESSAGE_PATH);
+        hamMessage = ClassLoaderUtils.getSystemResourceAsByteArray(HAM_MESSAGE_PATH);
     }
 
     @Test
-    void checkMailWithWrongPasswordShouldThrowUnauthorizedExceptionException() throws IOException {
+    void checkMailWithWrongPasswordShouldThrowUnauthorizedExceptionException() throws Exception {
         RSpamDClientConfiguration configuration = new RSpamDClientConfiguration(rSpamDExtension.getBaseUrl(), "wrongPassword", Optional.empty());
         RSpamDHttpClient client = new RSpamDHttpClient(configuration);
 
-        assertThatThrownBy(() -> client.checkV2(spamMessage).block())
+        assertThatThrownBy(() -> client.checkV2(new ByteArrayInputStream(spamMessage)).block())
             .hasMessage("{\"error\":\"Unauthorized\"}")
             .isInstanceOf(UnauthorizedException.class);
     }
 
     @Test
-    void learnSpamWithWrongPasswordShouldThrowUnauthorizedExceptionException() throws IOException {
+    void learnSpamWithWrongPasswordShouldThrowUnauthorizedExceptionException() throws Exception {
         RSpamDClientConfiguration configuration = new RSpamDClientConfiguration(rSpamDExtension.getBaseUrl(), "wrongPassword", Optional.empty());
         RSpamDHttpClient client = new RSpamDHttpClient(configuration);
 
-        assertThatThrownBy(() -> reportAsSpam(client, spamMessage))
+        assertThatThrownBy(() -> reportAsSpam(client, new ByteArrayInputStream(spamMessage)))
             .hasMessage("{\"error\":\"Unauthorized\"}")
             .isInstanceOf(UnauthorizedException.class);
     }
 
     @Test
-    void learnHamWithWrongPasswordShouldThrowUnauthorizedExceptionException() throws IOException {
+    void learnHamWithWrongPasswordShouldThrowUnauthorizedExceptionException() throws Exception {
         RSpamDClientConfiguration configuration = new RSpamDClientConfiguration(rSpamDExtension.getBaseUrl(), "wrongPassword", Optional.empty());
         RSpamDHttpClient client = new RSpamDHttpClient(configuration);
 
-        assertThatThrownBy(() -> reportAsHam(client, hamMessage))
+        assertThatThrownBy(() -> reportAsHam(client, new ByteArrayInputStream(spamMessage)))
             .hasMessage("{\"error\":\"Unauthorized\"}")
             .isInstanceOf(UnauthorizedException.class);
     }
 
     @Test
-    void checkSpamMailUsingRSpamDClientWithExactPasswordShouldReturnAnalysisResultAsSameAsUsingRawClient() throws IOException, MessagingException {
+    void checkSpamMailUsingRSpamDClientWithExactPasswordShouldReturnAnalysisResultAsSameAsUsingRawClient() throws Exception {
         RSpamDClientConfiguration configuration = new RSpamDClientConfiguration(rSpamDExtension.getBaseUrl(), PASSWORD, Optional.empty());
         RSpamDHttpClient client = new RSpamDHttpClient(configuration);
 
-        AnalysisResult analysisResult = client.checkV2(spamMessage).block();
+        AnalysisResult analysisResult = client.checkV2(new ByteArrayInputStream(spamMessage)).block();
         assertThat(analysisResult.getAction()).isEqualTo(AnalysisResult.Action.REJECT);
 
         RequestSpecification rspamdApi = WebAdminUtils.spec(Port.of(rSpamDExtension.dockerRSpamD().getPort()));
@@ -114,11 +111,11 @@ public class RSpamDHttpClientTest {
     }
 
     @Test
-    void checkHamMailUsingRSpamDClientWithExactPasswordShouldReturnAnalysisResultAsSameAsUsingRawClient() throws IOException, MessagingException {
+    void checkHamMailUsingRSpamDClientWithExactPasswordShouldReturnAnalysisResultAsSameAsUsingRawClient() throws Exception {
         RSpamDClientConfiguration configuration = new RSpamDClientConfiguration(rSpamDExtension.getBaseUrl(), PASSWORD, Optional.empty());
         RSpamDHttpClient client = new RSpamDHttpClient(configuration);
 
-        AnalysisResult analysisResult = client.checkV2(hamMessage).block();
+        AnalysisResult analysisResult = client.checkV2(new ByteArrayInputStream(hamMessage)).block();
         assertThat(analysisResult).isEqualTo(AnalysisResult.builder()
             .action(AnalysisResult.Action.NO_ACTION)
             .score(0.99F)
@@ -139,29 +136,29 @@ public class RSpamDHttpClientTest {
     }
 
     @Test
-    void learnSpamMailUsingRSpamDClientWithExactPasswordShouldWork() throws IOException {
+    void learnSpamMailUsingRSpamDClientWithExactPasswordShouldWork() throws Exception {
         RSpamDClientConfiguration configuration = new RSpamDClientConfiguration(rSpamDExtension.getBaseUrl(), PASSWORD, Optional.empty());
         RSpamDHttpClient client = new RSpamDHttpClient(configuration);
 
-        assertThatCode(() -> client.reportAsSpam(getInputStreamOfMessageHeaders(spamMessage), spamMessage.getInputStream()).block())
+        assertThatCode(() -> client.reportAsSpam(new ByteArrayInputStream(spamMessage)).block())
             .doesNotThrowAnyException();
     }
 
     @Test
-    void learnHamMailUsingRSpamDClientWithExactPasswordShouldWork() throws IOException {
+    void learnHamMailUsingRSpamDClientWithExactPasswordShouldWork() throws Exception {
         RSpamDClientConfiguration configuration = new RSpamDClientConfiguration(rSpamDExtension.getBaseUrl(), PASSWORD, Optional.empty());
         RSpamDHttpClient client = new RSpamDHttpClient(configuration);
 
-        assertThatCode(() -> client.reportAsHam(getInputStreamOfMessageHeaders(hamMessage), hamMessage.getInputStream()).block())
+        assertThatCode(() -> client.reportAsHam(new ByteArrayInputStream(hamMessage)).block())
             .doesNotThrowAnyException();
     }
 
-    private void reportAsSpam(RSpamDHttpClient client, MimeMessage mimeMessage) throws MessagingException, IOException {
-        client.reportAsSpam(getInputStreamOfMessageHeaders(mimeMessage), mimeMessage.getInputStream()).block();
+    private void reportAsSpam(RSpamDHttpClient client, InputStream inputStream) {
+        client.reportAsSpam(inputStream).block();
     }
 
-    private void reportAsHam(RSpamDHttpClient client, MimeMessage mimeMessage) throws MessagingException, IOException {
-        client.reportAsHam(getInputStreamOfMessageHeaders(mimeMessage), mimeMessage.getInputStream()).block();
+    private void reportAsHam(RSpamDHttpClient client, InputStream inputStream) {
+        client.reportAsHam(inputStream).block();
     }
 
 }


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