“Supports resume” is one of the least precise claims in browser file transfer. It may mean that a brief network outage heals while both tabs remain open. It may mean the receiver can refresh and keep downloaded chunks. Some people read it as a promise that the sender can reboot and the browser will silently continue reading a local file. Those cases do not have the same permissions or surviving data.
A dependable design does not reduce everything to a saved percentage. It answers who still holds the source, who persisted received ranges, how a new peer connection proves it belongs to an old task, and whether a task explicitly cancelled by a person can ever reappear.
Four kinds of interruption
| Interruption | Typical recovery | Requirement |
|---|---|---|
| Brief network loss; both pages stay open | Automatic | Reconcile task state and missing ranges after reconnect |
| Receiver refreshes | Usually automatic | Persisted chunks and manifest |
| Sender refreshes | Needs user action | Reselect and verify the original source |
| Both devices clear site data | Not recoverable | The local task records no longer exist |
Automatic recovery has a permission boundary. A trusted device can reconnect without first-contact approval, but a web page cannot bypass a file picker or silently reacquire a screen-capture stream. Those restrictions protect the user.
What the receiver persists
A task needs a transfer ID that cannot collide with another session, the sending device identity, expected size, modification hint, digest, chunk size, confirmed ranges, and current state. Chunks can live in IndexedDB or an appropriate file-writing API. Manifest and chunk commits should remain consistent so a refresh cannot advertise data that was never durably stored.
Saving “63%” is not enough. One missing block in the middle makes a single offset inaccurate. A range set or bitmap describes exactly which chunks are safe. After a refresh, the receiver rebuilds the UI from that record and requests only the gaps.
Rejoin the task on a new session
A refreshed WebRTC connection is a new transport. The peers authenticate device identities, then exchange compact summaries of unfinished work: transfer ID, file digest, total size, state version. When these match, the receiver sends compressed missing ranges. The sender resumes only after confirming that it still has the same source.
Control messages carry both session ID and task version. A late “complete” or “cancel” from a superseded connection cannot overwrite newer state. If both devices come online and initiate recovery at once, a deterministic coordinator rule prevents two sending loops from writing duplicate blocks.
Why the sender may have to reselect
The page could read the original local file because a person granted access through a file picker. After a refresh, JavaScript normally does not regain that temporary file object. The application may remember metadata, but it cannot pretend it still has the bytes.
The honest recovery screen asks for the original file again. It first compares size and basic metadata, then verifies a full SHA-256 digest or the protocol’s equivalent. Resume starts only after a match. Selecting the wrong file should leave receiver progress intact and offer another selection; it should not discard useful chunks.
Cancellation needs a durable tombstone
Consider a boundary bug: A cancels just as the connection drops; B never receives the message and revives the task after reconnecting. Treat cancellation as a versioned terminal record, sometimes called a tombstone. During the next state exchange, the newer terminal state wins over an older in-progress record.
A tombstone does not need permanent storage. Remove it after both sides acknowledge it, or after a sensible expiry. Until then, closing a panel must not erase the person’s intent. The same principle applies to “stop reconnecting,” which should survive refresh until the person starts a new connection.
All chunks is not the finish line
Once every range exists, the receiver assembles in order and calculates the digest. Only a match changes the state to verified and makes the result available. A mismatch may trigger repair of suspicious ranges; if repair cannot establish integrity, the interface should label the file unusable rather than quietly offer corrupted output.
Hashing a very large file takes time. Run it in a Worker where possible and show “verifying” as a distinct phase. Otherwise a person may close the page after seeing 100 percent, precisely before the check that makes the result trustworthy.
Local resume data needs cleanup
Partial chunks can contain sensitive material. Explain that they remain in this browser, offer a delete action for unfinished work, and clean them after completion, cancellation, expiry, or storage pressure. Telemetry does not need filenames, full digests, or local paths to measure whether resume succeeded.
On a shared computer, remove unfinished tasks and trusted devices before leaving. A received file should be deliberately saved to its destination instead of hiding indefinitely inside site storage.
Test the recovery boundaries
A clean transfer proves only the happy path. Refresh the receiver at 1 percent, 50 percent, and during verification. Refresh the sender and choose the correct file, the wrong file, and a same-named file with different content. Refresh both sides together. Cancel during a disconnect. Drop the cancel message and reconnect. Exhaust storage. Corrupt the final chunk. Every scenario must assert both interfaces, persisted ranges, and final bytes.
uCopy retains acknowledged progress through ordinary disconnects and receiver refreshes. After a sender refresh, it asks for the source again so it can verify it before continuing. That boundary is less flashy than promising that no progress can ever be lost, but it matches browser permissions and protects the file already received.