Choose each address book, calendar, task list and folder from the server by href, with a mode each, and hold every request to them #13
Labels
No labels
bug
documentation
enhancement
performance
security
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
Postulo/postulo-dav#13
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
This asks that the plugin "can only read and/or write the desired / specified calendar(s), contact list(s), task(s), files(s), folder(s), etc." Today a connection names one address book and one calendar by display name (default Postulo,
src/postulo_dav/sync.py:250-273), takes the first collection so named (src/postulo_dav/dav.py:173-178) and makes a missing one unless Read only is on (dav.py:180-200).Read here: "read and/or write" as a mode per chosen collection; "task(s)" and "files(s)" as their lists and folders (see Decisions).
What is wrong today
etags()joins every multistatushrefwith a plainurljoin, checking neither that it is under the collection nor its origin (dav.py:104-105, 204-221), as discovery does for principal and home (dav.py:136, 149); every request carries the Basic-auth credentials (dav.py:107-108). An address book's unlinked href is fetched and adopted (sync.py:528-549), then written and deleted.sync.py:425-457, 527-550), though the help text says "Only this address book is touched".sync.py:433-434, 458-466, 569-570, 589-601), and interviews gain false "removed from the calendar" entries. A collection the plugin made and someone renamed fares worse: the next run sendsMKCOLto its fixed address again, which a server must refuse (RFC 4918 §9.3.1), so every run fails (read from the code; not tried).sync.py:396-415;src/postulo/plugins/syncing.py:79-85in the core).tests/test_dav.py:48-51, 70).What the plugin should do
home()reads only the first,dav.py:146-149) fordisplayname,resourcetype,supported-calendar-component-set(absent means all, RFC 4791 §5.2.3),supported-address-dataandcurrent-user-privilege-set(RFC 3744 §5.4). Events get calendars accepting VEVENT; tasks, those accepting VTODO. Folders, which have no discovery (RFC 6764), are listed from a given address. A vanished choice is reported, not re-made; making a Postulo one stays possible.DAV:bindandDAV:write-content(RFC 3744 §3.9, §3.4), never onwrite-properties, which Nextcloud grants on read-only shares (https://bugzilla.mozilla.org/show_bug.cgi?id=2051561). A folder without ACL (only CalDAV and CardDAV need it) is offered writing, with a note.dav.py: an allowed origin, under a chosen collection, a method the mode allows. Excepted: discovery (PROPFIND, Depth 0 or 1, those properties) and making a requested collection. A request hook on the core'sclient()(event_hooks,src/postulo/plugins/http.py:139-145in the core) also sees redirects; the core's hook runs first and may swap the host for the approved address, keeping the name inHost(http.py:101-113). Sync runs stop listing the homes.Decisions
validate(): it would sign in on every save, unthrottled).Needs from the core
postulo/postulo#332: the form cannot offer the server's collections (static choices, no multi-select,
config_fields()sees no configuration, Test cannot write back). Until then: the last decision.New strings go through
uv run postulo-messages extract, fr-fr and pt-pt filled on the commit (the test gates them), and the 23 EU catalogues before a tag (uv run pytest -m release). New surface names mean repinning the core (pyproject.tomldev group pins commit1d6cdd7e0) and extendingtests/test_surface.py.Done when
From the list of DAV plugin improvements of 2026-09-30.
href#32From the efficiency and reliability audit of 2026-10-30 (finding PR4), what this issue does not yet say:
On the forge's
main(83710e9),src/postulo_dav/sync.py:623-634_collectionruns for each half of every run (sync.py:638-676):Server.principal(dav.py:252-274, a Depth 0PROPFINDon the typed address, then/.well-known/…, then/, stopping at the first that answers),Server.home(dav.py:276-289, one Depth 0PROPFIND), andfind_collection→collections(dav.py:291-321, one Depth 1PROPFINDof the home). So an idle run against a server that answers at the typed address makes 3 discovery requests per half, 6 in all, before the 2getetaglistings that are the actual work.Two of the six are identical: the principal probe of the address as typed is the same request for both halves (
principal("carddav")andprincipal("caldav")both try""first), andhome()sends_HOMES(dav.py:60-65), which already asks for both the address-book and the calendar home set in one body, twice.postulo-dav#13 (open, "Choose each address book, calendar, task list and folder from the server by href…") covers the main point: item 2 keeps each chosen collection by href in the connection, and item 4 says "Sync runs stop listing the homes." It waits on core #332 (a form that offers options found on the server). The PR2 core proposal (a per-connection sync state) would be another route, but #13 already removes the need for it here.
Nothing new to file. Add a comment to postulo-dav#13 saying that, until its collections-by-href lands,
Servercan remember the principal and the_HOMESanswer for the length of one run (a dictionary on the instance, which lives for one run), taking an idle run from 8 requests to 6 without any stored state. Once #13 lands, a run is the two listings plus whatever changed.Checked against
mainatdaee30b15(2026-10-30).