From 5d08beb3d2e2c25ac765fa54a670bd400a3fac69 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Thu, 14 Jan 2021 19:03:39 +0100 Subject: [PATCH] do cachejail search filtering in sql Signed-off-by: Robin Appelman --- lib/private/Files/Cache/Cache.php | 2 +- lib/private/Files/Cache/QuerySearchHelper.php | 2 + lib/private/Files/Cache/Wrapper/CacheJail.php | 60 ++++++++++++++++++- .../lib/Files/Cache/Wrapper/CacheJailTest.php | 37 ++++++++++++ 4 files changed, 97 insertions(+), 4 deletions(-) diff --git a/lib/private/Files/Cache/Cache.php b/lib/private/Files/Cache/Cache.php index 6de3c41e56..b8ca9e6e1b 100644 --- a/lib/private/Files/Cache/Cache.php +++ b/lib/private/Files/Cache/Cache.php @@ -113,7 +113,7 @@ class Cache implements ICache { $this->querySearchHelper = new QuerySearchHelper($this->mimetypeLoader); } - private function getQueryBuilder() { + protected function getQueryBuilder() { return new CacheQueryBuilder( $this->connection, \OC::$server->getSystemConfig(), diff --git a/lib/private/Files/Cache/QuerySearchHelper.php b/lib/private/Files/Cache/QuerySearchHelper.php index 574b4c18d5..5e33ad235a 100644 --- a/lib/private/Files/Cache/QuerySearchHelper.php +++ b/lib/private/Files/Cache/QuerySearchHelper.php @@ -175,6 +175,7 @@ class QuerySearchHelper { 'mimetype' => 'string', 'mtime' => 'integer', 'name' => 'string', + 'path' => 'string', 'size' => 'integer', 'tagname' => 'string', 'favorite' => 'boolean', @@ -184,6 +185,7 @@ class QuerySearchHelper { 'mimetype' => ['eq', 'like'], 'mtime' => ['eq', 'gt', 'lt', 'gte', 'lte'], 'name' => ['eq', 'like'], + 'path' => ['eq', 'like'], 'size' => ['eq', 'gt', 'lt', 'gte', 'lte'], 'tagname' => ['eq', 'like'], 'favorite' => ['eq'], diff --git a/lib/private/Files/Cache/Wrapper/CacheJail.php b/lib/private/Files/Cache/Wrapper/CacheJail.php index 6c1c17be02..27590fb741 100644 --- a/lib/private/Files/Cache/Wrapper/CacheJail.php +++ b/lib/private/Files/Cache/Wrapper/CacheJail.php @@ -29,8 +29,13 @@ namespace OC\Files\Cache\Wrapper; use OC\Files\Cache\Cache; +use OC\Files\Search\SearchBinaryOperator; +use OC\Files\Search\SearchComparison; use OC\Files\Search\SearchQuery; +use OCP\DB\QueryBuilder\IQueryBuilder; use OCP\Files\Cache\ICacheEntry; +use OCP\Files\Search\ISearchBinaryOperator; +use OCP\Files\Search\ISearchComparison; use OCP\Files\Search\ISearchQuery; /** @@ -49,6 +54,8 @@ class CacheJail extends CacheWrapper { public function __construct($cache, $root) { parent::__construct($cache); $this->root = $root; + $this->connection = \OC::$server->getDatabaseConnection(); + $this->mimetypeLoader = \OC::$server->getMimeTypeLoader(); } protected function getRoot() { @@ -221,7 +228,26 @@ class CacheJail extends CacheWrapper { * @return array an array of file data */ public function search($pattern) { - $results = $this->getCache()->search($pattern); + // normalize pattern + $pattern = $this->normalize($pattern); + + if ($pattern === '%%') { + return []; + } + + $query = $this->getQueryBuilder(); + $query->selectFileCache() + ->whereStorageId() + ->andWhere($query->expr()->like('path', $query->createNamedParameter($this->getRoot() . '/%'))) + ->andWhere($query->expr()->iLike('name', $query->createNamedParameter($pattern))); + + $result = $query->execute(); + $files = $result->fetchAll(); + $result->closeCursor(); + + $results = array_map(function (array $data) { + return self::cacheEntryFromData($data, $this->mimetypeLoader); + }, $files); return $this->formatSearchResults($results); } @@ -232,12 +258,40 @@ class CacheJail extends CacheWrapper { * @return array */ public function searchByMime($mimetype) { - $results = $this->getCache()->searchByMime($mimetype); + $mimeId = $this->mimetypeLoader->getId($mimetype); + + $query = $this->getQueryBuilder(); + $query->selectFileCache() + ->whereStorageId() + ->andWhere($query->expr()->like('path', $query->createNamedParameter($this->getRoot() . '/%'))); + + if (strpos($mimetype, '/')) { + $query->andWhere($query->expr()->eq('mimetype', $query->createNamedParameter($mimeId, IQueryBuilder::PARAM_INT))); + } else { + $query->andWhere($query->expr()->eq('mimepart', $query->createNamedParameter($mimeId, IQueryBuilder::PARAM_INT))); + } + + $result = $query->execute(); + $files = $result->fetchAll(); + $result->closeCursor(); + + $results = array_map(function (array $data) { + return self::cacheEntryFromData($data, $this->mimetypeLoader); + }, $files); return $this->formatSearchResults($results); } public function searchQuery(ISearchQuery $query) { - $simpleQuery = new SearchQuery($query->getSearchOperation(), 0, 0, $query->getOrder(), $query->getUser()); + $prefixFilter = new SearchComparison( + ISearchComparison::COMPARE_LIKE, + 'path', + $this->getRoot() . '/%' + ); + $operation = new SearchBinaryOperator( + ISearchBinaryOperator::OPERATOR_AND, + [$prefixFilter, $query->getSearchOperation()] + ); + $simpleQuery = new SearchQuery($operation, 0, 0, $query->getOrder(), $query->getUser()); $results = $this->getCache()->searchQuery($simpleQuery); $results = $this->formatSearchResults($results); diff --git a/tests/lib/Files/Cache/Wrapper/CacheJailTest.php b/tests/lib/Files/Cache/Wrapper/CacheJailTest.php index f0943ba5a0..83173efd3b 100644 --- a/tests/lib/Files/Cache/Wrapper/CacheJailTest.php +++ b/tests/lib/Files/Cache/Wrapper/CacheJailTest.php @@ -9,6 +9,11 @@ namespace Test\Files\Cache\Wrapper; use OC\Files\Cache\Wrapper\CacheJail; +use OC\Files\Search\SearchComparison; +use OC\Files\Search\SearchQuery; +use OC\User\User; +use OCP\Files\Search\ISearchComparison; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Test\Files\Cache\CacheTest; /** @@ -46,6 +51,38 @@ class CacheJailTest extends CacheTest { $this->assertEquals('foobar', $result[0]['path']); } + public function testSearchMimeOutsideJail() { + $file1 = 'foo/foobar'; + $file2 = 'folder/foobar'; + $data1 = ['size' => 100, 'mtime' => 50, 'mimetype' => 'foo/folder']; + + $this->sourceCache->put($file1, $data1); + $this->sourceCache->put($file2, $data1); + + $this->assertCount(2, $this->sourceCache->searchByMime('foo/folder')); + + $result = $this->cache->search('%foobar%'); + $this->assertCount(1, $result); + $this->assertEquals('foobar', $result[0]['path']); + } + + public function testSearchQueryOutsideJail() { + $file1 = 'foo/foobar'; + $file2 = 'folder/foobar'; + $data1 = ['size' => 100, 'mtime' => 50, 'mimetype' => 'foo/folder']; + + $this->sourceCache->put($file1, $data1); + $this->sourceCache->put($file2, $data1); + + $user = new User('foo', null, $this->createMock(EventDispatcherInterface::class)); + $query = new SearchQuery(new SearchComparison(ISearchComparison::COMPARE_EQUAL, 'name', 'foobar'), 10, 0, [], $user); + $this->assertCount(2, $this->sourceCache->searchQuery($query)); + + $result = $this->cache->search('%foobar%'); + $this->assertCount(1, $result); + $this->assertEquals('foobar', $result[0]['path']); + } + public function testClearKeepEntriesOutsideJail() { $file1 = 'foo/foobar'; $file2 = 'foo/foobar/asd';