summaryrefslogtreecommitdiffstats
path: root/lib/private/connector/sabre/filesplugin.php
diff options
context:
space:
mode:
authorVincent Petry <pvince81@owncloud.com>2015-02-12 12:29:01 +0100
committerThomas Müller <thomas.mueller@tmit.eu>2015-02-23 22:27:23 +0100
commit9f6dcb9d3e2f43f336dafeb739e04ba9614d9b5f (patch)
treefa72017a9bf76c526ddb3dfe0969f0584a4a7d67 /lib/private/connector/sabre/filesplugin.php
parent66e3211fd8a57b0fb296d1dcc980272721e9f99d (diff)
downloadnextcloud-server-9f6dcb9d3e2f43f336dafeb739e04ba9614d9b5f.tar.gz
nextcloud-server-9f6dcb9d3e2f43f336dafeb739e04ba9614d9b5f.zip
Sabre Update to 2.1
- 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
Diffstat (limited to 'lib/private/connector/sabre/filesplugin.php')
-rw-r--r--lib/private/connector/sabre/filesplugin.php179
1 files changed, 112 insertions, 67 deletions
diff --git a/lib/private/connector/sabre/filesplugin.php b/lib/private/connector/sabre/filesplugin.php
index d62f4e4ce53..1932dabd393 100644
--- a/lib/private/connector/sabre/filesplugin.php
+++ b/lib/private/connector/sabre/filesplugin.php
@@ -1,30 +1,21 @@
<?php
-/**
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
- * @author Thomas Müller <thomas.mueller@tmit.eu>
- * @author Vincent Petry <pvince81@owncloud.com>
- *
- * @copyright Copyright (c) 2015, ownCloud, Inc.
- * @license AGPL-3.0
- *
- * This code is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License, version 3,
- * along with this program. If not, see <http://www.gnu.org/licenses/>
- *
- */
-class OC_Connector_Sabre_FilesPlugin extends \Sabre\DAV\ServerPlugin
-{
+namespace OC\Connector\Sabre;
+
+use \Sabre\DAV\PropFind;
+use \Sabre\DAV\PropPatch;
+use \Sabre\HTTP\RequestInterface;
+use \Sabre\HTTP\ResponseInterface;
+
+class FilesPlugin extends \Sabre\DAV\ServerPlugin {
// namespace
const NS_OWNCLOUD = 'http://owncloud.org/ns';
+ const FILEID_PROPERTYNAME = '{http://owncloud.org/ns}id';
+ const PERMISSIONS_PROPERTYNAME = '{http://owncloud.org/ns}permissions';
+ const DOWNLOADURL_PROPERTYNAME = '{http://owncloud.org/ns}downloadURL';
+ const SIZE_PROPERTYNAME = '{http://owncloud.org/ns}size';
+ const GETETAG_PROPERTYNAME = '{DAV:}getetag';
+ const GETLASTMODIFIED_PROPERTYNAME = '{DAV:}getlastmodified';
/**
* Reference to main server object
@@ -34,6 +25,15 @@ class OC_Connector_Sabre_FilesPlugin extends \Sabre\DAV\ServerPlugin
private $server;
/**
+ * @var \Sabre\DAV\Tree
+ */
+ private $tree;
+
+ public function __construct(\Sabre\DAV\Tree $tree) {
+ $this->tree = $tree;
+ }
+
+ /**
* This initializes the plugin.
*
* This function is called by \Sabre\DAV\Server, after
@@ -47,69 +47,101 @@ class OC_Connector_Sabre_FilesPlugin extends \Sabre\DAV\ServerPlugin
public function initialize(\Sabre\DAV\Server $server) {
$server->xmlNamespaces[self::NS_OWNCLOUD] = 'oc';
- $server->protectedProperties[] = '{' . self::NS_OWNCLOUD . '}id';
- $server->protectedProperties[] = '{' . self::NS_OWNCLOUD . '}permissions';
- $server->protectedProperties[] = '{' . self::NS_OWNCLOUD . '}size';
- $server->protectedProperties[] = '{' . self::NS_OWNCLOUD . '}downloadURL';
+ $server->protectedProperties[] = self::FILEID_PROPERTYNAME;
+ $server->protectedProperties[] = self::PERMISSIONS_PROPERTYNAME;
+ $server->protectedProperties[] = self::SIZE_PROPERTYNAME;
+ $server->protectedProperties[] = self::DOWNLOADURL_PROPERTYNAME;
+
+ // normally these cannot be changed (RFC4918), but we want them modifiable through PROPPATCH
+ $allowedProperties = ['{DAV:}getetag', '{DAV:}getlastmodified'];
+ $server->protectedProperties = array_diff($server->protectedProperties, $allowedProperties);
$this->server = $server;
- $this->server->subscribeEvent('beforeGetProperties', array($this, 'beforeGetProperties'));
- $this->server->subscribeEvent('afterBind', array($this, 'sendFileIdHeader'));
- $this->server->subscribeEvent('afterWriteContent', array($this, 'sendFileIdHeader'));
+ $this->server->on('propFind', array($this, 'handleGetProperties'));
+ $this->server->on('propPatch', array($this, 'handleUpdateProperties'));
+ $this->server->on('afterBind', array($this, 'sendFileIdHeader'));
+ $this->server->on('afterWriteContent', array($this, 'sendFileIdHeader'));
+ $this->server->on('beforeMethod:GET', array($this, 'handleRangeHeaders'));
}
/**
* Adds all ownCloud-specific properties
*
- * @param string $path
+ * @param PropFind $propFind
* @param \Sabre\DAV\INode $node
- * @param array $requestedProperties
- * @param array $returnedProperties
* @return void
*/
- public function beforeGetProperties($path, \Sabre\DAV\INode $node, array &$requestedProperties, array &$returnedProperties) {
+ public function handleGetProperties(PropFind $propFind, \Sabre\DAV\INode $node) {
- if ($node instanceof OC_Connector_Sabre_Node) {
+ if ($node instanceof \OC\Connector\Sabre\Node) {
- $fileIdPropertyName = '{' . self::NS_OWNCLOUD . '}id';
- $permissionsPropertyName = '{' . self::NS_OWNCLOUD . '}permissions';
- if (array_search($fileIdPropertyName, $requestedProperties)) {
- unset($requestedProperties[array_search($fileIdPropertyName, $requestedProperties)]);
- }
- if (array_search($permissionsPropertyName, $requestedProperties)) {
- unset($requestedProperties[array_search($permissionsPropertyName, $requestedProperties)]);
- }
+ $propFind->handle(self::FILEID_PROPERTYNAME, function() use ($node) {
+ return $node->getFileId();
+ });
- /** @var $node OC_Connector_Sabre_Node */
- $fileId = $node->getFileId();
- if (!is_null($fileId)) {
- $returnedProperties[200][$fileIdPropertyName] = $fileId;
- }
+ $propFind->handle(self::PERMISSIONS_PROPERTYNAME, function() use ($node) {
+ return $node->getDavPermissions();
+ });
- $permissions = $node->getDavPermissions();
- if (!is_null($permissions)) {
- $returnedProperties[200][$permissionsPropertyName] = $permissions;
- }
+ $propFind->handle(self::GETETAG_PROPERTYNAME, function() use ($node) {
+ return $node->getEtag();
+ });
}
- if ($node instanceof OC_Connector_Sabre_File) {
- /** @var $node OC_Connector_Sabre_File */
- $directDownloadUrl = $node->getDirectDownload();
- if (isset($directDownloadUrl['url'])) {
- $directDownloadUrlPropertyName = '{' . self::NS_OWNCLOUD . '}downloadURL';
- $returnedProperties[200][$directDownloadUrlPropertyName] = $directDownloadUrl['url'];
- }
+ if ($node instanceof \OC\Connector\Sabre\File) {
+ $propFind->handle(self::DOWNLOADURL_PROPERTYNAME, function() use ($node) {
+ /** @var $node \OC\Connector\Sabre\File */
+ $directDownloadUrl = $node->getDirectDownload();
+ if (isset($directDownloadUrl['url'])) {
+ return $directDownloadUrl['url'];
+ }
+ return false;
+ });
}
- if ($node instanceof OC_Connector_Sabre_Directory) {
- $sizePropertyName = '{' . self::NS_OWNCLOUD . '}size';
-
- /** @var $node OC_Connector_Sabre_Directory */
- $returnedProperties[200][$sizePropertyName] = $node->getSize();
+ if ($node instanceof \OC\Connector\Sabre\Directory) {
+ $propFind->handle(self::SIZE_PROPERTYNAME, function() use ($node) {
+ return $node->getSize();
+ });
}
}
/**
+ * Update ownCloud-specific properties
+ *
+ * @param string $path
+ * @param PropPatch $propPatch
+ *
+ * @return void
+ */
+ public function handleUpdateProperties($path, PropPatch $propPatch) {
+ $propPatch->handle(self::GETLASTMODIFIED_PROPERTYNAME, function($time) use ($path) {
+ if (empty($time)) {
+ return false;
+ }
+ $node = $this->tree->getNodeForPath($path);
+ if (is_null($node)) {
+ return 404;
+ }
+ $node->touch($time);
+ return true;
+ });
+ $propPatch->handle(self::GETETAG_PROPERTYNAME, function($etag) use ($path) {
+ if (empty($etag)) {
+ return false;
+ }
+ $node = $this->tree->getNodeForPath($path);
+ if (is_null($node)) {
+ return 404;
+ }
+ if ($node->setEtag($etag) !== -1) {
+ return true;
+ }
+ return false;
+ });
+ }
+
+ /**
* @param string $filePath
* @param \Sabre\DAV\INode $node
* @throws \Sabre\DAV\Exception\BadRequest
@@ -117,8 +149,8 @@ class OC_Connector_Sabre_FilesPlugin extends \Sabre\DAV\ServerPlugin
public function sendFileIdHeader($filePath, \Sabre\DAV\INode $node = null) {
// chunked upload handling
if (isset($_SERVER['HTTP_OC_CHUNKED'])) {
- list($path, $name) = \Sabre\DAV\URLUtil::splitPath($filePath);
- $info = OC_FileChunking::decodeName($name);
+ list($path, $name) = \Sabre\HTTP\URLUtil::splitPath($filePath);
+ $info = \OC_FileChunking::decodeName($name);
if (!empty($info)) {
$filePath = $path . '/' . $info['name'];
}
@@ -129,7 +161,7 @@ class OC_Connector_Sabre_FilesPlugin extends \Sabre\DAV\ServerPlugin
return;
}
$node = $this->server->tree->getNodeForPath($filePath);
- if ($node instanceof OC_Connector_Sabre_Node) {
+ if ($node instanceof \OC\Connector\Sabre\Node) {
$fileId = $node->getFileId();
if (!is_null($fileId)) {
$this->server->httpResponse->setHeader('OC-FileId', $fileId);
@@ -137,4 +169,17 @@ class OC_Connector_Sabre_FilesPlugin extends \Sabre\DAV\ServerPlugin
}
}
+ /**
+ * Remove range headers if encryption is enabled.
+ *
+ * @param RequestInterface $request
+ * @param ResponseInterface $response
+ */
+ public function handleRangeHeaders(RequestInterface $request, ResponseInterface $response) {
+ if (\OC_App::isEnabled('files_encryption')) {
+ // encryption does not support range requests (yet)
+ $request->removeHeader('range');
+ }
+ }
+
}