Commit Graph

242 Commits

Author SHA1 Message Date
Conrad Hoffmann
dc63df9058 carddav: evaluate recurrence in match helper
The match helper will now properly return recurring events if any of
their recurrences fall into the queried time range. A test for this was
added as well.
2022-08-31 16:57:42 +02:00
Conrad Hoffmann
58dc8e4982 Update to latest version of go-ical
Needed for handling of recurring events.
2022-08-31 16:57:42 +02:00
Conrad Hoffmann
9adfd95fa9 carddav: run gofmt 2022-08-31 13:53:16 +02:00
Conrad Hoffmann
4264d321a5 caldav: fix match test example from RFC
See https://www.rfc-editor.org/errata/eid4164

The original RFC's appendix was missing a part of the calendar data used
in the examples. This will become relevant when adding tests for
retrieving recurring events.
2022-08-31 10:13:02 +02:00
Conrad Hoffmann
4a3cd0510f carddav: end-to-end test address book discovery
As the implementation evolves, it will be necessary to have more tests
to assert we don't break anything when making changes. This commit
introduces a test setup to test that server and client can handle the
address book discovery with various parameters. The test setup should be
easily extendable to cover even more ground as needed.
2022-07-13 08:45:11 +02:00
Simon Ser
987c9eef0b carddav: use "/.well-known/carddav/" as initial context path in Discover
See RFC 6764 section 6 item 3.
2022-07-13 08:43:40 +02:00
myml
e0764c06a3 fix: Response body was not closed causing the goroutine leak 2022-06-20 08:59:55 +02:00
Conrad Hoffmann
db966a275c carddav: do property filtering in match.Filter()
With this commit, the list of AddressObjects returned by `Filter()` will
always be a correct response to the query argument passed to it, even if
the input list contained objects with arbitraty properties present.
2022-06-03 08:36:05 +02:00
Conrad Hoffmann
21aea26c70 carddav: don't filter properties in test queries
As is, the tests in `match_test.go` test wrong behavior. They request
"partial retrieval" (i.e. filtering of returned properties), but compare
the returned result to the original input. They essentially rely on the
fact that property filtering is currently not implemented.

To fix this, simply make all existing test queries request all
properties. If property filtering gets implemented (correctly), the
tests will then continue to work. New tests can be added for testing
the property filtering itself.
2022-06-03 08:36:05 +02:00
Simon Ser
d7891ce50c internal: fix XML element struct naming
We were sometimes using TitleCase, sometimes Lowercase. Let's align
on the idiomatic Go naming and pick TitleCase everywhere.
2022-05-31 23:04:42 +02:00
Simon Ser
55a9274ba6 internal: use Namespace instead of "DAV:" 2022-05-31 17:10:30 +02:00
Simon Ser
1c71a7a1c4 internal: add more context to Response.DecodeProp errors 2022-05-31 17:04:44 +02:00
Simon Ser
d0fc22a428 internal: use errors.As in IsNotFound
Allows it to work properly with wrapped errors.
2022-05-31 16:58:45 +02:00
Simon Ser
9bc7a8f15b internal: drop Multistatus.Get
This is now unused.
2022-05-31 16:11:08 +02:00
Conrad Hoffmann
03633121d9 client: support redirects in PropfindFlat()
One common method for CalDAV or CardDAV clients to find the current user
principal URL is to request the `/.well-known` URL (see [RFC 6764,
section 6][1]), expecting a redirect. Such URL is for example a valid
result of the discovery phase described in that RFC. The expectation is
that a client, given such URL, is able to find the principal URL by
following a redirect when sending a PROPFIND request.

This change makes `PropfindFlat()` (and, by extension,
`FindCurrentUserPrincipal()`) handle such a redirect and correctly
return the requested properties, even if their HREF is different from
the original request path.

[1]: https://datatracker.ietf.org/doc/html/rfc6764#section-6
2022-05-31 16:05:54 +02:00
Conrad Hoffmann
13fa812f94 caldav: implement filter function for queries
This is not yet complete (see TODOs in code), but basic filtering of a
list of CaledarObjects works.

Includes test data from the RFC, which allows to use the RFCs examples
as test cases.
2022-05-25 18:57:16 +02:00
Simon Ser
06ecb0e64c webdav: add TODO about fallback in Client.FindCurrentUserPrincipal 2022-05-25 15:07:20 +02:00
Simon Ser
97e0b10b4f carddav: add Discover TODO about "path" key in TXT record 2022-05-25 14:57:05 +02:00
Conrad Hoffmann
5d845721d8 carddav: add Content-Length support to client 2022-05-24 11:18:11 +02:00
Conrad Hoffmann
1e99b70a62 carddav: set content length header for HEAD/GET requests
Now that the backend can supply this value, use it for explicitly
setting the header in GET/HEAD responses if available.
2022-05-24 11:18:11 +02:00
Conrad Hoffmann
a3e56141d9 carddav: add support for getcontentlength property
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
2022-05-24 11:18:11 +02:00
Simon Ser
9ed4abce57 caldav: add Content-Length support to client
Follow-up for https://github.com/emersion/go-webdav/pull/83.
2022-05-24 10:47:40 +02:00
Simon Ser
38a35d3545 carddav: improve Client.SyncCollection docs 2022-05-24 10:20:08 +02:00
Conrad Hoffmann
757a615e9f caldav: set content length header for HEAD/GET requests
Now that the backend can supply this value, use it for explicitly
setting the header in GET/HEAD responses if available.
2022-05-24 10:08:32 +02:00
Conrad Hoffmann
491af8e42c caldav: add support for getcontentlength property
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 CalDAV collection
listable with clients that do require it, e.g. cadaver.

[1]: https://datatracker.ietf.org/doc/html/rfc2518#section-13.4
2022-05-24 10:08:32 +02:00
Conrad Hoffmann
cabaf3268b carddav: return multistatus response on PROPPATCH
This does not implement any actual PROPPATCH logic, but makes the server
return a proper multistatus response with errors for each property
instead of a generic HTTP error.

It also adds the distinction between requests to the address book and
those to other resources. In CardDAV, only the address book itself has
properties that make sense to change via PROPPATCH. Those are responded
to with a 501, indicating that this needs further implementation.
Requests to other resources return 405 for each property, indicating
that the resources do not support PROPPATCH at all.
2022-05-23 11:30:03 +02:00
Conrad Hoffmann
b0c59cdea1 carddav/caldav: use 308 for .well-known redirects
This makes it a little less ambiguous (and, in case of Go clients, a lot
easier) that clients should follow the redirect by sending the same
PROPFIND request, including body, to the new location.

See also the documentation of [http.Client.Do()][1] and the comments in
[http.redirectBehavior()][2].

Confirmed to not make a difference for Evolution and Thunderbird
clients.

[1]: https://pkg.go.dev/net/http#Client.Do
[2]: https://cs.opensource.google/go/go/+/refs/tags/go1.18.2:src/net/http/client.go;drc=d8762b2f4532cc2e5ec539670b88bbc469a13938;l=502
2022-05-23 09:54:10 +02:00
Simon Ser
bc3faca3a0 carddav: only call CurrentUserPrincipal when necessary 2022-05-13 15:29:55 +02:00
Simon Ser
a346d42f42 caldav: only call CurrentUserPrincipal when necessary 2022-05-13 15:29:55 +02:00
Conrad Hoffmann
e971269ffb Add function to validate calendar for CalDAV
CalDAV imposes a set of constraints on iCal Calendar objects. They are
spelled out in RFC 4791, section 4.1 [1]. Add an exported function to
validate a calendar according to those constraints, and return data that
is necessary for further CalDAV processing and which can only be
extracted if the calendar meets these constraints.

[1]: https://datatracker.ietf.org/doc/html/rfc4791#section-4.1
2022-05-13 09:20:23 +02:00
Simon Ser
346cfadd34 webdav: rename ServeUserPrincipal to ServePrincipal
A principal may represent something else than a user, for instance
it may represent a group.

Also rename UserPrincipalPath to CurrentUserPrincipalPath, because
the principal being served may not represent the current user.
2022-05-12 18:44:43 +02:00
Conrad Hoffmann
303aef52f3 caldav: implement handleMultiget()
The implementation has feature parity with the CardDAV one.
2022-05-12 17:32:30 +02:00
Conrad Hoffmann
585b01a7a8 Implement GET/HEAD/PUT for calendar objects
Still missing a few features, but works to a certain extend. Requires
an update to the backend interface to support the operations
2022-05-12 14:50:26 +02:00
Conrad Hoffmann
cdb0de3b99 Return calendar description in PROPFIND 2022-05-12 14:50:26 +02:00
Conrad Hoffmann
6887b6b812 Support custom user principal and home set paths
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.
2022-05-11 11:12:04 +02:00
Conrad Hoffmann
b5c6f8927c Add exported function to create HTTPError
This can be used by backends to influence the status code returned to
clients for errors that occurred in the backend.
2022-05-03 16:56:13 +02:00
Conrad Hoffmann
95a4ae783b carddav: use AddressBook.Path in PROPFIND response 2022-05-02 20:58:00 +02:00
Conrad Hoffmann
8931e14cf6 caldav: use Calendar.Path in PROPFIND response 2022-05-02 20:56:38 +02:00
Simon Ser
d8a8af0448 internal: don't send an empty error element
According to RFC 4918 section 14.5, the error element can't be empty.
2022-05-02 20:41:33 +02:00
Simon Ser
3f8b212b0d internal: add Response.Err
Builds a detailed HTTPError + Error if the Response is a failure.
It contains more context than just the HTTPError.
2022-05-02 15:43:43 +02:00
Simon Ser
8cc6542f1c carddav: use partial error response on multiget failure
Instead of making the whole HTTP request fail when a single address
object cannot be fetched, return a partial error response.
2022-05-02 15:43:43 +02:00
Simon Ser
46ebe58ac2 internal: introduce NewErrorResponse
Same as NewOKResponse but for errors.
2022-05-02 15:43:43 +02:00
Simon Ser
4e8c5effe3 Replace DAVError with HTTPError + Error
That way we can avoid having different ways of representing the
same error value.
2022-05-02 15:43:43 +02:00
Simon Ser
8738a105fc internal: add HTTPError.Unwrap
This allows callers to access the underlying error via errors.Unwrap.
2022-05-02 15:43:43 +02:00
Konstantinos Koukas
25dfbaf95e caldav: add supported-calendar-component-set field 2022-04-12 09:38:26 +02:00
Conrad Hoffmann
6401d9ed45 caldav: extend query filter types
The basic types related to queries and filtering are missing some
features specified in the RFC (as also noted in the TODO comments). This
adds several of the missing elements, working towards being able to
handle all RFC-compliant queries.

The work is not fully done, e.g. the collation for text-match is still
not handled, but it's getting pretty close.
2022-04-01 18:29:58 +02:00
Conrad Hoffmann
7dafedd290 Add type-safe precondition errors for CalDAV 2022-04-01 16:22:04 +02:00
Conrad Hoffmann
c4206ba616 carddav: pass If-(None-)Match to backend
This simply extends the interfaces to pass on the values if they were
used, relying on the backend to handle things accordingly.
2022-03-22 09:28:24 +01:00
Conrad Hoffmann
52215c1690 Pass request context to backend interface
This aligns the caldav interface with the carddav one (see #53).
2022-03-16 20:11:00 +01:00
Simon Ser
106d4e1c88 caldav: add basic server
A lot of features a still missing, but basic discovery works.

Co-authored-by: Conrad Hoffmann <ch@bitfehler.net>
2022-03-16 16:47:29 +01:00