summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
m---------3rdparty0
-rw-r--r--apps/files/appinfo/remote.php33
-rwxr-xr-xapps/files_encryption/tests/webdav.php12
-rw-r--r--apps/files_sharing/publicwebdav.php22
-rw-r--r--lib/private/appframework/http/request.php4
-rw-r--r--lib/private/connector/sabre/appenabledplugin.php2
-rw-r--r--lib/private/connector/sabre/auth.php54
-rw-r--r--lib/private/connector/sabre/custompropertiesbackend.php347
-rw-r--r--lib/private/connector/sabre/directory.php83
-rw-r--r--lib/private/connector/sabre/exception/entitytoolarge.php25
-rw-r--r--lib/private/connector/sabre/exception/filelocked.php28
-rw-r--r--lib/private/connector/sabre/exception/unsupportedmediatype.php25
-rw-r--r--lib/private/connector/sabre/exceptionloggerplugin.php28
-rw-r--r--lib/private/connector/sabre/file.php84
-rw-r--r--lib/private/connector/sabre/filesplugin.php179
-rw-r--r--lib/private/connector/sabre/locks.php52
-rw-r--r--lib/private/connector/sabre/maintenanceplugin.php30
-rw-r--r--lib/private/connector/sabre/node.php156
-rw-r--r--lib/private/connector/sabre/objecttree.php54
-rw-r--r--lib/private/connector/sabre/principal.php18
-rw-r--r--lib/private/connector/sabre/quotaplugin.php41
-rw-r--r--lib/private/connector/sabre/request.php50
-rw-r--r--lib/private/connector/sabre/server.php292
-rw-r--r--lib/private/connector/sabre/taglist.php3
-rw-r--r--lib/private/connector/sabre/tagsplugin.php175
-rw-r--r--lib/private/files/storage/common.php2
-rw-r--r--lib/private/files/storage/dav.php73
-rw-r--r--lib/private/vobject/compoundproperty.php69
-rw-r--r--lib/private/vobject/stringproperty.php77
-rw-r--r--tests/lib/connector/sabre/custompropertiesbackend.php248
-rw-r--r--tests/lib/connector/sabre/directory.php21
-rw-r--r--tests/lib/connector/sabre/file.php18
-rw-r--r--tests/lib/connector/sabre/filesplugin.php174
-rw-r--r--tests/lib/connector/sabre/node.php2
-rw-r--r--tests/lib/connector/sabre/objecttree.php123
-rw-r--r--tests/lib/connector/sabre/principal.php3
-rw-r--r--tests/lib/connector/sabre/quotaplugin.php38
-rw-r--r--tests/lib/connector/sabre/tagsplugin.php204
-rw-r--r--tests/lib/vobject.php40
39 files changed, 1534 insertions, 1355 deletions
diff --git a/3rdparty b/3rdparty
-Subproject 59f092231c6036838746262a4db80997908bb06
+Subproject 588b1308f4abf58acb3bb8519f6952d9890cca8
diff --git a/apps/files/appinfo/remote.php b/apps/files/appinfo/remote.php
index f9fa792e133..98db95041fe 100644
--- a/apps/files/appinfo/remote.php
+++ b/apps/files/appinfo/remote.php
@@ -27,14 +27,14 @@
*
*/
// Backends
-$authBackend = new OC_Connector_Sabre_Auth();
-$lockBackend = new OC_Connector_Sabre_Locks();
-$requestBackend = new OC_Connector_Sabre_Request();
+$authBackend = new \OC\Connector\Sabre\Auth();
+$lockBackend = new \OC\Connector\Sabre\Locks();
// Fire up server
$objectTree = new \OC\Connector\Sabre\ObjectTree();
-$server = new OC_Connector_Sabre_Server($objectTree);
-$server->httpRequest = $requestBackend;
+$server = new \OC\Connector\Sabre\Server($objectTree);
+// Set URL explicitly due to reverse-proxy situations
+$server->httpRequest->setUrl(\OC::$server->getRequest()->getRequestUri());
$server->setBaseUri($baseuri);
// Load plugins
@@ -42,22 +42,33 @@ $defaults = new OC_Defaults();
$server->addPlugin(new \Sabre\DAV\Auth\Plugin($authBackend, $defaults->getName()));
$server->addPlugin(new \Sabre\DAV\Locks\Plugin($lockBackend));
$server->addPlugin(new \Sabre\DAV\Browser\Plugin(false, false)); // Show something in the Browser, but no upload
-$server->addPlugin(new OC_Connector_Sabre_FilesPlugin());
-$server->addPlugin(new OC_Connector_Sabre_MaintenancePlugin());
-$server->addPlugin(new OC_Connector_Sabre_ExceptionLoggerPlugin('webdav'));
+$server->addPlugin(new \OC\Connector\Sabre\FilesPlugin($objectTree));
+$server->addPlugin(new \OC\Connector\Sabre\MaintenancePlugin());
+$server->addPlugin(new \OC\Connector\Sabre\ExceptionLoggerPlugin('webdav'));
// wait with registering these until auth is handled and the filesystem is setup
-$server->subscribeEvent('beforeMethod', function () use ($server, $objectTree) {
+$server->on('beforeMethod', function () use ($server, $objectTree) {
$view = \OC\Files\Filesystem::getView();
$rootInfo = $view->getFileInfo('');
// Create ownCloud Dir
$mountManager = \OC\Files\Filesystem::getMountManager();
- $rootDir = new OC_Connector_Sabre_Directory($view, $rootInfo);
+ $rootDir = new \OC\Connector\Sabre\Directory($view, $rootInfo);
$objectTree->init($rootDir, $view, $mountManager);
$server->addPlugin(new \OC\Connector\Sabre\TagsPlugin($objectTree, \OC::$server->getTagManager()));
- $server->addPlugin(new OC_Connector_Sabre_QuotaPlugin($view));
+ $server->addPlugin(new \OC\Connector\Sabre\QuotaPlugin($view));
+
+ // custom properties plugin must be the last one
+ $server->addPlugin(
+ new \Sabre\DAV\PropertyStorage\Plugin(
+ new \OC\Connector\Sabre\CustomPropertiesBackend(
+ $objectTree,
+ \OC::$server->getDatabaseConnection(),
+ \OC::$server->getUserSession()->getUser()
+ )
+ )
+ );
}, 30); // priority 30: after auth (10) and acl(20), before lock(50) and handling the request
// And off we go!
diff --git a/apps/files_encryption/tests/webdav.php b/apps/files_encryption/tests/webdav.php
index 0d5a8f82f2c..8fe5ffe0363 100755
--- a/apps/files_encryption/tests/webdav.php
+++ b/apps/files_encryption/tests/webdav.php
@@ -216,35 +216,33 @@ class Webdav extends TestCase {
*/
function handleWebdavRequest($body = false) {
// Backends
- $authBackend = $this->getMockBuilder('OC_Connector_Sabre_Auth')
+ $authBackend = $this->getMockBuilder('OC\Connector\Sabre\Auth')
->setMethods(['validateUserPass'])
->getMock();
$authBackend->expects($this->any())
->method('validateUserPass')
->will($this->returnValue(true));
- $lockBackend = new \OC_Connector_Sabre_Locks();
- $requestBackend = new \OC_Connector_Sabre_Request();
+ $lockBackend = new \OC\Connector\Sabre\Locks();
// Create ownCloud Dir
$root = '/' . $this->userId . '/files';
$view = new \OC\Files\View($root);
- $publicDir = new \OC_Connector_Sabre_Directory($view, $view->getFileInfo(''));
+ $publicDir = new \OC\Connector\Sabre\Directory($view, $view->getFileInfo(''));
$objectTree = new \OC\Connector\Sabre\ObjectTree();
$mountManager = \OC\Files\Filesystem::getMountManager();
$objectTree->init($publicDir, $view, $mountManager);
// Fire up server
$server = new \Sabre\DAV\Server($publicDir);
- $server->httpRequest = $requestBackend;
$server->setBaseUri('/remote.php/webdav/');
// Load plugins
$server->addPlugin(new \Sabre\DAV\Auth\Plugin($authBackend, 'ownCloud'));
$server->addPlugin(new \Sabre\DAV\Locks\Plugin($lockBackend));
$server->addPlugin(new \Sabre\DAV\Browser\Plugin(false)); // Show something in the Browser, but no upload
- $server->addPlugin(new \OC_Connector_Sabre_QuotaPlugin($view));
- $server->addPlugin(new \OC_Connector_Sabre_MaintenancePlugin());
+ $server->addPlugin(new \OC\Connector\Sabre\QuotaPlugin($view));
+ $server->addPlugin(new \OC\Connector\Sabre\MaintenancePlugin());
$server->debugExceptions = true;
// Totally ugly hack to setup the FS
diff --git a/apps/files_sharing/publicwebdav.php b/apps/files_sharing/publicwebdav.php
index 30c8588ee3f..abed58b5ee2 100644
--- a/apps/files_sharing/publicwebdav.php
+++ b/apps/files_sharing/publicwebdav.php
@@ -34,13 +34,13 @@ OC_Util::obEnd();
// Backends
$authBackend = new OCA\Files_Sharing\Connector\PublicAuth(\OC::$server->getConfig());
-$lockBackend = new OC_Connector_Sabre_Locks();
-$requestBackend = new OC_Connector_Sabre_Request();
+$lockBackend = new \OC\Connector\Sabre\Locks();
// Fire up server
$objectTree = new \OC\Connector\Sabre\ObjectTree();
-$server = new OC_Connector_Sabre_Server($objectTree);
-$server->httpRequest = $requestBackend;
+$server = new \OC\Connector\Sabre\Server($objectTree);
+// Set URL explicitly due to reverse-proxy situations
+$server->httpRequest->setUrl(\OC::$server->getRequest()->getRequestUri());
$server->setBaseUri($baseuri);
// Load plugins
@@ -48,12 +48,12 @@ $defaults = new OC_Defaults();
$server->addPlugin(new \Sabre\DAV\Auth\Plugin($authBackend, $defaults->getName()));
$server->addPlugin(new \Sabre\DAV\Locks\Plugin($lockBackend));
$server->addPlugin(new \Sabre\DAV\Browser\Plugin(false)); // Show something in the Browser, but no upload
-$server->addPlugin(new OC_Connector_Sabre_FilesPlugin());
-$server->addPlugin(new OC_Connector_Sabre_MaintenancePlugin());
-$server->addPlugin(new OC_Connector_Sabre_ExceptionLoggerPlugin('webdav'));
+$server->addPlugin(new \OC\Connector\Sabre\FilesPlugin($objectTree));
+$server->addPlugin(new \OC\Connector\Sabre\MaintenancePlugin());
+$server->addPlugin(new \OC\Connector\Sabre\ExceptionLoggerPlugin('webdav'));
// wait with registering these until auth is handled and the filesystem is setup
-$server->subscribeEvent('beforeMethod', function () use ($server, $objectTree, $authBackend) {
+$server->on('beforeMethod', function () use ($server, $objectTree, $authBackend) {
$share = $authBackend->getShare();
$owner = $share['uid_owner'];
$isWritable = $share['permissions'] & (\OCP\Constants::PERMISSION_UPDATE | \OCP\Constants::PERMISSION_CREATE);
@@ -74,14 +74,14 @@ $server->subscribeEvent('beforeMethod', function () use ($server, $objectTree, $
// Create ownCloud Dir
if ($rootInfo->getType() === 'dir') {
- $root = new OC_Connector_Sabre_Directory($view, $rootInfo);
+ $root = new \OC\Connector\Sabre\Directory($view, $rootInfo);
} else {
- $root = new OC_Connector_Sabre_File($view, $rootInfo);
+ $root = new \OC\Connector\Sabre\File($view, $rootInfo);
}
$mountManager = \OC\Files\Filesystem::getMountManager();
$objectTree->init($root, $view, $mountManager);
- $server->addPlugin(new OC_Connector_Sabre_QuotaPlugin($view));
+ $server->addPlugin(new \OC\Connector\Sabre\QuotaPlugin($view));
}, 30); // priority 30: after auth (10) and acl(20), before lock(50) and handling the request
// And off we go!
diff --git a/lib/private/appframework/http/request.php b/lib/private/appframework/http/request.php
index dad5cb050ca..e47811d0df9 100644
--- a/lib/private/appframework/http/request.php
+++ b/lib/private/appframework/http/request.php
@@ -543,7 +543,7 @@ class Request implements \ArrayAccess, \Countable, IRequest {
// strip off the script name's dir and file name
// FIXME: Sabre does not really belong here
- list($path, $name) = \Sabre\DAV\URLUtil::splitPath($scriptName);
+ list($path, $name) = \Sabre\HTTP\URLUtil::splitPath($scriptName);
if (!empty($path)) {
if($path === $pathInfo || strpos($pathInfo, $path.'/') === 0) {
$pathInfo = substr($pathInfo, strlen($path));
@@ -575,7 +575,7 @@ class Request implements \ArrayAccess, \Countable, IRequest {
}
$pathInfo = $this->getRawPathInfo();
- // following is taken from \Sabre\DAV\URLUtil::decodePathSegment
+ // following is taken from \Sabre\HTTP\URLUtil::decodePathSegment
$pathInfo = rawurldecode($pathInfo);
$encoding = mb_detect_encoding($pathInfo, ['UTF-8', 'ISO-8859-1']);
diff --git a/lib/private/connector/sabre/appenabledplugin.php b/lib/private/connector/sabre/appenabledplugin.php
index 68356d3378c..e38af40c08e 100644
--- a/lib/private/connector/sabre/appenabledplugin.php
+++ b/lib/private/connector/sabre/appenabledplugin.php
@@ -69,7 +69,7 @@ class AppEnabledPlugin extends ServerPlugin {
public function initialize(\Sabre\DAV\Server $server) {
$this->server = $server;
- $this->server->subscribeEvent('beforeMethod', array($this, 'checkAppEnabled'), 30);
+ $this->server->on('beforeMethod', array($this, 'checkAppEnabled'), 30);
}
/**
diff --git a/lib/private/connector/sabre/auth.php b/lib/private/connector/sabre/auth.php
index a095ee6e045..0fc76ea9df2 100644
--- a/lib/private/connector/sabre/auth.php
+++ b/lib/private/connector/sabre/auth.php
@@ -1,31 +1,7 @@
<?php
-/**
- * @author Arthur Schiwon <blizzz@owncloud.com>
- * @author Bart Visscher <bartv@thisnet.nl>
- * @author Jakob Sack <mail@jakobsack.de>
- * @author Lukas Reschke <lukas@owncloud.com>
- * @author Markus Goetz <markus@woboq.com>
- * @author Michael Gapczynski <gapczynskim@gmail.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
- * @author Thomas Müller <thomas.mueller@tmit.eu>
- *
- * @copyright Copyright (c) 2015, ownCloud, Inc.
- * @license AGPL-3.0
- *
- * This code is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License, version 3,
- * along with this program. If not, see <http://www.gnu.org/licenses/>
- *
- */
-class OC_Connector_Sabre_Auth extends \Sabre\DAV\Auth\Backend\AbstractBasic {
+namespace OC\Connector\Sabre;
+
+class Auth extends \Sabre\DAV\Auth\Backend\AbstractBasic {
const DAV_AUTHENTICATED = 'AUTHENTICATED_TO_DAV_BACKEND';
/**
@@ -55,19 +31,19 @@ class OC_Connector_Sabre_Auth extends \Sabre\DAV\Auth\Backend\AbstractBasic {
* @return bool
*/
protected function validateUserPass($username, $password) {
- if (OC_User::isLoggedIn() &&
- $this->isDavAuthenticated(OC_User::getUser())
+ if (\OC_User::isLoggedIn() &&
+ $this->isDavAuthenticated(\OC_User::getUser())
) {
- OC_Util::setupFS(OC_User::getUser());
+ \OC_Util::setupFS(\OC_User::getUser());
\OC::$server->getSession()->close();
return true;
} else {
- OC_Util::setUpFS(); //login hooks may need early access to the filesystem
- if(OC_User::login($username, $password)) {
+ \OC_Util::setUpFS(); //login hooks may need early access to the filesystem
+ if(\OC_User::login($username, $password)) {
// make sure we use owncloud's internal username here
// and not the HTTP auth supplied one, see issue #14048
- $ocUser = OC_User::getUser();
- OC_Util::setUpFS($ocUser);
+ $ocUser = \OC_User::getUser();
+ \OC_Util::setUpFS($ocUser);
\OC::$server->getSession()->set(self::DAV_AUTHENTICATED, $ocUser);
\OC::$server->getSession()->close();
return true;
@@ -86,7 +62,7 @@ class OC_Connector_Sabre_Auth extends \Sabre\DAV\Auth\Backend\AbstractBasic {
* @return string|null
*/
public function getCurrentUser() {
- $user = OC_User::getUser();
+ $user = \OC_User::getUser();
if($user && $this->isDavAuthenticated($user)) {
return $user;
}
@@ -117,11 +93,11 @@ class OC_Connector_Sabre_Auth extends \Sabre\DAV\Auth\Backend\AbstractBasic {
* @return bool
*/
private function auth(\Sabre\DAV\Server $server, $realm) {
- if (OC_User::handleApacheAuth() ||
- (OC_User::isLoggedIn() && is_null(\OC::$server->getSession()->get(self::DAV_AUTHENTICATED)))
+ if (\OC_User::handleApacheAuth() ||
+ (\OC_User::isLoggedIn() && is_null(\OC::$server->getSession()->get(self::DAV_AUTHENTICATED)))
) {
- $user = OC_User::getUser();
- OC_Util::setupFS($user);
+ $user = \OC_User::getUser();
+ \OC_Util::setupFS($user);
$this->currentUser = $user;
\OC::$server->getSession()->close();
return true;
diff --git a/lib/private/connector/sabre/custompropertiesbackend.php b/lib/private/connector/sabre/custompropertiesbackend.php
new file mode 100644
index 00000000000..eaf13238b63
--- /dev/null
+++ b/lib/private/connector/sabre/custompropertiesbackend.php
@@ -0,0 +1,347 @@
+<?php
+
+/**
+ * ownCloud
+ *
+ * @author Vincent Petry
+ * @copyright 2015 Vincent Petry <pvince81@owncloud.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace OC\Connector\Sabre;
+
+use \Sabre\DAV\PropFind;
+use \Sabre\DAV\PropPatch;
+use \Sabre\HTTP\RequestInterface;
+use \Sabre\HTTP\ResponseInterface;
+
+class CustomPropertiesBackend implements \Sabre\DAV\PropertyStorage\Backend\BackendInterface {
+
+ /**
+ * Ignored properties
+ *
+ * @var array
+ */
+ private $ignoredProperties = array(
+ '{DAV:}getcontentlength',
+ '{DAV:}getcontenttype',
+ '{DAV:}getetag',
+ '{DAV:}quota-used-bytes',
+ '{DAV:}quota-available-bytes',
+ '{DAV:}quota-available-bytes',
+ '{http://owncloud.org/ns}permissions',
+ '{http://owncloud.org/ns}downloadURL',
+ '{http://owncloud.org/ns}dDC',
+ '{http://owncloud.org/ns}size',
+ );
+
+ /**
+ * @var \Sabre\DAV\Tree
+ */
+ private $tree;
+
+ /**
+ * @var \OCP\IDBConnection
+ */
+ private $connection;
+
+ /**
+ * @var \OCP\IUser
+ */
+ private $user;
+
+ /**
+ * Properties cache
+ *
+ * @var array
+ */
+ private $cache = [];
+
+ /**
+ * @param \Sabre\DAV\Tree $tree node tree
+ * @param \OCP\IDBConnection $connection database connection
+ * @param \OCP\IUser $user owner of the tree and properties
+ */
+ public function __construct(
+ \Sabre\DAV\Tree $tree,
+ \OCP\IDBConnection $connection,
+ \OCP\IUser $user) {
+ $this->tree = $tree;
+ $this->connection = $connection;
+ $this->user = $user->getUID();
+ }
+
+ /**
+ * Fetches properties for a path.
+ *
+ * @param string $path
+ * @param PropFind $propFind
+ * @return void
+ */
+ public function propFind($path, PropFind $propFind) {
+ $node = $this->tree->getNodeForPath($path);
+ if (!($node instanceof \OC\Connector\Sabre\Node)) {
+ return;
+ }
+
+ $requestedProps = $propFind->get404Properties();
+
+ // these might appear
+ $requestedProps = array_diff(
+ $requestedProps,
+ $this->ignoredProperties
+ );
+
+ if (empty($requestedProps)) {
+ return;
+ }
+
+ if ($node instanceof \OC\Connector\Sabre\Directory
+ && $propFind->getDepth() !== 0
+ ) {
+ // note: pre-fetching only supported for depth <= 1
+ $this->loadChildrenProperties($node, $requestedProps);
+ }
+
+ $props = $this->getProperties($node, $requestedProps);
+ foreach ($props as $propName => $propValue) {
+ $propFind->set($propName, $propValue);
+ }
+ }
+
+ /**
+ * Updates properties for a path
+ *
+ * @param string $path
+ * @param PropPatch $propPatch
+ *
+ * @return void
+ */
+ public function propPatch($path, PropPatch $propPatch) {
+ $node = $this->tree->getNodeForPath($path);
+ if (!($node instanceof \OC\Connector\Sabre\Node)) {
+ return;
+ }
+
+ $propPatch->handleRemaining(function($changedProps) use ($node) {
+ return $this->updateProperties($node, $changedProps);
+ });
+ }
+
+ /**
+ * This method is called after a node is deleted.
+ *
+ * @param string $path path of node for which to delete properties
+ */
+ public function delete($path) {
+ $statement = $this->connection->prepare(
+ 'DELETE FROM `*PREFIX*properties` WHERE `userid` = ? AND `propertypath` = ?'
+ );
+ $statement->execute(array($this->user, '/' . $path));
+ $statement->closeCursor();
+
+ unset($this->cache[$path]);
+ }
+
+ /**
+ * This method is called after a successful MOVE
+ *
+ * @param string $source
+ * @param string $destination
+ *
+ * @return void
+ */
+ public function move($source, $destination) {
+ $statement = $this->connection->prepare(
+ 'UPDATE `*PREFIX*properties` SET `propertypath` = ?' .
+ ' WHERE `userid` = ? AND `propertypath` = ?'
+ );
+ $statement->execute(array('/' . $destination, $this->user, '/' . $source));
+ $statement->closeCursor();
+ }
+
+ /**
+ * Returns a list of properties for this nodes.;
+ * @param \OC\Connector\Sabre\Node $node
+ * @param array $requestedProperties requested properties or empty array for "all"
+ * @return array
+ * @note The properties list is a list of propertynames the client
+ * requested, encoded as xmlnamespace#tagName, for example:
+ * http://www.example.org/namespace#author If the array is empty, all
+ * properties should be returned
+ */
+ private function getProperties(\OC\Connector\Sabre\Node $node, array $requestedProperties) {
+ $path = $node->getPath();
+ if (isset($this->cache[$path])) {
+ return $this->cache[$path];
+ }
+
+ // TODO: chunking if more than 1000 properties
+ $sql = 'SELECT * FROM `*PREFIX*properties` WHERE `userid` = ? AND `propertypath` = ?';
+
+ $whereValues = array($this->user, $path);
+ $whereTypes = array(null, null);
+
+ if (!empty($requestedProperties)) {
+ // request only a subset
+ $sql .= ' AND `propertyname` in (?)';
+ $whereValues[] = $requestedProperties;
+ $whereTypes[] = \Doctrine\DBAL\Connection::PARAM_STR_ARRAY;
+ }
+
+ $result = $this->connection->executeQuery(
+ $sql,
+ $whereValues,
+ $whereTypes
+ );
+
+ $props = [];
+ while ($row = $result->fetch()) {
+ $props[$row['propertyname']] = $row['propertyvalue'];
+ }
+
+ $result->closeCursor();
+
+ $this->cache[$path] = $props;
+ return $props;
+ }
+
+ /**
+ * Update properties
+ *
+ * @param \OC\Connector\Sabre\Node $node node for which to update properties
+ * @param array $properties array of properties to update
+ *
+ * @return bool
+ */
+ private function updateProperties($node, $properties) {
+ $path = $node->getPath();
+
+ $deleteStatement = $this->connection->prepare(
+ 'DELETE FROM `*PREFIX*properties`' .
+ ' WHERE `userid` = ? AND `propertypath` = ? AND `propertyname` = ?'
+ );
+
+ $insertStatement = $this->connection->prepare(
+ 'INSERT INTO `*PREFIX*properties`' .
+ ' (`userid`,`propertypath`,`propertyname`,`propertyvalue`) VALUES(?,?,?,?)'
+ );
+
+ $updateStatement = $this->connection->prepare(
+ 'UPDATE `*PREFIX*properties` SET `propertyvalue` = ?' .
+ ' WHERE `userid` = ? AND `propertypath` = ? AND `propertyname` = ?'
+ );
+
+ // TODO: use "insert or update" strategy ?
+ $existing = $this->getProperties($node, array());
+ $this->connection->beginTransaction();
+ foreach ($properties as $propertyName => $propertyValue) {
+ // If it was null, we need to delete the property
+ if (is_null($propertyValue)) {
+ if (array_key_exists($propertyName, $existing)) {
+ $deleteStatement->execute(
+ array(
+ $this->user,
+ $path,
+ $propertyName
+ )
+ );
+ $deleteStatement->closeCursor();
+ }
+ } else {
+ if (!array_key_exists($propertyName, $existing)) {
+ $insertStatement->execute(
+ array(
+ $this->user,
+ $path,
+ $propertyName,
+ $propertyValue
+ )
+ );
+ $insertStatement->closeCursor();
+ } else {
+ $updateStatement->execute(
+ array(
+ $propertyValue,
+ $this->user,
+ $path,
+ $propertyName
+ )
+ );
+ $updateStatement->closeCursor();
+ }
+ }
+ }
+
+ $this->connection->commit();
+ unset($this->cache[$path]);
+
+ return true;
+ }
+
+ /**
+ * Bulk load properties for directory children
+ *
+ * @param \OC\Connector\Sabre\Directory $node
+ * @param array $requestedProperties requested properties
+ *
+ * @return void
+ */
+ private function loadChildrenProperties(\OC\Connector\Sabre\Directory $node, $requestedProperties) {
+ $path = $node->getPath();
+ if (isset($this->cache[$path])) {
+ // we already loaded them at some point
+ return;
+ }
+
+ $childNodes = $node->getChildren();
+ // pre-fill cache
+ foreach ($childNodes as $childNode) {
+ $this->cache[$childNode->getPath()] = [];
+ }
+
+ $sql = 'SELECT * FROM `*PREFIX*properties` WHERE `userid` = ? AND `propertypath` LIKE ?';
+ $sql .= ' AND `propertyname` in (?) ORDER BY `propertypath`, `propertyname`';
+
+ $result = $this->connection->executeQuery(
+ $sql,
+ array($this->user, rtrim($path, '/') . '/%', $requestedProperties),
+ array(null, null, \Doctrine\DBAL\Connection::PARAM_STR_ARRAY)
+ );
+
+ $props = [];
+ $oldPath = null;
+ $props = [];
+ while ($row = $result->fetch()) {
+ $path = $row['propertypath'];
+ if ($oldPath !== $path) {
+ // save previously gathered props
+ $this->cache[$oldPath] = $props;
+ $oldPath = $path;
+ // prepare props for next path
+ $props = [];
+ }
+ $props[$row['propertyname']] = $row['propertyvalue'];
+ }
+ if (!is_null($oldPath)) {
+ // save props from last run
+ $this->cache[$oldPath] = $props;
+ }
+
+ $result->closeCursor();
+ }
+
+}
diff --git a/lib/private/connector/sabre/directory.php b/lib/private/connector/sabre/directory.php
index 682fd62ee37..f13a0d7bbd8 100644
--- a/lib/private/connector/sabre/directory.php
+++ b/lib/private/connector/sabre/directory.php
@@ -1,4 +1,6 @@
<?php
+namespace OC\Connector\Sabre;
+
/**
* @author Arthur Schiwon <blizzz@owncloud.com>
* @author Bart Visscher <bartv@thisnet.nl>
@@ -24,7 +26,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*/
-class OC_Connector_Sabre_Directory extends OC_Connector_Sabre_Node
+class Directory extends \OC\Connector\Sabre\Node
implements \Sabre\DAV\ICollection, \Sabre\DAV\IQuota {
/**
@@ -74,7 +76,7 @@ class OC_Connector_Sabre_Directory extends OC_Connector_Sabre_Node
if (isset($_SERVER['HTTP_OC_CHUNKED'])) {
// exit if we can't create a new file and we don't updatable existing file
- $info = OC_FileChunking::decodeName($name);
+ $info = \OC_FileChunking::decodeName($name);
if (!$this->fileView->isCreatable($this->path) &&
!$this->fileView->isUpdatable($this->path . '/' . $info['name'])
) {
@@ -91,7 +93,7 @@ class OC_Connector_Sabre_Directory extends OC_Connector_Sabre_Node
$path = $this->fileView->getAbsolutePath($this->path) . '/' . $name;
// using a dummy FileInfo is acceptable here since it will be refreshed after the put is complete
$info = new \OC\Files\FileInfo($path, null, null, array(), null);
- $node = new OC_Connector_Sabre_File($this->fileView, $info);
+ $node = new \OC\Connector\Sabre\File($this->fileView, $info);
return $node->put($data);
} catch (\OCP\Files\StorageNotAvailableException $e) {
throw new \Sabre\DAV\Exception\ServiceUnavailable($e->getMessage());
@@ -143,9 +145,9 @@ class OC_Connector_Sabre_Directory extends OC_Connector_Sabre_Node
}
if ($info['mimetype'] == 'httpd/unix-directory') {
- $node = new OC_Connector_Sabre_Directory($this->fileView, $info);
+ $node = new \OC\Connector\Sabre\Directory($this->fileView, $info);
} else {
- $node = new OC_Connector_Sabre_File($this->fileView, $info);
+ $node = new \OC\Connector\Sabre\File($this->fileView, $info);
}
return $node;
}
@@ -161,42 +163,9 @@ class OC_Connector_Sabre_Directory extends OC_Connector_Sabre_Node
}
$folderContent = $this->fileView->getDirectoryContent($this->path);
- $properties = array();
- $paths = array();
- foreach ($folderContent as $info) {
- $name = $info->getName();
- $paths[] = $this->path . '/' . $name;
- $properties[$this->path . '/' . $name][self::GETETAG_PROPERTYNAME] = '"' . $info->getEtag() . '"';
- }
- // TODO: move this to a beforeGetPropertiesForPath event to pre-cache properties
- // TODO: only fetch the requested properties
- if (count($paths) > 0) {
- //
- // the number of arguments within IN conditions are limited in most databases
- // we chunk $paths into arrays of 200 items each to meet this criteria
- //
- $chunks = array_chunk($paths, 200, false);
- foreach ($chunks as $pack) {
- $placeholders = join(',', array_fill(0, count($pack), '?'));
- $query = OC_DB::prepare('SELECT * FROM `*PREFIX*properties`'
- . ' WHERE `userid` = ?' . ' AND `propertypath` IN (' . $placeholders . ')');
- array_unshift($pack, OC_User::getUser()); // prepend userid
- $result = $query->execute($pack);
- while ($row = $result->fetchRow()) {
- $propertypath = $row['propertypath'];
- $propertyname = $row['propertyname'];
- $propertyvalue = $row['propertyvalue'];
- if ($propertyname !== self::GETETAG_PROPERTYNAME) {
- $properties[$propertypath][$propertyname] = $propertyvalue;
- }
- }
- }
- }
-
$nodes = array();
foreach ($folderContent as $info) {
$node = $this->getChild($info->getName(), $info);
- $node->setPropertyCache($properties[$this->path . '/' . $info->getName()]);
$nodes[] = $node;
}
$this->dirContent = $nodes;
@@ -210,7 +179,13 @@ class OC_Connector_Sabre_Directory extends OC_Connector_Sabre_Node
* @return bool
*/
public function childExists($name) {
-
+ // note: here we do NOT resolve the chunk file name to the real file name
+ // to make sure we return false when checking for file existence with a chunk
+ // file name.
+ // This is to make sure that "createFile" is still triggered
+ // (required old code) instead of "updateFile".
+ //
+ // TODO: resolve chunk file name here and implement "updateFile"
$path = $this->path . '/' . $name;
return $this->fileView->file_exists($path);
@@ -245,7 +220,7 @@ class OC_Connector_Sabre_Directory extends OC_Connector_Sabre_Node
return $this->quotaInfo;
}
try {
- $storageInfo = OC_Helper::getStorageInfo($this->info->getPath(), $this->info);
+ $storageInfo = \OC_Helper::getStorageInfo($this->info->getPath(), $this->info);
$this->quotaInfo = array(
$storageInfo['used'],
$storageInfo['free']
@@ -256,32 +231,4 @@ class OC_Connector_Sabre_Directory extends OC_Connector_Sabre_Node
}
}
- /**
- * Returns a list of properties for this nodes.;
- *
- * The properties list is a list of propertynames the client requested,
- * encoded as xmlnamespace#tagName, for example:
- * http://www.example.org/namespace#author
- * If the array is empty, all properties should be returned
- *
- * @param array $properties
- * @return array
- */
- public function getProperties($properties) {
- $props = parent::getProperties($properties);
- if (in_array(self::GETETAG_PROPERTYNAME, $properties) && !isset($props[self::GETETAG_PROPERTYNAME])) {
- $props[self::GETETAG_PROPERTYNAME] = $this->info->getEtag();
- }
- return $props;
- }
-
- /**
- * Returns the size of the node, in bytes
- *
- * @return int
- */
- public function getSize() {
- return $this->info->getSize();
- }
-
}
diff --git a/lib/private/connector/sabre/exception/entitytoolarge.php b/lib/private/connector/sabre/exception/entitytoolarge.php
index 2d2a264fe6f..e18ac859dd5 100644
--- a/lib/private/connector/sabre/exception/entitytoolarge.php
+++ b/lib/private/connector/sabre/exception/entitytoolarge.php
@@ -1,24 +1,9 @@
<?php
-/**
- * @author Thomas Müller <thomas.mueller@tmit.eu>
- *
- * @copyright Copyright (c) 2015, ownCloud, Inc.
- * @license AGPL-3.0
- *
- * This code is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License, version 3,
- * along with this program. If not, see <http://www.gnu.org/licenses/>
- *
- */
-class OC_Connector_Sabre_Exception_EntityTooLarge extends \Sabre\DAV\Exception {
+
+
+namespace OC\Connector\Sabre\Exception;
+
+class EntityTooLarge extends \Sabre\DAV\Exception {
/**
* Returns the HTTP status code for this exception
diff --git a/lib/private/connector/sabre/exception/filelocked.php b/lib/private/connector/sabre/exception/filelocked.php
index ce110e3cb37..6b6b7b0d856 100644
--- a/lib/private/connector/sabre/exception/filelocked.php
+++ b/lib/private/connector/sabre/exception/filelocked.php
@@ -1,26 +1,10 @@
<?php
-/**
- * @author Lukas Reschke <lukas@owncloud.com>
- * @author Owen Winkler <a_github@midnightcircus.com>
- * @author Thomas Müller <thomas.mueller@tmit.eu>
- *
- * @copyright Copyright (c) 2015, ownCloud, Inc.
- * @license AGPL-3.0
- *
- * This code is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License, version 3,
- * along with this program. If not, see <http://www.gnu.org/licenses/>
- *
- */
-class OC_Connector_Sabre_Exception_FileLocked extends \Sabre\DAV\Exception {
+
+namespace OC\Connector\Sabre\Exception;
+
+use Exception;
+
+class FileLocked extends \Sabre\DAV\Exception {
public function __construct($message = "", $code = 0, Exception $previous = null) {
if($previous instanceof \OCP\Files\LockNotAcquiredException) {
diff --git a/lib/private/connector/sabre/exception/unsupportedmediatype.php b/lib/private/connector/sabre/exception/unsupportedmediatype.php
index ce6db21d89b..5a3716ae71b 100644
--- a/lib/private/connector/sabre/exception/unsupportedmediatype.php
+++ b/lib/private/connector/sabre/exception/unsupportedmediatype.php
@@ -1,24 +1,9 @@
<?php
-/**
- * @author Thomas Müller <thomas.mueller@tmit.eu>
- *
- * @copyright Copyright (c) 2015, ownCloud, Inc.
- * @license AGPL-3.0
- *
- * This code is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License, version 3,
- * along with this program. If not, see <http://www.gnu.org/licenses/>
- *
- */
-class OC_Connector_Sabre_Exception_UnsupportedMediaType extends \Sabre\DAV\Exception {
+
+
+namespace OC\Connector\Sabre\Exception;
+
+class UnsupportedMediaType extends \Sabre\DAV\Exception {
/**
* Returns the HTTP status code for this exception
diff --git a/lib/private/connector/sabre/exceptionloggerplugin.php b/lib/private/connector/sabre/exceptionloggerplugin.php
index 2b2753c47e4..6ae57b3ec56 100644
--- a/lib/private/connector/sabre/exceptionloggerplugin.php
+++ b/lib/private/connector/sabre/exceptionloggerplugin.php
@@ -1,26 +1,8 @@
<?php
-/**
- * @author Thomas Müller <thomas.mueller@tmit.eu>
- * @author Vincent Petry <pvince81@owncloud.com>
- *
- * @copyright Copyright (c) 2015, ownCloud, Inc.
- * @license AGPL-3.0
- *
- * This code is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License, version 3,
- * along with this program. If not, see <http://www.gnu.org/licenses/>
- *
- */
-class OC_Connector_Sabre_ExceptionLoggerPlugin extends \Sabre\DAV\ServerPlugin
-{
+
+namespace OC\Connector\Sabre;
+
+class ExceptionLoggerPlugin extends \Sabre\DAV\ServerPlugin {
private $nonFatalExceptions = array(
'Sabre\DAV\Exception\NotAuthenticated' => true,
// the sync client uses this to find out whether files exist,
@@ -54,7 +36,7 @@ class OC_Connector_Sabre_ExceptionLoggerPlugin extends \Sabre\DAV\ServerPlugin
*/
public function initialize(\Sabre\DAV\Server $server) {
- $server->subscribeEvent('exception', array($this, 'logException'), 10);
+ $server->on('exception', array($this, 'logException'), 10);
}
/**
diff --git a/lib/private/connector/sabre/file.php b/lib/private/connector/sabre/file.php
index 9b529d2e0f1..0355376c46b 100644
--- a/lib/private/connector/sabre/file.php
+++ b/lib/private/connector/sabre/file.php
@@ -1,38 +1,7 @@
<?php
-/**
- * @author Andreas Fischer <bantu@owncloud.com>
- * @author Bart Visscher <bartv@thisnet.nl>
- * @author Bjoern Schiessle <schiessle@owncloud.com>
- * @author chli1 <chli1@users.noreply.github.com>
- * @author Chris Wilson <chris+github@qwirx.com>
- * @author Jakob Sack <mail@jakobsack.de>
- * @author Joas Schilling <nickvergessen@gmx.de>
- * @author Jörn Friedrich Dreyer <jfd@butonic.de>
- * @author Lukas Reschke <lukas@owncloud.com>
- * @author Owen Winkler <a_github@midnightcircus.com>
- * @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
- * @author Thomas Müller <thomas.mueller@tmit.eu>
- * @author Thomas Tanghus <thomas@tanghus.net>
- * @author Vincent Petry <pvince81@owncloud.com>
- *
- * @copyright Copyright (c) 2015, ownCloud, Inc.
- * @license AGPL-3.0
- *
- * This code is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License, version 3,
- * along with this program. If not, see <http://www.gnu.org/licenses/>
- *
- */
-class OC_Connector_Sabre_File extends OC_Connector_Sabre_Node implements \Sabre\DAV\IFile {
+namespace OC\Connector\Sabre;
+
+class File extends \OC\Connector\Sabre\Node implements \Sabre\DAV\IFile {
/**
* Updates the data
@@ -52,11 +21,12 @@ class OC_Connector_Sabre_File extends OC_Connector_Sabre_Node implements \Sabre\
* return an ETag, and just return null.
*
* @param resource $data
+ *
* @throws \Sabre\DAV\Exception\Forbidden
- * @throws OC_Connector_Sabre_Exception_UnsupportedMediaType
+ * @throws \OC\Connector\Sabre\Exception\UnsupportedMediaType
* @throws \Sabre\DAV\Exception\BadRequest
* @throws \Sabre\DAV\Exception
- * @throws OC_Connector_Sabre_Exception_EntityTooLarge
+ * @throws \OC\Connector\Sabre\Exception\EntityTooLarge
* @throws \Sabre\DAV\Exception\ServiceUnavailable
* @return string|null
*/
@@ -110,11 +80,11 @@ class OC_Connector_Sabre_File extends OC_Connector_Sabre_Node implements \Sabre\
} catch (\OCP\Files\EntityTooLargeException $e) {
// the file is too big to be stored
- throw new OC_Connector_Sabre_Exception_EntityTooLarge($e->getMessage());
+ throw new \OC\Connector\Sabre\Exception\EntityTooLarge($e->getMessage());
} catch (\OCP\Files\InvalidContentException $e) {
// the file content is not permitted
- throw new OC_Connector_Sabre_Exception_UnsupportedMediaType($e->getMessage());
+ throw new \OC\Connector\Sabre\Exception\UnsupportedMediaType($e->getMessage());
} catch (\OCP\Files\InvalidPathException $e) {
// the path for the file was not valid
@@ -122,7 +92,7 @@ class OC_Connector_Sabre_File extends OC_Connector_Sabre_Node implements \Sabre\
throw new \Sabre\DAV\Exception\Forbidden($e->getMessage());
} catch (\OCP\Files\LockNotAcquiredException $e) {
// the file is currently being written to by another process
- throw new OC_Connector_Sabre_Exception_FileLocked($e->getMessage(), $e->getCode(), $e);
+ throw new \OC\Connector\Sabre\Exception\FileLocked($e->getMessage(), $e->getCode(), $e);
} catch (\OCA\Files_Encryption\Exception\EncryptionException $e) {
throw new \Sabre\DAV\Exception\Forbidden($e->getMessage());
} catch (\OCP\Files\StorageNotAvailableException $e) {
@@ -155,7 +125,7 @@ class OC_Connector_Sabre_File extends OC_Connector_Sabre_Node implements \Sabre\
}
catch (\OCP\Files\LockNotAcquiredException $e) {
// the file is currently being written to by another process
- throw new OC_Connector_Sabre_Exception_FileLocked($e->getMessage(), $e->getCode(), $e);
+ throw new \OC\Connector\Sabre\Exception\FileLocked($e->getMessage(), $e->getCode(), $e);
}
}
@@ -215,34 +185,6 @@ class OC_Connector_Sabre_File extends OC_Connector_Sabre_Node implements \Sabre\
} catch (\OCP\Files\StorageNotAvailableException $e) {
throw new \Sabre\DAV\Exception\ServiceUnavailable("Failed to unlink: ".$e->getMessage());
}
-
- // remove properties
- $this->removeProperties();
-
- }
-
- /**
- * Returns the size of the node, in bytes
- *
- * @return int|float
- */
- public function getSize() {
- return $this->info->getSize();
- }
-
- /**
- * Returns the ETag for a file
- *
- * An ETag is a unique identifier representing the current version of the
- * file. If the file changes, the ETag MUST change. The ETag is an
- * arbitrary string, but MUST be surrounded by double-quotes.
- *
- * Return null if the ETag can not effectively be determined
- *
- * @return mixed
- */
- public function getETag() {
- return '"' . $this->info->getEtag() . '"';
}
/**
@@ -288,13 +230,13 @@ class OC_Connector_Sabre_File extends OC_Connector_Sabre_Node implements \Sabre\
*/
private function createFileChunked($data)
{
- list($path, $name) = \Sabre\DAV\URLUtil::splitPath($this->path);
+ list($path, $name) = \Sabre\HTTP\URLUtil::splitPath($this->path);
- $info = OC_FileChunking::decodeName($name);
+ $info = \OC_FileChunking::decodeName($name);
if (empty($info)) {
throw new \Sabre\DAV\Exception\NotImplemented();
}
- $chunk_handler = new OC_FileChunking($info);
+ $chunk_handler = new \OC_FileChunking($info);
$bytesWritten = $chunk_handler->store($info['index'], $data);
//detect aborted upload
diff --git a/lib/private/connector/sabre/filesplugin.php b/lib/private/connector/sabre/filesplugin.php
index d62f4e4ce53..1932dabd393 100644
--- a/lib/private/connector/sabre/filesplugin.php
+++ b/lib/private/connector/sabre/filesplugin.php
@@ -1,30 +1,21 @@
<?php
-/**
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
- * @author Thomas Müller <thomas.mueller@tmit.eu>
- * @author Vincent Petry <pvince81@owncloud.com>
- *
- * @copyright Copyright (c) 2015, ownCloud, Inc.
- * @license AGPL-3.0
- *
- * This code is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License, version 3,
- * along with this program. If not, see <http://www.gnu.org/licenses/>
- *
- */
-class OC_Connector_Sabre_FilesPlugin extends \Sabre\DAV\ServerPlugin
-{
+namespace OC\Connector\Sabre;
+
+use \Sabre\DAV\PropFind;
+use \Sabre\DAV\PropPatch;
+use \Sabre\HTTP\RequestInterface;
+use \Sabre\HTTP\ResponseInterface;
+
+class FilesPlugin extends \Sabre\DAV\ServerPlugin {
// namespace
const NS_OWNCLOUD = 'http://owncloud.org/ns';
+ const FILEID_PROPERTYNAME = '{http://owncloud.org/ns}id';
+ const PERMISSIONS_PROPERTYNAME = '{http://owncloud.org/ns}permissions';
+ const DOWNLOADURL_PROPERTYNAME = '{http://owncloud.org/ns}downloadURL';
+ const SIZE_PROPERTYNAME = '{http://owncloud.org/ns}size';
+ const GETETAG_PROPERTYNAME = '{DAV:}getetag';
+ const GETLASTMODIFIED_PROPERTYNAME = '{DAV:}getlastmodified';
/**
* Reference to main server object
@@ -34,6 +25,15 @@ class OC_Connector_Sabre_FilesPlugin extends \Sabre\DAV\ServerPlugin
private $server;
/**
+ * @var \Sabre\DAV\Tree
+ */
+ private $tree;
+
+ public function __construct(\Sabre\DAV\Tree $tree) {
+ $this->tree = $tree;
+ }
+
+ /**
* This initializes the plugin.
*
* This function is called by \Sabre\DAV\Server, after
@@ -47,69 +47,101 @@ class OC_Connector_Sabre_FilesPlugin extends \Sabre\DAV\ServerPlugin
public function initialize(\Sabre\DAV\Server $server) {
$server->xmlNamespaces[self::NS_OWNCLOUD] = 'oc';
- $server->protectedProperties[] = '{' . self::NS_OWNCLOUD . '}id';
- $server->protectedProperties[] = '{' . self::NS_OWNCLOUD . '}permissions';
- $server->protectedProperties[] = '{' . self::NS_OWNCLOUD . '}size';
- $server->protectedProperties[] = '{' . self::NS_OWNCLOUD . '}downloadURL';
+ $server->protectedProperties[] = self::FILEID_PROPERTYNAME;
+ $server->protectedProperties[] = self::PERMISSIONS_PROPERTYNAME;
+ $server->protectedProperties[] = self::SIZE_PROPERTYNAME;
+ $server->protectedProperties[] = self::DOWNLOADURL_PROPERTYNAME;
+
+ // normally these cannot be changed (RFC4918), but we want them modifiable through PROPPATCH
+ $allowedProperties = ['{DAV:}getetag', '{DAV:}getlastmodified'];
+ $server->protectedProperties = array_diff($server->protectedProperties, $allowedProperties);
$this->server = $server;
- $this->server->subscribeEvent('beforeGetProperties', array($this, 'beforeGetProperties'));
- $this->server->subscribeEvent('afterBind', array($this, 'sendFileIdHeader'));
- $this->server->subscribeEvent('afterWriteContent', array($this, 'sendFileIdHeader'));
+ $this->server->on('propFind', array($this, 'handleGetProperties'));
+ $this->server->on('propPatch', array($this, 'handleUpdateProperties'));
+ $this->server->on('afterBind', array($this, 'sendFileIdHeader'));
+ $this->server->on('afterWriteContent', array($this, 'sendFileIdHeader'));
+ $this->server->on('beforeMethod:GET', array($this, 'handleRangeHeaders'));
}
/**
* Adds all ownCloud-specific properties
*
- * @param string $path
+ * @param PropFind $propFind
* @param \Sabre\DAV\INode $node
- * @param array $requestedProperties
- * @param array $returnedProperties
* @return void
*/
- public function beforeGetProperties($path, \Sabre\DAV\INode $node, array &$requestedProperties, array &$returnedProperties) {
+ public function handleGetProperties(PropFind $propFind, \Sabre\DAV\INode $node) {
- if ($node instanceof OC_Connector_Sabre_Node) {
+ if ($node instanceof \OC\Connector\Sabre\Node) {
- $fileIdPropertyName = '{' . self::NS_OWNCLOUD . '}id';
- $permissionsPropertyName = '{' . self::NS_OWNCLOUD . '}permissions';
- if (array_search($fileIdPropertyName, $requestedProperties)) {
- unset($requestedProperties[array_search($fileIdPropertyName, $requestedProperties)]);
- }
- if (array_search($permissionsPropertyName, $requestedProperties)) {
- unset($requestedProperties[array_search($permissionsPropertyName, $requestedProperties)]);
- }
+ $propFind->handle(self::FILEID_PROPERTYNAME, function() use ($node) {
+ return $node->getFileId();
+ });
- /** @var $node OC_Connector_Sabre_Node */
- $fileId = $node->getFileId();
- if (!is_null($fileId)) {
- $returnedProperties[200][$fileIdPropertyName] = $fileId;
- }
+ $propFind->handle(self::PERMISSIONS_PROPERTYNAME, function() use ($node) {
+ return $node->getDavPermissions();
+ });
- $permissions = $node->getDavPermissions();
- if (!is_null($permissions)) {
- $returnedProperties[200][$permissionsPropertyName] = $permissions;
- }
+ $propFind->handle(self::GETETAG_PROPERTYNAME, function() use ($node) {
+ return $node->getEtag();
+ });
}
- if ($node instanceof OC_Connector_Sabre_File) {
- /** @var $node OC_Connector_Sabre_File */
- $directDownloadUrl = $node->getDirectDownload();
- if (isset($directDownloadUrl['url'])) {
- $directDownloadUrlPropertyName = '{' . self::NS_OWNCLOUD . '}downloadURL';
- $returnedProperties[200][$directDownloadUrlPropertyName] = $directDownloadUrl['url'];
- }
+ if ($node instanceof \OC\Connector\Sabre\File) {
+ $propFind->handle(self::DOWNLOADURL_PROPERTYNAME, function() use ($node) {
+ /** @var $node \OC\Connector\Sabre\File */
+ $directDownloadUrl = $node->getDirectDownload();
+ if (isset($directDownloadUrl['url'])) {
+ return $directDownloadUrl['url'];
+ }
+ return false;
+ });
}
- if ($node instanceof OC_Connector_Sabre_Directory) {
- $sizePropertyName = '{' . self::NS_OWNCLOUD . '}size';
-
- /** @var $node OC_Connector_Sabre_Directory */
- $returnedProperties[200][$sizePropertyName] = $node->getSize();
+ if ($node instanceof \OC\Connector\Sabre\Directory) {
+ $propFind->handle(self::SIZE_PROPERTYNAME, function() use ($node) {
+ return $node->getSize();
+ });
}
}
/**
+ * Update ownCloud-specific properties
+ *
+ * @param string $path
+ * @param PropPatch $propPatch
+ *
+ * @return void
+ */
+ public function handleUpdateProperties($path, PropPatch $propPatch) {
+ $propPatch->handle(self::GETLASTMODIFIED_PROPERTYNAME, function($time) use ($path) {
+ if (empty($time)) {
+ return false;
+ }
+ $node = $this->tree->getNodeForPath($path);
+ if (is_null($node)) {
+ return 404;
+ }
+ $node->touch($time);
+ return true;
+ });
+ $propPatch->handle(self::GETETAG_PROPERTYNAME, function($etag) use ($path) {
+ if (empty($etag)) {
+ return false;
+ }
+ $node = $this->tree->getNodeForPath($path);
+ if (is_null($node)) {
+ return 404;
+ }
+ if ($node->setEtag($etag) !== -1) {
+ return true;
+ }
+ return false;
+ });
+ }
+
+ /**
* @param string $filePath
* @param \Sabre\DAV\INode $node
* @throws \Sabre\DAV\Exception\BadRequest
@@ -117,8 +149,8 @@ class OC_Connector_Sabre_FilesPlugin extends \Sabre\DAV\ServerPlugin
public function sendFileIdHeader($filePath, \Sabre\DAV\INode $node = null) {
// chunked upload handling
if (isset($_SERVER['HTTP_OC_CHUNKED'])) {
- list($path, $name) = \Sabre\DAV\URLUtil::splitPath($filePath);
- $info = OC_FileChunking::decodeName($name);
+ list($path, $name) = \Sabre\HTTP\URLUtil::splitPath($filePath);
+ $info = \OC_FileChunking::decodeName($name);
if (!empty($info)) {
$filePath = $path . '/' . $info['name'];
}
@@ -129,7 +161,7 @@ class OC_Connector_Sabre_FilesPlugin extends \Sabre\DAV\ServerPlugin
return;
}
$node = $this->server->tree->getNodeForPath($filePath);
- if ($node instanceof OC_Connector_Sabre_Node) {
+ if ($node instanceof \OC\Connector\Sabre\Node) {
$fileId = $node->getFileId();
if (!is_null($fileId)) {
$this->server->httpResponse->setHeader('OC-FileId', $fileId);
@@ -137,4 +169,17 @@ class OC_Connector_Sabre_FilesPlugin extends \Sabre\DAV\ServerPlugin
}
}
+ /**
+ * Remove range headers if encryption is enabled.
+ *
+ * @param RequestInterface $request
+ * @param ResponseInterface $response
+ */
+ public function handleRangeHeaders(RequestInterface $request, ResponseInterface $response) {
+ if (\OC_App::isEnabled('files_encryption')) {
+ // encryption does not support range requests (yet)
+ $request->removeHeader('range');
+ }
+ }
+
}
diff --git a/lib/private/connector/sabre/locks.php b/lib/private/connector/sabre/locks.php
index ec14f1d71b5..a212c9597c4 100644
--- a/lib/private/connector/sabre/locks.php
+++ b/lib/private/connector/sabre/locks.php
@@ -1,29 +1,9 @@
<?php
-/**
- * @author Bart Visscher <bartv@thisnet.nl>
- * @author Felix Moeller <mail@felixmoeller.de>
- * @author Jakob Sack <mail@jakobsack.de>
- * @author Jörn Friedrich Dreyer <jfd@butonic.de>
- * @author Robin Appelman <icewind@owncloud.com>
- * @author Thomas Müller <thomas.mueller@tmit.eu>
- *
- * @copyright Copyright (c) 2015, ownCloud, Inc.
- * @license AGPL-3.0
- *
- * This code is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License, version 3,
- * along with this program. If not, see <http://www.gnu.org/licenses/>
- *
- */
-class OC_Connector_Sabre_Locks extends \Sabre\DAV\Locks\Backend\AbstractBackend {
+
+namespace OC\Connector\Sabre;
+
+
+class Locks extends \Sabre\DAV\Locks\Backend\AbstractBackend {
/**
* Returns a list of \Sabre\DAV\Locks_LockInfo objects
@@ -48,12 +28,12 @@ class OC_Connector_Sabre_Locks extends \Sabre\DAV\Locks\Backend\AbstractBackend
// nothing
$query = 'SELECT * FROM `*PREFIX*locks`'
.' WHERE `userid` = ? AND (`created` + `timeout`) > '.time().' AND (( `uri` = ?)';
- if (OC_Config::getValue( "dbtype") === 'oci') {
+ if (\OC_Config::getValue( "dbtype") === 'oci') {
//FIXME oracle hack: need to explicitly cast CLOB to CHAR for comparison
$query = 'SELECT * FROM `*PREFIX*locks`'
.' WHERE `userid` = ? AND (`created` + `timeout`) > '.time().' AND (( to_char(`uri`) = ?)';
}
- $params = array(OC_User::getUser(), $uri);
+ $params = array(\OC_User::getUser(), $uri);
// We need to check locks for every part in the uri.
$uriParts = explode('/', $uri);
@@ -68,7 +48,7 @@ class OC_Connector_Sabre_Locks extends \Sabre\DAV\Locks\Backend\AbstractBackend
if ($currentPath) $currentPath.='/';
$currentPath.=$part;
//FIXME oracle hack: need to explicitly cast CLOB to CHAR for comparison
- if (OC_Config::getValue( "dbtype") === 'oci') {
+ if (\OC_Config::getValue( "dbtype") === 'oci') {
$query.=' OR (`depth` != 0 AND to_char(`uri`) = ?)';
} else {
$query.=' OR (`depth` != 0 AND `uri` = ?)';
@@ -80,7 +60,7 @@ class OC_Connector_Sabre_Locks extends \Sabre\DAV\Locks\Backend\AbstractBackend
if ($returnChildLocks) {
//FIXME oracle hack: need to explicitly cast CLOB to CHAR for comparison
- if (OC_Config::getValue( "dbtype") === 'oci') {
+ if (\OC_Config::getValue( "dbtype") === 'oci') {
$query.=' OR (to_char(`uri`) LIKE ?)';
} else {
$query.=' OR (`uri` LIKE ?)';
@@ -90,7 +70,7 @@ class OC_Connector_Sabre_Locks extends \Sabre\DAV\Locks\Backend\AbstractBackend
}
$query.=')';
- $result = OC_DB::executeAudited( $query, $params );
+ $result = \OC_DB::executeAudited( $query, $params );
$lockList = array();
while( $row = $result->fetchRow()) {
@@ -138,22 +118,22 @@ class OC_Connector_Sabre_Locks extends \Sabre\DAV\Locks\Backend\AbstractBackend
$sql = 'UPDATE `*PREFIX*locks`'
.' SET `owner` = ?, `timeout` = ?, `scope` = ?, `depth` = ?, `uri` = ?, `created` = ?'
.' WHERE `userid` = ? AND `token` = ?';
- $result = OC_DB::executeAudited( $sql, array(
+ $result = \OC_DB::executeAudited( $sql, array(
$lockInfo->owner,
$lockInfo->timeout,
$lockInfo->scope,
$lockInfo->depth,
$uri,
$lockInfo->created,
- OC_User::getUser(),
+ \OC_User::getUser(),
$lockInfo->token)
);
} else {
$sql = 'INSERT INTO `*PREFIX*locks`'
.' (`userid`,`owner`,`timeout`,`scope`,`depth`,`uri`,`created`,`token`)'
.' VALUES (?,?,?,?,?,?,?,?)';
- $result = OC_DB::executeAudited( $sql, array(
- OC_User::getUser(),
+ $result = \OC_DB::executeAudited( $sql, array(
+ \OC_User::getUser(),
$lockInfo->owner,
$lockInfo->timeout,
$lockInfo->scope,
@@ -178,11 +158,11 @@ class OC_Connector_Sabre_Locks extends \Sabre\DAV\Locks\Backend\AbstractBackend
public function unlock($uri, \Sabre\DAV\Locks\LockInfo $lockInfo) {
$sql = 'DELETE FROM `*PREFIX*locks` WHERE `userid` = ? AND `uri` = ? AND `token` = ?';
- if (OC_Config::getValue( "dbtype") === 'oci') {
+ if (\OC_Config::getValue( "dbtype") === 'oci') {
//FIXME oracle hack: need to explicitly cast CLOB to CHAR for comparison
$sql = 'DELETE FROM `*PREFIX*locks` WHERE `userid` = ? AND to_char(`uri`) = ? AND `token` = ?';
}
- $result = OC_DB::executeAudited( $sql, array(OC_User::getUser(), $uri, $lockInfo->token));
+ $result = \OC_DB::executeAudited( $sql, array(\OC_User::getUser(), $uri, $lockInfo->token));
return $result === 1;
diff --git a/lib/private/connector/sabre/maintenanceplugin.php b/lib/private/connector/sabre/maintenanceplugin.php
index 3d4e19ec470..ff55cdceab6 100644
--- a/lib/private/connector/sabre/maintenanceplugin.php
+++ b/lib/private/connector/sabre/maintenanceplugin.php
@@ -1,25 +1,7 @@
<?php
-/**
- * @author Bart Visscher <bartv@thisnet.nl>
- * @author Thomas Müller <thomas.mueller@tmit.eu>
- *
- * @copyright Copyright (c) 2015, ownCloud, Inc.
- * @license AGPL-3.0
- *
- * This code is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License, version 3,
- * along with this program. If not, see <http://www.gnu.org/licenses/>
- *
- */
-class OC_Connector_Sabre_MaintenancePlugin extends \Sabre\DAV\ServerPlugin
+namespace OC\Connector\Sabre;
+
+class MaintenancePlugin extends \Sabre\DAV\ServerPlugin
{
/**
@@ -43,7 +25,7 @@ class OC_Connector_Sabre_MaintenancePlugin extends \Sabre\DAV\ServerPlugin
public function initialize(\Sabre\DAV\Server $server) {
$this->server = $server;
- $this->server->subscribeEvent('beforeMethod', array($this, 'checkMaintenanceMode'), 10);
+ $this->server->on('beforeMethod', array($this, 'checkMaintenanceMode'), 10);
}
/**
@@ -55,10 +37,10 @@ class OC_Connector_Sabre_MaintenancePlugin extends \Sabre\DAV\ServerPlugin
* @return bool
*/
public function checkMaintenanceMode() {
- if (OC_Config::getValue('maintenance', false)) {
+ if (\OC_Config::getValue('maintenance', false)) {
throw new \Sabre\DAV\Exception\ServiceUnavailable();
}
- if (OC::checkUpgrade(false)) {
+ if (\OC::checkUpgrade(false)) {
throw new \Sabre\DAV\Exception\ServiceUnavailable('Upgrade needed');
}
diff --git a/lib/private/connector/sabre/node.php b/lib/private/connector/sabre/node.php
index 7df4453cb25..8fee6a4eb4e 100644
--- a/lib/private/connector/sabre/node.php
+++ b/lib/private/connector/sabre/node.php
@@ -1,36 +1,4 @@
<?php
-/**
- * @author Arthur Schiwon <blizzz@owncloud.com>
- * @author Bart Visscher <bartv@thisnet.nl>
- * @author Björn Schießle <schiessle@owncloud.com>
- * @author Jakob Sack <mail@jakobsack.de>
- * @author Jörn Friedrich Dreyer <jfd@butonic.de>
- * @author Klaas Freitag <freitag@owncloud.com>
- * @author Markus Goetz <markus@woboq.com>
- * @author Morris Jobke <hey@morrisjobke.de>
- * @author Robin Appelman <icewind@owncloud.com>
- * @author Sam Tuke <mail@samtuke.com>
- * @author Thomas Müller <thomas.mueller@tmit.eu>
- * @author Vincent Petry <pvince81@owncloud.com>
- *
- * @copyright Copyright (c) 2015, ownCloud, Inc.
- * @license AGPL-3.0
- *
- * This code is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License, version 3,
- * along with this program. If not, see <http://www.gnu.org/licenses/>
- *
- */
-use Sabre\DAV\URLUtil;
-use OC\Connector\Sabre\TagList;
/**
* ownCloud
@@ -52,10 +20,10 @@ use OC\Connector\Sabre\TagList;
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
*/
-abstract class OC_Connector_Sabre_Node implements \Sabre\DAV\INode, \Sabre\DAV\IProperties {
- const GETETAG_PROPERTYNAME = '{DAV:}getetag';
- const LASTMODIFIED_PROPERTYNAME = '{DAV:}lastmodified';
+namespace OC\Connector\Sabre;
+
+abstract class Node implements \Sabre\DAV\INode {
/**
* Allow configuring the method used to generate Etags
*
@@ -111,6 +79,15 @@ abstract class OC_Connector_Sabre_Node implements \Sabre\DAV\INode, \Sabre\DAV\I
}
/**
+ * Returns the full path
+ *
+ * @return string
+ */
+ public function getPath() {
+ return $this->path;
+ }
+
+ /**
* Renames the node
* @param string $name The new name
* @throws \Sabre\DAV\Exception\BadRequest
@@ -123,23 +100,19 @@ abstract class OC_Connector_Sabre_Node implements \Sabre\DAV\INode, \Sabre\DAV\I
throw new \Sabre\DAV\Exception\Forbidden();
}
- list($parentPath,) = URLUtil::splitPath($this->path);
- list(, $newName) = URLUtil::splitPath($name);
+ list($parentPath,) = \Sabre\HTTP\URLUtil::splitPath($this->path);
+ list(, $newName) = \Sabre\HTTP\URLUtil::splitPath($name);
if (!\OCP\Util::isValidFileName($newName)) {
throw new \Sabre\DAV\Exception\BadRequest();
}
$newPath = $parentPath . '/' . $newName;
- $oldPath = $this->path;
$this->fileView->rename($this->path, $newPath);
$this->path = $newPath;
- $query = OC_DB::prepare('UPDATE `*PREFIX*properties` SET `propertypath` = ?'
- . ' WHERE `userid` = ? AND `propertypath` = ?');
- $query->execute(array($newPath, OC_User::getUser(), $oldPath));
$this->refreshInfo();
}
@@ -170,91 +143,38 @@ abstract class OC_Connector_Sabre_Node implements \Sabre\DAV\INode, \Sabre\DAV\I
}
/**
- * Updates properties on this node,
- * @see \Sabre\DAV\IProperties::updateProperties
- * @param array $properties
- * @return boolean
+ * Returns the ETag for a file
+ *
+ * An ETag is a unique identifier representing the current version of the
+ * file. If the file changes, the ETag MUST change. The ETag is an
+ * arbitrary string, but MUST be surrounded by double-quotes.
+ *
+ * Return null if the ETag can not effectively be determined
+ *
+ * @return string
*/
- public function updateProperties($properties) {
- $existing = $this->getProperties(array());
- foreach ($properties as $propertyName => $propertyValue) {
- // If it was null, we need to delete the property
- if (is_null($propertyValue)) {
- if (array_key_exists($propertyName, $existing)) {
- $query = OC_DB::prepare('DELETE FROM `*PREFIX*properties`'
- . ' WHERE `userid` = ? AND `propertypath` = ? AND `propertyname` = ?');
- $query->execute(array(OC_User::getUser(), $this->path, $propertyName));
- }
- } else {
- if (strcmp($propertyName, self::GETETAG_PROPERTYNAME) === 0) {
- \OC\Files\Filesystem::putFileInfo($this->path, array('etag' => $propertyValue));
- } elseif (strcmp($propertyName, self::LASTMODIFIED_PROPERTYNAME) === 0) {
- $this->touch($propertyValue);
- } else {
- if (!array_key_exists($propertyName, $existing)) {
- $query = OC_DB::prepare('INSERT INTO `*PREFIX*properties`'
- . ' (`userid`,`propertypath`,`propertyname`,`propertyvalue`) VALUES(?,?,?,?)');
- $query->execute(array(OC_User::getUser(), $this->path, $propertyName, $propertyValue));
- } else {
- $query = OC_DB::prepare('UPDATE `*PREFIX*properties` SET `propertyvalue` = ?'
- . ' WHERE `userid` = ? AND `propertypath` = ? AND `propertyname` = ?');
- $query->execute(array($propertyValue, OC_User::getUser(), $this->path, $propertyName));
- }
- }
- }
-
- }
- $this->setPropertyCache(null);
- return true;
+ public function getETag() {
+ return '"' . $this->info->getEtag() . '"';
}
/**
- * removes all properties for this node and user
+ * Sets the ETag
+ *
+ * @param string $etag
+ *
+ * @return int file id of updated file or -1 on failure
*/
- public function removeProperties() {
- $query = OC_DB::prepare('DELETE FROM `*PREFIX*properties`'
- . ' WHERE `userid` = ? AND `propertypath` = ?');
- $query->execute(array(OC_User::getUser(), $this->path));
-
- $this->setPropertyCache(null);
+ public function setETag($etag) {
+ return $this->fileView->putFileInfo($this->path, array('etag' => $etag));
}
/**
- * Returns a list of properties for this nodes.;
- * @param array $properties
- * @return array
- * @note The properties list is a list of propertynames the client
- * requested, encoded as xmlnamespace#tagName, for example:
- * http://www.example.org/namespace#author If the array is empty, all
- * properties should be returned
+ * Returns the size of the node, in bytes
+ *
+ * @return int|float
*/
- public function getProperties($properties) {
-
- if (is_null($this->property_cache)) {
- $sql = 'SELECT * FROM `*PREFIX*properties` WHERE `userid` = ? AND `propertypath` = ?';
- $result = OC_DB::executeAudited($sql, array(OC_User::getUser(), $this->path));
-
- $this->property_cache = array();
- while ($row = $result->fetchRow()) {
- $this->property_cache[$row['propertyname']] = $row['propertyvalue'];
- }
-
- $this->property_cache[self::GETETAG_PROPERTYNAME] = '"' . $this->info->getEtag() . '"';
- }
-
- // if the array was empty, we need to return everything
- if (count($properties) == 0) {
- return $this->property_cache;
- }
-
- $props = array();
- foreach ($properties as $property) {
- if (isset($this->property_cache[$property])) {
- $props[$property] = $this->property_cache[$property];
- }
- }
-
- return $props;
+ public function getSize() {
+ return $this->info->getSize();
}
/**
@@ -271,7 +191,7 @@ abstract class OC_Connector_Sabre_Node implements \Sabre\DAV\INode, \Sabre\DAV\I
*/
public function getFileId() {
if ($this->info->getId()) {
- $instanceId = OC_Util::getInstanceId();
+ $instanceId = \OC_Util::getInstanceId();
$id = sprintf('%08d', $this->info->getId());
return $id . $instanceId;
}
diff --git a/lib/private/connector/sabre/objecttree.php b/lib/private/connector/sabre/objecttree.php
index 8793b612936..585be637813 100644
--- a/lib/private/connector/sabre/objecttree.php
+++ b/lib/private/connector/sabre/objecttree.php
@@ -30,7 +30,7 @@ use OC\Files\Mount\MoveableMount;
use OCP\Files\StorageInvalidException;
use OCP\Files\StorageNotAvailableException;
-class ObjectTree extends \Sabre\DAV\ObjectTree {
+class ObjectTree extends \Sabre\DAV\Tree {
/**
* @var \OC\Files\View
@@ -44,8 +44,6 @@ class ObjectTree extends \Sabre\DAV\ObjectTree {
/**
* Creates the object
- *
- * This method expects the rootObject to be passed as a parameter
*/
public function __construct() {
}
@@ -62,6 +60,35 @@ class ObjectTree extends \Sabre\DAV\ObjectTree {
}
/**
+ * If the given path is a chunked file name, converts it
+ * to the real file name. Only applies if the OC-CHUNKED header
+ * is present.
+ *
+ * @param string $path chunk file path to convert
+ *
+ * @return string path to real file
+ */
+ private function resolveChunkFile($path) {
+ if (isset($_SERVER['HTTP_OC_CHUNKED'])) {
+ // resolve to real file name to find the proper node
+ list($dir, $name) = \Sabre\HTTP\URLUtil::splitPath($path);
+ if ($dir == '/' || $dir == '.') {
+ $dir = '';
+ }
+
+ $info = \OC_FileChunking::decodeName($name);
+ // only replace path if it was really the chunked file
+ if (isset($info['transferid'])) {
+ // getNodePath is called for multiple nodes within a chunk
+ // upload call
+ $path = $dir . '/' . $info['name'];
+ $path = ltrim($path, '/');
+ }
+ }
+ return $path;
+ }
+
+ /**
* Returns the INode object for the requested path
*
* @param string $path
@@ -102,12 +129,15 @@ class ObjectTree extends \Sabre\DAV\ObjectTree {
$info = null;
}
} else {
+ // resolve chunk file name to real name, if applicable
+ $path = $this->resolveChunkFile($path);
+
// read from cache
try {
$info = $this->fileView->getFileInfo($path);
} catch (StorageNotAvailableException $e) {
throw new \Sabre\DAV\Exception\ServiceUnavailable('Storage not available');
- } catch (StorageInvalidException $e){
+ } catch (StorageInvalidException $e) {
throw new \Sabre\DAV\Exception\NotFound('Storage ' . $path . ' is invalid');
}
}
@@ -117,9 +147,9 @@ class ObjectTree extends \Sabre\DAV\ObjectTree {
}
if ($info->getType() === 'dir') {
- $node = new \OC_Connector_Sabre_Directory($this->fileView, $info);
+ $node = new \OC\Connector\Sabre\Directory($this->fileView, $info);
} else {
- $node = new \OC_Connector_Sabre_File($this->fileView, $info);
+ $node = new \OC\Connector\Sabre\File($this->fileView, $info);
}
$this->cache[$path] = $node;
@@ -146,8 +176,8 @@ class ObjectTree extends \Sabre\DAV\ObjectTree {
if ($sourceNode instanceof \Sabre\DAV\ICollection and $this->nodeExists($destinationPath)) {
throw new \Sabre\DAV\Exception\Forbidden('Could not copy directory ' . $sourceNode . ', target exists');
}
- list($sourceDir,) = \Sabre\DAV\URLUtil::splitPath($sourcePath);
- list($destinationDir,) = \Sabre\DAV\URLUtil::splitPath($destinationPath);
+ list($sourceDir,) = \Sabre\HTTP\URLUtil::splitPath($sourcePath);
+ list($destinationDir,) = \Sabre\HTTP\URLUtil::splitPath($destinationPath);
$isMovableMount = false;
$sourceMount = $this->mountManager->find($this->fileView->getAbsolutePath($sourcePath));
@@ -183,12 +213,6 @@ class ObjectTree extends \Sabre\DAV\ObjectTree {
throw new \Sabre\DAV\Exception\ServiceUnavailable($e->getMessage());
}
- // update properties
- $query = \OC_DB::prepare('UPDATE `*PREFIX*properties` SET `propertypath` = ?'
- . ' WHERE `userid` = ? AND `propertypath` = ?');
- $query->execute(array(\OC\Files\Filesystem::normalizePath($destinationPath), \OC_User::getUser(),
- \OC\Files\Filesystem::normalizePath($sourcePath)));
-
$this->markDirty($sourceDir);
$this->markDirty($destinationDir);
@@ -229,7 +253,7 @@ class ObjectTree extends \Sabre\DAV\ObjectTree {
throw new \Sabre\DAV\Exception\ServiceUnavailable($e->getMessage());
}
- list($destinationDir,) = \Sabre\DAV\URLUtil::splitPath($destination);
+ list($destinationDir,) = \Sabre\HTTP\URLUtil::splitPath($destination);
$this->markDirty($destinationDir);
}
}
diff --git a/lib/private/connector/sabre/principal.php b/lib/private/connector/sabre/principal.php
index 917d9887393..06842cc7b90 100644
--- a/lib/private/connector/sabre/principal.php
+++ b/lib/private/connector/sabre/principal.php
@@ -30,6 +30,7 @@ namespace OC\Connector\Sabre;
use OCP\IUserManager;
use OCP\IConfig;
+use \Sabre\DAV\PropPatch;
class Principal implements \Sabre\DAVACL\PrincipalBackend\BackendInterface {
/** @var IConfig */
@@ -137,7 +138,7 @@ class Principal implements \Sabre\DAVACL\PrincipalBackend\BackendInterface {
* @throws \Sabre\DAV\Exception
*/
public function getGroupMembership($principal) {
- list($prefix, $name) = \Sabre\DAV\URLUtil::splitPath($principal);
+ list($prefix, $name) = \Sabre\HTTP\URLUtil::splitPath($principal);
$group_membership = array();
if ($prefix === 'principals') {
@@ -174,19 +175,28 @@ class Principal implements \Sabre\DAVACL\PrincipalBackend\BackendInterface {
/**
* @param string $path
- * @param array $mutations
+ * @param PropPatch $propPatch
* @return int
*/
- function updatePrincipal($path, $mutations) {
+ function updatePrincipal($path, PropPatch $propPatch) {
return 0;
}
/**
* @param string $prefixPath
* @param array $searchProperties
+ * @param string $test
* @return array
*/
- function searchPrincipals($prefixPath, array $searchProperties) {
+ function searchPrincipals($prefixPath, array $searchProperties, $test = 'allof') {
return [];
}
+
+ /**
+ * @param string $uri
+ * @return string
+ */
+ function findByUri($uri) {
+ return '';
+ }
}
diff --git a/lib/private/connector/sabre/quotaplugin.php b/lib/private/connector/sabre/quotaplugin.php
index 8601f8aada6..6c0f9f3f950 100644
--- a/lib/private/connector/sabre/quotaplugin.php
+++ b/lib/private/connector/sabre/quotaplugin.php
@@ -1,31 +1,6 @@
<?php
-/**
- * @author Felix Moeller <mail@felixmoeller.de>
- * @author Morris Jobke <hey@morrisjobke.de>
- * @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
- * @author scambra <sergio@entrecables.com>
- * @author Scrutinizer Auto-Fixer <auto-fixer@scrutinizer-ci.com>
- * @author Thomas Müller <thomas.mueller@tmit.eu>
- * @author Vincent Petry <pvince81@owncloud.com>
- *
- * @copyright Copyright (c) 2015, ownCloud, Inc.
- * @license AGPL-3.0
- *
- * This code is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License, version 3,
- * along with this program. If not, see <http://www.gnu.org/licenses/>
- *
- */
-use Sabre\DAV\URLUtil;
+
+namespace OC\Connector\Sabre;
/**
* This plugin check user quota and deny creating files when they exceeds the quota.
@@ -34,7 +9,7 @@ use Sabre\DAV\URLUtil;
* @copyright Copyright (C) 2012 entreCables S.L. All rights reserved.
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
*/
-class OC_Connector_Sabre_QuotaPlugin extends \Sabre\DAV\ServerPlugin {
+class QuotaPlugin extends \Sabre\DAV\ServerPlugin {
/**
* @var \OC\Files\View
@@ -70,8 +45,8 @@ class OC_Connector_Sabre_QuotaPlugin extends \Sabre\DAV\ServerPlugin {
$this->server = $server;
- $server->subscribeEvent('beforeWriteContent', array($this, 'checkQuota'), 10);
- $server->subscribeEvent('beforeCreateFile', array($this, 'checkQuota'), 10);
+ $server->on('beforeWriteContent', array($this, 'checkQuota'), 10);
+ $server->on('beforeCreateFile', array($this, 'checkQuota'), 10);
}
/**
@@ -88,11 +63,11 @@ class OC_Connector_Sabre_QuotaPlugin extends \Sabre\DAV\ServerPlugin {
if (substr($uri, 0, 1) !== '/') {
$uri = '/' . $uri;
}
- list($parentUri, $newName) = URLUtil::splitPath($uri);
+ list($parentUri, $newName) = \Sabre\HTTP\URLUtil::splitPath($uri);
$req = $this->server->httpRequest;
if ($req->getHeader('OC-Chunked')) {
- $info = OC_FileChunking::decodeName($newName);
- $chunkHandler = new OC_FileChunking($info);
+ $info = \OC_FileChunking::decodeName($newName);
+ $chunkHandler = new \OC_FileChunking($info);
// subtract the already uploaded size to see whether
// there is still enough space for the remaining chunks
$length -= $chunkHandler->getCurrentSize();
diff --git a/lib/private/connector/sabre/request.php b/lib/private/connector/sabre/request.php
deleted file mode 100644
index 35fd671edd0..00000000000
--- a/lib/private/connector/sabre/request.php
+++ /dev/null
@@ -1,50 +0,0 @@
-<?php
-/**
- * @author Bart Visscher <bartv@thisnet.nl>
- * @author Lukas Reschke <lukas@owncloud.com>
- * @author Stefan Herbrechtsmeier <stefan@herbrechtsmeier.net>
- * @author Thomas Müller <thomas.mueller@tmit.eu>
- *
- * @copyright Copyright (c) 2015, ownCloud, Inc.
- * @license AGPL-3.0
- *
- * This code is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License, version 3,
- * along with this program. If not, see <http://www.gnu.org/licenses/>
- *
- */
-class OC_Connector_Sabre_Request extends \Sabre\HTTP\Request {
- /**
- * Returns the requested uri
- *
- * @return string
- */
- public function getUri() {
- return \OC::$server->getRequest()->getRequestUri();
- }
-
- /**
- * Returns a specific item from the _SERVER array.
- *
- * Do not rely on this feature, it is for internal use only.
- *
- * @param string $field
- * @return string
- */
- public function getRawServerValue($field) {
- if($field == 'REQUEST_URI') {
- return $this->getUri();
- }
- else{
- return isset($this->_SERVER[$field])?$this->_SERVER[$field]:null;
- }
- }
-}
diff --git a/lib/private/connector/sabre/server.php b/lib/private/connector/sabre/server.php
index f17f46a81cf..0dc81554d56 100644
--- a/lib/private/connector/sabre/server.php
+++ b/lib/private/connector/sabre/server.php
@@ -1,38 +1,13 @@
<?php
+namespace OC\Connector\Sabre;
+
/**
- * @author Andreas Fischer <bantu@owncloud.com>
- * @author Jörn Friedrich Dreyer <jfd@butonic.de>
- * @author scolebrook <scolebrook@mac.com>
- * @author Thomas Müller <thomas.mueller@tmit.eu>
- * @author Vincent Petry <pvince81@owncloud.com>
- *
- * @copyright Copyright (c) 2015, ownCloud, Inc.
- * @license AGPL-3.0
- *
- * This code is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
+ * Class \OC\Connector\Sabre\Server
*
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License, version 3,
- * along with this program. If not, see <http://www.gnu.org/licenses/>
+ * This class overrides some methods from @see \Sabre\DAV\Server.
*
*/
-class OC_Connector_Sabre_Server extends Sabre\DAV\Server {
-
- /**
- * @var string
- */
- private $overLoadedUri = null;
-
- /**
- * @var boolean
- */
- private $ignoreRangeHeader = false;
+class Server extends \Sabre\DAV\Server {
/**
* @see \Sabre\DAV\Server
@@ -40,261 +15,6 @@ class OC_Connector_Sabre_Server extends Sabre\DAV\Server {
public function __construct($treeOrNode = null) {
parent::__construct($treeOrNode);
self::$exposeVersion = false;
- }
-
- public function getRequestUri() {
-
- if (!is_null($this->overLoadedUri)) {
- return $this->overLoadedUri;
- }
-
- return parent::getRequestUri();
- }
-
- public function checkPreconditions($handleAsGET = false) {
- // chunked upload handling
- if (isset($_SERVER['HTTP_OC_CHUNKED'])) {
- $filePath = parent::getRequestUri();
- list($path, $name) = \Sabre\DAV\URLUtil::splitPath($filePath);
- $info = OC_FileChunking::decodeName($name);
- if (!empty($info)) {
- $filePath = $path . '/' . $info['name'];
- $this->overLoadedUri = $filePath;
- }
- }
-
- $result = parent::checkPreconditions($handleAsGET);
- $this->overLoadedUri = null;
- return $result;
- }
-
- public function getHTTPRange() {
- if ($this->ignoreRangeHeader) {
- return null;
- }
- return parent::getHTTPRange();
- }
-
- protected function httpGet($uri) {
- $range = $this->getHTTPRange();
-
- if (OC_App::isEnabled('files_encryption') && $range) {
- // encryption does not support range requests
- $this->ignoreRangeHeader = true;
- }
- return parent::httpGet($uri);
- }
-
- /**
- * @see \Sabre\DAV\Server
- */
- protected function httpPropfind($uri) {
-
- // $xml = new \Sabre\DAV\XMLReader(file_get_contents('php://input'));
- $requestedProperties = $this->parsePropFindRequest($this->httpRequest->getBody(true));
-
- $depth = $this->getHTTPDepth(1);
- // The only two options for the depth of a propfind is 0 or 1
- // if ($depth!=0) $depth = 1;
-
- $newProperties = $this->getPropertiesForPath($uri,$requestedProperties,$depth);
-
- // This is a multi-status response
- $this->httpResponse->sendStatus(207);
- $this->httpResponse->setHeader('Content-Type','application/xml; charset=utf-8');
- $this->httpResponse->setHeader('Vary','Brief,Prefer');
-
- // Normally this header is only needed for OPTIONS responses, however..
- // iCal seems to also depend on these being set for PROPFIND. Since
- // this is not harmful, we'll add it.
- $features = array('1','3', 'extended-mkcol');
- foreach($this->plugins as $plugin) {
- $features = array_merge($features,$plugin->getFeatures());
- }
-
- $this->httpResponse->setHeader('DAV',implode(', ',$features));
-
- $prefer = $this->getHTTPPrefer();
- $minimal = $prefer['return-minimal'];
-
- $data = $this->generateMultiStatus($newProperties, $minimal);
- $this->httpResponse->sendBody($data);
-
- }
-
- /**
- * Small helper to support PROPFIND with DEPTH_INFINITY.
- * @param string $path
- */
- private function addPathNodesRecursively(&$nodes, $path) {
- foreach($this->tree->getChildren($path) as $childNode) {
- $nodes[$path . '/' . $childNode->getName()] = $childNode;
- if ($childNode instanceof \Sabre\DAV\ICollection)
- $this->addPathNodesRecursively($nodes, $path . '/' . $childNode->getName());
- }
- }
-
- public function getPropertiesForPath($path, $propertyNames = array(), $depth = 0) {
-
- // if ($depth!=0) $depth = 1;
-
- $path = rtrim($path,'/');
-
- // This event allows people to intercept these requests early on in the
- // process.
- //
- // We're not doing anything with the result, but this can be helpful to
- // pre-fetch certain expensive live properties.
- $this->broadCastEvent('beforeGetPropertiesForPath', array($path, $propertyNames, $depth));
-
- $returnPropertyList = array();
-
- $parentNode = $this->tree->getNodeForPath($path);
- $nodes = array(
- $path => $parentNode
- );
- if ($depth==1 && $parentNode instanceof \Sabre\DAV\ICollection) {
- foreach($this->tree->getChildren($path) as $childNode)
- $nodes[$path . '/' . $childNode->getName()] = $childNode;
- } else if ($depth == self::DEPTH_INFINITY && $parentNode instanceof \Sabre\DAV\ICollection) {
- $this->addPathNodesRecursively($nodes, $path);
- }
-
- // If the propertyNames array is empty, it means all properties are requested.
- // We shouldn't actually return everything we know though, and only return a
- // sensible list.
- $allProperties = count($propertyNames)==0;
-
- foreach($nodes as $myPath=>$node) {
-
- $currentPropertyNames = $propertyNames;
-
- $newProperties = array(
- '200' => array(),
- '404' => array(),
- );
-
- if ($allProperties) {
- // Default list of propertyNames, when all properties were requested.
- $currentPropertyNames = array(
- '{DAV:}getlastmodified',
- '{DAV:}getcontentlength',
- '{DAV:}resourcetype',
- '{DAV:}quota-used-bytes',
- '{DAV:}quota-available-bytes',
- '{DAV:}getetag',
- '{DAV:}getcontenttype',
- );
- }
-
- // If the resourceType was not part of the list, we manually add it
- // and mark it for removal. We need to know the resourcetype in order
- // to make certain decisions about the entry.
- // WebDAV dictates we should add a / and the end of href's for collections
- $removeRT = false;
- if (!in_array('{DAV:}resourcetype',$currentPropertyNames)) {
- $currentPropertyNames[] = '{DAV:}resourcetype';
- $removeRT = true;
- }
-
- $result = $this->broadcastEvent('beforeGetProperties',array($myPath, $node, &$currentPropertyNames, &$newProperties));
- // If this method explicitly returned false, we must ignore this
- // node as it is inaccessible.
- if ($result===false) continue;
-
- if (count($currentPropertyNames) > 0) {
-
- if ($node instanceof \Sabre\DAV\IProperties) {
- $nodeProperties = $node->getProperties($currentPropertyNames);
-
- // The getProperties method may give us too much,
- // properties, in case the implementor was lazy.
- //
- // So as we loop through this list, we will only take the
- // properties that were actually requested and discard the
- // rest.
- foreach($currentPropertyNames as $k=>$currentPropertyName) {
- if (isset($nodeProperties[$currentPropertyName])) {
- unset($currentPropertyNames[$k]);
- $newProperties[200][$currentPropertyName] = $nodeProperties[$currentPropertyName];
- }
- }
-
- }
-
- }
-
- foreach($currentPropertyNames as $prop) {
-
- if (isset($newProperties[200][$prop])) continue;
-
- switch($prop) {
- case '{DAV:}getlastmodified' : if ($node->getLastModified()) $newProperties[200][$prop] = new \Sabre\DAV\Property\GetLastModified($node->getLastModified()); break;
- case '{DAV:}getcontentlength' :
- if ($node instanceof \Sabre\DAV\IFile) {
- $size = $node->getSize();
- if (!is_null($size)) {
- $newProperties[200][$prop] = 0 + $size;
- }
- }
- break;
- case '{DAV:}quota-used-bytes' :
- if ($node instanceof \Sabre\DAV\IQuota) {
- $quotaInfo = $node->getQuotaInfo();
- $newProperties[200][$prop] = $quotaInfo[0];
- }
- break;
- case '{DAV:}quota-available-bytes' :
- if ($node instanceof \Sabre\DAV\IQuota) {
- $quotaInfo = $node->getQuotaInfo();
- $newProperties[200][$prop] = $quotaInfo[1];
- }
- break;
- case '{DAV:}getetag' : if ($node instanceof \Sabre\DAV\IFile && $etag = $node->getETag()) $newProperties[200][$prop] = $etag; break;
- case '{DAV:}getcontenttype' : if ($node instanceof \Sabre\DAV\IFile && $ct = $node->getContentType()) $newProperties[200][$prop] = $ct; break;
- case '{DAV:}supported-report-set' :
- $reports = array();
- foreach($this->plugins as $plugin) {
- $reports = array_merge($reports, $plugin->getSupportedReportSet($myPath));
- }
- $newProperties[200][$prop] = new \Sabre\DAV\Property\SupportedReportSet($reports);
- break;
- case '{DAV:}resourcetype' :
- $newProperties[200]['{DAV:}resourcetype'] = new \Sabre\DAV\Property\ResourceType();
- foreach($this->resourceTypeMapping as $className => $resourceType) {
- if ($node instanceof $className) $newProperties[200]['{DAV:}resourcetype']->add($resourceType);
- }
- break;
-
- }
-
- // If we were unable to find the property, we will list it as 404.
- if (!$allProperties && !isset($newProperties[200][$prop])) $newProperties[404][$prop] = null;
-
- }
-
- $this->broadcastEvent('afterGetProperties',array(trim($myPath,'/'),&$newProperties, $node));
-
- $newProperties['href'] = trim($myPath,'/');
-
- // Its is a WebDAV recommendation to add a trailing slash to collectionnames.
- // Apple's iCal also requires a trailing slash for principals (rfc 3744), though this is non-standard.
- if ($myPath!='' && isset($newProperties[200]['{DAV:}resourcetype'])) {
- $rt = $newProperties[200]['{DAV:}resourcetype'];
- if ($rt->is('{DAV:}collection') || $rt->is('{DAV:}principal')) {
- $newProperties['href'] .='/';
- }
- }
-
- // If the resourcetype property was manually added to the requested property list,
- // we will remove it again.
- if ($removeRT) unset($newProperties[200]['{DAV:}resourcetype']);
-
- $returnPropertyList[] = $newProperties;
-
- }
-
- return $returnPropertyList;
-
+ $this->enablePropfindDepthInfinity = true;
}
}
diff --git a/lib/private/connector/sabre/taglist.php b/lib/private/connector/sabre/taglist.php
index 22b422c20b3..97f9e797579 100644
--- a/lib/private/connector/sabre/taglist.php
+++ b/lib/private/connector/sabre/taglist.php
@@ -83,9 +83,10 @@ class TagList extends DAV\Property {
* It will only decode tag values.
*
* @param \DOMElement $dom
+ * @param array $propertyMap
* @return \OC\Connector\Sabre\TagList
*/
- static function unserialize(\DOMElement $dom) {
+ static function unserialize(\DOMElement $dom, array $propertyMap) {
$tags = array();
foreach($dom->childNodes as $child) {
diff --git a/lib/private/connector/sabre/tagsplugin.php b/lib/private/connector/sabre/tagsplugin.php
index 87de08d333e..7756eb45bda 100644
--- a/lib/private/connector/sabre/tagsplugin.php
+++ b/lib/private/connector/sabre/tagsplugin.php
@@ -41,6 +41,9 @@ namespace OC\Connector\Sabre;
*
*/
+use \Sabre\DAV\PropFind;
+use \Sabre\DAV\PropPatch;
+
class TagsPlugin extends \Sabre\DAV\ServerPlugin
{
@@ -76,13 +79,19 @@ class TagsPlugin extends \Sabre\DAV\ServerPlugin
private $cachedTags;
/**
+ * @var \Sabre\DAV\Tree
+ */
+ private $tree;
+
+ /**
+ * @param \Sabre\DAV\Tree $tree tree
* @param \OCP\ITagManager $tagManager tag manager
*/
- public function __construct(\Sabre\DAV\ObjectTree $objectTree, \OCP\ITagManager $tagManager) {
- $this->objectTree = $objectTree;
+ public function __construct(\Sabre\DAV\Tree $tree, \OCP\ITagManager $tagManager) {
+ $this->tree = $tree;
$this->tagManager = $tagManager;
$this->tagger = null;
- $this->cachedTags = null;
+ $this->cachedTags = array();
}
/**
@@ -102,25 +111,8 @@ class TagsPlugin extends \Sabre\DAV\ServerPlugin
$server->propertyMap[self::TAGS_PROPERTYNAME] = 'OC\\Connector\\Sabre\\TagList';
$this->server = $server;
- $this->server->subscribeEvent('beforeGetProperties', array($this, 'beforeGetProperties'));
- $this->server->subscribeEvent('beforeGetPropertiesForPath', array($this, 'beforeGetPropertiesForPath'));
- $this->server->subscribeEvent('updateProperties', array($this, 'updateProperties'));
- }
-
- /**
- * Searches and removes a value from the given array
- *
- * @param array $requestedProps
- * @param string $propName to remove
- * @return boolean true if the property was present, false otherwise
- */
- private function findAndRemoveProperty(&$requestedProps, $propName) {
- $index = array_search($propName, $requestedProps);
- if ($index !== false) {
- unset($requestedProps[$index]);
- return true;
- }
- return false;
+ $this->server->on('propFind', array($this, 'handleGetProperties'));
+ $this->server->on('propPatch', array($this, 'handleUpdateProperties'));
}
/**
@@ -166,7 +158,10 @@ class TagsPlugin extends \Sabre\DAV\ServerPlugin
return $this->cachedTags[$fileId];
} else {
$tags = $this->getTagger()->getTagsForObjects(array($fileId));
- if ($tags) {
+ if ($tags !== false) {
+ if (empty($tags)) {
+ return array();
+ }
return current($tags);
}
}
@@ -200,108 +195,98 @@ class TagsPlugin extends \Sabre\DAV\ServerPlugin
}
/**
- * Pre-fetch tags info
+ * Adds tags and favorites properties to the response,
+ * if requested.
*
- * @param string $path
- * @param array $requestedProperties
- * @param integer $depth
+ * @param PropFind $propFind
+ * @param \Sabre\DAV\INode $node
* @return void
*/
- public function beforeGetPropertiesForPath(
- $path,
- array $requestedProperties,
- $depth
+ public function handleGetProperties(
+ PropFind $propFind,
+ \Sabre\DAV\INode $node
) {
- $node = $this->objectTree->getNodeForPath($path);
- if (!($node instanceof \OC_Connector_Sabre_Directory)) {
+ if (!($node instanceof \OC\Connector\Sabre\Node)) {
return;
}
- if ($this->findAndRemoveProperty($requestedProperties, self::TAGS_PROPERTYNAME)
- || $this->findAndRemoveProperty($requestedProperties, self::FAVORITE_PROPERTYNAME)
- ) {
- $fileIds = array();
+ // need prefetch ?
+ if ($node instanceof \OC\Connector\Sabre\Directory
+ && $propFind->getDepth() !== 0
+ && (!is_null($propFind->getStatus(self::TAGS_PROPERTYNAME))
+ || !is_null($propFind->getStatus(self::FAVORITE_PROPERTYNAME))
+ )) {
// note: pre-fetching only supported for depth <= 1
$folderContent = $node->getChildren();
- // TODO: refactor somehow with the similar array that is created
- // in getChildren()
+ $fileIds[] = (int)$node->getId();
foreach ($folderContent as $info) {
- $fileIds[] = $info->getId();
+ $fileIds[] = (int)$info->getId();
}
$tags = $this->getTagger()->getTagsForObjects($fileIds);
- if ($tags) {
- $this->cachedTags = $tags;
+ if ($tags === false) {
+ // the tags API returns false on error...
+ $tags = array();
}
- }
- }
- /**
- * Adds tags and favorites properties to the response,
- * if requested.
- *
- * @param string $path
- * @param \Sabre\DAV\INode $node
- * @param array $requestedProperties
- * @param array $returnedProperties
- * @return void
- */
- public function beforeGetProperties(
- $path,
- \Sabre\DAV\INode $node,
- array &$requestedProperties,
- array &$returnedProperties
- ) {
- if (!($node instanceof \OC_Connector_Sabre_Node)) {
- return;
+ $this->cachedTags = $this->cachedTags + $tags;
+ $emptyFileIds = array_diff($fileIds, array_keys($tags));
+ // also cache the ones that were not found
+ foreach ($emptyFileIds as $fileId) {
+ $this->cachedTags[$fileId] = [];
+ }
}
$tags = null;
$isFav = null;
- if ($this->findAndRemoveProperty($requestedProperties, self::TAGS_PROPERTYNAME)) {
+
+ $propFind->handle(self::TAGS_PROPERTYNAME, function() use ($tags, &$isFav, $node) {
list($tags, $isFav) = $this->getTagsAndFav($node->getId());
- $returnedProperties[200][self::TAGS_PROPERTYNAME] = new TagList($tags);
- }
- if ($this->findAndRemoveProperty($requestedProperties, self::FAVORITE_PROPERTYNAME)) {
- if (is_null($tags)) {
- list($tags, $isFav) = $this->getTagsAndFav($node->getId());
+ return new TagList($tags);
+ });
+
+ $propFind->handle(self::FAVORITE_PROPERTYNAME, function() use ($isFav, $node) {
+ if (is_null($isFav)) {
+ list(, $isFav) = $this->getTagsAndFav($node->getId());
}
- $returnedProperties[200][self::FAVORITE_PROPERTYNAME] = $isFav;
- }
+ return $isFav;
+ });
}
/**
* Updates tags and favorites properties, if applicable.
*
* @param string $path
- * @param \Sabre\DAV\INode $node
- * @param array $requestedProperties
- * @param array $returnedProperties
- * @return bool success status
+ * @param PropPatch $propPatch
+ *
+ * @return void
*/
- public function updateProperties(array &$properties, array &$result, \Sabre\DAV\INode $node) {
- if (!($node instanceof \OC_Connector_Sabre_Node)) {
- return;
- }
+ public function handleUpdateProperties($path, PropPatch $propPatch) {
+ $propPatch->handle(self::TAGS_PROPERTYNAME, function($tagList) use ($path) {
+ $node = $this->tree->getNodeForPath($path);
+ if (is_null($node)) {
+ return 404;
+ }
+ $this->updateTags($node->getId(), $tagList->getTags());
+ return true;
+ });
- $fileId = $node->getId();
- if (isset($properties[self::TAGS_PROPERTYNAME])) {
- $tagsProp = $properties[self::TAGS_PROPERTYNAME];
- unset($properties[self::TAGS_PROPERTYNAME]);
- $this->updateTags($fileId, $tagsProp->getTags());
- $result[200][self::TAGS_PROPERTYNAME] = new TagList($tagsProp->getTags());
- }
- if (isset($properties[self::FAVORITE_PROPERTYNAME])) {
- $favState = $properties[self::FAVORITE_PROPERTYNAME];
- unset($properties[self::FAVORITE_PROPERTYNAME]);
+ $propPatch->handle(self::FAVORITE_PROPERTYNAME, function($favState) use ($path) {
+ $node = $this->tree->getNodeForPath($path);
+ if (is_null($node)) {
+ return 404;
+ }
if ((int)$favState === 1 || $favState === 'true') {
- $favState = true;
- $this->getTagger()->tagAs($fileId, self::TAG_FAVORITE);
+ $this->getTagger()->tagAs($node->getId(), self::TAG_FAVORITE);
} else {
- $favState = false;
- $this->getTagger()->unTag($fileId, self::TAG_FAVORITE);
+ $this->getTagger()->unTag($node->getId(), self::TAG_FAVORITE);
}
- $result[200][self::FAVORITE_PROPERTYNAME] = $favState;
- }
- return true;
+
+ if (is_null($favState)) {
+ // confirm deletion
+ return 204;
+ }
+
+ return 200;
+ });
}
}
diff --git a/lib/private/files/storage/common.php b/lib/private/files/storage/common.php
index 56aa5328c78..d8df8f948cb 100644
--- a/lib/private/files/storage/common.php
+++ b/lib/private/files/storage/common.php
@@ -382,7 +382,7 @@ abstract class Common implements \OC\Files\Storage\Storage {
* @return string|false
*/
public function getETag($path) {
- $ETagFunction = \OC_Connector_Sabre_Node::$ETagFunction;
+ $ETagFunction = \OC\Connector\Sabre\Node::$ETagFunction;
if ($ETagFunction) {
$hash = call_user_func($ETagFunction, $path);
return $hash;
diff --git a/lib/private/files/storage/dav.php b/lib/private/files/storage/dav.php
index 0d70f612ec0..477a3b499c0 100644
--- a/lib/private/files/storage/dav.php
+++ b/lib/private/files/storage/dav.php
@@ -38,7 +38,7 @@ namespace OC\Files\Storage;
use OCP\Files\StorageInvalidException;
use OCP\Files\StorageNotAvailableException;
-use Sabre\DAV\Exception;
+use Sabre\DAV\ClientHttpException;
class DAV extends \OC\Files\Storage\Common {
protected $password;
@@ -104,6 +104,7 @@ class DAV extends \OC\Files\Storage\Common {
);
$this->client = new \Sabre\DAV\Client($settings);
+ $this->client->setThrowExceptions(true);
if ($this->secure === true && $this->certPath) {
$this->client->addTrustedCertificates($this->certPath);
@@ -152,9 +153,10 @@ class DAV extends \OC\Files\Storage\Common {
}
\OC\Files\Stream\Dir::register($id, $content);
return opendir('fakedir://' . $id);
- } catch (Exception\NotFound $e) {
- return false;
- } catch (\Sabre\DAV\Exception $e) {
+ } catch (ClientHttpException $e) {
+ if ($e->getHttpStatus() === 404) {
+ return false;
+ }
$this->convertSabreException($e);
return false;
} catch (\Exception $e) {
@@ -174,9 +176,10 @@ class DAV extends \OC\Files\Storage\Common {
$responseType = $response["{DAV:}resourcetype"]->resourceType;
}
return (count($responseType) > 0 and $responseType[0] == "{DAV:}collection") ? 'dir' : 'file';
- } catch (Exception\NotFound $e) {
- return false;
- } catch (\Sabre\DAV\Exception $e) {
+ } catch (ClientHttpException $e) {
+ if ($e->getHttpStatus() === 404) {
+ return false;
+ }
$this->convertSabreException($e);
return false;
} catch (\Exception $e) {
@@ -192,9 +195,10 @@ class DAV extends \OC\Files\Storage\Common {
try {
$this->client->propfind($this->encodePath($path), array('{DAV:}resourcetype'));
return true; //no 404 exception
- } catch (Exception\NotFound $e) {
- return false;
- } catch (\Sabre\DAV\Exception $e) {
+ } catch (ClientHttpException $e) {
+ if ($e->getHttpStatus() === 404) {
+ return false;
+ }
$this->convertSabreException($e);
return false;
} catch (\Exception $e) {
@@ -311,9 +315,10 @@ class DAV extends \OC\Files\Storage\Common {
if ($this->file_exists($path)) {
try {
$this->client->proppatch($this->encodePath($path), array('{DAV:}lastmodified' => $mtime));
- } catch (Exception\NotImplemented $e) {
- return false;
- } catch (\Sabre\DAV\Exception $e) {
+ } catch (ClientHttpException $e) {
+ if ($e->getHttpStatus() === 501) {
+ return false;
+ }
$this->convertSabreException($e);
return false;
} catch (\Exception $e) {
@@ -367,7 +372,7 @@ class DAV extends \OC\Files\Storage\Common {
$this->removeCachedFile($path1);
$this->removeCachedFile($path2);
return true;
- } catch (\Sabre\DAV\Exception $e) {
+ } catch (ClientHttpException $e) {
$this->convertSabreException($e);
return false;
} catch (\Exception $e) {
@@ -385,7 +390,7 @@ class DAV extends \OC\Files\Storage\Common {
$this->client->request('COPY', $path1, null, array('Destination' => $path2));
$this->removeCachedFile($path2);
return true;
- } catch (\Sabre\DAV\Exception $e) {
+ } catch (ClientHttpException $e) {
$this->convertSabreException($e);
return false;
} catch (\Exception $e) {
@@ -404,11 +409,12 @@ class DAV extends \OC\Files\Storage\Common {
'mtime' => strtotime($response['{DAV:}getlastmodified']),
'size' => (int)isset($response['{DAV:}getcontentlength']) ? $response['{DAV:}getcontentlength'] : 0,
);
- } catch (Exception\NotFound $e) {
- return array();
- } catch (\Sabre\DAV\Exception $e) {
+ } catch (ClientHttpException $e) {
+ if ($e->getHttpStatus() === 404) {
+ return array();
+ }
$this->convertSabreException($e);
- return false;
+ return array();
} catch (\Exception $e) {
// TODO: log for now, but in the future need to wrap/rethrow exception
\OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR);
@@ -433,9 +439,10 @@ class DAV extends \OC\Files\Storage\Common {
} else {
return false;
}
- } catch (Exception\NotFound $e) {
- return false;
- } catch (\Sabre\DAV\Exception $e) {
+ } catch (ClientHttpException $e) {
+ if ($e->getHttpStatus() === 404) {
+ return false;
+ }
$this->convertSabreException($e);
return false;
} catch (\Exception $e) {
@@ -478,16 +485,13 @@ class DAV extends \OC\Files\Storage\Common {
try {
$response = $this->client->request($method, $this->encodePath($path), $body);
return $response['statusCode'] == $expected;
- } catch (Exception\NotFound $e) {
- if ($method === 'DELETE') {
+ } catch (ClientHttpException $e) {
+ if ($e->getHttpStatus() === 404 && $method === 'DELETE') {
return false;
}
$this->convertSabreException($e);
return false;
- } catch (\Sabre\DAV\Exception $e) {
- $this->convertSabreException($e);
- return false;
} catch (\Exception $e) {
// TODO: log for now, but in the future need to wrap/rethrow exception
\OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR);
@@ -591,9 +595,10 @@ class DAV extends \OC\Files\Storage\Common {
$remoteMtime = strtotime($response['{DAV:}getlastmodified']);
return $remoteMtime > $time;
}
- } catch (Exception\NotFound $e) {
- return false;
} catch (Exception $e) {
+ if ($e->getHttpStatus() === 404) {
+ return false;
+ }
$this->convertSabreException($e);
return false;
}
@@ -603,19 +608,19 @@ class DAV extends \OC\Files\Storage\Common {
* Convert sabre DAV exception to a storage exception,
* then throw it
*
- * @param \Sabre\Dav\Exception $e sabre exception
+ * @param ClientException $e sabre exception
* @throws StorageInvalidException if the storage is invalid, for example
* when the authentication expired or is invalid
* @throws StorageNotAvailableException if the storage is not available,
* which might be temporary
*/
- private function convertSabreException(\Sabre\Dav\Exception $e) {
+ private function convertSabreException(ClientException $e) {
\OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR);
- if ($e instanceof \Sabre\DAV\Exception\NotAuthenticated) {
+ if ($e->getHttpStatus() === 401) {
// either password was changed or was invalid all along
throw new StorageInvalidException(get_class($e).': '.$e->getMessage());
- } else if ($e instanceof \Sabre\DAV\Exception\MethodNotAllowed) {
- // ignore exception, false will be returned
+ } else if ($e->getHttpStatus() === 405) {
+ // ignore exception for MethodNotAllowed, false will be returned
return;
}
diff --git a/lib/private/vobject/compoundproperty.php b/lib/private/vobject/compoundproperty.php
deleted file mode 100644
index aaeeeed527e..00000000000
--- a/lib/private/vobject/compoundproperty.php
+++ /dev/null
@@ -1,69 +0,0 @@
-<?php
-/**
- * @author Christopher Schäpers <kondou@ts.unde.re>
- * @author Thomas Tanghus <thomas@tanghus.net>
- *
- * @copyright Copyright (c) 2015, ownCloud, Inc.
- * @license AGPL-3.0
- *
- * This code is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License, version 3,
- * along with this program. If not, see <http://www.gnu.org/licenses/>
- *
- */
-namespace OC\VObject;
-
-/**
- * This class overrides \Sabre\VObject\Property::serialize() to not
- * double escape commas and semi-colons in compound properties.
-*/
-class CompoundProperty extends \Sabre\VObject\Property\Compound {
-
- /**
- * Turns the object back into a serialized blob.
- *
- * @return string
- */
- public function serialize() {
-
- $str = $this->name;
- if ($this->group) {
- $str = $this->group . '.' . $this->name;
- }
-
- foreach($this->parameters as $param) {
- $str.=';' . $param->serialize();
- }
- $src = array(
- "\n",
- );
- $out = array(
- '\n',
- );
- $str.=':' . str_replace($src, $out, $this->value);
-
- $out = '';
- while(strlen($str) > 0) {
- if (strlen($str) > 75) {
- $out .= mb_strcut($str, 0, 75, 'utf-8') . "\r\n";
- $str = ' ' . mb_strcut($str, 75, strlen($str), 'utf-8');
- } else {
- $out .= $str . "\r\n";
- $str = '';
- break;
- }
- }
-
- return $out;
-
- }
-
-}
diff --git a/lib/private/vobject/stringproperty.php b/lib/private/vobject/stringproperty.php
deleted file mode 100644
index a0911563061..00000000000
--- a/lib/private/vobject/stringproperty.php
+++ /dev/null
@@ -1,77 +0,0 @@
-<?php
-/**
- * @author Christopher Schäpers <kondou@ts.unde.re>
- * @author Thomas Tanghus <thomas@tanghus.net>
- *
- * @copyright Copyright (c) 2015, ownCloud, Inc.
- * @license AGPL-3.0
- *
- * This code is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License, version 3,
- * along with this program. If not, see <http://www.gnu.org/licenses/>
- *
- */
-namespace OC\VObject;
-
-/**
- * This class overrides \Sabre\VObject\Property::serialize() properly
- * escape commas and semi-colons in string properties.
-*/
-class StringProperty extends \Sabre\VObject\Property {
-
- /**
- * Turns the object back into a serialized blob.
- *
- * @return string
- */
- public function serialize() {
-
- $str = $this->name;
- if ($this->group) {
- $str = $this->group . '.' . $this->name;
- }
-
- foreach($this->parameters as $param) {
- $str.=';' . $param->serialize();
- }
-
- $src = array(
- '\\',
- "\n",
- ';',
- ',',
- );
- $out = array(
- '\\\\',
- '\n',
- '\;',
- '\,',
- );
- $value = strtr($this->value, array('\,' => ',', '\;' => ';', '\\\\' => '\\'));
- $str.=':' . str_replace($src, $out, $value);
-
- $out = '';
- while(strlen($str) > 0) {
- if (strlen($str) > 75) {
- $out .= mb_strcut($str, 0, 75, 'utf-8') . "\r\n";
- $str = ' ' . mb_strcut($str, 75, strlen($str), 'utf-8');
- } else {
- $out .= $str . "\r\n";
- $str = '';
- break;
- }
- }
-
- return $out;
-
- }
-
-}
diff --git a/tests/lib/connector/sabre/custompropertiesbackend.php b/tests/lib/connector/sabre/custompropertiesbackend.php
new file mode 100644
index 00000000000..ee0c3c4e53d
--- /dev/null
+++ b/tests/lib/connector/sabre/custompropertiesbackend.php
@@ -0,0 +1,248 @@
+<?php
+
+namespace Tests\Connector\Sabre;
+
+/**
+ * Copyright (c) 2015 Vincent Petry <pvince81@owncloud.com>
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+class CustomPropertiesBackend extends \Test\TestCase {
+
+ /**
+ * @var \Sabre\DAV\Server
+ */
+ private $server;
+
+ /**
+ * @var \Sabre\DAV\ObjectTree
+ */
+ private $tree;
+
+ /**
+ * @var \OC\Connector\Sabre\CustomPropertiesBackend
+ */
+ private $plugin;
+
+ /**
+ * @var \OCP\IUser
+ */
+ private $user;
+
+ public function setUp() {
+ parent::setUp();
+ $this->server = new \Sabre\DAV\Server();
+ $this->tree = $this->getMockBuilder('\Sabre\DAV\Tree')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $userId = $this->getUniqueID('testcustompropertiesuser');
+
+ $this->user = $this->getMock('\OCP\IUser');
+ $this->user->expects($this->any())
+ ->method('getUID')
+ ->will($this->returnValue($userId));
+
+ $this->plugin = new \OC\Connector\Sabre\CustomPropertiesBackend(
+ $this->tree,
+ \OC::$server->getDatabaseConnection(),
+ $this->user
+ );
+ }
+
+ public function tearDown() {
+ $connection = \OC::$server->getDatabaseConnection();
+ $deleteStatement = $connection->prepare(
+ 'DELETE FROM `*PREFIX*properties`' .
+ ' WHERE `userid` = ?'
+ );
+ $deleteStatement->execute(
+ array(
+ $this->user->getUID(),
+ )
+ );
+ $deleteStatement->closeCursor();
+ }
+
+ private function createTestNode($class) {
+ $node = $this->getMockBuilder($class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $node->expects($this->any())
+ ->method('getId')
+ ->will($this->returnValue(123));
+
+ $node->expects($this->any())
+ ->method('getPath')
+ ->will($this->returnValue('/dummypath'));
+
+ return $node;
+ }
+
+ private function applyDefaultProps($path = '/dummypath') {
+ // properties to set
+ $propPatch = new \Sabre\DAV\PropPatch(array(
+ 'customprop' => 'value1',
+ 'customprop2' => 'value2',
+ ));
+
+ $this->plugin->propPatch(
+ $path,
+ $propPatch
+ );
+
+ $propPatch->commit();
+
+ $this->assertEmpty($propPatch->getRemainingMutations());
+
+ $result = $propPatch->getResult();
+ $this->assertEquals(200, $result['customprop']);
+ $this->assertEquals(200, $result['customprop2']);
+ }
+
+ /**
+ * Test setting/getting properties
+ */
+ public function testSetGetPropertiesForFile() {
+ $node = $this->createTestNode('\OC\Connector\Sabre\File');
+ $this->tree->expects($this->any())
+ ->method('getNodeForPath')
+ ->with('/dummypath')
+ ->will($this->returnValue($node));
+
+ $this->applyDefaultProps();
+
+ $propFind = new \Sabre\DAV\PropFind(
+ '/dummypath',
+ array(
+ 'customprop',
+ 'customprop2',
+ 'unsetprop',
+ ),
+ 0
+ );
+
+ $this->plugin->propFind(
+ '/dummypath',
+ $propFind
+ );
+
+ $this->assertEquals('value1', $propFind->get('customprop'));
+ $this->assertEquals('value2', $propFind->get('customprop2'));
+ $this->assertEquals(array('unsetprop'), $propFind->get404Properties());
+ }
+
+ /**
+ * Test getting properties from directory
+ */
+ public function testGetPropertiesForDirectory() {
+ $rootNode = $this->createTestNode('\OC\Connector\Sabre\Directory');
+
+ $nodeSub = $this->getMockBuilder('\OC\Connector\Sabre\File')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $nodeSub->expects($this->any())
+ ->method('getId')
+ ->will($this->returnValue(456));
+
+ $nodeSub->expects($this->any())
+ ->method('getPath')
+ ->will($this->returnValue('/dummypath/test.txt'));
+
+ $rootNode->expects($this->once())
+ ->method('getChildren')
+ ->will($this->returnValue(array($nodeSub)));
+
+ $this->tree->expects($this->at(0))
+ ->method('getNodeForPath')
+ ->with('/dummypath')
+ ->will($this->returnValue($rootNode));
+
+ $this->tree->expects($this->at(1))
+ ->method('getNodeForPath')
+ ->with('/dummypath/test.txt')
+ ->will($this->returnValue($nodeSub));
+
+ $this->tree->expects($this->at(2))
+ ->method('getNodeForPath')
+ ->with('/dummypath')
+ ->will($this->returnValue($rootNode));
+
+ $this->tree->expects($this->at(3))
+ ->method('getNodeForPath')
+ ->with('/dummypath/test.txt')
+ ->will($this->returnValue($nodeSub));
+
+ $this->applyDefaultProps('/dummypath');
+ $this->applyDefaultProps('/dummypath/test.txt');
+
+ $propNames = array(
+ 'customprop',
+ 'customprop2',
+ 'unsetprop',
+ );
+
+ $propFindRoot = new \Sabre\DAV\PropFind(
+ '/dummypath',
+ $propNames,
+ 1
+ );
+
+ $propFindSub = new \Sabre\DAV\PropFind(
+ '/dummypath/test.txt',
+ $propNames,
+ 0
+ );
+
+ $this->plugin->propFind(
+ '/dummypath',
+ $propFindRoot
+ );
+
+ $this->plugin->propFind(
+ '/dummypath/test.txt',
+ $propFindSub
+ );
+
+ // TODO: find a way to assert that no additional SQL queries were
+ // run while doing the second propFind
+
+ $this->assertEquals('value1', $propFindRoot->get('customprop'));
+ $this->assertEquals('value2', $propFindRoot->get('customprop2'));
+ $this->assertEquals(array('unsetprop'), $propFindRoot->get404Properties());
+
+ $this->assertEquals('value1', $propFindSub->get('customprop'));
+ $this->assertEquals('value2', $propFindSub->get('customprop2'));
+ $this->assertEquals(array('unsetprop'), $propFindSub->get404Properties());
+ }
+
+ /**
+ * Test delete property
+ */
+ public function testDeleteProperty() {
+ $node = $this->createTestNode('\OC\Connector\Sabre\File');
+ $this->tree->expects($this->any())
+ ->method('getNodeForPath')
+ ->with('/dummypath')
+ ->will($this->returnValue($node));
+
+ $this->applyDefaultProps();
+
+ $propPatch = new \Sabre\DAV\PropPatch(array(
+ 'customprop' => null,
+ ));
+
+ $this->plugin->propPatch(
+ '/dummypath',
+ $propPatch
+ );
+
+ $propPatch->commit();
+
+ $this->assertEmpty($propPatch->getRemainingMutations());
+
+ $result = $propPatch->getResult();
+ $this->assertEquals(204, $result['customprop']);
+ }
+}
diff --git a/tests/lib/connector/sabre/directory.php b/tests/lib/connector/sabre/directory.php
index 599a6ca3f7c..e7fbd1d27b6 100644
--- a/tests/lib/connector/sabre/directory.php
+++ b/tests/lib/connector/sabre/directory.php
@@ -27,7 +27,7 @@ class Test_OC_Connector_Sabre_Directory extends \Test\TestCase {
->method('getPath')
->will($this->returnValue(''));
- return new OC_Connector_Sabre_Directory($this->view, $this->info);
+ return new \OC\Connector\Sabre\Directory($this->view, $this->info);
}
/**
@@ -131,7 +131,7 @@ class Test_OC_Connector_Sabre_Directory extends \Test\TestCase {
->method('getRelativePath')
->will($this->returnValue(''));
- $dir = new OC_Connector_Sabre_Directory($this->view, $this->info);
+ $dir = new \OC\Connector\Sabre\Directory($this->view, $this->info);
$nodes = $dir->getChildren();
$this->assertEquals(2, count($nodes));
@@ -139,21 +139,6 @@ class Test_OC_Connector_Sabre_Directory extends \Test\TestCase {
// calling a second time just returns the cached values,
// does not call getDirectoryContents again
$nodes = $dir->getChildren();
-
- $properties = array('testprop', OC_Connector_Sabre_Node::GETETAG_PROPERTYNAME);
- $this->assertEquals(2, count($nodes));
- $this->assertEquals(
- array(
- OC_Connector_Sabre_Node::GETETAG_PROPERTYNAME => '"abc"'
- ),
- $nodes[0]->getProperties($properties)
- );
- $this->assertEquals(
- array(
- OC_Connector_Sabre_Node::GETETAG_PROPERTYNAME => '"def"'
- ),
- $nodes[1]->getProperties($properties)
- );
}
public function testGetQuotaInfo() {
@@ -182,7 +167,7 @@ class Test_OC_Connector_Sabre_Directory extends \Test\TestCase {
->method('getStorage')
->will($this->returnValue($storage));
- $dir = new OC_Connector_Sabre_Directory($this->view, $this->info);
+ $dir = new \OC\Connector\Sabre\Directory($this->view, $this->info);
$this->assertEquals([200, 800], $dir->getQuotaInfo()); //200 used, 800 free
}
}
diff --git a/tests/lib/connector/sabre/file.php b/tests/lib/connector/sabre/file.php
index 33dc78f87d8..2ef5fd794be 100644
--- a/tests/lib/connector/sabre/file.php
+++ b/tests/lib/connector/sabre/file.php
@@ -26,7 +26,7 @@ class Test_OC_Connector_Sabre_File extends \Test\TestCase {
'permissions'=>\OCP\Constants::PERMISSION_ALL
), null);
- $file = new OC_Connector_Sabre_File($view, $info);
+ $file = new \OC\Connector\Sabre\File($view, $info);
// action
$file->put('test data');
@@ -52,7 +52,7 @@ class Test_OC_Connector_Sabre_File extends \Test\TestCase {
'permissions' => \OCP\Constants::PERMISSION_ALL
), null);
- $file = new OC_Connector_Sabre_File($view, $info);
+ $file = new \OC\Connector\Sabre\File($view, $info);
$this->assertNotEmpty($file->put('test data'));
}
@@ -86,7 +86,7 @@ class Test_OC_Connector_Sabre_File extends \Test\TestCase {
'permissions' => \OCP\Constants::PERMISSION_ALL
), null);
- $file = new OC_Connector_Sabre_File($view, $info);
+ $file = new \OC\Connector\Sabre\File($view, $info);
// action
$file->put('test data');
@@ -109,7 +109,7 @@ class Test_OC_Connector_Sabre_File extends \Test\TestCase {
$info = new \OC\Files\FileInfo('/super*star.txt', null, null, array(
'permissions' => \OCP\Constants::PERMISSION_ALL
), null);
- $file = new OC_Connector_Sabre_File($view, $info);
+ $file = new \OC\Connector\Sabre\File($view, $info);
// action
$file->put('test data');
@@ -130,7 +130,7 @@ class Test_OC_Connector_Sabre_File extends \Test\TestCase {
$info = new \OC\Files\FileInfo('/super*star.txt', null, null, array(
'permissions' => \OCP\Constants::PERMISSION_ALL
), null);
- $file = new OC_Connector_Sabre_File($view, $info);
+ $file = new \OC\Connector\Sabre\File($view, $info);
$file->setName('/super*star.txt');
}
@@ -163,7 +163,7 @@ class Test_OC_Connector_Sabre_File extends \Test\TestCase {
'permissions' => \OCP\Constants::PERMISSION_ALL
), null);
- $file = new OC_Connector_Sabre_File($view, $info);
+ $file = new \OC\Connector\Sabre\File($view, $info);
// action
$file->put('test data');
@@ -185,7 +185,7 @@ class Test_OC_Connector_Sabre_File extends \Test\TestCase {
'permissions' => \OCP\Constants::PERMISSION_ALL
), null);
- $file = new OC_Connector_Sabre_File($view, $info);
+ $file = new \OC\Connector\Sabre\File($view, $info);
// action
$file->delete();
@@ -203,7 +203,7 @@ class Test_OC_Connector_Sabre_File extends \Test\TestCase {
'permissions' => 0
), null);
- $file = new OC_Connector_Sabre_File($view, $info);
+ $file = new \OC\Connector\Sabre\File($view, $info);
// action
$file->delete();
@@ -226,7 +226,7 @@ class Test_OC_Connector_Sabre_File extends \Test\TestCase {
'permissions' => \OCP\Constants::PERMISSION_ALL
), null);
- $file = new OC_Connector_Sabre_File($view, $info);
+ $file = new \OC\Connector\Sabre\File($view, $info);
// action
$file->delete();
diff --git a/tests/lib/connector/sabre/filesplugin.php b/tests/lib/connector/sabre/filesplugin.php
new file mode 100644
index 00000000000..54d43d66dda
--- /dev/null
+++ b/tests/lib/connector/sabre/filesplugin.php
@@ -0,0 +1,174 @@
+<?php
+
+namespace Tests\Connector\Sabre;
+
+/**
+ * Copyright (c) 2015 Vincent Petry <pvince81@owncloud.com>
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+class FilesPlugin extends \Test\TestCase {
+ const GETETAG_PROPERTYNAME = \OC\Connector\Sabre\FilesPlugin::GETETAG_PROPERTYNAME;
+ const FILEID_PROPERTYNAME = \OC\Connector\Sabre\FilesPlugin::FILEID_PROPERTYNAME;
+ const SIZE_PROPERTYNAME = \OC\Connector\Sabre\FilesPlugin::SIZE_PROPERTYNAME;
+ const PERMISSIONS_PROPERTYNAME = \OC\Connector\Sabre\FilesPlugin::PERMISSIONS_PROPERTYNAME;
+ const GETLASTMODIFIED_PROPERTYNAME = \OC\Connector\Sabre\FilesPlugin::GETLASTMODIFIED_PROPERTYNAME;
+ const DOWNLOADURL_PROPERTYNAME = \OC\Connector\Sabre\FilesPlugin::DOWNLOADURL_PROPERTYNAME;
+
+ /**
+ * @var \Sabre\DAV\Server
+ */
+ private $server;
+
+ /**
+ * @var \Sabre\DAV\ObjectTree
+ */
+ private $tree;
+
+ /**
+ * @var \OC\Connector\Sabre\FilesPlugin
+ */
+ private $plugin;
+
+ public function setUp() {
+ parent::setUp();
+ $this->server = new \Sabre\DAV\Server();
+ $this->tree = $this->getMockBuilder('\Sabre\DAV\Tree')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->plugin = new \OC\Connector\Sabre\FilesPlugin($this->tree);
+ $this->plugin->initialize($this->server);
+ }
+
+ private function createTestNode($class) {
+ $node = $this->getMockBuilder($class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $node->expects($this->any())
+ ->method('getId')
+ ->will($this->returnValue(123));
+
+ $this->tree->expects($this->any())
+ ->method('getNodeForPath')
+ ->with('/dummypath')
+ ->will($this->returnValue($node));
+
+ $node->expects($this->any())
+ ->method('getFileId')
+ ->will($this->returnValue(123));
+ $node->expects($this->any())
+ ->method('getEtag')
+ ->will($this->returnValue('"abc"'));
+ $node->expects($this->any())
+ ->method('getDavPermissions')
+ ->will($this->returnValue('R'));
+
+ return $node;
+ }
+
+ /**
+ */
+ public function testGetPropertiesForFile() {
+ $node = $this->createTestNode('\OC\Connector\Sabre\File');
+
+ $propFind = new \Sabre\DAV\PropFind(
+ '/dummyPath',
+ array(
+ self::GETETAG_PROPERTYNAME,
+ self::FILEID_PROPERTYNAME,
+ self::SIZE_PROPERTYNAME,
+ self::PERMISSIONS_PROPERTYNAME,
+ self::DOWNLOADURL_PROPERTYNAME,
+ ),
+ 0
+ );
+
+ $node->expects($this->once())
+ ->method('getDirectDownload')
+ ->will($this->returnValue(array('url' => 'http://example.com/')));
+ $node->expects($this->never())
+ ->method('getSize');
+
+ $this->plugin->handleGetProperties(
+ $propFind,
+ $node
+ );
+
+ $this->assertEquals('"abc"', $propFind->get(self::GETETAG_PROPERTYNAME));
+ $this->assertEquals(123, $propFind->get(self::FILEID_PROPERTYNAME));
+ $this->assertEquals(null, $propFind->get(self::SIZE_PROPERTYNAME));
+ $this->assertEquals('R', $propFind->get(self::PERMISSIONS_PROPERTYNAME));
+ $this->assertEquals('http://example.com/', $propFind->get(self::DOWNLOADURL_PROPERTYNAME));
+ $this->assertEquals(array(self::SIZE_PROPERTYNAME), $propFind->get404Properties());
+ }
+
+ public function testGetPropertiesForDirectory() {
+ $node = $this->createTestNode('\OC\Connector\Sabre\Directory');
+
+ $propFind = new \Sabre\DAV\PropFind(
+ '/dummyPath',
+ array(
+ self::GETETAG_PROPERTYNAME,
+ self::FILEID_PROPERTYNAME,
+ self::SIZE_PROPERTYNAME,
+ self::PERMISSIONS_PROPERTYNAME,
+ self::DOWNLOADURL_PROPERTYNAME,
+ ),
+ 0
+ );
+
+ $node->expects($this->never())
+ ->method('getDirectDownload');
+ $node->expects($this->once())
+ ->method('getSize')
+ ->will($this->returnValue(1025));
+
+ $this->plugin->handleGetProperties(
+ $propFind,
+ $node
+ );
+
+ $this->assertEquals('"abc"', $propFind->get(self::GETETAG_PROPERTYNAME));
+ $this->assertEquals(123, $propFind->get(self::FILEID_PROPERTYNAME));
+ $this->assertEquals(1025, $propFind->get(self::SIZE_PROPERTYNAME));
+ $this->assertEquals('R', $propFind->get(self::PERMISSIONS_PROPERTYNAME));
+ $this->assertEquals(null, $propFind->get(self::DOWNLOADURL_PROPERTYNAME));
+ $this->assertEquals(array(self::DOWNLOADURL_PROPERTYNAME), $propFind->get404Properties());
+ }
+
+ public function testUpdateProps() {
+ $node = $this->createTestNode('\OC\Connector\Sabre\File');
+
+ $testDate = 'Fri, 13 Feb 2015 00:01:02 GMT';
+
+ $node->expects($this->once())
+ ->method('touch')
+ ->with($testDate);
+
+ $node->expects($this->once())
+ ->method('setEtag')
+ ->with('newetag')
+ ->will($this->returnValue(true));
+
+ // properties to set
+ $propPatch = new \Sabre\DAV\PropPatch(array(
+ self::GETETAG_PROPERTYNAME => 'newetag',
+ self::GETLASTMODIFIED_PROPERTYNAME => $testDate
+ ));
+
+ $this->plugin->handleUpdateProperties(
+ '/dummypath',
+ $propPatch
+ );
+
+ $propPatch->commit();
+
+ $this->assertEmpty($propPatch->getRemainingMutations());
+
+ $result = $propPatch->getResult();
+ $this->assertEquals(200, $result[self::GETLASTMODIFIED_PROPERTYNAME]);
+ $this->assertEquals(200, $result[self::GETETAG_PROPERTYNAME]);
+ }
+
+}
diff --git a/tests/lib/connector/sabre/node.php b/tests/lib/connector/sabre/node.php
index 1e927deed44..e1ae05b2170 100644
--- a/tests/lib/connector/sabre/node.php
+++ b/tests/lib/connector/sabre/node.php
@@ -49,7 +49,7 @@ class Node extends \Test\TestCase {
->will($this->returnValue($type));
$view = $this->getMock('\OC\Files\View');
- $node = new \OC_Connector_Sabre_File($view, $info);
+ $node = new \OC\Connector\Sabre\File($view, $info);
$this->assertEquals($expected, $node->getDavPermissions());
}
}
diff --git a/tests/lib/connector/sabre/objecttree.php b/tests/lib/connector/sabre/objecttree.php
index 2548066214b..3c972fe6f0f 100644
--- a/tests/lib/connector/sabre/objecttree.php
+++ b/tests/lib/connector/sabre/objecttree.php
@@ -10,7 +10,7 @@ namespace Test\OC\Connector\Sabre;
use OC\Files\FileInfo;
-use OC_Connector_Sabre_Directory;
+use OC\Connector\Sabre\Directory;
use PHPUnit_Framework_TestCase;
class TestDoubleFileView extends \OC\Files\View {
@@ -103,7 +103,7 @@ class ObjectTree extends \Test\TestCase {
$info = new FileInfo('', null, null, array(), null);
- $rootDir = new OC_Connector_Sabre_Directory($view, $info);
+ $rootDir = new Directory($view, $info);
$objectTree = $this->getMock('\OC\Connector\Sabre\ObjectTree',
array('nodeExists', 'getNodeForPath'),
array($rootDir, $view));
@@ -119,4 +119,123 @@ class ObjectTree extends \Test\TestCase {
$objectTree->move($source, $dest);
}
+ /**
+ * @dataProvider nodeForPathProvider
+ */
+ public function testGetNodeForPath(
+ $inputFileName,
+ $fileInfoQueryPath,
+ $outputFileName,
+ $type,
+ $enableChunkingHeader
+ ) {
+
+ if ($enableChunkingHeader) {
+ $_SERVER['HTTP_OC_CHUNKED'] = true;
+ }
+
+ $rootNode = $this->getMockBuilder('\OC\Connector\Sabre\Directory')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $mountManager = $this->getMock('\OC\Files\Mount\Manager');
+ $view = $this->getMock('\OC\Files\View');
+ $fileInfo = $this->getMock('\OCP\Files\FileInfo');
+ $fileInfo->expects($this->once())
+ ->method('getType')
+ ->will($this->returnValue($type));
+ $fileInfo->expects($this->once())
+ ->method('getName')
+ ->will($this->returnValue($outputFileName));
+
+ $view->expects($this->once())
+ ->method('getFileInfo')
+ ->with($fileInfoQueryPath)
+ ->will($this->returnValue($fileInfo));
+
+ $tree = new \OC\Connector\Sabre\ObjectTree();
+ $tree->init($rootNode, $view, $mountManager);
+
+ $node = $tree->getNodeForPath($inputFileName);
+
+ $this->assertNotNull($node);
+ $this->assertEquals($outputFileName, $node->getName());
+
+ if ($type === 'file') {
+ $this->assertTrue($node instanceof \OC\Connector\Sabre\File);
+ } else {
+ $this->assertTrue($node instanceof \OC\Connector\Sabre\Directory);
+ }
+
+ unset($_SERVER['HTTP_OC_CHUNKED']);
+ }
+
+ function nodeForPathProvider() {
+ return array(
+ // regular file
+ array(
+ 'regularfile.txt',
+ 'regularfile.txt',
+ 'regularfile.txt',
+ 'file',
+ false
+ ),
+ // regular directory
+ array(
+ 'regulardir',
+ 'regulardir',
+ 'regulardir',
+ 'dir',
+ false
+ ),
+ // regular file with chunking
+ array(
+ 'regularfile.txt',
+ 'regularfile.txt',
+ 'regularfile.txt',
+ 'file',
+ true
+ ),
+ // regular directory with chunking
+ array(
+ 'regulardir',
+ 'regulardir',
+ 'regulardir',
+ 'dir',
+ true
+ ),
+ // file with chunky file name
+ array(
+ 'regularfile.txt-chunking-123566789-10-1',
+ 'regularfile.txt',
+ 'regularfile.txt',
+ 'file',
+ true
+ ),
+ // regular file in subdir
+ array(
+ 'subdir/regularfile.txt',
+ 'subdir/regularfile.txt',
+ 'regularfile.txt',
+ 'file',
+ false
+ ),
+ // regular directory in subdir
+ array(
+ 'subdir/regulardir',
+ 'subdir/regulardir',
+ 'regulardir',
+ 'dir',
+ false
+ ),
+ // file with chunky file name in subdir
+ array(
+ 'subdir/regularfile.txt-chunking-123566789-10-1',
+ 'subdir/regularfile.txt',
+ 'regularfile.txt',
+ 'file',
+ true
+ ),
+ );
+ }
+
}
diff --git a/tests/lib/connector/sabre/principal.php b/tests/lib/connector/sabre/principal.php
index 5d13aa4421e..1841a79bec7 100644
--- a/tests/lib/connector/sabre/principal.php
+++ b/tests/lib/connector/sabre/principal.php
@@ -10,6 +10,7 @@
namespace Test\Connector\Sabre;
+use \Sabre\DAV\PropPatch;
use OCP\IUserManager;
use OCP\IConfig;
@@ -240,7 +241,7 @@ class Principal extends \Test\TestCase {
}
public function testUpdatePrincipal() {
- $this->assertSame(0, $this->connector->updatePrincipal('foo', []));
+ $this->assertSame(0, $this->connector->updatePrincipal('foo', new PropPatch(array())));
}
public function testSearchPrincipals() {
diff --git a/tests/lib/connector/sabre/quotaplugin.php b/tests/lib/connector/sabre/quotaplugin.php
index f08637854ce..48f8f319ae4 100644
--- a/tests/lib/connector/sabre/quotaplugin.php
+++ b/tests/lib/connector/sabre/quotaplugin.php
@@ -14,14 +14,14 @@ class Test_OC_Connector_Sabre_QuotaPlugin extends \Test\TestCase {
private $server;
/**
- * @var OC_Connector_Sabre_QuotaPlugin
+ * @var \OC\Connector\Sabre\QuotaPlugin
*/
private $plugin;
private function init($quota) {
$view = $this->buildFileViewMock($quota);
$this->server = new \Sabre\DAV\Server();
- $this->plugin = new OC_Connector_Sabre_QuotaPlugin($view);
+ $this->plugin = new \OC\Connector\Sabre\QuotaPlugin($view);
$this->plugin->initialize($this->server);
}
@@ -30,7 +30,7 @@ class Test_OC_Connector_Sabre_QuotaPlugin extends \Test\TestCase {
*/
public function testLength($expected, $headers) {
$this->init(0);
- $this->server->httpRequest = new \Sabre\HTTP\Request($headers);
+ $this->server->httpRequest = new \Sabre\HTTP\Request(null, null, $headers);
$length = $this->plugin->getLength();
$this->assertEquals($expected, $length);
}
@@ -41,7 +41,7 @@ class Test_OC_Connector_Sabre_QuotaPlugin extends \Test\TestCase {
public function testCheckQuota($quota, $headers) {
$this->init($quota);
- $this->server->httpRequest = new Sabre\HTTP\Request($headers);
+ $this->server->httpRequest = new \Sabre\HTTP\Request(null, null, $headers);
$result = $this->plugin->checkQuota('');
$this->assertTrue($result);
}
@@ -53,39 +53,39 @@ class Test_OC_Connector_Sabre_QuotaPlugin extends \Test\TestCase {
public function testCheckExceededQuota($quota, $headers) {
$this->init($quota);
- $this->server->httpRequest = new Sabre\HTTP\Request($headers);
+ $this->server->httpRequest = new \Sabre\HTTP\Request(null, null, $headers);
$this->plugin->checkQuota('');
}
public function quotaOkayProvider() {
return array(
array(1024, array()),
- array(1024, array('HTTP_X_EXPECTED_ENTITY_LENGTH' => '1024')),
- array(1024, array('HTTP_CONTENT_LENGTH' => '512')),
- array(1024, array('HTTP_OC_TOTAL_LENGTH' => '1024', 'HTTP_CONTENT_LENGTH' => '512')),
- // \OCP\Files\FileInfo::SPACE_UNKNOWN = -2
+ array(1024, array('X-EXPECTED-ENTITY-LENGTH' => '1024')),
+ array(1024, array('CONTENT-LENGTH' => '512')),
+ array(1024, array('OC-TOTAL-LENGTH' => '1024', 'CONTENT-LENGTH' => '512')),
+ // \OCP\Files\FileInfo::SPACE-UNKNOWN = -2
array(-2, array()),
- array(-2, array('HTTP_X_EXPECTED_ENTITY_LENGTH' => '1024')),
- array(-2, array('HTTP_CONTENT_LENGTH' => '512')),
- array(-2, array('HTTP_OC_TOTAL_LENGTH' => '1024', 'HTTP_CONTENT_LENGTH' => '512')),
+ array(-2, array('X-EXPECTED-ENTITY-LENGTH' => '1024')),
+ array(-2, array('CONTENT-LENGTH' => '512')),
+ array(-2, array('OC-TOTAL-LENGTH' => '1024', 'CONTENT-LENGTH' => '512')),
);
}
public function quotaExceededProvider() {
return array(
- array(1023, array('HTTP_X_EXPECTED_ENTITY_LENGTH' => '1024')),
- array(511, array('HTTP_CONTENT_LENGTH' => '512')),
- array(2047, array('HTTP_OC_TOTAL_LENGTH' => '2048', 'HTTP_CONTENT_LENGTH' => '1024')),
+ array(1023, array('X-EXPECTED-ENTITY-LENGTH' => '1024')),
+ array(511, array('CONTENT-LENGTH' => '512')),
+ array(2047, array('OC-TOTAL-LENGTH' => '2048', 'CONTENT-LENGTH' => '1024')),
);
}
public function lengthProvider() {
return array(
array(null, array()),
- array(1024, array('HTTP_X_EXPECTED_ENTITY_LENGTH' => '1024')),
- array(512, array('HTTP_CONTENT_LENGTH' => '512')),
- array(2048, array('HTTP_OC_TOTAL_LENGTH' => '2048', 'HTTP_CONTENT_LENGTH' => '1024')),
- array(4096, array('HTTP_OC_TOTAL_LENGTH' => '2048', 'HTTP_X_EXPECTED_ENTITY_LENGTH' => '4096')),
+ array(1024, array('X-EXPECTED-ENTITY-LENGTH' => '1024')),
+ array(512, array('CONTENT-LENGTH' => '512')),
+ array(2048, array('OC-TOTAL-LENGTH' => '2048', 'CONTENT-LENGTH' => '1024')),
+ array(4096, array('OC-TOTAL-LENGTH' => '2048', 'X-EXPECTED-ENTITY-LENGTH' => '4096')),
);
}
diff --git a/tests/lib/connector/sabre/tagsplugin.php b/tests/lib/connector/sabre/tagsplugin.php
index 2afea061ec3..f8af73fecfb 100644
--- a/tests/lib/connector/sabre/tagsplugin.php
+++ b/tests/lib/connector/sabre/tagsplugin.php
@@ -42,7 +42,7 @@ class TagsPlugin extends \Test\TestCase {
public function setUp() {
parent::setUp();
$this->server = new \Sabre\DAV\Server();
- $this->tree = $this->getMockBuilder('\Sabre\DAV\ObjectTree')
+ $this->tree = $this->getMockBuilder('\Sabre\DAV\Tree')
->disableOriginalConstructor()
->getMock();
$this->tagger = $this->getMock('\OCP\ITags');
@@ -59,7 +59,7 @@ class TagsPlugin extends \Test\TestCase {
* @dataProvider tagsGetPropertiesDataProvider
*/
public function testGetProperties($tags, $requestedProperties, $expectedProperties) {
- $node = $this->getMockBuilder('\OC_Connector_Sabre_Node')
+ $node = $this->getMockBuilder('\OC\Connector\Sabre\Node')
->disableOriginalConstructor()
->getMock();
$node->expects($this->any())
@@ -76,29 +76,35 @@ class TagsPlugin extends \Test\TestCase {
->with($this->equalTo(array(123)))
->will($this->returnValue(array(123 => $tags)));
- $returnedProperties = array();
-
- $this->plugin->beforeGetProperties(
- '',
- $node,
+ $propFind = new \Sabre\DAV\PropFind(
+ '/dummyPath',
$requestedProperties,
- $returnedProperties
+ 0
);
- $this->assertEquals($expectedProperties, $returnedProperties);
+ $this->plugin->handleGetProperties(
+ $propFind,
+ $node
+ );
+
+ $result = $propFind->getResultForMultiStatus();
+
+ $this->assertEmpty($result[404]);
+ unset($result[404]);
+ $this->assertEquals($expectedProperties, $result);
}
/**
* @dataProvider tagsGetPropertiesDataProvider
*/
public function testPreloadThenGetProperties($tags, $requestedProperties, $expectedProperties) {
- $node1 = $this->getMockBuilder('\OC_Connector_Sabre_File')
+ $node1 = $this->getMockBuilder('\OC\Connector\Sabre\File')
->disableOriginalConstructor()
->getMock();
$node1->expects($this->any())
->method('getId')
->will($this->returnValue(111));
- $node2 = $this->getMockBuilder('\OC_Connector_Sabre_File')
+ $node2 = $this->getMockBuilder('\OC\Connector\Sabre\File')
->disableOriginalConstructor()
->getMock();
$node2->expects($this->any())
@@ -113,7 +119,7 @@ class TagsPlugin extends \Test\TestCase {
$expectedCallCount = 1;
}
- $node = $this->getMockBuilder('\OC_Connector_Sabre_Directory')
+ $node = $this->getMockBuilder('\OC\Connector\Sabre\Directory')
->disableOriginalConstructor()
->getMock();
$node->expects($this->any())
@@ -123,14 +129,9 @@ class TagsPlugin extends \Test\TestCase {
->method('getChildren')
->will($this->returnValue(array($node1, $node2)));
- $this->tree->expects($this->once())
- ->method('getNodeForPath')
- ->with('/subdir')
- ->will($this->returnValue($node));
-
$this->tagger->expects($this->exactly($expectedCallCount))
->method('getTagsForObjects')
- ->with($this->equalTo(array(111, 222)))
+ ->with($this->equalTo(array(123, 111, 222)))
->will($this->returnValue(
array(
111 => $tags,
@@ -138,22 +139,41 @@ class TagsPlugin extends \Test\TestCase {
)
));
- $returnedProperties = array();
-
- $this->plugin->beforeGetPropertiesForPath(
+ // simulate sabre recursive PROPFIND traversal
+ $propFindRoot = new \Sabre\DAV\PropFind(
'/subdir',
$requestedProperties,
1
);
-
- $this->plugin->beforeGetProperties(
+ $propFind1 = new \Sabre\DAV\PropFind(
'/subdir/test.txt',
- $node1,
$requestedProperties,
- $returnedProperties
+ 0
+ );
+ $propFind2 = new \Sabre\DAV\PropFind(
+ '/subdir/test2.txt',
+ $requestedProperties,
+ 0
);
- $this->assertEquals($expectedProperties, $returnedProperties);
+ $this->plugin->handleGetProperties(
+ $propFindRoot,
+ $node
+ );
+ $this->plugin->handleGetProperties(
+ $propFind1,
+ $node1
+ );
+ $this->plugin->handleGetProperties(
+ $propFind2,
+ $node2
+ );
+
+ $result = $propFind1->getResultForMultiStatus();
+
+ $this->assertEmpty($result[404]);
+ unset($result[404]);
+ $this->assertEquals($expectedProperties, $result);
}
function tagsGetPropertiesDataProvider() {
@@ -193,7 +213,9 @@ class TagsPlugin extends \Test\TestCase {
array(
array('tag1', 'tag2', self::TAG_FAVORITE),
array(),
- array(),
+ array(
+ 200 => array()
+ ),
),
// request both with none set, receive both
array(
@@ -212,13 +234,18 @@ class TagsPlugin extends \Test\TestCase {
public function testUpdateTags() {
// this test will replace the existing tags "tagremove" with "tag1" and "tag2"
// and keep "tagkeep"
- $node = $this->getMockBuilder('\OC_Connector_Sabre_Node')
+ $node = $this->getMockBuilder('\OC\Connector\Sabre\Node')
->disableOriginalConstructor()
->getMock();
$node->expects($this->any())
->method('getId')
->will($this->returnValue(123));
+ $this->tree->expects($this->any())
+ ->method('getNodeForPath')
+ ->with('/dummypath')
+ ->will($this->returnValue($node));
+
$this->tagger->expects($this->at(0))
->method('getTagsForObjects')
->with($this->equalTo(array(123)))
@@ -238,58 +265,109 @@ class TagsPlugin extends \Test\TestCase {
->with(123, 'tagremove');
// properties to set
- $properties = array(
+ $propPatch = new \Sabre\DAV\PropPatch(array(
self::TAGS_PROPERTYNAME => new \OC\Connector\Sabre\TagList(array('tag1', 'tag2', 'tagkeep'))
- );
- $result = array();
+ ));
- $this->plugin->updateProperties(
- $properties,
- $result,
- $node
+ $this->plugin->handleUpdateProperties(
+ '/dummypath',
+ $propPatch
);
+ $propPatch->commit();
+
// all requested properties removed, as they were processed already
- $this->assertEmpty($properties);
+ $this->assertEmpty($propPatch->getRemainingMutations());
+
+ $result = $propPatch->getResult();
+ $this->assertEquals(200, $result[self::TAGS_PROPERTYNAME]);
+ $this->assertFalse(isset($result[self::FAVORITE_PROPERTYNAME]));
+ }
+
+ public function testUpdateTagsFromScratch() {
+ $node = $this->getMockBuilder('\OC\Connector\Sabre\Node')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $node->expects($this->any())
+ ->method('getId')
+ ->will($this->returnValue(123));
+
+ $this->tree->expects($this->any())
+ ->method('getNodeForPath')
+ ->with('/dummypath')
+ ->will($this->returnValue($node));
+
+ $this->tagger->expects($this->at(0))
+ ->method('getTagsForObjects')
+ ->with($this->equalTo(array(123)))
+ ->will($this->returnValue(array()));
+
+ // then tag as tag1 and tag2
+ $this->tagger->expects($this->at(1))
+ ->method('tagAs')
+ ->with(123, 'tag1');
+ $this->tagger->expects($this->at(2))
+ ->method('tagAs')
+ ->with(123, 'tag2');
- $this->assertEquals(
- new \OC\Connector\Sabre\TagList(array('tag1', 'tag2', 'tagkeep')),
- $result[200][self::TAGS_PROPERTYNAME]
+ // properties to set
+ $propPatch = new \Sabre\DAV\PropPatch(array(
+ self::TAGS_PROPERTYNAME => new \OC\Connector\Sabre\TagList(array('tag1', 'tag2', 'tagkeep'))
+ ));
+
+ $this->plugin->handleUpdateProperties(
+ '/dummypath',
+ $propPatch
);
- $this->assertFalse(isset($result[200][self::FAVORITE_PROPERTYNAME]));
+
+ $propPatch->commit();
+
+ // all requested properties removed, as they were processed already
+ $this->assertEmpty($propPatch->getRemainingMutations());
+
+ $result = $propPatch->getResult();
+ $this->assertEquals(200, $result[self::TAGS_PROPERTYNAME]);
+ $this->assertFalse(false, isset($result[self::FAVORITE_PROPERTYNAME]));
}
public function testUpdateFav() {
// this test will replace the existing tags "tagremove" with "tag1" and "tag2"
// and keep "tagkeep"
- $node = $this->getMockBuilder('\OC_Connector_Sabre_Node')
+ $node = $this->getMockBuilder('\OC\Connector\Sabre\Node')
->disableOriginalConstructor()
->getMock();
$node->expects($this->any())
->method('getId')
->will($this->returnValue(123));
+ $this->tree->expects($this->any())
+ ->method('getNodeForPath')
+ ->with('/dummypath')
+ ->will($this->returnValue($node));
+
// set favorite tag
$this->tagger->expects($this->once())
->method('tagAs')
->with(123, self::TAG_FAVORITE);
// properties to set
- $properties = array(
+ $propPatch = new \Sabre\DAV\PropPatch(array(
self::FAVORITE_PROPERTYNAME => true
- );
- $result = array();
- $this->plugin->updateProperties(
- $properties,
- $result,
- $node
+ ));
+
+ $this->plugin->handleUpdateProperties(
+ '/dummypath',
+ $propPatch
);
+ $propPatch->commit();
+
// all requested properties removed, as they were processed already
- $this->assertEmpty($properties);
+ $this->assertEmpty($propPatch->getRemainingMutations());
- $this->assertTrue($result[200][self::FAVORITE_PROPERTYNAME]);
- $this->assertFalse(isset($result[200][self::TAGS_PROPERTYNAME]));
+ $result = $propPatch->getResult();
+ $this->assertFalse(false, isset($result[self::TAGS_PROPERTYNAME]));
+ $this->assertEquals(200, isset($result[self::FAVORITE_PROPERTYNAME]));
// unfavorite now
// set favorite tag
@@ -297,18 +375,24 @@ class TagsPlugin extends \Test\TestCase {
->method('unTag')
->with(123, self::TAG_FAVORITE);
- $properties = array(
+ // properties to set
+ $propPatch = new \Sabre\DAV\PropPatch(array(
self::FAVORITE_PROPERTYNAME => false
+ ));
+
+ $this->plugin->handleUpdateProperties(
+ '/dummypath',
+ $propPatch
);
- $result = array();
- $this->plugin->updateProperties(
- $properties,
- $result,
- $node
- );
- $this->assertFalse($result[200][self::FAVORITE_PROPERTYNAME]);
- $this->assertFalse(isset($result[200][self::TAGS_PROPERTYNAME]));
+ $propPatch->commit();
+
+ // all requested properties removed, as they were processed already
+ $this->assertEmpty($propPatch->getRemainingMutations());
+
+ $result = $propPatch->getResult();
+ $this->assertFalse(false, isset($result[self::TAGS_PROPERTYNAME]));
+ $this->assertEquals(200, isset($result[self::FAVORITE_PROPERTYNAME]));
}
}
diff --git a/tests/lib/vobject.php b/tests/lib/vobject.php
deleted file mode 100644
index 6fabf30e48f..00000000000
--- a/tests/lib/vobject.php
+++ /dev/null
@@ -1,40 +0,0 @@
-<?php
-/**
- * Copyright (c) 2013 Thomas Tanghus (thomas@tanghus.net)
- * This file is licensed under the Affero General Public License version 3 or
- * later.
- * See the COPYING-README file.
- */
-
-class Test_VObject extends \Test\TestCase {
-
- protected function setUp() {
- parent::setUp();
-
- Sabre\VObject\Property::$classMap['SUMMARY'] = 'OC\VObject\StringProperty';
- Sabre\VObject\Property::$classMap['ORG'] = 'OC\VObject\CompoundProperty';
- }
-
- function testStringProperty() {
- $property = Sabre\VObject\Property::create('SUMMARY', 'Escape;this,please');
- $this->assertEquals("SUMMARY:Escape\;this\,please\r\n", $property->serialize());
- }
-
- function testCompoundProperty() {
-
- $arr = array(
- 'ABC, Inc.',
- 'North American Division',
- 'Marketing;Sales',
- );
-
- $property = Sabre\VObject\Property::create('ORG');
- $property->setParts($arr);
-
- $this->assertEquals('ABC\, Inc.;North American Division;Marketing\;Sales', $property->value);
- $this->assertEquals('ORG:ABC\, Inc.;North American Division;Marketing\;Sales' . "\r\n", $property->serialize());
- $this->assertEquals(3, count($property->getParts()));
- $parts = $property->getParts();
- $this->assertEquals('Marketing;Sales', $parts[2]);
- }
-}