From effb7dc8ba00c683e3b6717eaf1f358ce1c69b87 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Thu, 15 Apr 2021 17:14:57 +0200 Subject: [PATCH] set mimetype for objects uploaded to object storages Signed-off-by: Robin Appelman --- apps/files_external/lib/Lib/Storage/AmazonS3.php | 9 +++++++-- apps/files_external/lib/Lib/Storage/Swift.php | 9 +++++++-- lib/private/Files/ObjectStore/Azure.php | 14 +++++++------- .../Files/ObjectStore/ObjectStoreStorage.php | 4 ++-- lib/private/Files/ObjectStore/S3ObjectTrait.php | 6 +++++- .../Files/ObjectStore/StorageObjectStore.php | 8 +------- lib/private/Files/ObjectStore/Swift.php | 9 +++------ lib/public/Files/ObjectStore/IObjectStore.php | 3 ++- .../Files/ObjectStore/FailDeleteObjectStore.php | 4 ++-- .../lib/Files/ObjectStore/FailWriteObjectStore.php | 2 +- tests/lib/Files/ObjectStore/S3Test.php | 2 +- 11 files changed, 38 insertions(+), 32 deletions(-) diff --git a/apps/files_external/lib/Lib/Storage/AmazonS3.php b/apps/files_external/lib/Lib/Storage/AmazonS3.php index 9ea278d722..50bea958b6 100644 --- a/apps/files_external/lib/Lib/Storage/AmazonS3.php +++ b/apps/files_external/lib/Lib/Storage/AmazonS3.php @@ -50,6 +50,7 @@ use OC\Files\Cache\CacheEntry; use OC\Files\ObjectStore\S3ConnectionTrait; use OC\Files\ObjectStore\S3ObjectTrait; use OCP\Constants; +use OCP\Files\IMimeTypeDetector; class AmazonS3 extends \OC\Files\Storage\Common { use S3ConnectionTrait; @@ -68,12 +69,16 @@ class AmazonS3 extends \OC\Files\Storage\Common { /** @var CappedMemoryCache|array */ private $filesCache; + /** @var IMimeTypeDetector */ + private $mimeDetector; + public function __construct($parameters) { parent::__construct($parameters); $this->parseParams($parameters); $this->objectCache = new CappedMemoryCache(); $this->directoryCache = new CappedMemoryCache(); $this->filesCache = new CappedMemoryCache(); + $this->mimeDetector = \OC::$server->get(IMimeTypeDetector::class); } /** @@ -573,7 +578,7 @@ class AmazonS3 extends \OC\Files\Storage\Common { try { if (!$this->file_exists($path)) { - $mimeType = \OC::$server->getMimeTypeDetector()->detectPath($path); + $mimeType = $this->mimeDetector->detectPath($path); $this->getConnection()->putObject([ 'Bucket' => $this->bucket, 'Key' => $this->cleanKey($path), @@ -684,7 +689,7 @@ class AmazonS3 extends \OC\Files\Storage\Common { public function writeBack($tmpFile, $path) { try { $source = fopen($tmpFile, 'r'); - $this->writeObject($path, $source); + $this->writeObject($path, $source, $this->mimeDetector->detectPath($path)); $this->invalidateCache($path); unlink($tmpFile); diff --git a/apps/files_external/lib/Lib/Storage/Swift.php b/apps/files_external/lib/Lib/Storage/Swift.php index f338111746..5082816b2c 100644 --- a/apps/files_external/lib/Lib/Storage/Swift.php +++ b/apps/files_external/lib/Lib/Storage/Swift.php @@ -47,6 +47,7 @@ use GuzzleHttp\Psr7\Uri; use Icewind\Streams\CallbackWrapper; use Icewind\Streams\IteratorDirectory; use OC\Files\ObjectStore\SwiftFactory; +use OCP\Files\IMimeTypeDetector; use OCP\Files\StorageBadConfigException; use OCP\ILogger; use OpenStack\Common\Error\BadResponseError; @@ -76,6 +77,9 @@ class Swift extends \OC\Files\Storage\Common { /** @var \OC\Files\ObjectStore\Swift */ private $objectStore; + /** @var IMimeTypeDetector */ + private $mimeDetector; + /** * Key value cache mapping path to data object. Maps path to * \OpenCloud\OpenStack\ObjectStorage\Resource\DataObject for existing @@ -205,6 +209,7 @@ class Swift extends \OC\Files\Storage\Common { ); $this->objectStore = new \OC\Files\ObjectStore\Swift($this->params, $this->connectionFactory); $this->bucket = $params['bucket']; + $this->mimeDetector = \OC::$server->get(IMimeTypeDetector::class); } public function mkdir($path) { @@ -466,7 +471,7 @@ class Swift extends \OC\Files\Storage\Common { } return true; } else { - $mimeType = \OC::$server->getMimeTypeDetector()->detectPath($path); + $mimeType = $this->mimeDetector->detectPath($path); $this->getContainer()->createObject([ 'name' => $path, 'content' => '', @@ -588,7 +593,7 @@ class Swift extends \OC\Files\Storage\Common { public function writeBack($tmpFile, $path) { $fileData = fopen($tmpFile, 'r'); - $this->objectStore->writeObject($path, $fileData); + $this->objectStore->writeObject($path, $fileData, $this->mimeDetector->detectPath($path)); // invalidate target object to force repopulation on fetch $this->objectCache->remove($path); unlink($tmpFile); diff --git a/lib/private/Files/ObjectStore/Azure.php b/lib/private/Files/ObjectStore/Azure.php index 2ef13d60c5..9faaf385bd 100644 --- a/lib/private/Files/ObjectStore/Azure.php +++ b/lib/private/Files/ObjectStore/Azure.php @@ -24,6 +24,7 @@ namespace OC\Files\ObjectStore; use MicrosoftAzure\Storage\Blob\BlobRestProxy; +use MicrosoftAzure\Storage\Blob\Models\CreateBlockBlobOptions; use MicrosoftAzure\Storage\Common\Exceptions\ServiceException; use OCP\Files\ObjectStore\IObjectStore; @@ -100,13 +101,12 @@ class Azure implements IObjectStore { return $blob->getContentStream(); } - /** - * @param string $urn the unified resource name used to identify the object - * @param resource $stream stream with the data to write - * @throws \Exception when something goes wrong, message will be logged - */ - public function writeObject($urn, $stream) { - $this->getBlobClient()->createBlockBlob($this->containerName, $urn, $stream); + public function writeObject($urn, $stream, string $mimetype = null) { + $options = new CreateBlockBlobOptions(); + if ($mimetype) { + $options->setContentType($mimetype); + } + $this->getBlobClient()->createBlockBlob($this->containerName, $urn, $stream, $options); } /** diff --git a/lib/private/Files/ObjectStore/ObjectStoreStorage.php b/lib/private/Files/ObjectStore/ObjectStoreStorage.php index 5d2cbe61ab..598dd4f80a 100644 --- a/lib/private/Files/ObjectStore/ObjectStoreStorage.php +++ b/lib/private/Files/ObjectStore/ObjectStoreStorage.php @@ -486,13 +486,13 @@ class ObjectStoreStorage extends \OC\Files\Storage\Common { ]); $size = $writtenSize; }); - $this->objectStore->writeObject($urn, $countStream); + $this->objectStore->writeObject($urn, $countStream, $mimetype); if (is_resource($countStream)) { fclose($countStream); } $stat['size'] = $size; } else { - $this->objectStore->writeObject($urn, $stream); + $this->objectStore->writeObject($urn, $stream, $mimetype); } } catch (\Exception $ex) { if (!$exists) { diff --git a/lib/private/Files/ObjectStore/S3ObjectTrait.php b/lib/private/Files/ObjectStore/S3ObjectTrait.php index 4d6ac3608d..250f8fd1ed 100644 --- a/lib/private/Files/ObjectStore/S3ObjectTrait.php +++ b/lib/private/Files/ObjectStore/S3ObjectTrait.php @@ -78,10 +78,11 @@ trait S3ObjectTrait { /** * @param string $urn the unified resource name used to identify the object * @param resource $stream stream with the data to write + * @param string|null $mimetype the mimetype to set for the remove object @since 22.0.0 * @throws \Exception when something goes wrong, message will be logged * @since 7.0.0 */ - public function writeObject($urn, $stream) { + public function writeObject($urn, $stream, string $mimetype = null) { $count = 0; $countStream = CallbackWrapper::wrap($stream, function ($read) use (&$count) { $count += $read; @@ -91,6 +92,9 @@ trait S3ObjectTrait { 'bucket' => $this->bucket, 'key' => $urn, 'part_size' => $this->uploadPartSize, + 'params' => [ + 'ContentType' => $mimetype + ] ]); try { diff --git a/lib/private/Files/ObjectStore/StorageObjectStore.php b/lib/private/Files/ObjectStore/StorageObjectStore.php index 2076bb3f88..a3fbc3cec7 100644 --- a/lib/private/Files/ObjectStore/StorageObjectStore.php +++ b/lib/private/Files/ObjectStore/StorageObjectStore.php @@ -65,13 +65,7 @@ class StorageObjectStore implements IObjectStore { throw new \Exception(); } - /** - * @param string $urn the unified resource name used to identify the object - * @param resource $stream stream with the data to write - * @throws \Exception when something goes wrong, message will be logged - * @since 7.0.0 - */ - public function writeObject($urn, $stream) { + public function writeObject($urn, $stream, string $mimetype = null) { $handle = $this->storage->fopen($urn, 'w'); if ($handle) { stream_copy_to_stream($stream, $handle); diff --git a/lib/private/Files/ObjectStore/Swift.php b/lib/private/Files/ObjectStore/Swift.php index 1b0888b070..f9cccd0e20 100644 --- a/lib/private/Files/ObjectStore/Swift.php +++ b/lib/private/Files/ObjectStore/Swift.php @@ -74,12 +74,7 @@ class Swift implements IObjectStore { return $this->params['container']; } - /** - * @param string $urn the unified resource name used to identify the object - * @param resource $stream stream with the data to write - * @throws \Exception from openstack lib when something goes wrong - */ - public function writeObject($urn, $stream) { + public function writeObject($urn, $stream, string $mimetype = null) { $tmpFile = \OC::$server->getTempManager()->getTemporaryFile('swiftwrite'); file_put_contents($tmpFile, $stream); $handle = fopen($tmpFile, 'rb'); @@ -88,12 +83,14 @@ class Swift implements IObjectStore { $this->getContainer()->createObject([ 'name' => $urn, 'stream' => stream_for($handle), + 'contentType' => $mimetype, ]); } else { $this->getContainer()->createLargeObject([ 'name' => $urn, 'stream' => stream_for($handle), 'segmentSize' => SWIFT_SEGMENT_SIZE, + 'contentType' => $mimetype, ]); } } diff --git a/lib/public/Files/ObjectStore/IObjectStore.php b/lib/public/Files/ObjectStore/IObjectStore.php index e9d948682f..ea97cd7d38 100644 --- a/lib/public/Files/ObjectStore/IObjectStore.php +++ b/lib/public/Files/ObjectStore/IObjectStore.php @@ -52,10 +52,11 @@ interface IObjectStore { /** * @param string $urn the unified resource name used to identify the object * @param resource $stream stream with the data to write + * @param string|null $mimetype the mimetype to set for the remove object @since 22.0.0 * @throws \Exception when something goes wrong, message will be logged * @since 7.0.0 */ - public function writeObject($urn, $stream); + public function writeObject($urn, $stream, string $mimetype = null); /** * @param string $urn the unified resource name used to identify the object diff --git a/tests/lib/Files/ObjectStore/FailDeleteObjectStore.php b/tests/lib/Files/ObjectStore/FailDeleteObjectStore.php index c755657faf..5160abe574 100644 --- a/tests/lib/Files/ObjectStore/FailDeleteObjectStore.php +++ b/tests/lib/Files/ObjectStore/FailDeleteObjectStore.php @@ -40,8 +40,8 @@ class FailDeleteObjectStore implements IObjectStore { return $this->objectStore->readObject($urn); } - public function writeObject($urn, $stream) { - return $this->objectStore->writeObject($urn, $stream); + public function writeObject($urn, $stream, string $mimetype = null) { + return $this->objectStore->writeObject($urn, $stream, $mimetype); } public function deleteObject($urn) { diff --git a/tests/lib/Files/ObjectStore/FailWriteObjectStore.php b/tests/lib/Files/ObjectStore/FailWriteObjectStore.php index b9c8751fda..559d004cd0 100644 --- a/tests/lib/Files/ObjectStore/FailWriteObjectStore.php +++ b/tests/lib/Files/ObjectStore/FailWriteObjectStore.php @@ -40,7 +40,7 @@ class FailWriteObjectStore implements IObjectStore { return $this->objectStore->readObject($urn); } - public function writeObject($urn, $stream) { + public function writeObject($urn, $stream, string $mimetype = null) { // emulate a failed write that didn't throw an error return true; } diff --git a/tests/lib/Files/ObjectStore/S3Test.php b/tests/lib/Files/ObjectStore/S3Test.php index c1e7948e3c..9781421238 100644 --- a/tests/lib/Files/ObjectStore/S3Test.php +++ b/tests/lib/Files/ObjectStore/S3Test.php @@ -25,7 +25,7 @@ use Icewind\Streams\Wrapper; use OC\Files\ObjectStore\S3; class MultiPartUploadS3 extends S3 { - public function writeObject($urn, $stream) { + public function writeObject($urn, $stream, string $mimetype = null) { $this->getConnection()->upload($this->bucket, $urn, $stream, 'private', [ 'mup_threshold' => 1, ]);