Skip to content

Commit 9d681dd

Browse files
committed
Initial draft for PROPFIND for symlinks
1 parent fd719e6 commit 9d681dd

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
@@ -160,6 +160,7 @@ public function initialize(Server $server) {
160160
$this->server->on('afterBind', [$this, 'sendFileIdHeader']);
161161
$this->server->on('afterWriteContent', [$this, 'sendFileIdHeader']);
162162
$this->server->on('method:GET', [$this,'httpGet']);
163+
$this->server->on('method:PROPFIND', [$this, 'httpPropFind']);
163164
$this->server->on('afterMethod:GET', [$this,'afterHttpGet']);
164165
$this->server->on('afterMethod:GET', [$this, 'handleDownloadToken']);
165166
$this->server->on('afterResponse', function ($request, ResponseInterface $response) {
@@ -225,6 +226,76 @@ public function handleDownloadToken(RequestInterface $request, ResponseInterface
225226
}
226227
}
227228

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

0 commit comments

Comments
 (0)