You are viewing a plain text version of this content. The canonical link for it is here.
Posted to oak-commits@jackrabbit.apache.org by ma...@apache.org on 2020/12/18 22:26:00 UTC

svn commit: r1884613 - in /jackrabbit/oak/trunk: oak-blob-cloud/src/main/java/org/apache/jackrabbit/oak/blob/cloud/s3/ oak-blob-plugins/src/main/java/org/apache/jackrabbit/oak/plugins/blob/datastore/directaccess/ oak-blob-plugins/src/test/java/org/apac...

Author: mattryan
Date: Fri Dec 18 22:26:00 2020
New Revision: 1884613

URL: http://svn.apache.org/viewvc?rev=1884613&view=rev
Log:
OAK-9304 Use ISO-8859-1 encoding in filename portion of DBA download URI specification

Modified:
    jackrabbit/oak/trunk/oak-blob-cloud/src/main/java/org/apache/jackrabbit/oak/blob/cloud/s3/S3Backend.java
    jackrabbit/oak/trunk/oak-blob-cloud/src/main/java/org/apache/jackrabbit/oak/blob/cloud/s3/Utils.java
    jackrabbit/oak/trunk/oak-blob-plugins/src/main/java/org/apache/jackrabbit/oak/plugins/blob/datastore/directaccess/DataRecordDownloadOptions.java
    jackrabbit/oak/trunk/oak-blob-plugins/src/test/java/org/apache/jackrabbit/oak/plugins/blob/datastore/directaccess/AbstractDataRecordAccessProviderTest.java
    jackrabbit/oak/trunk/oak-blob-plugins/src/test/java/org/apache/jackrabbit/oak/plugins/blob/datastore/directaccess/DataRecordDownloadOptionsTest.java

Modified: jackrabbit/oak/trunk/oak-blob-cloud/src/main/java/org/apache/jackrabbit/oak/blob/cloud/s3/S3Backend.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-blob-cloud/src/main/java/org/apache/jackrabbit/oak/blob/cloud/s3/S3Backend.java?rev=1884613&r1=1884612&r2=1884613&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-blob-cloud/src/main/java/org/apache/jackrabbit/oak/blob/cloud/s3/S3Backend.java (original)
+++ jackrabbit/oak/trunk/oak-blob-cloud/src/main/java/org/apache/jackrabbit/oak/blob/cloud/s3/S3Backend.java Fri Dec 18 22:26:00 2020
@@ -17,10 +17,6 @@
 
 package org.apache.jackrabbit.oak.blob.cloud.s3;
 
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.collect.Iterables.filter;
-import static java.lang.Thread.currentThread;
-
 import java.io.ByteArrayInputStream;
 import java.io.File;
 import java.io.IOException;
@@ -43,6 +39,22 @@ import java.util.concurrent.ExecutorServ
 import java.util.concurrent.Executors;
 import java.util.concurrent.TimeUnit;
 
+import org.apache.commons.io.IOUtils;
+import org.apache.jackrabbit.core.data.DataIdentifier;
+import org.apache.jackrabbit.core.data.DataRecord;
+import org.apache.jackrabbit.core.data.DataStoreException;
+import org.apache.jackrabbit.core.data.util.NamedThreadFactory;
+import org.apache.jackrabbit.oak.commons.PropertiesUtil;
+import org.apache.jackrabbit.oak.plugins.blob.datastore.directaccess.DataRecordDownloadOptions;
+import org.apache.jackrabbit.oak.plugins.blob.datastore.directaccess.DataRecordUpload;
+import org.apache.jackrabbit.oak.plugins.blob.datastore.directaccess.DataRecordUploadException;
+import org.apache.jackrabbit.oak.plugins.blob.datastore.directaccess.DataRecordUploadToken;
+import org.apache.jackrabbit.oak.spi.blob.AbstractDataRecord;
+import org.apache.jackrabbit.oak.spi.blob.AbstractSharedBackend;
+import org.jetbrains.annotations.NotNull;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
 import com.amazonaws.AmazonClientException;
 import com.amazonaws.AmazonServiceException;
 import com.amazonaws.HttpMethod;
@@ -83,22 +95,10 @@ import com.google.common.cache.CacheBuil
 import com.google.common.collect.AbstractIterator;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
-import org.apache.commons.io.IOUtils;
-import org.apache.http.protocol.HTTP;
-import org.apache.jackrabbit.core.data.DataIdentifier;
-import org.apache.jackrabbit.core.data.DataRecord;
-import org.apache.jackrabbit.core.data.DataStoreException;
-import org.apache.jackrabbit.core.data.util.NamedThreadFactory;
-import org.apache.jackrabbit.oak.commons.PropertiesUtil;
-import org.apache.jackrabbit.oak.plugins.blob.datastore.directaccess.DataRecordDownloadOptions;
-import org.apache.jackrabbit.oak.plugins.blob.datastore.directaccess.DataRecordUpload;
-import org.apache.jackrabbit.oak.plugins.blob.datastore.directaccess.DataRecordUploadException;
-import org.apache.jackrabbit.oak.plugins.blob.datastore.directaccess.DataRecordUploadToken;
-import org.apache.jackrabbit.oak.spi.blob.AbstractDataRecord;
-import org.apache.jackrabbit.oak.spi.blob.AbstractSharedBackend;
-import org.jetbrains.annotations.NotNull;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.collect.Iterables.filter;
+import static java.lang.Thread.currentThread;
 
 /**
  * A data store backend that stores data on Amazon S3.
@@ -188,7 +188,7 @@ public class S3Backend extends AbstractS
                                     + "] not configured and cannot be derived from environment");
                 }
             } else if (Utils.DEFAULT_AWS_BUCKET_REGION.equals(region)) {
-                    region = Region.US_Standard.toString();
+                region = Region.US_Standard.toString();
             }
 
             createBucketIfNeeded(region);
@@ -262,7 +262,15 @@ public class S3Backend extends AbstractS
     private void createBucketIfNeeded(final String region) {
         try {
             if (!s3service.doesBucketExist(bucket)) {
-                CreateBucketRequest req = new CreateBucketRequest(bucket, region);
+                String bucketRegion = region;
+                if (Utils.US_EAST_1_AWS_BUCKET_REGION.equals(region)) {
+                    // The SDK has changed such that if the region is us-east-1
+                    // the region value should not be provided in the
+                    // request to create the bucket.
+                    // See https://stackoverflow.com/questions/51912072/invalidlocationconstraint-error-while-creating-s3-bucket-when-the-used-command-i
+                    bucketRegion = null;
+                }
+                CreateBucketRequest req = new CreateBucketRequest(bucket, bucketRegion);
                 s3service.createBucket(req);
                 if (Utils.waitForBucket(s3service, bucket)) {
                     LOG.error("Bucket [{}] does not exist in [{}] and was not automatically created",

Modified: jackrabbit/oak/trunk/oak-blob-cloud/src/main/java/org/apache/jackrabbit/oak/blob/cloud/s3/Utils.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-blob-cloud/src/main/java/org/apache/jackrabbit/oak/blob/cloud/s3/Utils.java?rev=1884613&r1=1884612&r2=1884613&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-blob-cloud/src/main/java/org/apache/jackrabbit/oak/blob/cloud/s3/Utils.java (original)
+++ jackrabbit/oak/trunk/oak-blob-cloud/src/main/java/org/apache/jackrabbit/oak/blob/cloud/s3/Utils.java Fri Dec 18 22:26:00 2020
@@ -24,6 +24,10 @@ import java.io.InputStream;
 import java.util.Map;
 import java.util.Properties;
 
+import org.jetbrains.annotations.NotNull;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
 import com.amazonaws.AmazonClientException;
 import com.amazonaws.ClientConfiguration;
 import com.amazonaws.Protocol;
@@ -36,9 +40,6 @@ import com.amazonaws.services.s3.model.O
 import com.amazonaws.services.s3.model.S3ObjectSummary;
 import com.amazonaws.util.StringUtils;
 import com.google.common.collect.Maps;
-import org.jetbrains.annotations.NotNull;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 /**
  * Amazon S3 utilities.
@@ -57,6 +58,11 @@ public final class Utils {
     public static final String DEFAULT_AWS_BUCKET_REGION = "us-standard";
 
     /**
+     * The value for the us-east-1 region.
+     */
+    public static final String US_EAST_1_AWS_BUCKET_REGION = "us-east-1";
+
+    /**
      * constants to define endpoint to various AWS region
      */
     public static final String AWSDOTCOM = "amazonaws.com";

Modified: jackrabbit/oak/trunk/oak-blob-plugins/src/main/java/org/apache/jackrabbit/oak/plugins/blob/datastore/directaccess/DataRecordDownloadOptions.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-blob-plugins/src/main/java/org/apache/jackrabbit/oak/plugins/blob/datastore/directaccess/DataRecordDownloadOptions.java?rev=1884613&r1=1884612&r2=1884613&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-blob-plugins/src/main/java/org/apache/jackrabbit/oak/plugins/blob/datastore/directaccess/DataRecordDownloadOptions.java (original)
+++ jackrabbit/oak/trunk/oak-blob-plugins/src/main/java/org/apache/jackrabbit/oak/plugins/blob/datastore/directaccess/DataRecordDownloadOptions.java Fri Dec 18 22:26:00 2020
@@ -22,13 +22,15 @@ package org.apache.jackrabbit.oak.plugin
 import java.nio.charset.StandardCharsets;
 import java.util.Set;
 
-import com.google.common.base.Joiner;
-import com.google.common.base.Strings;
-import com.google.common.collect.Sets;
 import org.apache.jackrabbit.oak.api.blob.BlobDownloadOptions;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
+import com.google.common.base.Charsets;
+import com.google.common.base.Joiner;
+import com.google.common.base.Strings;
+import com.google.common.collect.Sets;
+
 /**
  * Contains download options for downloading a data record directly from a
  * storage location using the direct download feature.
@@ -155,9 +157,12 @@ public class DataRecordDownloadOptions {
     private String formatContentDispositionHeader(@NotNull final String dispositionType,
                                                   @NotNull final String fileName,
                                                   @Nullable final String rfc8187EncodedFileName) {
+        String iso_8859_1_fileName = new String(Charsets.ISO_8859_1.encode(fileName).array()).replace("\"", "\\\"");
         return null != rfc8187EncodedFileName ?
-                String.format("%s; filename=\"%s\"; filename*=UTF-8''%s", dispositionType, fileName, rfc8187EncodedFileName) :
-                String.format("%s; filename=\"%s\"", dispositionType, fileName);
+                String.format("%s; filename=\"%s\"; filename*=UTF-8''%s",
+                        dispositionType, iso_8859_1_fileName, rfc8187EncodedFileName) :
+                String.format("%s; filename=\"%s\"",
+                        dispositionType, iso_8859_1_fileName);
     }
 
     private String rfc8187Encode(@NotNull final String input) {

Modified: jackrabbit/oak/trunk/oak-blob-plugins/src/test/java/org/apache/jackrabbit/oak/plugins/blob/datastore/directaccess/AbstractDataRecordAccessProviderTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-blob-plugins/src/test/java/org/apache/jackrabbit/oak/plugins/blob/datastore/directaccess/AbstractDataRecordAccessProviderTest.java?rev=1884613&r1=1884612&r2=1884613&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-blob-plugins/src/test/java/org/apache/jackrabbit/oak/plugins/blob/datastore/directaccess/AbstractDataRecordAccessProviderTest.java (original)
+++ jackrabbit/oak/trunk/oak-blob-plugins/src/test/java/org/apache/jackrabbit/oak/plugins/blob/datastore/directaccess/AbstractDataRecordAccessProviderTest.java Fri Dec 18 22:26:00 2020
@@ -18,15 +18,6 @@
  */
 package org.apache.jackrabbit.oak.plugins.blob.datastore.directaccess;
 
-import static com.google.common.io.ByteStreams.toByteArray;
-import static org.apache.jackrabbit.oak.plugins.blob.datastore.DataStoreUtils.randomStream;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.StringWriter;
@@ -35,14 +26,12 @@ import java.net.URI;
 import java.net.URLDecoder;
 import java.nio.charset.Charset;
 import java.util.Arrays;
+import java.util.List;
 import java.util.Map;
 import java.util.Properties;
 
 import javax.net.ssl.HttpsURLConnection;
 
-import com.google.common.base.Strings;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
 import org.apache.commons.io.IOUtils;
 import org.apache.jackrabbit.core.data.DataIdentifier;
 import org.apache.jackrabbit.core.data.DataRecord;
@@ -55,6 +44,19 @@ import org.junit.Test;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.google.common.base.Strings;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+
+import static com.google.common.io.ByteStreams.toByteArray;
+import static org.apache.jackrabbit.oak.plugins.blob.datastore.DataStoreUtils.randomStream;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
 public abstract class AbstractDataRecordAccessProviderTest {
     protected static final Logger LOG = LoggerFactory.getLogger(AbstractDataRecordAccessProviderTest.class);
 
@@ -174,42 +176,67 @@ public abstract class AbstractDataRecord
 
     @Test
     public void testGetDownloadURIWithCustomHeadersIT() throws DataStoreException, IOException {
+        List<String> fileNames = Lists.newArrayList(
+                "image.png",
+                "beautiful landscape.png",
+                "\"filename-with-double-quotes\".png",
+                "filename-with-one\"double-quote.jpg",
+                "Umläutfile.png"
+                );
+        List<String> iso_8859_1_fileNames = Lists.newArrayList(
+                "image.png",
+                "beautiful landscape.png",
+                "\\\"filename-with-double-quotes\\\".png",
+                "filename-with-one\\\"double-quote.jpg",
+                "Umla?utfile.png"
+        );
+        List<String> rfc8187_fileNames = Lists.newArrayList(
+                "image.png",
+                "beautiful%20landscape.png",
+                "%22filename-with-double-quotes%22.png",
+                "filename-with-one%22double-quote.jpg",
+                "Umla%CC%88utfile.png"
+        );
+
         DataRecord record = null;
         DataRecordAccessProvider dataStore = getDataStore();
         try {
             InputStream testStream = randomStream(0, 256);
             record = doSynchronousAddRecord((DataStore) dataStore, testStream);
             String mimeType = "image/png";
-            String fileName = "album cover.png";
-            String encodedFileName = "album%20cover.png";
             String dispositionType = "inline";
-            DataRecordDownloadOptions downloadOptions =
-                    DataRecordDownloadOptions.fromBlobDownloadOptions(
-                            new BlobDownloadOptions(
-                                    mimeType,
-                                    null,
-                                    fileName,
-                                    dispositionType
-                            )
-                    );
-            URI uri = dataStore.getDownloadURI(record.getIdentifier(),
-                    downloadOptions);
+            for (int i=0; i<fileNames.size(); i++) {
+                String fileName = fileNames.get(i);
+                String iso_8859_1_fileName = iso_8859_1_fileNames.get(i);
+                String encodedFileName = rfc8187_fileNames.get(i);
+                DataRecordDownloadOptions downloadOptions =
+                        DataRecordDownloadOptions.fromBlobDownloadOptions(
+                                new BlobDownloadOptions(
+                                        mimeType,
+                                        null,
+                                        fileName,
+                                        dispositionType
+                                )
+                        );
+                URI uri = dataStore.getDownloadURI(record.getIdentifier(),
+                        downloadOptions
+                );
+
+                HttpsURLConnection conn = (HttpsURLConnection) uri.toURL().openConnection();
+                conn.setRequestMethod("GET");
+                assertEquals(200, conn.getResponseCode());
+
+                assertEquals(mimeType, conn.getHeaderField("Content-Type"));
+                assertEquals(
+                        String.format("%s; filename=\"%s\"; filename*=UTF-8''%s",
+                                dispositionType, iso_8859_1_fileName, encodedFileName
+                        ),
+                        conn.getHeaderField("Content-Disposition")
+                );
 
-            HttpsURLConnection conn = (HttpsURLConnection) uri.toURL().openConnection();
-            conn.setRequestMethod("GET");
-            assertEquals(200, conn.getResponseCode());
-
-            assertEquals(mimeType, conn.getHeaderField("Content-Type"));
-            assertEquals(
-                    String.format("%s; filename=\"%s\"; filename*=UTF-8''%s",
-                            dispositionType, fileName,
-                            encodedFileName
-                    ),
-                    conn.getHeaderField("Content-Disposition")
-            );
-
-            testStream.reset();
-            assertTrue(Arrays.equals(toByteArray(testStream), toByteArray(conn.getInputStream())));
+                testStream.reset();
+                assertTrue(Arrays.equals(toByteArray(testStream), toByteArray(conn.getInputStream())));
+            }
         }
         finally {
             if (null != record) {

Modified: jackrabbit/oak/trunk/oak-blob-plugins/src/test/java/org/apache/jackrabbit/oak/plugins/blob/datastore/directaccess/DataRecordDownloadOptionsTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-blob-plugins/src/test/java/org/apache/jackrabbit/oak/plugins/blob/datastore/directaccess/DataRecordDownloadOptionsTest.java?rev=1884613&r1=1884612&r2=1884613&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-blob-plugins/src/test/java/org/apache/jackrabbit/oak/plugins/blob/datastore/directaccess/DataRecordDownloadOptionsTest.java (original)
+++ jackrabbit/oak/trunk/oak-blob-plugins/src/test/java/org/apache/jackrabbit/oak/plugins/blob/datastore/directaccess/DataRecordDownloadOptionsTest.java Fri Dec 18 22:26:00 2020
@@ -19,16 +19,19 @@
 
 package org.apache.jackrabbit.oak.plugins.blob.datastore.directaccess;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.fail;
+import java.util.List;
+
+import org.apache.jackrabbit.oak.api.blob.BlobDownloadOptions;
+import org.junit.Test;
 
 import com.google.common.base.Joiner;
 import com.google.common.base.Strings;
 import com.google.common.collect.Lists;
-import org.apache.jackrabbit.oak.api.blob.BlobDownloadOptions;
-import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.fail;
 
 public class DataRecordDownloadOptionsTest {
     private static final String MEDIA_TYPE_IMAGE_PNG = "image/png";
@@ -255,4 +258,44 @@ public class DataRecordDownloadOptionsTe
                 null
         );
     }
+
+    @Test
+    public void testGetContentDispositionWithSpecialCharacterFilenames() {
+        List<String> filenames = Lists.newArrayList(
+                "image.png",
+                "text.txt",
+                "filename with spaces.jpg",
+                "\"filename-with-double-quotes\".jpg",
+                "filename-with-one\"double-quote.jpg",
+                "Umläutfile.jpg"
+        );
+        List<String> iso_8859_1_filenames = Lists.newArrayList(
+                "image.png",
+                "text.txt",
+                "filename with spaces.jpg",
+                "\\\"filename-with-double-quotes\\\".jpg",
+                "filename-with-one\\\"double-quote.jpg",
+                "Umla?utfile.jpg"
+        );
+        List<String> rfc8187_filenames = Lists.newArrayList(
+                "image.png",
+                "text.txt",
+                "filename%20with%20spaces.jpg",
+                "%22filename-with-double-quotes%22.jpg",
+                "filename-with-one%22double-quote.jpg",
+                "Umla%CC%88utfile.jpg"
+        );
+
+        for (String dispositionType : Lists.newArrayList(DISPOSITION_TYPE_INLINE, DISPOSITION_TYPE_ATTACHMENT)) {
+            for (int i=0; i<filenames.size(); i++) {
+                String fileName = filenames.get(i);
+                String iso_8859_1_fileName = iso_8859_1_filenames.get(i);
+                String rfc8187_fileName = rfc8187_filenames.get(i);
+                verifyContentDispositionHeader(
+                        getOptions(null, null, fileName, dispositionType),
+                        getContentDispositionHeader(iso_8859_1_fileName, rfc8187_fileName, dispositionType)
+                );
+            }
+        }
+    }
 }