Skip to content

Commit 2e9f063

Browse files
authored
Explainer for Document-Policy in Workers (#1182)
* Add DP in Wokrers explainer * Fix format * Remove blob worker * Address feedback-1
1 parent 852dc33 commit 2e9f063

File tree

1 file changed

+164
-0
lines changed

1 file changed

+164
-0
lines changed
Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
# Document Policy in Workers
2+
3+
## Authors:
4+
5+
- [Monica Chintala](https://github.com/monica-ch) - Engineer at Microsoft Edge
6+
- [Victor Huang](https://github.com/victorhuangwq) - Product Manager at Microsoft Edge
7+
8+
## Participate
9+
- [How does document policy work in workers?](https://github.com/WICG/js-self-profiling/issues/33)
10+
11+
## Introduction
12+
13+
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.
14+
15+
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.
16+
17+
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.
18+
19+
## Motivation
20+
21+
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.
22+
23+
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.
24+
25+
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:
26+
27+
- Profiling within workers is impossible, even when a site has safely opted in at the document level.
28+
- Developers must rely on less accurate instrumentation or host-specific debugging (e.g., DevTools CDP sessions).
29+
30+
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.
31+
32+
## Goals
33+
34+
- Define how Document Policy applies to all worker types (Dedicated, Shared, and Service Workers)
35+
- Enable policy-gated features (like js-self-profiling) to work in workers when appropriately configured
36+
- Align Worker Policy Inheritance with existing standards
37+
38+
## Non-Goals
39+
40+
- This proposal doesn’t add new worker configuration APIs or redefine existing Document Policy semantics.
41+
- 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.
42+
43+
## Use Cases
44+
- Web performance analysis: Enables JS Self-Profiling in workers to capture CPU stacks during background computation.
45+
- Large-scale apps using workers: Allow frameworks that offload data processing or rendering to workers to apply consistent profiling.
46+
47+
## Proposed solution: Use Document Policy response headers as authoritative, inherit only for local schemes
48+
49+
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.
50+
51+
### Semantics by Worker Type
52+
53+
**Dedicated Workers:**
54+
- For network scripts: Parse `Document-Policy` from the worker script's HTTP response headers
55+
- If no `Document-Policy` header is present: Each feature uses its spec-defined default value (same as document contexts)
56+
- For local schemes (blob:, data:): Worker inherits the creator's Document Policy, since no response exists to consult
57+
58+
**Shared Workers:**
59+
- For network scripts: Document Policy is established from the worker script's HTTP response headers when the worker is first created
60+
- When multiple documents attach to the same worker:
61+
- The shared worker's policy remains fixed based on the script response, regardless of which document initiated the creation
62+
- Documents can connect to the worker regardless of their own Document Policy settings
63+
- For local schemes: Behavior mirrors dedicated workers, inherit from the creator's policy
64+
65+
**Service Workers:**
66+
- The SW registration script response is the authoritative source of Document Policy
67+
- Since Service Workers can start independently of any document, they do not inherit policy from any creator
68+
- Policy remains consistent across all clients controlled by the service worker
69+
70+
**Network Worker with Document-Policy Header:**
71+
72+
HTTP Response for worker script:
73+
```http
74+
Document-Policy: js-profiling
75+
```
76+
Having this header in the script response enables Document-Policy in the worker, allowing developers to use features that the policy supports.
77+
78+
**Using Profiler in Worker:**
79+
80+
If Document-Policy is enabled in the worker, developers can use the Profiler:
81+
```js
82+
// Start a profiling session
83+
const profiler = new Profiler({ sampleInterval: 10, maxBufferSize: 10_000 });
84+
doWork();
85+
const trace = await profiler.stop();
86+
console.log(JSON.stringify(trace));
87+
```
88+
89+
### Rationale: Why Response Headers for Network Workers?
90+
91+
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.
92+
93+
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.
94+
95+
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.
96+
97+
Inheritance is therefore limited to local schemes (blob:, data:), which have no HTTP response to carry headers. This approach:
98+
- Aligns with Document Policy's header-based model
99+
- Matches how COEP and CSP already inherit for blob/data workers in the HTML specification
100+
- Prevents cross-origin policy leakage
101+
- Ensures consistent, predictable behavior
102+
103+
## Considered Alternatives
104+
105+
### Alternative 1: Inherit Document Policy from Creator
106+
107+
In this approach, workers directly inherit the `Document-Policy` of their creating document for both local schemes and network workers.
108+
109+
**Semantics:**
110+
- **Dedicated Worker**: Inherits the creator document's effective Document Policy
111+
- **Shared Worker**: The first creator's policy applies, later attachers must match or are ignored
112+
- **Service Worker**: Policy is obtained from the Service Worker script's response headers
113+
114+
**Pros:**
115+
- Avoids per-worker header duplication
116+
- Simpler to implement and understand
117+
- Keeps behavior predictable for same-origin creations
118+
119+
**Cons:**
120+
- Risk of cross-origin policy leakage where a document's policy could improperly constrain another origin's worker
121+
- Violates origin isolation principles
122+
- 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.
123+
124+
### Alternative 2: Opt-in Inheritance via Constructor Flag
125+
126+
In this approach, inheritance of the creator's `Document-Policy` is explicitly gated by a constructor option at worker creation time.
127+
128+
**API Design:**
129+
```webidl
130+
partial dictionary WorkerOptions {
131+
boolean inheritDocumentPolicy = false; // optional
132+
};
133+
```
134+
135+
**Semantics:**
136+
- When `inheritDocumentPolicy` is true: Worker inherits creator's effective Document Policy for both local and network scripts
137+
- When false or unspecified: Worker does not inherit, policy enforcement is disabled by default
138+
- Applies to Dedicated and Shared Workers only
139+
- Service Workers always derive policy from the registration script response
140+
141+
**Pros:**
142+
- Gives developers explicit control
143+
- Helps prevent unintentional policy propagation
144+
- Opt-in approach is safer by default
145+
146+
**Cons:**
147+
- Adds new API surface and complexity
148+
- Diverges from existing worker-creation semantics
149+
- Introduces additional specification and testing burden
150+
- Requires developers to explicitly opt-in for workers, which is cumbersome
151+
152+
## Privacy, and Security Considerations
153+
154+
- Document Policy inheritance is limited to same-origin and local scheme workers to prevent cross-origin policy leakage.
155+
- Inherited policies cannot expand privileges beyond what the creator or script origin allows.
156+
- Worker script responses define the effective policy, ensuring each origin controls its own features.
157+
- Service Workers always use their registration script’s policy, keeping background execution isolated.
158+
- The proposal adds no new fingerprinting or cross-origin exposure surfaces.
159+
160+
## References & Acknowledgements
161+
162+
Many thanks for valuable feedback and advice from:
163+
- [Alex Russell](https://github.com/slightlyoff)
164+
- [Ian Clelland](https://github.com/clelland) (Google)

0 commit comments

Comments
 (0)