Skip to content

[High][0.1.0] Abort before headers leaves sync HTTP requests pending #52

Description

@darekaze

High — fix or explicitly waive before powersync-lynx@0.1.0

Code review of main 5225ad1239416e06119c3cf4347774d62c64a775. This is a new code-level cancellation finding, separate from architecture review #51 and the packed Web typecheck blocker #50.

Trigger and impact

Start a sync HTTP request and abort while it is still waiting for response headers. The pending request is not promptly cancelled/settled by either path below. It can remain outstanding until the network completes or times out, delaying lifecycle work that awaits stream opening and leaving unwanted network work running.

Source evidence

  • HostFetch.ts:44–63 builds RequestInit from method, headers and body, but never passes request.signal to fetchImpl.
  • SyncStreamTransport.ts:28–43 does preserve the incoming signal, so it is lost inside HostFetch.
  • NativeHttpFetch.ts:105–152 rejects an already-aborted signal, but an abort after dispatch only sets a flag while streamIdForAbort is absent. It neither rejects the pending Promise nor cancels the request until a callback supplies a streaming ID.
  • The installed @powersync/shared-internals implementation of AbstractRemote.fetchStreamRaw relies on its nested controller to abort a fetch before it has a reader; reader cancellation only becomes available after headers.

This does not re-report the post-header native reader cancellation fixed in #36. The tests at lynx-remote-stream.test.ts:438–490 cover cancellation after the first chunk, and 885–909 covers pre-aborted input. Neither covers abort during the wait for headers. Related historical backlog: #38; architecture work #34 is closed.

Recommended fix / acceptance

  • Forward the incoming signal through HostFetch and verify a dispatched fetch rejects on abort before headers.
  • Settle the native request Promise promptly on abort after dispatch, remove its abort listener when appropriate, and safely cancel any native handle arriving in a late callback.
  • Define how native I/O itself is cancelled before headers; if the callback-only handle contract cannot support it yet, document and explicitly waive that residual limitation rather than treating Promise rejection as full cancellation.
  • Test through LynxRemote.fetchStream with delayed headers, late callbacks, and a never-completing fake request. Verify cancellation settles without waiting for the fake network response and does not leak a late stream.
  • Retain the existing pre-abort and post-header cancellation checks.

Validation status: source-verified control-flow defect. The proposed runtime reproduction was blocked by an execution approval usage-limit error and did not run; no measured device-level hang is claimed. No code changes were made. Close this issue in the fixing PR, or record an explicit release waiver with scope and residual risk.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions