Skip to content

fix(ios): don't start a media upload for a torn-down editor - #626

Closed
jkmassel wants to merge 0 commit into
fix/own-media-delegate-stronglyfrom
fix/media-upload-cancellation-check
Closed

jkmassel wants to merge 0 commit into
fix/own-media-delegate-stronglyfrom
fix/media-upload-cancellation-check

Conversation

@jkmassel

@jkmassel jkmassel commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

Stacked on #625. Third of ten PRs splitting #621.

What?

Both delivery paths could put bytes on the wire after the editor was gone. Check cancellation explicitly before delivery.

Why?

EditorViewController.deinit calls stop(), which cancels the in-flight connection tasks, but Swift cancellation is cooperative: the body read is an uninterruptible loop and a host's processFile need not check at all, so a request can reach delivery well after teardown. Whether it then actually reached WordPress rested entirely on URLSession noticing the cancellation.

That is not a guarantee the server can rely on. URLSessionProtocol is public and documented for dependency injection, and the obvious conformance for a host wrapping a callback-based stack — withCheckedThrowingContinuation around a completion handler — has no cancellation awareness at all. Such a host would upload deterministically after teardown, and the response is discarded either way, leaving an attachment on the site that nothing cleans up.

How?

MediaUploadServer.swift: try Task.checkCancellation() in processAndUpload before delivery, and before the passthrough forward. The guarantee now comes from this file rather than from the HTTP client's behavior. uploadErrorResponse already logs CancellationError quietly, and HTTPServer drops the response for a cancelled task.

Testing Instructions

Not covered by a test: reaching the window deterministically means driving teardown between the parse and the delivery of a live socket request, and a timing-based approximation would be flaky without pinning the behavior. Called out rather than faked.

  • swift test — host suite green
  • SwiftLint clean

@jkmassel jkmassel added [Type] Bug An existing feature does not function as intended iOS labels Sep 5, 2026
@jkmassel jkmassel self-assigned this Sep 5, 2026
@wpmobilebot

wpmobilebot commented Sep 5, 2026 •

Copy link
Copy Markdown

XCFramework Build

This PR's XCFramework is available for testing. Add the following to your Package.swift:

.package(url: "https://github.com/wordpress-mobile/GutenbergKit", branch: "pr-build/626")

Built from a05b2fd

@jkmassel
jkmassel force-pushed the fix/media-upload-cancellation-check branch from c51eaf6 to 970a5f4 Compare September 8, 2026 16:12
@jkmassel
jkmassel marked this pull request as ready for review September 8, 2026 20:24
@jkmassel
jkmassel force-pushed the fix/media-upload-cancellation-check branch from 970a5f4 to 0f30cd4 Compare September 8, 2026 21:12

@dcalhoun dcalhoun left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks sound to me. I tested these changes in the Demo app using #629.

I captured a nitpick from Claude that clarifies starting sending bytes is preventing.

Comment on lines +189 to +190
// As in `processAndUpload`: don't put bytes on the wire for a torn-down
// editor, regardless of whether the HTTP client honors cancellation.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Finding from Claude:

This keeps a torn-down editor from starting delivery, but "regardless of whether the HTTP client honors cancellation" (and "the guarantee now comes from this file" in the description) reads broader. With the session the description uses as motivation, a withCheckedThrowingContinuation-wrapped URLSessionProtocol, a teardown partway through the transfer still finishes the POST: this check has already passed, and performRaw (EditorHTTPClient.swift:137) awaits data(for:) with nothing to interrupt it. For a large video, that's most of the window.

Scope the wording to not starting? A line on URLSessionProtocol saying data(for:) must honor task cancellation would cover the rest.

Suggested change
// As in `processAndUpload`: don't put bytes on the wire for a torn-down
// editor, regardless of whether the HTTP client honors cancellation.
// As in `processAndUpload`: don't start putting bytes on the wire for a
// torn-down editor. Stopping a transfer already under way still depends on
// the HTTP client honoring cancellation.

@jkmassel
jkmassel force-pushed the fix/media-upload-cancellation-check branch from 0f30cd4 to 819b8ed Compare September 15, 2026 22:39
@jkmassel jkmassel closed this Sep 16, 2026
@jkmassel
jkmassel force-pushed the fix/media-upload-cancellation-check branch from 819b8ed to a05b2fd Compare September 16, 2026 19:40
@jkmassel

Copy link
Copy Markdown
Contributor Author

This moved to #625

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

iOS [Type] Bug An existing feature does not function as intended

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants