JAMES-1814 Encode Content-Disposition header in download servlet when necessary


Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/abb21de1
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/abb21de1
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/abb21de1

Branch: refs/heads/master
Commit: abb21de13fefe2c99626d2178f99a7002fd2b4f8
Parents: 7443396
Author: Laura Royet <lro...@linagora.com>
Authored: Wed Sep 21 12:20:48 2016 +0200
Committer: Laura Royet <lro...@linagora.com>
Committed: Wed Sep 21 12:20:48 2016 +0200

----------------------------------------------------------------------
 .../integration/cucumber/DownloadStepdefs.java  | 26 +++++++++++++++++++-
 .../test/resources/cucumber/DownloadGet.feature |  6 +++++
 .../org/apache/james/jmap/DownloadServlet.java  | 14 +++++++++--
 3 files changed, 43 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/abb21de1/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/methods/integration/cucumber/DownloadStepdefs.java
----------------------------------------------------------------------
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 6ef8a03..d000bb3 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
@@ -41,7 +41,9 @@ import org.apache.james.jmap.api.access.AccessToken;
 import org.apache.james.jmap.model.AttachmentAccessToken;
 import org.apache.james.mailbox.model.MailboxConstants;
 import org.apache.james.mailbox.model.MailboxPath;
+import org.apache.james.mime4j.codec.DecoderUtil;
 
+import com.google.common.base.CharMatcher;
 import com.google.common.base.Charsets;
 import com.google.common.base.MoreObjects;
 import com.google.common.base.Objects;
@@ -63,6 +65,7 @@ public class DownloadStepdefs {
     private static final String INVALID_ATTACHMENT_TOKEN = "usera@domain.tld_"
             + "2015-06-29T13:41:22.124Z_"
             + 
"DiZa0O14MjLWrAA8P6MG35Gt5CBp7mt5U1EH/M++rIoZK7nlGJ4dPW0dvZD7h4m3o5b/Yd8DXU5x2x4+s0HOOKzD7X0RMlsU7JHJMNLvTvRGWF/C+MUyC8Zce7DtnRVPEQX2uAZhL2PBABV07Vpa8kH+NxoS9CL955Bc1Obr4G+KN2JorADlocFQA6ElXryF5YS/HPZSvq1MTC6aJIP0ku8WRpRnbwgwJnn26YpcHXcJjbkCBtd9/BhlMV6xNd2hTBkfZmYdoNo+UKBaXWzLxAlbLuxjpxwvDNJfOEyWFPgHDoRvzP+G7KzhVWjanHAHrhF0GilEa/MKpOI1qHBSwA==";
+    private static final String UTF8_CONTENT_DIPOSITION_START = 
"Content-Disposition: attachment; filename*=\"";
 
     private final UserStepdefs userStepdefs;
     private final MainStepdefs mainStepdefs;
@@ -330,6 +333,27 @@ public class DownloadStepdefs {
 
     @Then("^the attachment is named \"([^\"]*)\"$")
     public void assertContentDisposition(String name) throws IOException {
-        
assertThat(response.getHeaders("Content-Disposition")).extracting(Header::toString).containsExactly("Content-Disposition:
 attachment; filename=\"" + name + "\"");
+        if (!CharMatcher.ASCII.matchesAllOf(name)) {
+            assertEncodedFilenameMatches(name);
+        } else {
+            
assertThat(response.getFirstHeader("Content-Disposition").getValue()).isEqualTo("attachment;
 filename=\"" + name + "\"");
+        }
+    }
+
+    private void assertEncodedFilenameMatches(String name) {
+        String contentDispositionHeader = 
response.getHeaders("Content-Disposition")[0].toString();
+        
assertThat(contentDispositionHeader).startsWith(UTF8_CONTENT_DIPOSITION_START);
+
+        String expectedFilename = 
decode(extractFilename(contentDispositionHeader));
+        assertThat(name).isEqualTo(expectedFilename);
+    }
+
+    private String extractFilename(String contentDispositionHeader) {
+        return 
contentDispositionHeader.substring(UTF8_CONTENT_DIPOSITION_START.length(), 
+                contentDispositionHeader.length() - 1);
+    }
+
+    private String decode(String name) {
+        return DecoderUtil.decodeEncodedWords(name, Charsets.UTF_8);
     }
 }

http://git-wip-us.apache.org/repos/asf/james-project/blob/abb21de1/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/resources/cucumber/DownloadGet.feature
----------------------------------------------------------------------
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 6772e4f..82828d1 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
@@ -22,3 +22,9 @@ Feature: Download GET
     When "usern...@domain.tld" downloads "2" with "myFileName.txt" name
     Then the user should receive that attachment
     And the attachment is named "myFileName.txt"
+
+  Scenario: Getting an attachment previously stored with a non ASCII name
+    Given "usern...@domain.tld" mailbox "inbox" contains a message "1" with an 
attachment "2"
+    When "usern...@domain.tld" downloads "2" with "ديناصور.odt" name
+    Then the user should receive that attachment
+    And the attachment is named "ديناصور.odt"
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/james-project/blob/abb21de1/server/protocols/jmap/src/main/java/org/apache/james/jmap/DownloadServlet.java
----------------------------------------------------------------------
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 0d140e6..45f5dcc 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
@@ -41,10 +41,13 @@ import 
org.apache.james.mailbox.exception.AttachmentNotFoundException;
 import org.apache.james.mailbox.exception.MailboxException;
 import org.apache.james.mailbox.model.Attachment;
 import org.apache.james.mailbox.model.AttachmentId;
+import org.apache.james.mime4j.codec.EncoderUtil;
+import org.apache.james.mime4j.codec.EncoderUtil.Usage;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.CharMatcher;
 
 public class DownloadServlet extends HttpServlet {
 
@@ -126,10 +129,17 @@ public class DownloadServlet extends HttpServlet {
     }
 
     private void addContentDispositionHeader(Optional<String> optionalName, 
HttpServletResponse resp) {
-        optionalName.ifPresent(name -> resp.addHeader("Content-Disposition", 
"attachment; filename=\"" + name + "\""));
+        optionalName.ifPresent(name -> 
addContentDispositionHeaderRegardingEncoding(name, resp));
+    }
+
+    private void addContentDispositionHeaderRegardingEncoding(String name, 
HttpServletResponse resp) {
+        if (CharMatcher.ASCII.matchesAllOf(name)) {
+            resp.addHeader("Content-Disposition", "attachment; filename=\"" + 
name + "\"");
+        } else {
+            resp.addHeader("Content-Disposition", "attachment; filename*=\"" + 
EncoderUtil.encodeEncodedWord(name, Usage.TEXT_TOKEN) + "\"");
+        }
     }
 
-    
     private MailboxSession getMailboxSession(HttpServletRequest req) {
         return (MailboxSession) 
req.getAttribute(AuthenticationFilter.MAILBOX_SESSION);
     }


---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscr...@james.apache.org
For additional commands, e-mail: server-dev-h...@james.apache.org

Reply via email to