[Bug]: AppCalendar CalendarObject returns no ETag, breaking CalDAV calendar-multiget
Nobody has claimed this yet.
- Dominant language
- PHP
- Stars
- 36.9k
- Forks
- 5.2k
- Avg merge
- 2d 3h
- Merged PRs (30d)
- 713
Description
⚠️ This issue respects the following points: ⚠️
- This is a bug, not a question or a configuration/webserver/proxy issue.
- This issue is not already reported on Github OR Nextcloud Community Forum (I've searched it).
- Nextcloud Server is up to date. See Maintenance and Release Schedule for supported versions.
- I agree to follow Nextcloud's Code of Conduct.
Bug description
Calendar objects exposed through OCP\Calendar\ICalendarProvider are wrapped for CalDAV by the AppCalendar DAV implementation but the resulting calendar objects don't provide an ETag. This breaks CalDAV clients which expect DAV:getetag to be present in the response to calendar-multiget.
DAVx5, for example, aborts synchronization with:
Received multi-get response without ETag
The problem can be traced to:
apps/dav/lib/CalDAV/AppCalendar/CalendarObject.php
where CalendarObject::getETag() returns null.
This is specifically reproducible with calendars supplied through OCP\Calendar\ICalendarProvider.
Possibly related to #29875, but that issue concerns an older Nextcloud version and an ETag missing after creating an event. However, this report concerns the current AppCalendar wrapper and calendar-multiget responses.
This appears related to #14103 ("Server Provides OC-ETag but not ETag"), which also caused DAVx⁵ synchronization to fail when a standard ETag was missing. However, this is a different code path: the problem occurs specifically for calendars exposed through OCP\Calendar\ICalendarProvider and wrapped as an AppCalendar. On Nextcloud 34.0.2, a calendar-multiget response for such calendar objects does not contain DAV:getetag. A normal GET of the same generated .ics object works correctly.
Cause
apps/dav/lib/CalDAV/AppCalendar/CalendarObject.php currently does not provide an ETag for the generated calendar object:
https://github.com/nextcloud/server/blob/v34.0.2/apps/dav/lib/CalDAV/AppCalendar/CalendarObject.php#L92-L94
Tested workaround
As a proof of concept I changed the AppCalendar CalendarObject to generate an ETag from the serialized calendar object instead of 'null':
public function getETag(): ?string {
return '"' . md5($this->get()) . '"';
}
After this change:
- PROPFIND returns an ETag
- calendar-multiget returns the ETag
- DAVx5 accepts the response
- synchronization succeeds
I don't suggest that MD5 of the serialized representation necessarily has to be the final implementation. The test only demonstrates that providing a stable content-dependent ETag fixes the interoperability problem.
Environment
Nextcloud Server: 34.0.2
PHP: 8.4
Web server: nginx
CalDAV client: DAVx5
Calendar components tested: VJOURNAL and VEVENT
Provider API: OCP\Calendar\ICalendarProvider
Steps to reproduce
- Create/register an
OCP\Calendar\ICalendarProvider. - Have the provider return one or more calendar components.
- Perform a
calendar-multigetREPORT requesting bothDAV:getetagandCALDAV:calendar-data.
Example request:
curl -u ''
-X REPORT
-H 'Depth: 1'
-H 'Content-Type: application/xml; charset=utf-8'
--data '
<c:calendar-multiget
xmlns:d="DAV:"
xmlns:c="urn:ietf:params:xml:ns:caldav">
<d:prop>
<d:getetag/>
<c:calendar-data/>
</d:prop>
<d:href>/remote.php/dav/calendars//app-generated--dav-wrapper--/.ics</d:href>
</c:calendar-multiget>'
'https:///remote.php/dav/calendars//app-generated--dav-wrapper--/'
Expected behavior
The response for every calendar object must contain a stable ETag which should change when the representation of the generated calendar object changes according to RFC4791. This allows CalDAV clients to identify and synchronize changed objects.
https://datatracker.ietf.org/doc/html/rfc4791#section-5.3.4
Actual behavior
calendar-data is returned, but no usable ETag is returned for the calendar object. DAVx5 consequently aborts synchronization with:
Received multi-get response without ETag
Nextcloud Server version
34.0.2
Operating system
Debian 12 Bookworm
PHP engine version
8.4.24
Web server
nginx version: nginx/1.22.1
Database engine version
'dbtype' => 'mysql',
'dbname' => 'nextcloud',
'dbhost' => 'localhost',
Is this bug present after an update or on a fresh install?
Fresh
Are you using the Nextcloud Server Encryption module?
None
What user-backends are you using?
- Default user-backend (database)
- LDAP/ Active Directory
- SSO - SAML
- Other
Configuration report
{
"system": {
"passwordsalt": "REMOVED SENSITIVE VALUE",
"secret": "REMOVED SENSITIVE VALUE",
"trusted_domains": [
"localhost",
""
],
"datadirectory": "REMOVED SENSITIVE VALUE",
"dbtype": "mysql",
"version": "34.0.2.1",
"overwrite.cli.url": "https:///drive",
"instanceid": "REMOVED SENSITIVE VALUE",
"dbname": "REMOVED SENSITIVE VALUE",
"dbhost": "REMOVED SENSITIVE VALUE",
"dbtableprefix": "oc_",
"mysql.utf8mb4": true,
"dbuser": "REMOVED SENSITIVE VALUE",
"dbpassword": "REMOVED SENSITIVE VALUE",
"installed": true,
"logfile": "/var/log/nextcloud/nextcloud.log",
"trashbin_retention_obligation": "auto, 30",
"versions_retention_obligation": "auto, 30",
"updatechecker": false,
"memcache.local": "\OC\Memcache\APCu",
"integrity.check.disabled": true,
"filelocking.enabled": true,
"memcache.locking": "\OC\Memcache\Redis",
"redis": {
"host": "REMOVED SENSITIVE VALUE",
"port": "6379",
"timeout": "0.0",
"password": "REMOVED SENSITIVE VALUE"
},
"maintenance": false
}
}
List of activated Apps
=== ENABLED APPS ===
Enabled:
- activity: 7.0.0
- app_api: 34.0.0
- appstore: 1.0.0
- bruteforcesettings: 7.0.0
- calendar: 6.5.4
- circles: 34.0.0
- cloud_federation_api: 1.18.0
- comments: 1.24.0
- contacts: 8.7.6
- contactsinteraction: 1.15.0
- dashboard: 7.14.0
- dav: 1.39.0
- federatedfilesharing: 1.24.0
- federation: 1.24.0
- files: 2.6.0
- files_downloadlimit: 5.2.0
- files_external: 1.26.0
- files_lock: 34.0.1
- files_pdfviewer: 7.0.0-dev.0
- files_reminders: 1.7.0
- files_scripts: 5.0.1
- files_sharing: 1.26.0
- files_trashbin: 1.24.0
- files_versions: 1.27.0
- files_zip: 3.0.1
- firstrunwizard: 7.0.0-dev.0
- gpoddersync: 3.17.0
- journal_caldav: 0.1.0
- journalnotes: 0.2.0
- logreader: 7.0.0
- lookup_server_connector: 1.22.0
- mail: 5.10.13
- nextcloud_announcements: 6.0.0
- notes: 6.0.2
- notifications: 7.0.0-dev.1
- oauth2: 1.22.0
- office: 1.0.0
- password_policy: 6.0.0-dev.0
- photos: 7.0.0
- privacy: 6.0.0-dev.1
- profile: 1.3.0
- provisioning_api: 1.24.0
- recommendations: 7.0.0
- related_resources: 5.0.0-dev.0
- repod: 4.2.1
- richdocuments: 11.1.0
- serverinfo: 6.0.0
- settings: 1.17.0
- sharebymail: 1.24.0
- sociallogin: 6.5.4
- support: 6.0.0
- survey_client: 6.0.0-dev.0
- systemtags: 1.24.0
- tasks: 0.18.1
- text: 8.0.0
- theming: 2.9.0
- twofactor_backupcodes: 1.23.0
- twofactor_totp: 16.0.0
- user_ldap: 1.25.0
- user_status: 1.14.0
- viewer: 7.0.0-dev.0
- weather_status: 1.14.0
- webhook_listeners: 1.6.0
- workflowengine: 2.16.0
Nextcloud Signing status
- enabled: false
- defaultModule:
Nextcloud Logs
Additional info
No response
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with apps/dav/lib/CalDAV/AppCalendar/CalendarObject.php, especially CalendarObject::getETag() and the generated object returned by get(). Reproduce the calendar-multiget request for an OCP\Calendar\ICalendarProvider calendar and verify that each response includes a stable ETag that changes when the calendar representation changes.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- php
- Domain
- api, backend
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 72/100