Ensure Service Worker intercepts requests from iframe blob-URL documents#837
Merged
Merged
Conversation
The WordPress site editor's canvas iframe is mounted from a blob: URL. Blob documents are not controlled by the service worker, so their subresource requests (load-scripts.php/load-styles.php, block assets) bypass the kernel HTTP bridge and 404 against the static origin even though the in-kernel nginx serves them correctly. Convert such iframes to about:srcdoc, which the service worker controls, via a reusable DOM patch injected into every bridged HTML document. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
prepare-merge: runtime/materialization tests passed against the synthetic PR merge; package staging and durable package publishing were skipped. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
Logged into wp-admin, opening the site editor produces a 404 for
wp-admin/load-scripts.php(andload-styles.php) in the browser demo. Therest of wp-admin works, so this looks like a WordPress/nginx bug — it isn't.
The browser demo serves WordPress from an in-kernel nginx/PHP stack and reaches
it through a service worker that intercepts
fetchfor the/app/…prefix andbridges it into the Wasm kernel. The service worker can only bridge requests
from documents it controls.
The block/site-editor canvas iframe is mounted from a
blob:URL(
URL.createObjectURL(new Blob([html], { type: "text/html" }))). Ablob:document is not service-worker-controlled (and has no base URL), so the
<script src=".../app/wp-admin/load-scripts.php?load[]=wp-polyfill">thatWordPress injects into that canvas bypasses the bridge entirely and is sent to
the page's real origin (Vite in dev, GitHub Pages in prod), which has no such
file → 404.
about:srcdociframes, by contrast, are controlled and work.Reproduced and confirmed in a real headless Chromium against the live demo: the
exact same URL returns 200 (33 KB of real JS) through the bridge from a
controlled document, but 404 when requested by the editor's
blob:canvasiframe. This is browser-app-specific — the request never reaches nginx.
What
A reusable, framework-free DOM patch that neutralizes the whole class of
"blob iframe escapes the bridge" issues for any app, without patching WordPress
or app code.
apps/browser-demos/public/blob-iframe-interceptor.js(new) — hooksBlob/URL.createObjectURL/URL.revokeObjectURLto tracktext/htmlblob URLs, and overrides
HTMLIFrameElementsrc(setter/getter) andsetAttributeso any iframe pointed at a text/html blob URL is rendered fromsrcdoc(anabout:srcdocdocument the service worker controls). Idempotent,a no-op unless a text/html blob iframe is created, preserves
iframe.srcread-back, and leaves all other blob usage (downloads, workers, media)
untouched.
apps/browser-demos/public/service-worker.js— inlines the interceptorinto the
<head>of every bridged HTML document (guarded/idempotent,HTML-only) so it runs before any app script creates a blob iframe. Applies to
all demos, not just WordPress.
apps/browser-demos/vite.config.ts— substitutes the interceptor sourceinto the SW via a
"__BLOB_IFRAME_INTERCEPTOR__"placeholder, mirroring theexisting
"__CORS_PROXY_URL__"mechanism (dev middleware + prodwriteBundle). Keeps the interceptor a separate, testable file.apps/browser-demos/test/kandelo-wordpress.spec.ts—@slowregressiontest: opens the site editor and asserts zero
load-scripts/load-styles404s and zero
/appescapes.docs/browser-support.md— documents the blob-URL service-workerboundary and the interceptor.
Verification
End-to-end in headless Chromium against the running demo:
404 frame=blob:… /app/wp-admin/load-scripts.php?load[]=wp-polyfill200 frame=about:srcdoc /app/wp-admin/load-scripts.php?load[]=wp-polyfill/appescapes;window.__kandeloBlobIframePatched === truein the admin document.Both JS files pass
node --check; no type errors in the changed files.Notes / follow-ups
script-srcCSP (WordPress admin doesn't). If a future app ships strict CSP, we'd switch
to a nonce or a same-origin
<script src>.vite buildhere (needsnode/nginx-vfsbinaries not published at this ABI locally); the prod path is aone-line mirror of the already-proven CORS substitution.
🤖 Generated with Claude Code