-
Notifications
You must be signed in to change notification settings - Fork 261
Explainer for Document-Policy in Workers #1182
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
Open
monica-ch
wants to merge
4
commits into
MicrosoftEdge:main
Choose a base branch
from
monica-ch:monicach-DP
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 3 commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,164 @@ | ||
| # Document Policy in Workers | ||
|
|
||
| ## Authors: | ||
|
|
||
| - [Monica Chintala](https://github.com/monica-ch) - Engineer at Microsoft Edge | ||
| - [Victor Huang](https://github.com/victorhuangwq) - Product Manager at Microsoft Edge | ||
|
|
||
| ## Participate | ||
| - [How does document policy work in workers?](https://github.com/WICG/js-self-profiling/issues/33) | ||
|
|
||
| ## Introduction | ||
|
|
||
| Modern web applications increasingly rely on Web Workers to offload computation from the main thread and maintain UI responsiveness. However, certain web platform feature, such as the JavaScript [js-self-profiling API](https://wicg.github.io/js-self-profiling/), are currently gated by [Document Policy](https://github.com/WICG/document-policy/blob/main/document-policy-explainer.md) and therefore unavailable inside workers. | ||
|
|
||
| This limitation prevents developers from gaining fine-grained CPU attribution and performance visibility within worker execution contexts, even when the top-level document has explicitly opted into the relevant policy. | ||
|
|
||
| To enable consistent and secure feature gating across browsing and worker contexts, this proposal extends Document Policy to workers by using the worker script's HTTP response headers for network workers, while local scheme workers (blob:, data:) inherit from their creator document. | ||
|
|
||
| ## Motivation | ||
|
|
||
| Applications such as Outlook and other large web clients routinely delegate performance-critical operations (e.g., parsing, computation, data processing) to workers. While the JS Self-Profiling API provides low-overhead sampling of JS stacks on the main thread, developers currently lack any equivalent visibility in workers. | ||
|
|
||
| Existing worker performance APIs, such as UserTiming, PerformanceObserver, and PerformanceResourceTiming reveal when tasks are slow, but not why. They cannot attribute CPU cost to specific JS stacks or identify blocking patterns inside the worker event loop. | ||
|
|
||
| Because the Self-Profiling API requires an explicit Document-Policy: js-profiling opt-in and Document Policy semantics are undefined for workers, feature exposure is currently blocked. As a result: | ||
|
|
||
| - Profiling within workers is impossible, even when a site has safely opted in at the document level. | ||
| - Developers must rely on less accurate instrumentation or host-specific debugging (e.g., DevTools CDP sessions). | ||
|
|
||
| Extending the Document Policy into workers resolves these gaps, ensures consistent enforcement semantics, and unlocks use of the Self-JS-Profiling API for worker contexts without adding new policies or API surfaces. | ||
|
|
||
| ## Goals | ||
|
|
||
| - Define how Document Policy applies to all worker types (Dedicated, Shared, and Service Workers) | ||
| - Enable policy-gated features (like js-self-profiling) to work in workers when appropriately configured | ||
| - Align Worker Policy Inheritance with existing standards | ||
|
|
||
| ## Non-Goals | ||
|
|
||
| - This proposal doesn’t add new worker configuration APIs or redefine existing Document Policy semantics. | ||
| - It also keeps Document Policy support in workers simple by avoiding any merge semantics or intersection rules across different policy features, and does not extend inheritance beyond local (blob:, data:) schemes. | ||
|
|
||
| ## Use Cases | ||
| - Web performance analysis: Enables JS Self-Profiling in workers to capture CPU stacks during background computation. | ||
| - Large-scale apps using workers: Allow frameworks that offload data processing or rendering to workers to apply consistent profiling. | ||
|
|
||
| ## Proposed solution: Use Document Policy response headers as authoritative, inherit only for local schemes | ||
|
|
||
| We propose Workers derive their Document Policy from the worker script's HTTP response headers. When no response exists (local blob:/data:), they inherit from the creator document. | ||
|
|
||
| ### Semantics by Worker Type | ||
|
|
||
| **Dedicated Workers:** | ||
| - For network scripts: Parse `Document-Policy` from the worker script's HTTP response headers | ||
| - If no `Document-Policy` header is present: Feature is disabled by default (e.g., self-js-profiling not exposed) | ||
| - For local schemes (blob:, data:): Worker inherits the creator's Document Policy, since no response exists to consult | ||
|
|
||
| **Shared Workers:** | ||
| - For network scripts: The worker script response headers define the effective Document Policy | ||
| - When multiple documents attach to the same worker: | ||
| - The first document that creates the worker establishes its effective document policy from the script's HTTP response header | ||
monica-ch marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| - Later attachers with mismatched policies are ignored. | ||
monica-ch marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| - For local schemes: Behavior mirrors dedicated workers, inherit from the creator's policy | ||
|
|
||
| **Service Workers:** | ||
| - The SW registration script response is the authoritative source of Document Policy | ||
| - Since Service Workers can start independently of any document, they do not inherit policy from any creator | ||
| - Policy remains consistent across all clients controlled by the service worker | ||
|
|
||
| **Network Worker with Document-Policy Header:** | ||
|
|
||
| HTTP Response for worker script: | ||
| ```http | ||
| Document-Policy: js-profiling | ||
| ``` | ||
| Having this header in the script response enables Document-Policy in the worker, allowing developers to use features that the policy supports. | ||
|
|
||
| **Using Profiler in Worker:** | ||
|
|
||
| If Document-Policy is enabled in the worker, developers can use the Profiler: | ||
| ```js | ||
| // Start a profiling session | ||
| const profiler = new Profiler({ sampleInterval: 10, maxBufferSize: 10_000 }); | ||
| doWork(); | ||
| const trace = await profiler.stop(); | ||
| console.log(JSON.stringify(trace)); | ||
| ``` | ||
|
|
||
| ### Rationale: Why Response Headers for Network Workers? | ||
|
|
||
| If we allowed inheritance for all workers, including network workers, the creator's policy could be applied to scripts from other origins. This would create owner-dependent behavior where the same worker script behaves differently depending on which document started it. | ||
|
|
||
| Since worker scripts are standalone HTTP resources that can define their own headers, including `Document-Policy`, inheriting the document's policy would override what the script's origin intended. | ||
|
|
||
| The response-driven model avoids this ambiguity. Each origin controls its own feature gating through headers, future policies stay scoped to the resource that declares them, and sites that can configure document headers can almost always configure worker script headers as well. | ||
|
|
||
| Inheritance is therefore limited to local schemes (blob:, data:), which have no HTTP response to carry headers. This approach: | ||
| - Aligns with Document Policy's header-based model | ||
| - Matches how COEP and CSP already inherit for blob/data workers in the HTML specification | ||
| - Prevents cross-origin policy leakage | ||
| - Ensures consistent, predictable behavior | ||
|
|
||
| ## Considered Alternatives | ||
|
|
||
| ### Alternative 1: Inherit Document Policy from Creator | ||
|
|
||
| In this approach, workers directly inherit the `Document-Policy` of their creating document for both local schemes and network workers. | ||
|
|
||
| **Semantics:** | ||
| - **Dedicated Worker**: Inherits the creator document's effective Document Policy | ||
| - **Shared Worker**: The first creator's policy applies, later attachers must match or are ignored | ||
| - **Service Worker**: Policy is obtained from the Service Worker script's response headers | ||
|
|
||
| **Pros:** | ||
| - Avoids per-worker header duplication | ||
| - Simpler to implement and understand | ||
| - Keeps behavior predictable for same-origin creations | ||
|
|
||
| **Cons:** | ||
| - Risk of cross-origin policy leakage where a document's policy could improperly constrain another origin's worker | ||
| - Violates origin isolation principles | ||
| - If `Document-Policy` is always inherited, every worker created by an opted-in document would automatically enable the underlying feature hooks, such as self-js-profiling api, introducing unnecessary runtime overhead even when those features are unused. | ||
|
|
||
| ### Alternative 2: Opt-in Inheritance via Constructor Flag | ||
|
|
||
| In this approach, inheritance of the creator's `Document-Policy` is explicitly gated by a constructor option at worker creation time. | ||
|
|
||
| **API Design:** | ||
| ```webidl | ||
| partial dictionary WorkerOptions { | ||
| boolean inheritDocumentPolicy = false; // optional | ||
| }; | ||
| ``` | ||
|
|
||
| **Semantics:** | ||
| - When `inheritDocumentPolicy` is true: Worker inherits creator's effective Document Policy for both local and network scripts | ||
| - When false or unspecified: Worker does not inherit, policy enforcement is disabled by default | ||
| - Applies to Dedicated and Shared Workers only | ||
| - Service Workers always derive policy from the registration script response | ||
|
|
||
| **Pros:** | ||
| - Gives developers explicit control | ||
| - Helps prevent unintentional policy propagation | ||
| - Opt-in approach is safer by default | ||
|
|
||
| **Cons:** | ||
| - Adds new API surface and complexity | ||
| - Diverges from existing worker-creation semantics | ||
| - Introduces additional specification and testing burden | ||
| - Requires developers to explicitly opt-in for workers, which is cumbersome | ||
|
|
||
| ## Privacy, and Security Considerations | ||
|
|
||
| - Document Policy inheritance is limited to same-origin and local scheme workers to prevent cross-origin policy leakage. | ||
| - Inherited policies cannot expand privileges beyond what the creator or script origin allows. | ||
| - Worker script responses define the effective policy, ensuring each origin controls its own features. | ||
| - Service Workers always use their registration script’s policy, keeping background execution isolated. | ||
| - The proposal adds no new fingerprinting or cross-origin exposure surfaces. | ||
|
|
||
| ## References & Acknowledgements | ||
|
|
||
| Many thanks for valuable feedback and advice from: | ||
| - [Alex Russell](https://github.com/slightlyoff) | ||
| - [Ian Clelland](https://github.com/clelland) (Google) | ||
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.
Uh oh!
There was an error while loading. Please reload this page.