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 e7d55850526ca94f6a86b63fd47dd2aad7518108 Author: Tran Tien Duc <dt...@linagora.com> AuthorDate: Thu May 2 17:26:33 2019 +0700 JAMES-2744 James download should provide Content-Type header --- .../org/apache/james/util/InputStreamUtils.java | 34 ++++++++++++++ .../apache/james/util/InputStreamUtilsTest.java | 53 ++++++++++++++++++++++ .../integration/cucumber/DownloadStepdefs.java | 22 ++++++--- .../test/resources/cucumber/DownloadGet.feature | 4 +- .../src/test/resources/eml/oneAttachment-part1.eml | 30 ++++++++++++ .../src/test/resources/eml/oneAttachment-part2.eml | 9 ++++ .../org/apache/james/jmap/DownloadServlet.java | 1 + 7 files changed, 145 insertions(+), 8 deletions(-) diff --git a/server/container/util/src/main/java/org/apache/james/util/InputStreamUtils.java b/server/container/util/src/main/java/org/apache/james/util/InputStreamUtils.java new file mode 100644 index 0000000..d522965 --- /dev/null +++ b/server/container/util/src/main/java/org/apache/james/util/InputStreamUtils.java @@ -0,0 +1,34 @@ +/**************************************************************** + * 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.util; + +import java.io.InputStream; +import java.io.SequenceInputStream; +import java.util.Arrays; +import java.util.stream.Stream; + +public class InputStreamUtils { + public static InputStream concat(InputStream inputStream, InputStream... additionalInputStreams) { + Stream<InputStream> inputStreams = Stream.concat(Stream.of(inputStream), Arrays.stream(additionalInputStreams)); + + return inputStreams.reduce(SequenceInputStream::new) + .get(); + } +} diff --git a/server/container/util/src/test/java/org/apache/james/util/InputStreamUtilsTest.java b/server/container/util/src/test/java/org/apache/james/util/InputStreamUtilsTest.java new file mode 100644 index 0000000..7ed1f97 --- /dev/null +++ b/server/container/util/src/test/java/org/apache/james/util/InputStreamUtilsTest.java @@ -0,0 +1,53 @@ +/**************************************************************** + * 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.util; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.io.ByteArrayInputStream; +import java.nio.charset.StandardCharsets; + +import org.junit.jupiter.api.Test; + +import com.google.common.primitives.Bytes; + +class InputStreamUtilsTest { + private static final byte[] CONTENT_1 = "content1".getBytes(StandardCharsets.UTF_8); + private static final byte[] CONTENT_2 = "content2".getBytes(StandardCharsets.UTF_8); + private static final byte[] EMPTY = "".getBytes(StandardCharsets.UTF_8); + + @Test + void concatShouldNoopWhenSingleArgument() { + assertThat(InputStreamUtils.concat(new ByteArrayInputStream(CONTENT_1))) + .hasSameContentAs(new ByteArrayInputStream(CONTENT_1)); + } + + @Test + void concatShouldReturnConcatenatedStreams() { + assertThat(InputStreamUtils.concat(new ByteArrayInputStream(CONTENT_1), new ByteArrayInputStream(CONTENT_2))) + .hasSameContentAs(new ByteArrayInputStream(Bytes.concat(CONTENT_1, CONTENT_2))); + } + + @Test + void concatShouldNoopWhenEmpty() { + assertThat(InputStreamUtils.concat(new ByteArrayInputStream(CONTENT_1), new ByteArrayInputStream(EMPTY))) + .hasSameContentAs(new ByteArrayInputStream(CONTENT_1)); + } +} \ No newline at end of file diff --git a/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/methods/integration/cucumber/DownloadStepdefs.java b/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/methods/integration/cucumber/DownloadStepdefs.java index b1450a0..8abff9d 100644 --- a/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/methods/integration/cucumber/DownloadStepdefs.java +++ b/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/methods/integration/cucumber/DownloadStepdefs.java @@ -24,6 +24,7 @@ import static org.assertj.core.api.Assertions.assertThat; import java.io.ByteArrayInputStream; import java.io.IOException; +import java.io.InputStream; import java.net.URI; import java.net.URISyntaxException; import java.nio.charset.StandardCharsets; @@ -49,6 +50,7 @@ import org.apache.james.mailbox.model.MailboxConstants; import org.apache.james.mailbox.model.MailboxPath; import org.apache.james.mailbox.model.MessageId; import org.apache.james.mime4j.codec.DecoderUtil; +import org.apache.james.util.InputStreamUtils; import com.google.common.base.CharMatcher; import com.google.common.base.MoreObjects; @@ -126,6 +128,20 @@ public class DownloadStepdefs { retrieveAndSaveAttachmentDetails(user, messageId, attachmentId, composedMessageId); } + @Given("^\"([^\"]*)\" mailbox \"([^\"]*)\" contains a message \"([^\"]*)\" with an attachment \"([^\"]*)\" having \"([^\"]*)\" contentType$") + public void appendMessageWithAttachmentToMailbox(String user, String mailbox, String messageId, String attachmentId, String contentType) throws Throwable { + MailboxPath mailboxPath = MailboxPath.forUser(user, mailbox); + + InputStream message = InputStreamUtils.concat( + ClassLoader.getSystemResourceAsStream("eml/oneAttachment-part1.eml"), + new ByteArrayInputStream(contentType.getBytes(StandardCharsets.UTF_8)), + ClassLoader.getSystemResourceAsStream("eml/oneAttachment-part2.eml")); + + ComposedMessageId composedMessageId = mainStepdefs.mailboxProbe.appendMessage(user, mailboxPath, AppendCommand.from(message)); + + retrieveAndSaveAttachmentDetails(user, messageId, attachmentId, composedMessageId); + } + @Given("^\"([^\"]*)\" mailbox \"([^\"]*)\" contains a message \"([^\"]*)\" with an inlined attachment \"([^\"]*)\"$") public void appendMessageWithInlinedAttachmentToMailbox(String user, String mailbox, String messageId, String attachmentId) throws Throwable { MailboxPath mailboxPath = MailboxPath.forUser(user, mailbox); @@ -456,12 +472,6 @@ public class DownloadStepdefs { assertThat(response.getFirstHeader("Content-Length").getValue()).isEqualTo(String.valueOf(size)); } - @Then("^there is no Content-Type$") - public void assertNoContentType() { - assertThat(response.getFirstHeader("Content-Type")) - .isNull(); - } - @Then("^the Content-Type is \"([^\"]*)\"$") public void assertContentType(String contentType) { assertThat(response.getFirstHeader("Content-Type").getValue()).isEqualTo(contentType); diff --git a/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/resources/cucumber/DownloadGet.feature b/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/resources/cucumber/DownloadGet.feature index 4b7c889..2639d86 100644 --- a/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/resources/cucumber/DownloadGet.feature +++ b/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/resources/cucumber/DownloadGet.feature @@ -51,10 +51,10 @@ Feature: Download GET And the attachment is named "ديناصور.odt" Scenario: Getting an attachment with a specified Content-Type - Given "al...@domain.tld" mailbox "INBOX" contains a message "1" with an attachment "2" + Given "al...@domain.tld" mailbox "INBOX" contains a message "1" with an attachment "2" having "application/pdf" contentType When "al...@domain.tld" downloads "2" with "myFileName.txt" name Then she can read that blob - And there is no Content-Type + And the Content-Type is "application/pdf" @BasicFeature Scenario: Getting a message blob previously stored diff --git a/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/resources/eml/oneAttachment-part1.eml b/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/resources/eml/oneAttachment-part1.eml new file mode 100644 index 0000000..1c7df76 --- /dev/null +++ b/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/resources/eml/oneAttachment-part1.eml @@ -0,0 +1,30 @@ +Mail content: +To: "=?utf-8?B?UmFuaSBBc3NhZg==?=" <rani.as...@jri.obm.lng.org> +Subject: =?utf-8?B?VHIuIDogUGhvdG9zICE=?= +Importance: Normal +MIME-Version: 1.0 +Content-Type: multipart/mixed; + boundary="----=_Part_0_1330682067197" + +------=_Part_0_1330682067197 +Content-Type: multipart/alternative; + boundary="----=_Part_2_1330682067197" + +------=_Part_2_1330682067197 +Content-Type: text/plain; + charset= utf-8 +Content-Transfer-Encoding: 8bit +Content-Disposition: inline + +Content of part 1-1 +------=_Part_2_1330682067197 +Content-Type: text/html; + charset= utf-8 +Content-Transfer-Encoding: 8bit +Content-Disposition: inline + +<b>Content of part 1-2</b> +------=_Part_2_1330682067197-- + +------=_Part_0_1330682067197 +Content-Type: \ No newline at end of file diff --git a/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/resources/eml/oneAttachment-part2.eml b/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/resources/eml/oneAttachment-part2.eml new file mode 100644 index 0000000..2e81c80 --- /dev/null +++ b/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/resources/eml/oneAttachment-part2.eml @@ -0,0 +1,9 @@ + +Content-Transfer-Encoding: base64 +Content-Disposition: attachment; + filename="gimp.png" + +iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAALxklEQVR4Ae2Xe0xUZ97H5X4RiyAXEARURBSYCzNnLjMwwAx3huGOIBcUFJERAUVRq+KlwHABFdu+b9+0766x1W21ttnUtE3rul6aGNtm3XbdWncjaa3VXrZRK6IgfPd3Tp6wOGmyo0v/cOMknxwy5xzO7/P8LueZaWlpaU80TwWeCvy3CcRwXJlUqp39RApIOE4i5hQPxBz30hMpIJIrjktkseMimfzPUyoglilTf/XVl8u1Ik4xrOJEEMu4wSkVEMmVZ6VSTeivFXy0TDZfIlfc0qil0KpIQM59P6UCUk71lVShPD1t2jT7qQ4+Sq32prq/GhfHjSXFSxGvEfMCQ1MsoLzOadT3pArFwBQ3LSdRqK4mJyfcz0xRwaCLRVKcBDEybmxqBRTKH8uXpEOj0/1MD3wuMTHR8T9adY4LoOD3KuPj7xYVGlGYo0e6 [...] + +------=_Part_0_1330682067197-- + diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/DownloadServlet.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/DownloadServlet.java index 6e2b272..ca317fd 100644 --- a/server/protocols/jmap/src/main/java/org/apache/james/jmap/DownloadServlet.java +++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/DownloadServlet.java @@ -127,6 +127,7 @@ public class DownloadServlet extends HttpServlet { addContentDispositionHeader(downloadPath.getName(), resp); resp.setHeader("Content-Length", String.valueOf(blob.getSize())); + resp.setHeader("Content-Type", blob.getContentType()); resp.setStatus(SC_OK); IOUtils.copy(blob.getStream(), resp.getOutputStream()); } catch (BlobNotFoundException e) { --------------------------------------------------------------------- To unsubscribe, e-mail: server-dev-unsubscr...@james.apache.org For additional commands, e-mail: server-dev-h...@james.apache.org