This diagram attempts to make sense of the CalDAV service autolocation process described in RFC 6764 Locating Services for Calendaring Extensions to WebDAV (CalDAV) and vCard Extensions to WebDAV (CardDAV) and, to a lesser extent, RFC 4791. The RFC is, in my opinion, not clear for a number of reasons; primarily in that the autolocation process is described haphazardly in bits and pieces that are scattered throughout the document. The diagram is my attempt to bring the separate pieces together.
Another problem with RFC 6764 is that the concept of context path, while central to the autolocation process, is never really clearly defined and only alluded to— in double quotes, as if the term is somehow slightly embarrassing and best avoided among polite company. In fact, the CalDAV context path can be understood simply as the starting point for the CalDAV service —the front door, so to speak— on a server that may be hosting other services alongside it. A service responding at the context path is, strictly speaking, offering the CalDAV protocol, but you shouldn't expect much to be happening there other than property queries about the calendar service in general and the current-user-principal in particular.
In addition there is the related concept of initial context path which is even more obliquely referred to. This is also a path on the server, whose only function is to support an HTTP redirect to the actual context path. No CalDAV service is present at this initial context path.
Lastly, I find that the RFC contradicts itself in how it prescribes whether a path determined from a DNS TXT path lookup should be interpreted as a ‘context path’ or merely as an ‘initial context path’.
Perhaps this is nitpicking but, to me, this adds to the overall confusion of an already complex set of interlocking autolocation processes described in the RFC. I hope my diagram is useful in clarifying it.
Note that we're disregarding at this point the username and credentials which are nearly completely orthogonal to service location.
Perhaps more predicably, icloud.com redirects to a subdomain.
$ dig -t SRV _caldavs._tcp.hekster.org ... ;; ANSWER SECTION: _caldavs._tcp.hekster.org. 1200 IN SRV 0 0 2080 server213.web-hosting.com.
$ dig -t SRV _caldavs._tcp.icloud.com ... ;; ANSWER SECTION: _caldavs._tcp.icloud.com. 3506 IN SRV 0 0 443 caldav.icloud.com.
Since icloud.com has no TXT record, we will have to jump to step ⑥; this is also the case if there had been a record but no path key. We'll return to this later.
$ dig -t TXT _caldavs._tcp.hekster.org ... ;; ANSWER SECTION: _caldavs._tcp.hekster.org. 1200 IN TXT "path=/"
$ dig -t TXT _caldavs._tcp.icloud.com ...
Since this is a resource explicitly associated with a specific user, you should expect to have to authenticate here; which is why we provide a username and password. These must have been obtained somewhere, which isn't explcitly shown in the diagram since credentials are really a feature of the service itself and not of autolocation. Again, expect the specific value of the ‘current user principal’ property to differ from user to user.
curl -X PROPFIND \ --header 'Content-Type: application/xml' \ --header 'Depth: 0' \ --user 'the-user-name:the-password' \ --data @- \ https://server213.web-hosting.com:2080/ <<EOF <?xml version='1.0' encoding='UTF-8'?> <D:propfind xmlns:D="DAV:"> <D:prop> <D:current-user-principal/> </D:prop> </D:propfind> EOF
<?xml version='1.0' encoding='UTF-8'?> <multistatus xmlns='DAV:'> <response> <href>/</href> <propstat> <prop> <current-user-principal> <href>/principals/__uids__/01234567-89AB-CDEF-0123-456789ABCDEF/</href> </current-user-principal> </prop> <status>HTTP/1.1 200 OK</status> </propstat> </response> </multistatus>
While §4 states that
The value of the [DNS TXT path] key MUST be the actual "context path" to the corresponding service on the serverimplying that HTTP redirects are not to be expected, this is contradicted in §6.3 which says
If present, the value of the “path” key is used for the initial “context path”.(note initial) which would imply the possibility of redirects, and §5 requires unequivocally that
clients MUST properly handle HTTP redirect responses for the [current-user-principal PROPFIND] request.See ⑥ for a description of the concept of an ‘initial context path’.
Also, on the matter of error handling RFC 6764 is somewhat confusing. According to §3;
If the initial "context path" derived from a TXT record generates HTTP errors when targeted by requests, the client SHOULD repeat its "bootstrapping" procedure using the appropriate ".well-known" URI instead.and go to ⑦. However §5 states that
If the server returns a 404 ("Not Found") HTTP status response to the request on the initial "context path", clients MAY try repeating the request on the "root" URI "/" or prompt the user for a suitable pathsuggesting, in addition, ⑨ and ⑪.
The path may be used to make HTTP requests on, but the request may not be answered there and rather must redirect elsewhere. For this reason the well-known path is referred to as merely an ‘initial context path’ which will redirect to the ‘actual context path’
Looking at the response now for icloud.com we see that, contrary to the admonition of §6.5 that
The server MUST redirect HTTP requests for that resource to the actual "context path" using one of the available mechanisms provided by HTTPand that
servers MUST NOT locate the actual CalDAV or CardDAV service endpoint at the ".well-known" URIthat iCloud does exactly that. I see this as confirmation that RFC 6764 is confusing at best and can only be properly read as a loose collection of heuristics.
Note also that iCloud returns the ‘current user principal’ in both the href of the current-user-principal property and the href of the response. Since we're querying for a property value, we expect the result as well, according to the rules of WebDAV, to be returned in the property. The href of the response is supposed to be related to the resource on which the property request was made. Note also that this is exactly how the response was returned in ④; so I think that iCloud is here again in error. In this case I don't think the WebDAV specification can be blamed; possibly it's done to support broken clients, or maybe it's just a bug. In any case, make sure to use the correct href.
curl -X PROPFIND \ --dump-header - \ --header 'Content-Type: application/xml' \ --header 'Depth: 0' \ --user 'the-user-name:the-password' \ --data @- \ https://caldav.icloud.com:443/.well-known/caldav/ <<EOF <?xml version='1.0' encoding='UTF-8'?> <D:propfind xmlns:D="DAV:"> <D:prop> <D:current-user-principal/> </D:prop> </D:propfind> EOF
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <multistatus xmlns="DAV:"> <response xmlns="DAV:"> <href>/123456789/principal/</href> <propstat> <prop> <current-user-principal xmlns="DAV:"> <href xmlns="DAV:">/123456789/principal/</href> </current-user-principal> </prop> <status>HTTP/1.1 200 OK</status> </propstat> </response>
With an explicit hostname and port number but without the initial context path, we can (re)try ⑥ and ⑦.
Establishing a connection but failing on the HTTP request suggests that we may have the hostname and port right but that the path is still wrong. If we have a user interface, and we haven't already prompted the user or we don't mind prompting again, we can go to ⑪ and do so in the hope of obtaining a path for the initial context.
All pages under this domain © Copyright 1999-2023 by: Ben Hekster