Skip to content

Commit 5d8f769

Browse files
committed
Initial draft for PROPFIND for symlinks
1 parent abf0b53 commit 5d8f769

File tree

1 file changed

+71
-0
lines changed

1 file changed

+71
-0
lines changed

apps/dav/lib/Connector/Sabre/FilesPlugin.php

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,7 @@ public function initialize(Server $server) {
169169
$this->server->on('afterBind', [$this, 'sendFileIdHeader']);
170170
$this->server->on('afterWriteContent', [$this, 'sendFileIdHeader']);
171171
$this->server->on('method:GET', [$this,'httpGet']);
172+
$this->server->on('method:PROPFIND', [$this, 'httpPropFind']);
172173
$this->server->on('afterMethod:GET', [$this,'afterHttpGet']);
173174
$this->server->on('afterMethod:GET', [$this, 'handleDownloadToken']);
174175
$this->server->on('afterResponse', function ($request, ResponseInterface $response) {
@@ -234,6 +235,76 @@ public function handleDownloadToken(RequestInterface $request, ResponseInterface
234235
}
235236
}
236237

238+
/**
239+
* Handle PROPFIND http requests for symlinks
240+
* @param RequestInterface $request
241+
* @param ResponseInterface $response
242+
*/
243+
public function httpPropFind(RequestInterface $request, ResponseInterface $response)
244+
{
245+
// only handle symlinks
246+
// TODO: probably doesn't work because PROPFIND will be called on root dir and children are returned
247+
$symlinkPath = $request->getPath();
248+
$fileInfo = \OC\Files\Filesystem::getView()->getFileInfo($symlinkPath);
249+
if (!$fileInfo || $fileInfo->getType() !== \OC\Files\FileInfo::TYPE_SYMLINK) {
250+
return;
251+
}
252+
253+
$requestBody = $request->getBodyAsString();
254+
if (strlen($requestBody)) {
255+
try {
256+
$propFindXml = $this->server->xml->expect('{DAV:}propfind', $requestBody);
257+
} catch (\Sabre\XML\ParseException $e) {
258+
throw new \Sabre\DAV\Exception\BadRequest($e->getMessage(), 0, $e);
259+
}
260+
} else {
261+
$propFindXml = new \Sabre\DAV\Xml\Request\PropFind();
262+
$propFindXml->allProp = true;
263+
$propFindXml->properties = [];
264+
}
265+
266+
$newProperties = [];
267+
foreach ($propFindXml->properties as $property) {
268+
if ($property === self::GETETAG_PROPERTYNAME) {
269+
$newProperties[$property] = [200, $fileInfo->getETag()];
270+
} elseif ($property === self::LASTMODIFIED_PROPERTYNAME) {
271+
// TODO
272+
} elseif ($property === self::CREATIONDATE_PROPERTYNAME) {
273+
// TODO
274+
} elseif ($property === self::UPLOAD_TIME_PROPERTYNAME) {
275+
// TODO
276+
} elseif ($property === self::SIZE_PROPERTYNAME) {
277+
$newProperties[$property] = [200, $fileInfo->getSize()];
278+
} else { // TODO: handle other properties that make sense for symlinks
279+
$newProperties[$property] = [404];
280+
}
281+
}
282+
283+
// This is a multi-status response
284+
$response->setStatus(207);
285+
$response->setHeader('Content-Type', 'application/xml; charset=utf-8');
286+
$response->setHeader('Vary', 'Brief,Prefer');
287+
288+
// Normally this header is only needed for OPTIONS responses, however..
289+
// iCal seems to also depend on these being set for PROPFIND. Since
290+
// this is not harmful, we'll add it.
291+
$features = ['1', '3', 'extended-mkcol'];
292+
foreach ($this->server->getPlugins() as $plugin) {
293+
$features = array_merge($features, $plugin->getFeatures());
294+
}
295+
$response->setHeader('DAV', implode(', ', $features));
296+
297+
$prefer = $this->server->getHTTPPrefer();
298+
$minimal = 'minimal' === $prefer['return'];
299+
300+
$data = $this->server->generateMultiStatus($newProperties, $minimal);
301+
$response->setBody($data);
302+
303+
// Sending back false will interrupt the event chain and tell the server
304+
// we've handled this method.
305+
return false;
306+
}
307+
237308
public function httpGet(RequestInterface $request, ResponseInterface $response) {
238309
// only handle symlinks
239310
$symlinkPath = $request->getPath();

0 commit comments

Comments
 (0)