filesplugin.php 4.9 KB
Newer Older
1
<?php
2
3
4
5
6
7
8
9
10
/**
 * ownCloud
 *
 * @author Thomas Müller
 * @copyright 2013 Thomas Müller <thomas.mueller@tmit.eu>
 *
 * @license AGPL3
 */

Vincent Petry's avatar
Vincent Petry committed
11
12
13
14
15
16
17
18
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 {
19
20

	// namespace
Thomas Müller's avatar
Thomas Müller committed
21
	const NS_OWNCLOUD = 'http://owncloud.org/ns';
Vincent Petry's avatar
Vincent Petry committed
22
23
24
25
26
27
	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';
28
29
30
31

	/**
	 * Reference to main server object
	 *
Thomas Müller's avatar
Thomas Müller committed
32
	 * @var \Sabre\DAV\Server
33
34
35
	 */
	private $server;

Vincent Petry's avatar
Vincent Petry committed
36
37
38
39
40
41
42
43
44
	/**
	 * @var \Sabre\DAV\Tree
	 */
	private $tree;

	public function __construct(\Sabre\DAV\Tree $tree) {
		$this->tree = $tree;
	}

45
46
47
	/**
	 * This initializes the plugin.
	 *
Thomas Müller's avatar
Thomas Müller committed
48
	 * This function is called by \Sabre\DAV\Server, after
49
50
51
52
	 * addPlugin is called.
	 *
	 * This method should set up the required event subscriptions.
	 *
Thomas Müller's avatar
Thomas Müller committed
53
	 * @param \Sabre\DAV\Server $server
54
55
	 * @return void
	 */
Thomas Müller's avatar
Thomas Müller committed
56
	public function initialize(\Sabre\DAV\Server $server) {
57
58

		$server->xmlNamespaces[self::NS_OWNCLOUD] = 'oc';
Vincent Petry's avatar
Vincent Petry committed
59
60
61
62
63
64
65
66
		$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);
67
68

		$this->server = $server;
Vincent Petry's avatar
Vincent Petry committed
69
70
71
72
		$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'));
73
74
75
76
77
	}

	/**
	 * Adds all ownCloud-specific properties
	 *
Vincent Petry's avatar
Vincent Petry committed
78
	 * @param PropFind $propFind
Thomas Müller's avatar
Thomas Müller committed
79
	 * @param \Sabre\DAV\INode $node
80
81
	 * @return void
	 */
Vincent Petry's avatar
Vincent Petry committed
82
	public function handleGetProperties(PropFind $propFind, \Sabre\DAV\INode $node) {
83

Vincent Petry's avatar
Vincent Petry committed
84
		if ($node instanceof \OC\Connector\Sabre\Node) {
85

Vincent Petry's avatar
Vincent Petry committed
86
87
88
			$propFind->handle(self::FILEID_PROPERTYNAME, function() use ($node) {
				return $node->getFileId();
			});
89

Vincent Petry's avatar
Vincent Petry committed
90
91
92
			$propFind->handle(self::PERMISSIONS_PROPERTYNAME, function() use ($node) {
				return $node->getDavPermissions();
			});
93

Vincent Petry's avatar
Vincent Petry committed
94
95
96
			$propFind->handle(self::GETETAG_PROPERTYNAME, function() use ($node) {
				return $node->getEtag();
			});
97
98
		}

Vincent Petry's avatar
Vincent Petry committed
99
100
101
102
103
104
105
106
107
		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;
			});
108
109
		}

Vincent Petry's avatar
Vincent Petry committed
110
111
112
113
		if ($node instanceof \OC\Connector\Sabre\Directory) {
			$propFind->handle(self::SIZE_PROPERTYNAME, function() use ($node) {
				return $node->getSize();
			});
114
		}
115
116
	}

Vincent Petry's avatar
Vincent Petry committed
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
	/**
	 * 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;
		});
	}

Thomas Müller's avatar
Thomas Müller committed
152
	/**
153
	 * @param string $filePath
Thomas Müller's avatar
Thomas Müller committed
154
155
	 * @param \Sabre\DAV\INode $node
	 * @throws \Sabre\DAV\Exception\BadRequest
Thomas Müller's avatar
Thomas Müller committed
156
	 */
Thomas Müller's avatar
Thomas Müller committed
157
	public function sendFileIdHeader($filePath, \Sabre\DAV\INode $node = null) {
158
159
		// chunked upload handling
		if (isset($_SERVER['HTTP_OC_CHUNKED'])) {
Vincent Petry's avatar
Vincent Petry committed
160
161
			list($path, $name) = \Sabre\HTTP\URLUtil::splitPath($filePath);
			$info = \OC_FileChunking::decodeName($name);
162
163
164
165
166
			if (!empty($info)) {
				$filePath = $path . '/' . $info['name'];
			}
		}

167
		// we get the node for the given $filePath here because in case of afterCreateFile $node is the parent folder
168
169
170
		if (!$this->server->tree->nodeExists($filePath)) {
			return;
		}
171
		$node = $this->server->tree->getNodeForPath($filePath);
Vincent Petry's avatar
Vincent Petry committed
172
		if ($node instanceof \OC\Connector\Sabre\Node) {
Thomas Müller's avatar
Thomas Müller committed
173
174
175
176
177
178
179
			$fileId = $node->getFileId();
			if (!is_null($fileId)) {
				$this->server->httpResponse->setHeader('OC-FileId', $fileId);
			}
		}
	}

180
}