Skip to content

Commit 80a35b1

Browse files
authored
Depth, content vs property updates (#56)
* [WIP] Depth * [WIP] Depth * [WIP] Property update vs content update, depth * Rename `on` to `trigger` * Update Web Push Topic header * PROPFIND: supported-triggers
1 parent 9b718e7 commit 80a35b1

File tree

8 files changed

+196
-50
lines changed

8 files changed

+196
-50
lines changed

content.mkd

Lines changed: 71 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,8 @@ The `topic` is a globally unique identifier for the collection. A specific colle
138138
- a random UUID for each collection; or
139139
- a salted hash (server-specific salt) of the canonical collection URL, encoded with base64.
140140

141+
[^todo] The `supported-triggers` element contains supported trigger methods (see {{content-updates}} and {{property-updates}}). Do we even need it? Is it optional? Default value? Specify all depths, max depths?
142+
141143
Clients can use WebDAV `PROPFIND` to retrieve these properties. Example:
142144

143145
~~~
@@ -147,6 +149,7 @@ PROPFIND https://example.com/webdav/collection/
147149
<prop>
148150
<P:transports/>
149151
<P:topic/>
152+
<P:supported-triggers/>
150153
</prop>
151154
</propfind>
152155
@@ -163,18 +166,67 @@ The comment shows how support for some other (not yet defined) transport could b
163166

164167
# Subscription Management
165168

166-
[^todo] ACL for registering subscriptions?
169+
[^todo] Permissions / what to report when user is not allowed to register push.
167170

168171

169172
## Subscription Registration
170173

171-
To subscribe to a collection, the client sends a `POST` request with `Content-Type: application/xml` to the collection it wants to subscribe. The root XML element of the XML body is `push-register` in the WebDAV-Push namespace (`https://bitfire.at/webdav-push`) and can be used to distinguish between a WebDAV-Push and other requests.
174+
To subscribe to a collection, the client sends a `POST` request with `Content-Type: application/xml` to the collection it wants to subscribe. The root XML element of the XML body is `push-register` and can be used to distinguish between WebDAV-Push and other requests.
175+
176+
The `push-register` element contains:
172177

173-
The `push-register` element contains exactly one `subscription` element, which contains all information the server needs to send a push message, plus an optional `expires` element that contains the requested expiration time in the `IMF-fixdate` format (as defined in {{RFC9110}}).
178+
* exactly one `subscription` element, which contains all information the server needs to send a push message,
179+
* an optional `trigger` element to specify the types of events the client wants to be notified about, and
180+
* an optional `expires` element that contains the requested expiration time in the `IMF-fixdate` format (as defined in {{RFC9110}}).
174181

175182
The `subscription` element specifies a subscription that shall be notified on updates and contains exactly one element with details about a specific subscription type. Within the scope of this document, only the `web-push-subscription` child element is defined (see {{transport-web-push}}).
176183

177-
[^todo] By now, only data updates of the collection itself and in direct members (equals `Depth: 1`) are sent. Maybe it could be specified that servers can send one notification per path segment? Implications?
184+
To specify which updates the client wants to be notified about, it uses the `trigger` element, which itself can contain:
185+
186+
* A `content-update` element to indicate the client's interest in notifications when the members of the collection change (_content update_).
187+
* A `property-update` element to indicate the client's interest in notifications when the WebDAV properties of the collection change (_property update_).
188+
189+
If the `trigger` element is missing or empty, the following default will be assumed:
190+
191+
~~~xml
192+
<!-- default "trigger" if not specified: -->
193+
<trigger xmlns="https://bitfire.at/webdav-push" xmlns:D="DAV:">
194+
<!-- client wants be notified about content updates of direct members -->
195+
<content-update>
196+
<D:sync-level>1</D:depth>
197+
</content-update>
198+
199+
<!-- client wants to be notified about property changes of the collection -->
200+
<property-update>
201+
<D:depth>0</D:depth>
202+
<D:prop/>
203+
</property-update>
204+
</trigger>
205+
~~~
206+
207+
### Content Updates {#content-updates}
208+
209+
A _content update_ occurs when a member is changed or removed, as defined in {{RFC6578}} _3.5 Types of Changes Reported on Subsequent Synchronizations_ (typically when a member is added or removed or its contents are modified). If the server supports {{RFC6578}}, a content update implies that the `{DAV:}sync-token` changes.
210+
211+
The `content` element can contain an optional `{DAV:}sync-level` element (default value when missing: `1`) that specifies whether the client is interested only in changes of internal members or of all members.
212+
213+
A server MUST support a `{DAV:}sync-level` of `1` and MAY support `infinite`. In case of `infinite`, the limitations described in {{RFC6578}} _3.3 Depth Behavior_ apply: notifications about changes in members which are not supported by the `DAV:sync-collection` report may not be sent. [^todo] XML error when not supported
214+
215+
### Property Updates {#property-updates}
216+
217+
A _property update_ occurs when the WebDAV properties of the collection or its members are modified. Notifications about properties update are controlled by two elements within `properties`:
218+
219+
1. The optional `{DAV:}depth` element (as defined in {{RFC4918}}, value if missing: `0`) specifies the depth:
220+
221+
* A depth of `0` means that the client is only interested in property updates of the subscribed collection itself.
222+
* A depth of `1` means that the client is interested in property updates of the subscribed collection and its internal members.
223+
* A depth of `infinite` means that the client is interested in property updates of the subscribed collection and all its members.
224+
225+
A server MUST support a `depth` of 0 and MAY support `1` and `infinite`. In case of `infinite`, the limitations described in {{RFC6578}} _3.3 Depth Behavior_ apply: notifications about changes in members which are not supported by the `DAV:sync-collection` report may not be sent. [^todo] XML error when not supported.
226+
227+
2. The optional `{DAV:}prop` element (as it may be used in a `PROPFIND` request) specified a list of properties that the client is interested in. The list of properties MUST NOT contain properties that represent a content update, especially `{DAV:}getetag`, `{DAV:}getlastmodified` and `{DAV:}sync-token`. If the `{DAV:}prop` element is not present or empty, the server chooses the properties that it considers to be useful for the client. [^todo] XML error when not supported.
228+
229+
### Response
178230

179231
Allowed response codes:
180232

@@ -257,12 +309,10 @@ Expired subscriptions MUST NOT be used anymore as chances are high that doing so
257309

258310
A WebDAV-Push server MUST notify registered subscriptions of a subscribed collection:
259311

260-
- on a _content update_ of the collection: this is when a member is changed or removed, (as explained in {{RFC6578}}), so that the `{DAV:}sync-token` changes;
261-
- on a _property update_ of the colleciton: this is when
262-
- certain properties of the collection (like `DAV:{display-name}`) itself change,
263-
- or the property itself is removed, which changes its `{DAV:status}` to 4xx.
312+
- on a _content update_ of the collection, if this was requested during subscription registration,
313+
- on a _property update_ of the collection, if this was requested during subscription registration.
264314

265-
[^todo] Which properties?
315+
[^todo] Content/property update changes
266316

267317

268318
## Push Message
@@ -292,15 +342,23 @@ Example 1:
292342
{::include xml/sample-push-message1.xml}
293343
~~~
294344

295-
Here, the contents of the collection with topic `O7M1nQ7cKkKTKsoS_j6Z3w` have changed and the new sync-token (after the change) is `http://example.com/ns/sync/1234`.
345+
Here, the contents of the collection with topic `O7M1nQ7cKkKTKsoS_j6Z3w` have changed and the new sync-token (after the change) is `http://example.com/ns/sync/1234`. The depth of one indicates that the notification was caused by addition/change/removal of an internal member.
296346

297347
Example 2:
298348

299349
~~~
300350
{::include xml/sample-push-message2.xml}
301351
~~~
302352

303-
Here the server notifies the client that the collection with topic `O7M1nQ7cKkKTKsoS_j6Z3w` is no longer available on the server.
353+
Here, the contents of the collection with topic `O7M1nQ7cKkKTKsoS_j6Z3w` have changed and the new sync-token (after the change) is `http://example.com/ns/sync/1234`. The infinite depth indicates that the notification was caused by addition/change/removal of a member.
354+
355+
Example 3:
356+
357+
~~~
358+
{::include xml/sample-push-message3.xml}
359+
~~~
360+
361+
Here the server notifies the client that the collection with topic `O7M1nQ7cKkKTKsoS_j6Z3w` is no longer available on the server. The zero depth indicates that this message is about the collection itself, and not about its members.
304362

305363

306364
## Removal of Invalid Subscriptions
@@ -351,6 +409,7 @@ collection.
351409

352410
[^todo] What happens when some component is hacked
353411

412+
[^todo] Topic header, don't use insecure hashes
354413

355414

356415
# Web Push Transport {#transport-web-push}
@@ -373,8 +432,6 @@ Usage of message encryption {{RFC8291}} and VAPID {{RFC8292}} is RECOMMENDED. If
373432

374433
Support for the Web Push transport is indicated by the `web-push` element in the `transports` collection property.
375434

376-
A WebDAV-Push server SHOULD use the collection topic as `Topic` header in push messages to replace previous notifications for the same collection.
377-
378435

379436
## Subscription Registration
380437

@@ -395,30 +452,10 @@ Example:
395452

396453
The push message is delivered via `POST` to the push resource, with `Content-Type: application/xml; charset="UTF-8"`.
397454

398-
The push topic SHOULD be used to generate the `Topic` header. Since RFC 8030 limits the `Topic` header to 32 characters from the URL and filename-safe Base64 alphabet, it's RECOMMENDED to use a hash of the push topic that meets these requirements as the header value.
399-
400-
The exact algorithm to derive the `Topic` header from the push topic can be chosen by the server.
455+
The server MAY send the push message with a `Topic` header so that an undelivered push message can be replaced by an updated one. The server MUST ensure that the meaning doesn't change when a push message is potentially replaced. Usually this means that the value is derived from the collection topic and the information whether the push message indicates a content and/or property update. The `Topic` header is visible to the push service, so its value MUST NOT contain sensitive information.
401456

402457
The server MAY use the `Urgency` header to set the priority of the push message. For instance, a CalDAV server may send push notifications for new/changed events with alarms that are scheduled within the next 15 minutes with `Urgency: high` so that users receive the alarm as soon as possible. Updates that are not that time-critical for the user, for instance in slowly changing collections like a holiday calendar may be sent with `Urgency: low`.
403458

404-
Example:
405-
406-
Push topic: `O7M1nQ7cKkKTKsoS_j6Z3w`
407-
SHA1(push topic): `47788cfcf010ece3030175b8fa63276bbaea4862`
408-
As base64url: `R3iM_PAQ7OMDAXW4-mMna7rqSGI`
409-
410-
(Note that SHA1 doesn't serve a cryptographical purpose here and is just used to generate a fixed-length hash out of the variable-length topic.)
411-
412-
So push message delivery is requested with this header:
413-
414-
~~~
415-
POST <push subscription URL>
416-
Content-Type: application/xml; charset="UTF-8"
417-
Topic: R3iM_PAQ7OMDAXW4-mMna7rqSGI
418-
419-
<push message body>
420-
~~~
421-
422459

423460
## VAPID
424461

xml/sample-propfind-multistatus.xml

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,15 @@
66
<P:web-push />
77

88
<!-- Not covered by this document:
9-
<P:some-other-transport>
10-
<P:some-parameter>...</P:some-parameter>
11-
</P:some-other-transport>
9+
<X:some-other-transport>
10+
<X:some-parameter>...</X:some-parameter>
11+
</X:some-other-transport>
1212
-->
1313
</P:transports>
14-
<P:topic xmlns="https://bitfire.at/webdav-push">O7M1nQ7cKkKTKsoS_j6Z3w</P:topic>
14+
<P:topic>O7M1nQ7cKkKTKsoS_j6Z3w</P:topic>
15+
<P:supported-triggers>
16+
<P:content-update />
17+
</P:supported-triggers>
1518
</prop>
1619
</response>
1720
</multistatus>

xml/sample-push-message1.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
<?xml version="1.0" encoding="utf-8" ?>
22
<P:push-message xmlns:D="DAV:" xmlns:P="https://bitfire.at/webdav-push">
3+
<D:depth>1</D:depth>
34
<D:propstat>
45
<D:prop>
56
<P:topic>O7M1nQ7cKkKTKsoS_j6Z3w</P:topic>

xml/sample-push-message2.xml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
<?xml version="1.0" encoding="utf-8" ?>
2-
<P:push-message xmlns:P="https://bitfire.at/webdav-push">
3-
<D:propstat xmlns:D="DAV:">
4-
<D:status>404 Not Found</D:status>
2+
<P:push-message xmlns:D="DAV:" xmlns:P="https://bitfire.at/webdav-push">
3+
<D:depth>infinity</D:depth>
4+
<D:propstat>
55
<D:prop>
66
<P:topic>O7M1nQ7cKkKTKsoS_j6Z3w</P:topic>
7+
<D:sync-token>http://example.com/ns/sync/1234</D:sync-token>
78
</D:prop>
89
</D:propstat>
910
</P:push-message>

xml/sample-push-message3.xml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?xml version="1.0" encoding="utf-8" ?>
2+
<P:push-message xmlns:D="DAV:" xmlns:P="https://bitfire.at/webdav-push">
3+
<D:depth>0</D:depth>
4+
<D:propstat>
5+
<D:status>404 Not Found</D:status>
6+
<D:prop>
7+
<P:topic>O7M1nQ7cKkKTKsoS_j6Z3w</P:topic>
8+
</D:prop>
9+
</D:propstat>
10+
</P:push-message>

xml/sample-registration.xml

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,20 @@
1-
<push-register xmlns="https://bitfire.at/webdav-push">
1+
<push-register xmlns="https://bitfire.at/webdav-push" xmlns:D="DAV:">
22
<subscription>
33
<web-push-subscription>
44
<push-resource>https://up.example.net/yohd4yai5Phiz1wi</push-resource>
55
</web-push-subscription>
66
</subscription>
7+
<trigger>
8+
<content-update>
9+
<D:sync-level>infinite</D:sync-level>
10+
</content-update>
11+
<property-update>
12+
<D:depth>0</D:depth>
13+
<D:prop>
14+
<D:displayname/>
15+
<D:owner/>
16+
</D:prop>
17+
</property-update>
18+
</trigger>
719
<expires>Wed, 20 Dec 2023 10:03:31 GMT</expires>
820
</push-register>

xml/validate-samples.rng

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,17 @@
1717
<text/>
1818
</element>
1919
<element name="prop">
20-
<zeroOrMore>
21-
<ref name="prop-transports"/>
22-
<ref name="prop-topic"/>
23-
</zeroOrMore>
20+
<interleave>
21+
<optional>
22+
<ref name="prop-transports"/>
23+
</optional>
24+
<optional>
25+
<ref name="prop-topic"/>
26+
</optional>
27+
<optional>
28+
<ref name="prop-supported-triggers"/>
29+
</optional>
30+
</interleave>
2431
</element>
2532
</element>
2633
</element>

xml/webdav-push.rng

Lines changed: 79 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,59 @@
2020
</define>
2121

2222

23+
<define name="trigger-content-update">
24+
<element name="content-update">
25+
<optional>
26+
<element ns="DAV:" name="sync-level"> <!-- defined in RFC 6578 -->
27+
<choice>
28+
<value>1</value>
29+
<value>infinite</value>
30+
</choice>
31+
</element>
32+
</optional>
33+
</element>
34+
</define>
35+
36+
<define name="trigger-property-update">
37+
<element name="property-update">
38+
<interleave>
39+
<optional>
40+
<element ns="DAV:" name="depth"> <!-- defined in WebDAV (RFC 4918) -->
41+
<choice>
42+
<value>0</value>
43+
<value>1</value>
44+
<value>infinite</value>
45+
</choice>
46+
</element>
47+
</optional>
48+
49+
<optional>
50+
<element ns="DAV:" name="prop"> <!-- defined in WebDAV (RFC 4918) -->
51+
<zeroOrMore>
52+
<element>
53+
<anyName/>
54+
<empty/>
55+
</element>
56+
</zeroOrMore>
57+
</element>
58+
</optional>
59+
</interleave>
60+
</element>
61+
</define>
62+
63+
<define name="prop-supported-triggers">
64+
<!-- supported triggers -->
65+
<element name="supported-triggers">
66+
<zeroOrMore>
67+
<ref name="trigger-content-update"/>
68+
</zeroOrMore>
69+
<zeroOrMore>
70+
<ref name="trigger-property-update"/>
71+
</zeroOrMore>
72+
</element>
73+
</define>
74+
75+
2376
<!-- Subscription Registration -->
2477

2578
<define name="subscription-registration">
@@ -32,6 +85,20 @@
3285
</choice>
3386
</element>
3487

88+
<!-- types of events -->
89+
<optional>
90+
<element name="trigger">
91+
<interleave>
92+
<optional>
93+
<ref name="trigger-content-update"/>
94+
</optional>
95+
<optional>
96+
<ref name="trigger-property-update"/>
97+
</optional>
98+
</interleave>
99+
</element>
100+
</optional>
101+
35102
<!-- expiration -->
36103
<optional>
37104
<element name="expires">
@@ -46,14 +113,22 @@
46113

47114
<define name="push-message">
48115
<element name="push-message">
49-
<element ns="DAV:" name="propstat"> <!-- defined in WebDAV (RFC 4918) -->
116+
<element ns="DAV:" name="depth"> <!-- defined in WebDAV (RFC 4918) -->
117+
<choice>
118+
<value>0</value>
119+
<value>1</value>
120+
<value>infinity</value>
121+
</choice>
122+
</element>
123+
124+
<element ns="DAV:" name="propstat"> <!-- defined in WebDAV (RFC 4918) -->
50125
<optional>
51-
<element ns="DAV:" name="status"> <!-- defined in WebDAV (RFC 4918) -->
126+
<element ns="DAV:" name="status"> <!-- defined in WebDAV (RFC 4918) -->
52127
<text/>
53128
</element>
54129
</optional>
55130

56-
<element ns="DAV:" name="prop"> <!-- defined in WebDAV (RFC 4918) -->
131+
<element ns="DAV:" name="prop"> <!-- defined in WebDAV (RFC 4918) -->
57132
<ref name="prop-topic"/>
58133

59134
<optional>
@@ -67,7 +142,7 @@
67142
</define>
68143

69144

70-
<!-- Web Push -->
145+
<!-- Web Push Properties -->
71146

72147
<define name="web-push-transport">
73148
<element name="web-push">

0 commit comments

Comments
 (0)