nextcloud / nextcloud/server

[Bug]: AppCalendar CalendarObject returns no ETag, breaking CalDAV calendar-multiget

Open
#63,537 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

0. Needs triage 34-feedback bug feature: caldav
Dominant language
PHP
Stars
36.9k
Forks
5.2k
Avg merge
2d 3h
Merged PRs (30d)
713

Description

⚠️ This issue respects the following points: ⚠️
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
  1. Create/register an OCP\Calendar\ICalendarProvider.
  2. Have the provider return one or more calendar components.
  3. Perform a calendar-multiget REPORT requesting both DAV:getetag and CALDAV: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

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.