Skip to content

Commit e61f0a0

Browse files
committed
Handle 404 in CardDAV multi get - refs #829
1 parent 9fb8b91 commit e61f0a0

File tree

7 files changed

+101
-17
lines changed

7 files changed

+101
-17
lines changed

lib/CardDAV/AddressBook.php

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,8 +102,10 @@ public function getMultipleChildren(array $paths)
102102
$objs = $this->carddavBackend->getMultipleCards($this->addressBookInfo['id'], $paths);
103103
$children = [];
104104
foreach ($objs as $obj) {
105-
$obj['acl'] = $this->getChildACL();
106-
$children[] = new Card($this->carddavBackend, $this->addressBookInfo, $obj);
105+
if (is_array($obj)) {
106+
$obj['acl'] = $this->getChildACL();
107+
$children[] = new Card($this->carddavBackend, $this->addressBookInfo, $obj);
108+
}
107109
}
108110

109111
return $children;

lib/DAV/Client.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
namespace Sabre\DAV;
66

7+
use Sabre\DAV\Xml\Response\MultiStatus;
78
use Sabre\HTTP;
89
use Sabre\Uri;
910

@@ -416,6 +417,7 @@ public function getAbsoluteUrl($url)
416417
*/
417418
public function parseMultiStatus($body)
418419
{
420+
/** @var MultiStatus $multistatus */
419421
$multistatus = $this->xml->expect('{DAV:}multistatus', $body);
420422

421423
$result = [];

lib/DAV/Server.php

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1015,19 +1015,22 @@ public function getPropertiesForMultiplePaths(array $paths, array $propertyNames
10151015
{
10161016
$result = [
10171017
];
1018-
10191018
$nodes = $this->tree->getMultipleNodes($paths);
1020-
10211019
foreach ($nodes as $path => $node) {
1022-
$propFind = new PropFind($path, $propertyNames);
1023-
$r = $this->getPropertiesByNode($propFind, $node);
1024-
if ($r) {
1025-
$result[$path] = $propFind->getResultForMultiStatus();
1020+
if (null === $node) {
1021+
$result[$path] = [];
10261022
$result[$path]['href'] = $path;
1027-
1028-
$resourceType = $this->getResourceTypeForNode($node);
1029-
if (in_array('{DAV:}collection', $resourceType) || in_array('{DAV:}principal', $resourceType)) {
1030-
$result[$path]['href'] .= '/';
1023+
$result[$path]['status'] = 404;
1024+
} else {
1025+
$propFind = new PropFind($path, $propertyNames);
1026+
$r = $this->getPropertiesByNode($propFind, $node);
1027+
if ($r) {
1028+
$result[$path] = $propFind->getResultForMultiStatus();
1029+
$result[$path]['href'] = $path;
1030+
$resourceType = $this->getResourceTypeForNode($node);
1031+
if (in_array('{DAV:}collection', $resourceType) || in_array('{DAV:}principal', $resourceType)) {
1032+
$result[$path]['href'] .= '/';
1033+
}
10311034
}
10321035
}
10331036
}
@@ -1665,9 +1668,11 @@ private function writeMultiStatus(Writer $w, $fileProperties, bool $strip404s)
16651668
if ($strip404s) {
16661669
unset($entry[404]);
16671670
}
1671+
$status = isset($entry['status']) ? $entry['status'] : null;
16681672
$response = new Xml\Element\Response(
16691673
ltrim($href, '/'),
1670-
$entry
1674+
$entry,
1675+
$status
16711676
);
16721677
$w->write([
16731678
'name' => '{DAV:}response',

lib/DAV/Tree.php

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
namespace Sabre\DAV;
66

7+
use Sabre\DAV\Exception\NotFound;
78
use Sabre\Uri;
89

910
/**
@@ -269,17 +270,35 @@ public function getMultipleNodes($paths)
269270
$result = [];
270271

271272
foreach ($parents as $parent => $children) {
272-
$parentNode = $this->getNodeForPath($parent);
273+
try {
274+
$parentNode = $this->getNodeForPath($parent);
275+
} catch (NotFound $ex) {
276+
foreach ($children as $child) {
277+
$fullPath = $parent.'/'.$child;
278+
$result[$fullPath] = null;
279+
}
280+
continue;
281+
}
273282
if ($parentNode instanceof IMultiGet) {
274283
foreach ($parentNode->getMultipleChildren($children) as $childNode) {
275284
$fullPath = $parent.'/'.$childNode->getName();
276285
$result[$fullPath] = $childNode;
277286
$this->cache[$fullPath] = $childNode;
278287
}
288+
foreach ($children as $child) {
289+
$fullPath = $parent.'/'.$child;
290+
if (!isset($result[$fullPath])) {
291+
$result[$fullPath] = null;
292+
}
293+
}
279294
} else {
280295
foreach ($children as $child) {
281296
$fullPath = $parent.'/'.$child;
282-
$result[$fullPath] = $this->getNodeForPath($fullPath);
297+
try {
298+
$result[$fullPath] = $this->getNodeForPath($fullPath);
299+
} catch (NotFound $ex) {
300+
$result[$fullPath] = null;
301+
}
283302
}
284303
}
285304
}

lib/DAV/Xml/Element/Response.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ class Response implements Element
2929
protected $href;
3030

3131
/**
32-
* Propertylist, ordered by HTTP status code.
32+
* Property list, ordered by HTTP status code.
3333
*
3434
* @var array
3535
*/
@@ -124,7 +124,7 @@ public function xmlSerialize(Writer $writer)
124124
$writer->writeElement('{DAV:}href', $writer->contextUri.\Sabre\HTTP\encodePath($this->getHref()));
125125

126126
$empty = true;
127-
$httpStatus = $this->getHTTPStatus();
127+
$httpStatus = $this->getHttpStatus();
128128

129129
// Add propstat elements
130130
foreach ($this->getResponseProperties() as $status => $properties) {

tests/Sabre/CardDAV/MultiGetTest.php

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,4 +96,59 @@ public function testMultiGetVCard4()
9696
],
9797
], $result);
9898
}
99+
100+
public function testMultiGet404()
101+
{
102+
$request = HTTP\Sapi::createFromServerArray([
103+
'REQUEST_METHOD' => 'REPORT',
104+
'REQUEST_URI' => '/addressbooks/user1/book1',
105+
]);
106+
107+
$request->setBody(
108+
'<?xml version="1.0"?>
109+
<c:addressbook-multiget xmlns:d="DAV:" xmlns:c="urn:ietf:params:xml:ns:carddav">
110+
<d:prop>
111+
<d:getetag />
112+
<c:address-data />
113+
</d:prop>
114+
<d:href>/addressbooks/user1/unknown/card1</d:href>
115+
<d:href>/addressbooks/user1/book1/card1</d:href>
116+
<d:href>/addressbooks/user1/book1/unknown-card</d:href>
117+
</c:addressbook-multiget>'
118+
);
119+
120+
$response = new HTTP\ResponseMock();
121+
122+
$this->server->httpRequest = $request;
123+
$this->server->httpResponse = $response;
124+
125+
$this->server->exec();
126+
127+
$this->assertEquals(207, $response->status, 'Incorrect status code. Full response body:'.$response->body);
128+
129+
$this->assertXmlStringEqualsXmlString('<?xml version="1.0"?>
130+
<d:multistatus xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns" xmlns:card="urn:ietf:params:xml:ns:carddav">
131+
<d:response>
132+
<d:href>/addressbooks/user1/unknown/card1</d:href>
133+
<d:status>HTTP/1.1 404 Not Found</d:status>
134+
</d:response>
135+
<d:response>
136+
<d:href>/addressbooks/user1/book1/card1</d:href>
137+
<d:propstat>
138+
<d:prop>
139+
<d:getetag>"ffe3b42186ba156c84fc1581c273f01c"</d:getetag>
140+
<card:address-data>BEGIN:VCARD
141+
VERSION:3.0
142+
UID:12345
143+
END:VCARD</card:address-data>
144+
</d:prop>
145+
<d:status>HTTP/1.1 200 OK</d:status>
146+
</d:propstat>
147+
</d:response>
148+
<d:response>
149+
<d:href>/addressbooks/user1/book1/unknown-card</d:href>
150+
<d:status>HTTP/1.1 404 Not Found</d:status>
151+
</d:response>
152+
</d:multistatus>', $response->body);
153+
}
99154
}

tests/Sabre/DAV/Sync/PluginTest.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ public function testSyncInitialSyncCollection()
9292

9393
self::assertEquals(207, $response->status, 'Full response body:'.$response->getBodyAsString());
9494

95+
/** @var DAV\Xml\Response\MultiStatus $multiStatus */
9596
$multiStatus = $this->server->xml->parse($response->getBodyAsString());
9697

9798
// Checking the sync-token

0 commit comments

Comments
 (0)