Skip to content

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

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

fix(ios): don't start a media upload for a torn-down editor#626
jkmassel wants to merge 1 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

Both delivery paths could put bytes on the wire after the editor was gone.
`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.

Check cancellation explicitly before delivery in `processAndUpload` and
before the passthrough forward, so the guarantee 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.

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.
@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

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 c51eaf6

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.

2 participants