caldav, carddav: support If-Match/If-None-Match on client PUT#209
Open
hstern wants to merge 1 commit into
Open
caldav, carddav: support If-Match/If-None-Match on client PUT#209hstern wants to merge 1 commit into
hstern wants to merge 1 commit into
Conversation
PutCalendarObject and PutAddressObject sent no conditional request headers, so a client could not perform an optimistic-concurrency write (overwrite only if the resource still carries an expected ETag). Add an options parameter to both, reusing the existing server-side PutCalendarObjectOptions / PutAddressObjectOptions types so the client and Backend interface mirror each other. A nil opts preserves the prior unconditional behaviour; a non-nil opts sets If-Match / If-None-Match. Also add webdav.HTTPErrorCode, so a client consumer can read the HTTP status off a returned error (e.g. distinguish 412 Precondition Failed from other failures) without reaching into the internal error type. Signed-off-by: Henry Stern <henry@stern.ca> Assisted-by: Claude Opus 4.8 <noreply@anthropic.com>
hstern
added a commit
to hstern/go-mailbox-720
that referenced
this pull request
Jun 26, 2026
Graph If-Match / @odata.etag optimistic concurrency on PATCH: faithful conditional PUT for events (CalDAV) + contacts (CardDAV); best-effort account-level ifInState for messages (JMAP). New calendar/contacts/mail ConditionalWriter capabilities; specsubset injects the If-Match param + @odata.etag property; precondition sentinels map to 412. Requires the go-webdav fork (client If-Match + HTTPErrorCode) via a go.mod replace, pending upstream emersion/go-webdav#209. Merged with --admin: the one red check (build-test) is the pre-existing flaky TestManagerDeliversForPrincipalOnChange in internal/notify, unrelated to this PR and tracked as MB720-58.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Motivation
caldav.Client.PutCalendarObjectandcarddav.Client.PutAddressObjectsend no conditional request headers, so a client cannot perform an optimistic-concurrency write — overwrite only if the resource still carries an expected ETag (If-Match), or create only if absent (If-None-Match). Both methods carried a// TODO: add support for If-None-Match and If-Match.Changes
PutCalendarObject/PutAddressObject, reusing the existing server-sidePutCalendarObjectOptions/PutAddressObjectOptionstypes so the client andBackendinterface now mirror each other. Anilopts preserves the prior unconditional behaviour; a non-nil opts setsIf-Match/If-None-Match.webdav.HTTPErrorCode(err) (int, bool), so a client consumer can read the HTTP status off a returned error (e.g. distinguish412 Precondition Failedfrom other failures) without reaching into theinternalerror type — there is currently no public way to do this.This is a breaking change to the two client method signatures (go-webdav is pre-1.0). Also removed some dead commented-out pipe code in
carddav/client.gowhile there.Tests
Added
caldav/client_ifmatch_test.goandcarddav/client_ifmatch_test.go(httptest-backed): assert theIf-Matchheader is sent, that a nil opts sends none, and that a 412 surfaces viawebdav.HTTPErrorCode.Signed-off-by: Henry Stern henry@stern.ca