]> source.dussan.org Git - nextcloud-server.git/commitdiff
Sabre Update to 2.1
authorVincent Petry <pvince81@owncloud.com>
Thu, 12 Feb 2015 11:29:01 +0000 (12:29 +0100)
committerThomas Müller <thomas.mueller@tmit.eu>
Mon, 23 Feb 2015 21:27:23 +0000 (22:27 +0100)
- VObject fixes for Sabre\VObject 3.3
- Remove VObject property workarounds
- Added prefetching for tags in sabre tags plugin
- Moved oc_properties logic to separate PropertyStorage backend (WIP)
- Fixed Sabre connector namespaces
- Improved files plugin to handle props on-demand
- Moved allowed props from server class to files plugin
- Fixed tags caching for files that are known to have no tags
  (less queries)
- Added/fixed unit tests for Sabre FilesPlugin, TagsPlugin
- Replace OC\Connector\Sabre\Request with direct call to
  httpRequest->setUrl()
- Fix exception detection in DAV client when using Sabre\DAV\Client
- Added setETag() on Node instead of using the static FileSystem
- Also preload tags/props when depth is infinity

39 files changed:
3rdparty
apps/files/appinfo/remote.php
apps/files_encryption/tests/webdav.php
apps/files_sharing/publicwebdav.php
lib/private/appframework/http/request.php
lib/private/connector/sabre/appenabledplugin.php
lib/private/connector/sabre/auth.php
lib/private/connector/sabre/custompropertiesbackend.php [new file with mode: 0644]
lib/private/connector/sabre/directory.php
lib/private/connector/sabre/exception/entitytoolarge.php
lib/private/connector/sabre/exception/filelocked.php
lib/private/connector/sabre/exception/unsupportedmediatype.php
lib/private/connector/sabre/exceptionloggerplugin.php
lib/private/connector/sabre/file.php
lib/private/connector/sabre/filesplugin.php
lib/private/connector/sabre/locks.php
lib/private/connector/sabre/maintenanceplugin.php
lib/private/connector/sabre/node.php
lib/private/connector/sabre/objecttree.php
lib/private/connector/sabre/principal.php
lib/private/connector/sabre/quotaplugin.php
lib/private/connector/sabre/request.php [deleted file]
lib/private/connector/sabre/server.php
lib/private/connector/sabre/taglist.php
lib/private/connector/sabre/tagsplugin.php
lib/private/files/storage/common.php
lib/private/files/storage/dav.php
lib/private/vobject/compoundproperty.php [deleted file]
lib/private/vobject/stringproperty.php [deleted file]
tests/lib/connector/sabre/custompropertiesbackend.php [new file with mode: 0644]
tests/lib/connector/sabre/directory.php
tests/lib/connector/sabre/file.php
tests/lib/connector/sabre/filesplugin.php [new file with mode: 0644]
tests/lib/connector/sabre/node.php
tests/lib/connector/sabre/objecttree.php
tests/lib/connector/sabre/principal.php
tests/lib/connector/sabre/quotaplugin.php
tests/lib/connector/sabre/tagsplugin.php
tests/lib/vobject.php [deleted file]

index 59f092231c6036838746262a4db80997908bb06f..588b1308f4abf58acb3bb8519f6952d9890cca89 160000 (submodule)
--- a/3rdparty
+++ b/3rdparty
@@ -1 +1 @@
-Subproject commit 59f092231c6036838746262a4db80997908bb06f
+Subproject commit 588b1308f4abf58acb3bb8519f6952d9890cca89
index f9fa792e13307f6dffb355c13b0930ec1b88e6d1..98db95041fecfbb4edeb8e58ec16e01c48fc035d 100644 (file)
  *
  */
 // 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!
index 0d5a8f82f2c579f3ca88bb90abbde510071cc578..8fe5ffe036343cde9c5ea7b233d520fcada8855f 100755 (executable)
@@ -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
index 30c8588ee3f047f4b0ad4efc71f85eed6c090f10..abed58b5ee2e86f799102567a2bfa532263afb7f 100644 (file)
@@ -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!
index dad5cb050ca8f54b454b41f74fbb1b5fc3958b4e..e47811d0df9e8b11d25ae5c3f1b2cca50f767654 100644 (file)
@@ -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']);
 
index 68356d3378ca3b429c8b14593f7c4a8c99a21d9a..e38af40c08e7f680e90ef8559fde27047cdfbdd5 100644 (file)
@@ -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);
        }
 
        /**
index a095ee6e0458d1e5d658e3936217d9b971076b87..0fc76ea9df2495ed3c607850d5b424b5a10615a5 100644 (file)
@@ -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 (file)
index 0000000..eaf1323
--- /dev/null
@@ -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();
+       }
+
+}
index 682fd62ee3721a773134fa1f9b728e9be6c50136..f13a0d7bbd81a4309eaf8e044e59108f36b58c7f 100644 (file)
@@ -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();
-       }
-
 }
index 2d2a264fe6f92467c0b8ee526aae848b5d5c20db..e18ac859dd594a87221827866ef011298f185abc 100644 (file)
@@ -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
index ce110e3cb371c318778cc851454cd59a4268a7d9..6b6b7b0d856a1e4cd206b17340502d8d68382fee 100644 (file)
@@ -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) {
index ce6db21d89b8c91be51d3e9cbc44e5bb498647fe..5a3716ae71bbba24a1fd6bfe3911708a45d7895c 100644 (file)
@@ -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
index 2b2753c47e49f30af3219ca2c30f6b45fc2284ff..6ae57b3ec5641ceff6d654e7c4a502bd951be441 100644 (file)
@@ -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);
        }
 
        /**
index 9b529d2e0f1be9e71f75440c159f206aa7ffef8b..0355376c46b80837e1cb15d70ae83f45753777b9 100644 (file)
@@ -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
index d62f4e4ce5398cba31236899616efa7690fc8909..1932dabd393b983aa57e6434ac57942c553565a5 100644 (file)
@@ -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
@@ -33,6 +24,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.
         *
@@ -47,68 +47,100 @@ 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
@@ -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');
+               }
+       }
+
 }
index ec14f1d71b5a73851c9fa7f7f9347ef86f36e0f9..a212c9597c42e6452ef428edbbb5a11c2a3ee58d 100644 (file)
@@ -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;
 
index 3d4e19ec470139ac8eb7840e85f2c151198b716e..ff55cdceab6fd302c5167e4cc29f8f05ef58db91 100644 (file)
@@ -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');
                }
 
index 7df4453cb25991f49d2c7903bd949190325def79..8fee6a4eb4e75af7b0446e95109e39b0d561cccf 100644 (file)
@@ -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
         *
@@ -110,6 +78,15 @@ abstract class OC_Connector_Sabre_Node implements \Sabre\DAV\INode, \Sabre\DAV\I
                return $this->info->getName();
        }
 
+       /**
+        * Returns the full path
+        *
+        * @return string
+        */
+       public function getPath() {
+               return $this->path;
+       }
+
        /**
         * Renames the node
         * @param string $name The new name
@@ -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;
                }
index 8793b6129362b685ddad16e298e46f149c2b4422..585be637813e1dc2be5a821405c5c090305a5c57 100644 (file)
@@ -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() {
        }
@@ -61,6 +59,35 @@ class ObjectTree extends \Sabre\DAV\ObjectTree {
                $this->mountManager = $mountManager;
        }
 
+       /**
+        * 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
         *
@@ -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);
        }
 }
index 917d9887393964b7201f721ce09cb586b9edd8c3..06842cc7b90ceadbe80a6397879057d607d43e03 100644 (file)
@@ -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 '';
+       }
 }
index 8601f8aada6b1ba487246982dd05231ade19d04b..6c0f9f3f950494d7bc505fa0691365751f13df8c 100644 (file)
@@ -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 (file)
index 35fd671..0000000
+++ /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;
-               }
-       }
-}
index f17f46a81cf59e171863e76129903529d406b821..0dc81554d567274b1269f3dd2fe169fb42bc2fb9 100644 (file)
@@ -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;
        }
 }
index 22b422c20b3b52033b659e42c17f1c16e5a9a632..97f9e7975793aba3b8412d94f55abac9a4a6dcdb 100644 (file)
@@ -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) {
index 87de08d333ee7d40964eda7108091b82ef5c67dd..7756eb45bdaa910f510c7c498acb9b725461cd87 100644 (file)
@@ -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;
+               });
        }
 }
index 56aa5328c7885db2a428cb7d6faef6b492963e14..d8df8f948cb50d4486f7ce0f6e10cae3bae964e0 100644 (file)
@@ -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;
index 0d70f612ec092a48c838416bc639ff0996c52388..477a3b499c0916c2fd1c78f9df5176ff5e9d51ad 100644 (file)
@@ -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,14 +485,11 @@ 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) {
@@ -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 (file)
index aaeeeed..0000000
+++ /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 (file)
index a091156..0000000
+++ /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 (file)
index 0000000..ee0c3c4
--- /dev/null
@@ -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']);
+       }
+}
index 599a6ca3f7c19dbfd934fc5e993c2f17a77090ef..e7fbd1d27b6f481581dd0263c0adf6d3d75c6e7b 100644 (file)
@@ -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
        }
 }
index 33dc78f87d8a7bcb5ba08b2a7dd68f70bdabc8c3..2ef5fd794be5c7d5a53fb007d40ca24fb2dc9714 100644 (file)
@@ -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 (file)
index 0000000..54d43d6
--- /dev/null
@@ -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]);
+       }
+
+}
index 1e927deed4484de168f0222c1c282bc693ac5cdc..e1ae05b21709b3ac8699923489cd6e4af534af66 100644 (file)
@@ -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());
        }
 }
index 2548066214b5440879ca742508c0473db1dad76d..3c972fe6f0fe6fc2f0b1b15717b5873f0fc49fa2 100644 (file)
@@ -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
+                       ),
+               );
+       }
+
 }
index 5d13aa4421ea5943cfd7688bdd7216ff67c78354..1841a79bec7e18253380163ef3be95d03165edee 100644 (file)
@@ -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() {
index f08637854ce46e89ce55b7e285c8e5ff9671597a..48f8f319ae402737329ef2a5d4c6637808f94e04 100644 (file)
@@ -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')),
                );
        }
 
index 2afea061ec3f360f66293cb226cae8fa2486fe7b..f8af73fecfb1022947aad32f3745fb063bf3f7b0 100644 (file)
@@ -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 (file)
index 6fabf30..0000000
+++ /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]);
-       }
-}