WebDAV-Push March 2025
Hirner Experimental [Page]
Workgroup:
Independent submission
Published:
Author:
R. Hirner
bitfire.at

Push for WebDAV (WebDAV-Push)

Abstract

This document specifies a protocol to notify WebDAV clients when the content or properties of a resource or its members are changed on the WebDAV server.

Currently, the only specified transport for these push notifications is Web Push (RFC 8030). However, the protocol could be used with other transports as well.

Table of Contents

1. Introduction

(This document is in work and subject of ongoing modification.)

WebDAV-Push is intended as a tool for WebDAV [RFC4918] clients to get notified about updates in resources (usually collections) in near time so that they can refresh their views, perform synchronization etc.

A client MUST NOT rely solely on WebDAV-Push, so it should also perform regular polling like when WebDAV-Push is not available. However if WebDAV-Push is available, the polling frequency can be significantly reduced.

Typical use cases:

1.1. Notational Conventions

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all capitals, as shown here.

1.2. Overview

W e b D A V - P u s h S e r v e r P u s h S e r v i c e W e b D A V - P u s h C l i e n t C r e a t e s u b s c r i p t i o n R e g i s t e r s u b s c r i p t i o n C o n t e n t u p d a t e n o t i f i c a t i o n
Figure 1: Basic WebDAV-Push Workflow

A WebDAV-Push server needs to

  • advertise WebDAV-Push and relevant information (service detection),

  • manage subscriptions to resources (usually collections), and

  • send push messages when a subscribed resource changes.

In order to manage subscriptions, a WebDAV server needs to

  • provide a way for clients to subscribe to a resource (with transport-specific information),

  • provide a way for clients to unsubscribe from a resource, and

  • handle expired or otherwise invalid subscriptions.

Notifications about updated resources have to be sent to all subscribed clients over the respective push transports.

A WebDAV-Push client typically

  • detects whether the server supports WebDAV-Push and which push transports,

  • connects to a push service (which is usually not operated by the same party as the WebDAV server),

  • subscribes to one or more resources on the server (with the data received from the push service),

  • receives push notifications that cause some client-side action (like to refresh the view or run synchronization),

  • re-subscribes to resources before the registrations expire,

  • unsubscribes from resources when notifications are not needed anymore.

WebDAV-Push is not restricted to a specific push transport. This allows even upcoming, yet unknown push transports to be used with WebDAV-Push. Push transport definitions can define extra properties and additional processing rules.

WebDAV-Push implementations SHOULD implement at least the Web Push transport (defined in Section 7). If possible, other push transports SHOULD be connected over a Web Push gateway instead of defining a new WebDAV-Push transport.

To use a proprietary push service, a client vendor may need to provide a rewrite proxy that offers a Web Push endpoint which signs and forwards the requests to the respective push service. If possible, VAPID should be used instead of such a proxy.

1.3. Terminology

If parts of a term are in brackets, it means that those parts may or may not be written together with the other parts. However it means the same in any case.

Push notification

push message or delivery of a push message

Push message

Actual network message that is sent from the server over a push transport to the client. Notifies the client that a specific resource (identified by its push topic) has changed.

In Web Push context, a WebDAV-Push server can send a push message (more exact, "request delivery of a push message") over the push service by POSTing the message to the client's subscription URL.

Push service

Infrastructure that implements a specific push transport. The push service is the actual network service between WebDAV-Push server and WebDAV-Push client.

For instance, if the push transport is Web Push is a Web app, the push service would be provided by the vendor of the browser that the client runs in.

(Push) subscription (URL)

The information that the client needs to provide to the server so that the server can send push notifications. The server can POST a push message to that URL.

If the transport is Web Push, the term "(push) subscription (URL)" as used in this document is equivalent to the Web Push term "push resource".

(Push) topic

Character sequence that identifies a WebDAV resource for push purposes (unique per WebDAV server). A specific resource could be reachable at different URLs, but it can only have one push topic.

(Push) transport

Protocol that defines an actual push mechanism. In this document, Web Push is the only defined push transport (see Section 7). However, WebDAV-Push may also be used with other push transports like proprietary or yet unknown protocols. In that case, it has to be specified how to use that protocol with WebDAV-Push. A push transport typically involves a push service.

Web Push

"Protocol for the delivery of real-time events to user agents", defined by [RFC8030]. Usually implemented in browsers (which means that major browser vendors provide their own push services), but there are also other implementations like [UnifiedPush]. Some parts (namely push message delivery from the push service to the client) specify implementation details that may be done by other means without changing the meaning of the RFC for WebDAV-Push servers and clients.

There are also additional standards that can be considered to belong to Web Push, especially VAPID ([RFC8292]) and Message Encryption ([RFC8291]).

WebDAV-Push

WebDAV-based protocol to notify clients about updates in resource using a push transport (in contrast to polling). Specified in this document.

(WebDAV-Push) client

WebDAV client that supports WebDAV-Push, for instance a CalDAV/CardDAV app on a mobile device

(WebDAV-Push) server

WebDAV server (for instance a CalDAV/CardDAV server) that implements WebDAV-Push

2. Service Detection

A server that supports WebDAV-Push MUST include "webdav-push" in the DAV header of an OPTIONS response for any resource that supports WebDAV-Push. The "webdav-push" value MUST indicate that all MUST level requirements of this document are met.

Example:

OPTIONS /calendars/
Host: caldav.example.com

HTTP/1.1 200 OK
Allow: OPTIONS, GET, HEAD, POST, PUT, DELETE, TRACE, COPY, MOVE
Allow: PROPFIND, PROPPATCH, LOCK, UNLOCK, REPORT, ACL
DAV: 1, 2, access-control, calendar-access, webdav-push
Content-Length: 0

Here, the OPTIONS response contains "webdav-push" in the DAV header to indicate that the resource supports the properties and operations defined in this document.

2.1. Push Properties

To provide information about WebDAV-Push support, new properties are defined. A server MUST provide the transports, topic and supported-triggers properties for resources that support WebDAV-Push. A server MUST NOT provide the topic and supported-triggers properties for resources that don't support WebDAV-Push (for instance for non-collection resources, if they're not supported).

The transports element lists available push transports. Within the scope of this document, the only supported transport is web-push (see Section 7). Although the property is defined on every Push-capable resource, its value is usually the same for every resource on the server.

The topic is a globally unique identifier for the resource. A specific resource could be reachable with different URLs, but it can have only one push topic. A server could for instance use a random UUID or a canonical URL that won't change over the lifetime of the resource. The value should be globally unique because a client can subscribe to resources from multiple servers and needs to be able to determine the correct one when it receives a push message.

The supported-triggers element MUST contain at least one of the following elements:

  • content-update if the resource supports push notifications on content updates (see Section 3.1.1). It contains a {DAV:}depth property that indicates the maximum supported depth.

  • property-update if the resource supports push notifications on property updates (see Section 3.1.2). It contains a {DAV:}depth property that indicates the maximum supported depth.

Clients can use WebDAV PROPFIND to retrieve these properties. WebDAV-Push SHOULD only be advertised to clients which are actually allowed to use it.

Example:

PROPFIND https://example.com/webdav/collection/
<?xml version="1.0" encoding="utf-8" ?>
<propfind xmlns="DAV:" xmlns:P="https://bitfire.at/webdav-push">
  <prop>
    <P:transports/>
    <P:topic/>
    <P:supported-triggers/>
  </prop>
</propfind>

HTTP/1.1 207 Multi-Status
<?xml version="1.0" encoding="utf-8" ?>
<multistatus xmlns="DAV:" xmlns:P="https://bitfire.at/webdav-push">
  <response>
    <href>/webdav/collection/</href>
    <prop>
      <P:transports>
        <P:web-push>
          <P:vapid-public-key type="p256ecdsa">BA1Hxzyi1RUM1b5wjxsn7nGxAszw2u61m164i3MrAIxHF6YK5h4SDYic-dRuU_RCPCfA5aq9ojSwk5Y2EmClBPs</P:vapid-public-key>
        </P:web-push>
        <!-- Not covered by this document:
        <X:some-other-transport>
          <X:some-parameter>...</X:some-parameter>
        </X:some-other-transport>
        -->
      </P:transports>
      <P:topic>O7M1nQ7cKkKTKsoS_j6Z3w</P:topic>
      <P:supported-triggers>
        <P:content-update>
          <depth>1</depth>
        </P:content-update>
        <P:property-update>
          <depth>0</depth>
        </P:property-update>
      </P:supported-triggers>
    </prop>
  </response>
</multistatus>

In this case, the queried collection supports WebDAV-Push in general and thus has a push topic. It supports the Web Push transport and provides a VAPID public key. Push notifications are supported for content updates of internal members and on property updates of the collection itself.

The comment shows how support for some other (not yet defined) transport could be advertised together with additional specific information that is required to use it.

3. Subscription Management

3.1. Subscription Registration

To subscribe to a resource, the client sends a POST request with Content-Type: application/xml to the resource 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.

The push-register element contains:

  • exactly one subscription element, which contains all information the server needs to send a push message,

  • exactly one trigger element to specify the type of updates the client wants to be notified about, and

  • an optional expires element that contains the requested expiration time in the IMF-fixdate format (as defined in Section 5.6.7 of [RFC9110]).

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 Section 7).

To specify which updates the client wants to be notified about, it uses the trigger element, which itself can contain:

  • A content-update element to indicate the client's interest in notifications when the contents of the subscribed resource or its members change ("content update").

  • A property-update element to indicate the client's interest in notifications when the WebDAV properties of the subscribed resource or its members change ("property update").

WebDAV-Push is intended more as a helpful tool to speed up things (like synchronization) than a strict query processor. So subscriptions are processed in a relaxed way: the server does its best to fulfill the request, but if a certain trigger is not available, it's downgraded or ignored instead of rejected with an error response. If a client needs to know which triggers are supported, it can use PROPFIND with supported-triggers. A client MUST expect the server to downgrade or ignore certain triggers when they're not (fully) supported, and MUST be prepared to receive an error when it registers a subscription with only unsupported triggers.

3.1.1. Content Updates

A "content update" occurs when the subscribed resource or a member is changed or removed, as defined in Section 3.5 of [RFC6578]. Typically, this is the case when the resource itself is modified or removed, or when a member is added or removed or its contents are modified. If the server supports [RFC6578], a content update of a collection usually implies that the {DAV:}sync-token changes.

The content element contains a {DAV:}depth element that specifies whether the client is interested

  • only in content updates of the subscribed resource (depth: 0),

  • only in content updates of the subscribed resource and its internal members (depth: 1), or

  • in content updates of the subscribed resource and its members (depth: infinite).

A content update of a collection itself (not of a member) only occurs when the collection has an entity body that is returned by GET and that body changes. A server MAY ignore such changes and not send notifications in that case.

A server SHOULD support content update notifications with a depth of at least 1 for every Push-capable collection.

If the subscribed resource doesn't support the content update trigger with the requested depth, the server MUST fall back to the lowest supported value instead. If the content update trigger isn't supported for the subscribed resource at all, it MUST be ignored.

In case the depth is infinite, the limitations described in Section 3.3 of [RFC6578] apply: notifications about changes in members which are not supported by the DAV:sync-collection report may not be sent.

3.1.2. Property Updates

A "property update" occurs when the WebDAV properties of the subscribed resource or its members are modified. Properties update notifications are controlled by two elements within the property-update element:

  1. The {DAV:}depth element specifies whether the client is interested

    • only in property updates of the subscribed resource (depth: 0),

    • only in property updates of the subscribed resource and its internal members (depth: 1), or

    • in property updates of the subscribed resource and its members (depth: infinite).

    If the subscribed resource doesn't support the content update trigger with the requested depth, the server MUST fall back to the lowest supported value instead. If the content update trigger isn't supported for the subscribed resource at all, it MUST be ignored.

    In case the depth is infinite, the limitations described in Section 3.3 of [RFC6578] apply: notifications about changes in members which are not supported by the DAV:sync-collection report may not be sent.

  2. The optional {DAV:}prop element (as used in a PROPFIND request) specifies a list of properties that the client is interested in.

    If the {DAV:}prop element is empty or not present, the server chooses a list of properties that it considers to be useful for the client. If the {DAV:}prop element is present and contains properties for which property update notifications are not supported, the server MUST ignore those unsupported properties. Also, a server MAY ignore the contents of a {DAV:prop} element at all and treat it like if it was empty or not present.

    Neither a server nor a client SHOULD use property update notifications for properties that automatically change on a content update, like {DAV:}getetag, {DAV:}getlastmodified and {DAV:}sync-token, because this would implicitly cause a property update for every content update. Notifications about content updates should instead be requested/sent explicitly as content update notifications.

The removal of a resource, including the subscribed resource, is not considered as a property update but as a content update.

3.1.3. Response

Allowed response codes:

  • 201 if the subscription was registered and the server wants to return additional information, like encryption details that are only valid for this subscription. The format of these details is specified by the respective transport definition.

  • 204 if the subscription was registered without additional information

  • 403 with precondition invalid-subscription when the request doesn't contain a valid subscription

  • 403 with precondition push-not-available if WebDAV-Push is not available for this resource or if the user is not allowed to register a push subscription for it

  • 403 with precondition no-supported-trigger when the request doesn't contain a trigger or when all requested triggers are ignored (because they're not supported)

  • other response code with usual HTTP/WebDAV semantics

When a subscription is registered the first time, the server creates a URL that identifies that registration (registration URL) which can be used to remove the subscription. The server MUST send the registration URL in the Location header.

The server MUST return a HTTP Expires header (as defined in Section 5.3 of [RFC9111]) in the IMF-fixdate format with the actual expiration date on the server, which may be shorter than the expiration requested by the client.

Example 1 (successful registration):

POST https://example.com/webdav/collection/
Content-Type: application/xml; charset="utf-8"

<?xml version="1.0" encoding="utf-8" ?>
<push-register xmlns="https://bitfire.at/webdav-push" xmlns:D="DAV:">
  <subscription>
    <web-push-subscription>
      <push-resource>https://up.example.net/yohd4yai5Phiz1wi</push-resource>
      <content-encoding>aes128gcm</content-encoding>
      <subscription-public-key type="p256dh">BCVxsr7N_eNgVRqvHtD0zTZsEc6-VV-JvLexhqUzORcxaOzi6-AYWXvTBHm4bjyPjs7Vd8pZGH6SRpkNtoIAiw4</subscription-public-key>
      <auth-secret>BTBZMqHH6r4Tts7J_aSIgg</auth-secret>
    </web-push-subscription>
  </subscription>
  <trigger>
    <content-update>
      <D:depth>infinite</D:depth>
    </content-update>
    <property-update>
      <D:depth>0</D:depth>
      <D:prop>
        <D:displayname/>
        <D:owner/>
      </D:prop>
    </property-update>
  </trigger>
  <expires>Wed, 20 Dec 2023 10:03:31 GMT</expires>
</push-register>

HTTP/1.1 204 No Content
Location: https://example.com/webdav/subscriptions/io6Efei4ooph
Expires: Wed, 02 Oct 2024 07:28:00 GMT

Example 2: A client registers a content update trigger with a depth of infinite and a property update trigger with a depth of 1, but the collection supports only content update triggers with a depth of 1 and doesn't support the property update trigger at all, it registers the subscription and responds with 201. Notifications will then only be sent on content updates with a depth of 1 (trigger downgraded by server). On property updates, notifications will not be sent (trigger ignored by server).

Example 3: A client registers a property update trigger with a depth of 0 and the collection doesn't support property update triggers at all, the server ignores the trigger. So all triggers of the request are ignored and the server responds with 403 with no-supported-trigger.

3.2. Subscription Updates

Every subscription has a transport-specific unique identifier (the push resource in case of Web Push).

A server MUST NOT register a subscription with the same identifier multiple times for the same resource. Instead, when a client wants to register a subscription with an identifier that is already registered for the requested resource, the server MUST update the registration with the given details and the expiration date.

The response is the same as for subscription registration.

3.3. Subscription Removal

A client can explicitly unsubscribe from a resource by sending a DELETE request to the previously acquired registration URL.

Allowed response codes:

  • 204 if the registered subscription was removed.

  • 404 if the registration URL is unknown (or expired).

  • other response code with usual HTTP/WebDAV semantics

Sample request:

DELETE https://example.com/webdav/subscriptions/io6Efei4ooph

HTTP/1.1 204 Unregistered

3.4. Expiration

Clients MAY specify an expiration date-time when they register a subscription.

A server SHOULD take the expiration specified by a client into consideration, but MAY impose its own (often stricter) expiration rules, for instance to keep their database clean or because the client has specified an implausible late expiration. A server MUST allow subscriptions to be valid at least three days.

Clients have to refresh their registrations regularly and before the expiration date to keep them working. They can expect that subscriptions usually stay valid until their expiration, although there may be special circumstances that cause all subscriptions to be reset, like when the server software is changed.

Expired subscriptions MUST NOT be used anymore as chances are high that doing so would cause errors.

4. Push Notification

A WebDAV-Push server MUST notify registered subscriptions of a subscribed resource:

4.1. Push Message

The push message body consists of a push-message element, which contains information about the affected resource:

  • a topic element with the push topic,

  • a content-update element in case of a content update, and/or

  • a property-update element in case of a property update.

The content-update element SHOULD contain a {DAV:}sync-token element so that a client can ignore the push message when it already knows the latest state.

Example:

<?xml version="1.0" encoding="utf-8" ?>
<push-message xmlns="https://bitfire.at/webdav-push" xmlns:D="DAV:">
  <topic>O7M1nQ7cKkKTKsoS_j6Z3w</topic>
  <content-update>
    <D:sync-token>http://example.com/sync/10</D:sync-token>
  </content-update>
  <property-update />
</push-message>

Here, both the contents and the properties of the resource (or its members, depending on the registered trigger) with topic O7M1nQ7cKkKTKsoS_j6Z3w have changed. The new sync-token (after the change) is http://example.com/sync/10.

When necessary or useful, a server MAY

  • impose a rate limit for push messages,

  • delay push messages (usually for a short time, for instance to avoid multiple push messages for ongoing changes in the user interface),

  • merge/omit push messages.

Such measures SHOULD not change the overall meaning of the push notifications so that the client can still perform its desired action. For instance, of a series of push messages that contain only content updates and occur shortly after each other, all but the last message can be omitted. If one of the push messages signals a property update, it can't be just omitted because the client then wouldn't know that a property update happened.

4.2. Removal of Invalid Subscriptions

A WebDAV-Push server MUST ensure that invalid subscriptions (encountered when trying to sending a push notification) are removed at some time.

An invalid subscription is a subscription that push notifications can't be delivered to. Usually the push service returns an HTTP error code like 404 when it receives a notification for an invalid subscription. There may also be other conditions that render a subscription invalid, like a non-resolvable hostname or an encryption handshake error.

A server MAY use some logic like remembering the last successful delivery plus some tolerance interval to defer removal of an invalid subscription. Doing so will make WebDAV-Push more reliable in case of temporary problems and avoid temporal "holes" between subscription removal and re-registration.

5. CalDAV/CardDAV

WebDAV-Push can be used with CalDAV ([RFC4791]) and CardDAV ([RFC6352]) to provide short-time update notifications when collections (calendars, address books) or entries (contacts, events, …) change.

Depending on the features of a CalDAV/CardDAV client, it could for instance subscribe to:

CalDAV/CardDAV servers that support WebDAV-Push SHOULD support:

6. Security Considerations

The general requirements from Section 8 of [RFC8030] apply regardless of which transport is used. Especially:

Push services could relate clients over metadata and heuristics. For instance, clients which are at the same time notified by a specific WebDAV-Push server have probably subscribed the same resource.

See RFC 3552 and RFC 6973 TO BE DONE

Topic header, don't use insecure hashes TO BE DONE

How sensitive are the data, how to minimize risks TO BE DONE

What happens when information leaks TO BE DONE

What happens when some component is hacked TO BE DONE

7. Web Push Transport

WebDAV-Push can be used with Web Push [RFC8030] as a transport to deliver WebDAV-Push notifications directly to compliant user agents, like Web browsers which come with their own push service infrastructure.

When the Web Push transport is used for WebDAV-Push,

Corresponding terminology:

Message encryption (Section 7.3) MUST be used. VAPID (Section 7.2) SHOULD be used. (If other methods to provide a security context for Web Push become established, those can be used and necessary WebDAV properties shall be added to this document.)

A server that supports the Web Push transport MUST list the web-push element in the transports property.

W e b P u s h W e b D A V - P u s h S e r v e r S e r v i c e W e b D A V - P u s h C l i e n t G e t V A P I D p u b l i c k e y C r e a t e r e s t r i c t e d s u b s c r i p t i o n R e g i s t e r s u b s c r i p t i o n ( w i t h e n c r y p t i o n ) C o n t e n t / p r o p e r t y u p d a t e n o t i f i c a t i o n ( e n c r y p t e d ) ( e n c r y p t e d )
Figure 2: WebDAV-Push over Web Push with VAPID and Message Encryption

7.1. Subscription Registration

To register a Web Push subscription, the subscription element of the push-register request contains exactly one web-push-subscription.

The web-push-subscription element represents the public information of a Web Push subscription that is shared with the WebDAV-Push server.

It contains exactly one push-resource element, which specifies the absolute URI that identifies the endpoint where Web Push notifications are sent to.

A Web Push subscription is uniquely identified by its push resource.

7.2. VAPID

VAPID [RFC8292] binds push subscriptions to the specific WebDAV-Push server.

A WebDAV-Push server that supports VAPID stores a key pair. It exposes an additional transport property vapid-public-key within the web-push element, which contains the VAPID public key in uncompressed form and base64url encoded. The attribute type="p256ecdsa" MUST be added to allow different key types in the future. See Section 2.1 for an example.

If available, the client MUST use this key to create a restricted subscription at the push service, except when it knows that the push service doesn't support VAPID.

A client can expect the VAPID public key to be the same for all resources on the server. However the VAPID public key can still sometimes change (for instance when the server or user data is moved to another machine). In that case a client has to create new restricted subscriptions because the old ones won't work anymore.

When the server provides a VAPID public key, it MUST include a corresponding Authorization header when sending a push message in order to prove its identity to the push service.

7.3. Message Encryption

Message encryption hides details of push messages from the push services. Before creating the subscription, the client generates a key pair as defined in [RFC8291].

When the client then registers this subscription at the server, it MUST include these subscription properties:

  • content-encoding – how the encrypted content is encoded; currently only aes128gcm is supported

  • subscription-public-key – public key of the user agent's key pair in uncompressed form and base64url encoded; attribute type="p256dh" MUST be added to allow different key types in the future

  • auth-secret – authentication secret

These properties are bound to the subscription (which is identified by the push resource). A server doesn't need to store these properties for every registration, but only once for the subscription.

The server uses these data to encrypt the payload before sending it to the push service. The client then decrypts the payload again.

7.4. Push Message

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

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. The Topic header is visible to the push service, so its value MUST NOT contain sensitive information.

For instance, the header value could be derived with a secure hash function from

  • the collection topic,

  • whether the push message contains a content update,

  • whether the push message contains a property update, and

  • a secret that is only used for this purpose.

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 instance in slowly changing collections like a holiday calendar could be sent with Urgency: low.

8. XML Schema

When XML element names are used without namespace in this document, they are in the WebDAV-Push namespace: https://bitfire.at/webdav-push

All XML elements defined by this document reside in this namespace.

To reference element names in another namespace, the {ns}element syntax is used. For instance, {DAV:}prop means the prop XML element in the DAV: namespace.

The XML schema formally defines the XML elements used by this document and is expressed in [RELAXNG].

<grammar xmlns="http://relaxng.org/ns/structure/1.0" ns="https://bitfire.at/webdav-push">

  <!-- new WebDAV collection properties -->

  <!-- available push transports -->
  <define name="prop-transports">
    <element name="transports">
      <choice>
        <ref name="web-push-transport"/>
        <!-- or other transport, not covered by this schema -->
      </choice>
    </element>
  </define>

  <!-- push topic -->
  <define name="prop-topic">
    <element name="topic">
      <text/>
    </element>
  </define>

  <define name="prop-supported-triggers-content-update">
    <element name="content-update">
      <ref name="prop-dav-depth"/>
    </element>
  </define>
  <define name="prop-supported-triggers-property-update">
    <element name="property-update">
      <ref name="prop-dav-depth"/>
    </element>
  </define>
  <!-- supported triggers -->
  <define name="prop-supported-triggers">
    <element name="supported-triggers">
      <choice>
        <ref name="prop-supported-triggers-content-update"/>
        <ref name="prop-supported-triggers-property-update"/>
        <interleave>
          <ref name="prop-supported-triggers-content-update"/>
          <ref name="prop-supported-triggers-property-update"/>
        </interleave>
      </choice>
    </element>
  </define>


  <!-- subscription registration -->

  <define name="subscription-registration-trigger-content-update">
    <element name="content-update">
      <!-- requested depth -->
      <ref name="prop-dav-depth"/>
    </element>
  </define>
  <define name="subscription-registration-trigger-property-update">
    <element name="property-update">
      <!-- requested depth -->
      <ref name="prop-dav-depth"/>

      <!-- properties client is interested in -->
      <optional>
        <element ns="DAV:" name="prop">   <!-- list of properties, as in PROPFIND request -->
          <zeroOrMore>
            <element>
              <anyName/>
              <empty/>
            </element>
          </zeroOrMore>
        </element>
      </optional>
    </element>
  </define>
  <define name="subscription-registration">
    <element name="push-register">
      <!-- subscription to register -->
      <element name="subscription">
        <choice>
          <ref name="web-push-subscription"/>
          <!-- or other subscription, not covered by this schema -->
        </choice>
      </element>

      <!-- events that trigger a push notification -->
      <element name="trigger">
        <choice>
          <ref name="subscription-registration-trigger-content-update"/>
          <ref name="subscription-registration-trigger-property-update"/>
          <interleave>
            <ref name="subscription-registration-trigger-content-update"/>
            <ref name="subscription-registration-trigger-property-update"/>
          </interleave>
        </choice>
      </element>

      <!-- expiration -->
      <optional>
        <element name="expires">
          <text/>   <!-- date-time in IMF-fixdate format -->
        </element>
      </optional>
    </element>
  </define>


  <!-- XML error conditions (precondition/postcondition) for use with {DAV:}error element -->

  <define name="precondition-invalid-subscription">
    <element name="invalid-subscription">
      <empty/>
    </element>
  </define>

  <define name="precondition-push-not-available">
    <element name="push-not-available">
      <empty/>
    </element>
  </define>

  <define name="precondition-no-trigger-supported">
    <element name="no-trigger-supported">
      <empty/>
    </element>
  </define>


  <!-- push message -->

  <define name="push-message">
    <element name="push-message">
      <interleave>
        <!-- collection topic -->
        <ref name="prop-topic"/>

        <!-- content update -->
        <zeroOrMore>
          <element name="content-update">
            <optional>
              <ref name="prop-dav-sync-token"/>
            </optional>
          </element>
        </zeroOrMore>

        <!-- property update -->
        <zeroOrMore>
          <element name="property-update">
            <empty/>
          </element>
        </zeroOrMore>
      </interleave>
    </element>
  </define>


  <!-- Web Push properties -->

  <define name="web-push-transport">
    <element name="web-push">
      <!-- VAPID key -->
      <optional>
        <element name="vapid-public-key">
          <attribute name="type">
            <choice>
              <value>p256ecdsa</value>
              <!-- or other type / not covered by this schema -->
            </choice>
          </attribute>
          <text/>
        </element>
      </optional>
    </element>
  </define>

  <define name="web-push-subscription">
    <element name="web-push-subscription">
      <interleave>
        <!-- push resource (absolute URI) -->
        <element name="push-resource">
          <text/>
        </element>

        <!-- message encryption -->
        <element name="content-encoding">
          <choice>
            <value>aes128gcm</value>    <!-- defined in RFC8188 -->
            <!-- or other encoding / not covered by this schema -->
          </choice>
        </element>

        <element name="subscription-public-key">
          <attribute name="type">
            <choice>
              <value>p256dh</value>
              <!-- or other type / not covered by this schema -->
            </choice>
          </attribute>
          <text/>
        </element>

        <element name="auth-secret">
          <text/>
        </element>
      </interleave>
    </element>
  </define>


  <!-- external properties (only informational) -->

  <define name="prop-dav-depth">        <!-- defined in WebDAV (RFC 4918) -->
    <element ns="DAV:" name="depth">
      <choice>
        <value>0</value>
        <value>1</value>
        <value>infinite</value>
      </choice>
    </element>
  </define>

  <define name="prop-dav-sync-token">   <!-- defined in RFC 6578 -->
    <element ns="DAV:" name="sync-token">
      <text/>
    </element>
  </define>

</grammar>

9. References

9.1. Normative References

[RELAXNG]
The Organization for the Advancement of Structured Information Standards, "RELAX NG Specification", , <https://relaxng.org/spec-20011203.html>.
[RFC2119]
Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", BCP 14, RFC 2119, DOI 10.17487/RFC2119, , <https://www.rfc-editor.org/rfc/rfc2119>.
[RFC4918]
Dusseault, L., Ed., "HTTP Extensions for Web Distributed Authoring and Versioning (WebDAV)", RFC 4918, DOI 10.17487/RFC4918, , <https://www.rfc-editor.org/rfc/rfc4918>.
[RFC6578]
Daboo, C. and A. Quillaud, "Collection Synchronization for Web Distributed Authoring and Versioning (WebDAV)", RFC 6578, DOI 10.17487/RFC6578, , <https://www.rfc-editor.org/rfc/rfc6578>.
[RFC8030]
Thomson, M., Damaggio, E., and B. Raymor, Ed., "Generic Event Delivery Using HTTP Push", RFC 8030, DOI 10.17487/RFC8030, , <https://www.rfc-editor.org/rfc/rfc8030>.
[RFC8174]
Leiba, B., "Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words", BCP 14, RFC 8174, DOI 10.17487/RFC8174, , <https://www.rfc-editor.org/rfc/rfc8174>.
[RFC8291]
Thomson, M., "Message Encryption for Web Push", RFC 8291, DOI 10.17487/RFC8291, , <https://www.rfc-editor.org/rfc/rfc8291>.
[RFC8292]
Thomson, M. and P. Beverloo, "Voluntary Application Server Identification (VAPID) for Web Push", RFC 8292, DOI 10.17487/RFC8292, , <https://www.rfc-editor.org/rfc/rfc8292>.
[RFC9110]
Fielding, R., Ed., Nottingham, M., Ed., and J. Reschke, Ed., "HTTP Semantics", STD 97, RFC 9110, DOI 10.17487/RFC9110, , <https://www.rfc-editor.org/rfc/rfc9110>.
[RFC9111]
Fielding, R., Ed., Nottingham, M., Ed., and J. Reschke, Ed., "HTTP Caching", STD 98, RFC 9111, DOI 10.17487/RFC9111, , <https://www.rfc-editor.org/rfc/rfc9111>.

9.2. Informative References

[RFC3744]
Clemm, G., Reschke, J., Sedlar, E., and J. Whitehead, "Web Distributed Authoring and Versioning (WebDAV) Access Control Protocol", RFC 3744, DOI 10.17487/RFC3744, , <https://www.rfc-editor.org/rfc/rfc3744>.
[RFC4791]
Daboo, C., Desruisseaux, B., and L. Dusseault, "Calendaring Extensions to WebDAV (CalDAV)", RFC 4791, DOI 10.17487/RFC4791, , <https://www.rfc-editor.org/rfc/rfc4791>.
[RFC6352]
Daboo, C., "CardDAV: vCard Extensions to Web Distributed Authoring and Versioning (WebDAV)", RFC 6352, DOI 10.17487/RFC6352, , <https://www.rfc-editor.org/rfc/rfc6352>.
[RFC6638]
Daboo, C. and B. Desruisseaux, "Scheduling Extensions to CalDAV", RFC 6638, DOI 10.17487/RFC6638, , <https://www.rfc-editor.org/rfc/rfc6638>.
[UnifiedPush]
"UnifiedPush", <https://unifiedpush.org>.

Author's Address

Ricki Hirner
bitfire web engineering GmbH
Florastraße 27
2540 Bad Vöslau
Austria