This is done properly in the carddav and caldav packages, but the custom
function does not know what the user intends to serve, so it must be
passed in from the user. Without this, certain clients (e.g. DAVx5)
will be unable to discover endpoints served this way.
Also slightly extend the supported methods returned on OPTIONS requests.
REPORT is properly supported, the others are mostly for not giving
clients the impression that the resources are read-only.
Allow the backend to provide a value for the `getcontentlength` property
as described in [RFC 2518 section 13.4][1].
The implementation treats is as optional, allthough it is a required
property per RFC. Most clients do perfectly fine without it, though.
Properly setting this in the backend makes the CardDAV collection
listable with clients that do require it, e.g. cadaver.
[1]: https://datatracker.ietf.org/doc/html/rfc2518#section-13.4
Currently, the user principal path and the home set path are both
hardcoded to "/", for both CalDAV and CardDAV. This poses a challenge if
one wishes to run a CardDAV and CalDAV server in the same server.
This commit introduces the concept of a UserPrincipalBackend. This
backend must provide the path of the current user's principal URL from
the given request context.
The CalDAV and CardDAV backends are extended to also function as
UserPrincipalBackend. In addition, they are required to supply the path
of the respective home set (`calendar-home-set` and
`addressbook-home-set`). The CardDAV and CalDAV servers act accordingly.
The individual servers will continue to work as before (including the
option of keeping everything at "/"). If one wishes to run CardDAV and
CalDAV in parallel, the new `webdav.ServeUserPrincipal()` can be used as
a convenience function to serve a common user principal URL for both
servers. The input for this function can be easily computed by the
application by getting the home set paths from the backends and using
`caldav.NewCalendarHomeSet()` and `carddav.NewAddressbookHomeSet()` to
create the home sets.
Note that the storage backend will have to know about these paths as
well. For any non-trivial use case, a storage backend should probably
have access to the same UserPrincipalBackend. That is, however, an
implementation detail and doesn't have to be reflected in the
interfaces.