Skip to content

feat(upload): Support If-Match precondition on chunked assembly - #234

Merged
marinofaggiana merged 1 commit into
mainfrom
i2h3/chunked-upload-if-match
Jul 21, 2026
Merged

feat(upload): Support If-Match precondition on chunked assembly#234
marinofaggiana merged 1 commit into
mainfrom
i2h3/chunked-upload-if-match

Conversation

@i2h3

@i2h3 i2h3 commented Jul 17, 2026

Copy link
Copy Markdown
Collaborator

This is a fix to improve upload data integrity and conflict detection for chunked transmissions. This is based on actual customer support tickets and reports in conjunction with Adobe Creative Cloud apps.

Summary

Adds an optional ifMatch parameter to uploadChunkAsync so clients can perform optimistic-concurrency conflict detection on chunked (large-file) uploads.

When set, the ETag precondition is applied only to the final assembly MOVE that materializes the destination file. If the destination changed since the base version the client edited, the server rejects the assembly with 412 Precondition Failed instead of silently overwriting the newer copy.

Why

Single-request PUT uploads can already carry If-Match via NKRequestOptions.customHeader. The chunked path could not: uploadChunkAsync reuses one customHeader bag for both the per-chunk PUTs and the assembly MOVE, so injecting If-Match there would ride on the chunk PUTs too — and those target brand-new chunk resources, so the precondition would spuriously fail with 412. This PR closes that gap.

The macOS desktop client uses this for save-conflict protection (Adobe Creative Suite rapid re-saves, multi-device edits); the single-PUT half is at nextcloud/desktop#10393. The chunked path will be wired there once this lands and is released.

What changed

  • New ifMatch: String? = nil parameter on uploadChunkAsync.
  • Applied to options.customHeader["If-Match"] only immediately before the assembly MOVE, never during the chunk PUT loop.
  • Cleared again right after the MOVE, so it does not leak onto the post-assembly PROPFIND readback (whose target carries a fresh ETag after a successful MOVE).

Default nil → existing callers are unaffected; behavior is identical unless a caller opts in.

Testing

The core NextcloudKit target builds clean. The chunked path is WebDAV (PROPFIND/MKCOL/MOVE), which the repo's Mocker-based unit tests can't represent (standard HTTP methods only), so it is exercised via live-server integration testing — consistent with how the rest of the WebDAV surface is covered here. End-to-end conflict behavior will also be validated through the desktop client once its chunked path consumes this parameter.

Note: swift build of the whole package currently fails in the unrelated NextcloudKitUI target (WKWebView.isInspectable needs macOS 13.3 but the package targets macOS 11) — pre-existing on main, untouched by this PR. The core NextcloudKit target builds cleanly.

Add an optional `ifMatch` parameter to `uploadChunkAsync`. When set, the
ETag precondition is applied ONLY to the final assembly MOVE that
materializes the destination file — never to the chunk PUTs, which target
brand-new chunk resources and would spuriously fail with 412. It is also
cleared before the post-assembly PROPFIND readback, whose target carries a
fresh ETag after a successful MOVE.

This lets clients perform optimistic-concurrency conflict detection for
chunked (large-file) uploads: if the destination changed since the base
version the client edited, the server rejects the assembly with 412
Precondition Failed instead of silently overwriting the newer copy.
Single-request PUT uploads can already carry `If-Match` via
`NKRequestOptions.customHeader`; this closes the gap for the chunked path,
where the shared header bag would otherwise leak the precondition onto the
chunk PUTs.

Signed-off-by: Iva Horn <iva.horn@nextcloud.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@i2h3 i2h3 self-assigned this Jul 17, 2026
@i2h3 i2h3 added bug Something isn't working medium Medium priority labels Jul 17, 2026
@github-project-automation github-project-automation Bot moved this to 🧭 Planning evaluation (don't pick) in 💻 Desktop Clients team Jul 17, 2026
@i2h3 i2h3 moved this from 🧭 Planning evaluation (don't pick) to 🏗️ In progress in 💻 Desktop Clients team Jul 17, 2026
@i2h3 i2h3 removed their assignment Jul 20, 2026
@i2h3 i2h3 added this to the 7.4.0 milestone Jul 20, 2026
@i2h3 i2h3 added the 3. to review Waiting for reviews label Jul 20, 2026
@marinofaggiana
marinofaggiana merged commit e566494 into main Jul 21, 2026
4 checks passed
@github-project-automation github-project-automation Bot moved this from 🏗️ In progress to ☑️ Done in 💻 Desktop Clients team Jul 21, 2026
@i2h3
i2h3 deleted the i2h3/chunked-upload-if-match branch July 21, 2026 09:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

3. to review Waiting for reviews bug Something isn't working medium Medium priority

Projects

Status: ☑️ Done

Development

Successfully merging this pull request may close these issues.

2 participants