Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] feat: run scripts inside cross-origin iframe #318

Closed
wants to merge 3 commits into from

Conversation

emilisb
Copy link
Contributor

@emilisb emilisb commented Dec 12, 2022

Still WIP but should not change much - any feedback is appreciated

(Sorry for such a long description)

This PR allows executing scripts inside an iframe which can be moved to a different origin. Based on discussion in issue #5.

Motivation

Executing 3rd party code on a different origin improves isolation even further because scripts can no longer access IndexedDB or fetch resources from the main document origin.

Enabling the feature

  1. (Optional) Deploy Partytown to a different origin domain/subdomain.
  2. Add sandboxLib property to partytown config, e.g. sandboxLib: 'http://partytown-sandbox.my-site.com/~partytown/'. This path can also lead to same-origin Partytown lib path, although it will not introduce any additional isolation because the workers will be created on same origin.

This feature is currently opt-in because it introduces a completely new Main Thread-Web Worker and Main Thread-Service Worker communication mechanism. However, I think it might become default in the future. The startup might be just a bit slower, but performance difference should be unnoticeable.

How it works

Previously, Partytown used to load a sandbox script which later spawned a web worker and a service worker. The hierarchy looked like this.

  • my-site.com
    • my-site.com/~partytown/partytown-sw.js
    • my-site.com/~partytown/partytown-ww-sw.js

Now, with sandboxLib defined, Partytown loads an iframe (from a possibly different origin) which spawns web worker and service worker under same domain as the iframe.

  • my-site.com
    • my-site-sandbox.com/~partytown/partytown-isolation-sw.html
      • my-site-sandbox.com/~partytown/partytown-sw.js
      • my-site-sandbox.com/~partytown/partytown-ww-sw.js

Previously, web worker was spawned from main document, meaning you could attach a message listener to the worker and access the DOM directly from within the listener.

Now, the worker is spawned inside a different origin iframe, meaning postMessage must be used instead. In #5 the proposed solution was to have an extra postMessage call between main document to the iframe, but that would lead to an additional message hop and slightly worse performance (I tested this appraoch, it led to an overhead of 100 ms in PT Benchmark). In my PR I use MessageChannel for all main doc-worker communication, and I only communicate with the iframe to pass MessagePort.

So in other words, the new isolated iframe is only responsible for registering web worker/service worker and passing MessagePort to them.

The new communication works like this:

  1. Sandbox (main document) adds the isolation iframe to the main document, creates a message channel and passes MessagePort to the iframe via postMessage (one MessagePort for WW and one for SW).
  2. The isolated iframe (cross-origin) creates a web worker (and service worker in case SW is used) and passes the message ports to the workers.
  3. The workers receive MessagePort, then an event listener is set for the port. From now on workers use messagePort.postMessage instead of the default worker scope postMessage.
  4. A direct communication between main document sandbox and cross-origin workers is now established and can be used without an additional message hop.

Known issues

  1. I could not move the sandbox to a different domain on Chrome when Atomics are used. A subdomain works properly (my-site.com and sandbox.my-site.com) but when the origin is not same-site,postMessage messages with SharedArrayBuffer never arrive (no errors in console).
  2. Atomics do not work on Safari when wrapped within an iframe, even when on same origin - getting error TypeError: Typed array for wait/notify must wrap a SharedArrayBuffer.

I would appreciate any ideas on these issues.

Questions for Partydown devs

  • Why does SW sandbox currently run inside an iframe? I cannot understand how it improves the isolation. I changed it to run inside a script when the isolation iframe is used, is that OK?

TODO:

  • verify origin in iframe postmessage calls

@vercel
Copy link

vercel bot commented Dec 12, 2022

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Updated
partytown ✅ Ready (Inspect) Visit Preview Dec 13, 2022 at 10:50AM (UTC)

@adamdbradley
Copy link
Contributor

The service worker version runs in an iframe so that the XHR requests can be intercepted by the scoped service worker. As for the issues you've run into, if i recall those are some of the road blocks I ran into in the past, so the current solution was one that works everywhere.

@gioboa
Copy link
Member

gioboa commented Nov 1, 2023

HI @emilisb this PR is still valid or is it abandoned?

@gioboa
Copy link
Member

gioboa commented Jan 7, 2024

I close this PR b/c it's stale. Thanks.

@gioboa gioboa closed this Jan 7, 2024
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.

3 participants