Skip to content

Commit

Permalink
do cachejail search filtering in sql
Browse files Browse the repository at this point in the history
Signed-off-by: Robin Appelman <robin@icewind.nl>
  • Loading branch information
icewind1991 authored and kesselb committed Mar 16, 2021
1 parent a6357eb commit 5d08beb
Show file tree
Hide file tree
Showing 4 changed files with 97 additions and 4 deletions.
2 changes: 1 addition & 1 deletion lib/private/Files/Cache/Cache.php
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ public function __construct(IStorage $storage) {
$this->querySearchHelper = new QuerySearchHelper($this->mimetypeLoader);
}

private function getQueryBuilder() {
protected function getQueryBuilder() {
return new CacheQueryBuilder(
$this->connection,
\OC::$server->getSystemConfig(),
Expand Down
2 changes: 2 additions & 0 deletions lib/private/Files/Cache/QuerySearchHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@ private function validateComparison(ISearchComparison $operator) {
'mimetype' => 'string',
'mtime' => 'integer',
'name' => 'string',
'path' => 'string',
'size' => 'integer',
'tagname' => 'string',
'favorite' => 'boolean',
Expand All @@ -184,6 +185,7 @@ private function validateComparison(ISearchComparison $operator) {
'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'],
Expand Down
60 changes: 57 additions & 3 deletions lib/private/Files/Cache/Wrapper/CacheJail.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;

/**
Expand All @@ -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() {
Expand Down Expand Up @@ -221,7 +228,26 @@ private function formatSearchResults($results) {
* @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);
}

Expand All @@ -232,12 +258,40 @@ public function search($pattern) {
* @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);

Expand Down
37 changes: 37 additions & 0 deletions tests/lib/Files/Cache/Wrapper/CacheJailTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;

/**
Expand Down Expand Up @@ -46,6 +51,38 @@ public function testSearchOutsideJail() {
$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';
Expand Down

0 comments on commit 5d08beb

Please sign in to comment.