fix(dav): return RFC 4791 no-uid-conflict on duplicate calendar UID#61640
fix(dav): return RFC 4791 no-uid-conflict on duplicate calendar UID#61640ndo84bw wants to merge 1 commit into
Conversation
Assisted-by: ClaudeCode:claude-opus-4-8[1m] Signed-off-by: Nico Donath <ndo84bw@gmx.de>
|
Thanks for the patch What is the difference to #61207? |
|
Hi @ChristophWurst, The difference is the approach. #61207 tried to fix it in the server: it detected the duplicate UID and rewrote the client's request onto the existing object - the server guessing what the client meant. But the actual cause is on the client side: Thunderbird should re-fetch the calendar when it hits the conflict. This PR deliberately does not do that. It only corrects the server's response: on a duplicate UID, NC currently returns a non-standard 400; with this PR it returns the RFC 4791 409 with CALDAV:no-uid-conflict (and a DAV:href to the existing object) - the same 409 that Radicale and SOGo already return. I had hoped Thunderbird would then recover on its own, but it doesn't yet - so I'm also pushing for the client-side fix in Thunderbird (Bug 1717401). As long as NC answers with the non-standard 400, one side or the other needs a quirk. Once NC returns the standard 409 and Thunderbird acts on it (sync before accept/update), neither side needs a quirk. |
Processing message failed. Status: 80004005.#17915Summary
If a client attempts to create (PUT) a calendar object whose UID already exists in the target calendar, NC currently responds with a generic
400 Bad Request("Calendar object with uid already exists in this calendar collection."). RFC 4791 specifies a separate precondition for this exact case. This PR implements it:CalDavBackend::createCalendarObjectnow throwsOCA\DAV\CalDAV\Exception\UidConflict(inherits fromSabre\DAV\Exception\Conflict-> 409), which satisfies the RFC 4791 precondition (Section 5.3.2.1)CALDAV:no-uid-conflictwith aDAV:hrefpointing to the existing object:This ensures the server is spec-compliant and provides the client with a machine-readable reference to the conflicting object, allowing the client to correct itself (by writing to the href or synchronizing).
Status 409 instead of 403: RFC 4791 Section 1.3 - the client CAN resolve the conflict and resend, hence 409 (not 403).
Background / Motivation
If you accept an email event invitation from NC in Thunderbird and try to add it to the calendar of the same NC instance as the organizer before Thunderbird has synchronized its calendar with NC, Thunderbird will attempt to PUT the event using a UUID that already exists on the server.
This is a client issue (Thunderbird should sync before accepting) and is known as: Thunderbird Bug 1717401 ("Accepting invitation before calendar sync fails (Status 80004005)"). This PR does not resolve this issue in NC. It merely makes the server response more precise - providing a clean basis for a client (TB) to respond to.
Testing
Manuell live (CalDAV-PUT gegen eine laufende Instanz):
409 Conflictwithcal:no-uid-conflict+d:href409 UidConflictwithno-uid-conflict/hrefduring "accept-before-sync" instead of the generic 400 (see video)duplicate-uuid-nc-small.mp4
Duplicate-UID behavior across CalDAV servers
CALDAV:no-uid-conflict+DAV:hrefCALDAV:no-uid-conflict(no href)DAV:error"Event UID already in use"Note
Changing the exception class affects one catch site outside the diff: CalendarImpl::createFromStringInServer (catch (Conflict)) now wraps the duplicate-UID case into the contractual CalendarException instead of letting the former BadRequest escape uncaught. No other catch sites are affected.
TODO
Checklist
3. to review, feature component)stable32)AI (if applicable)