Skip to content

Close a content script's port when the worker hangs up, even while an extension page holds it - #1203

Merged
timche merged 1 commit into
mainfrom
fix-proxy-port-disconnect
Oct 20, 2026
Merged

timche merged 1 commit into
mainfrom
fix-proxy-port-disconnect

Conversation

@timche

@timche timche commented Oct 20, 2026

Copy link
Copy Markdown
Collaborator

Suppose an extension's service worker deliberately calls port.disconnect() on a content script's port while one of the extension's own pages is open in the default session. Today the content script's onDisconnect fires only once that page closes. The proxy counts the open page as another receiving end of the port, and on the worker's hang-up endWorkerLeg closes only the worker's leg.

Chrome closes the whole channel in this case. disconnect() reaches MessageService::ClosePortImpl with close_channel=true, which goes to CloseChannelImpl, and that notifies the opener (extensions/browser/api/messaging/message_service.cc). A context that goes away closes with close_channel=false instead. So the refusal and worker-stop paths keep endWorkerLeg, and only the deliberate hang-up now calls closeShimPort(port, { notifyWorker: false }).

There is no changelog line. The page-leg fan-out (122cb76) is in no release, so no user has met this bug.

This also evens out CI's e2e shards (#1201, #1201). Five extension-proxy tests opened such a page first, and each waited out a 15 s probe deadline.

Proof

New unit test closes when the worker hangs up, though a page still holds it, run with bun test --isolate packages/electron-extensions/runtime-proxy.

Before, with main's runtime-proxy.ts:

(fail) a content script's runtime.connect > closes when the worker hangs up, though a page still holds it [1001.87ms]
354 pass
1 fail

After:

355 pass
0 fail

Then op run --env-file .env.e2e.op -- bun run test:e2e tests/extension-proxy.e2e.ts on macOS. All 19 tests passed both times, and the whole file went from 2.3 min to 1.1 min:

Test main this branch
:363 both accounts' popups reach the one worker 17.9 s 2.9 s
:431 every extension context has chrome and no browser 18.1 s 2.5 s
:556 a page navigating away disconnects the port 17.9 s 2.9 s
:1009 storage is one store 17.9 s 3.0 s
:1100 storage.onChanged fires in the worker and the shim session 17.9 s 3.0 s

Risk

The change reaches only content-script ports that have page legs, which in the shipped catalog means Bitwarden. Ports with no page legs already took the closeShimPort(notifyWorker: false) path. Revert by reverting this PR.

@timche
timche merged commit 9046009 into main Oct 20, 2026
8 checks passed
@timche
timche deleted the fix-proxy-port-disconnect branch October 20, 2026 12:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant