1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
|
<!DOCTYPE html>
<meta charset="utf-8"/>
<title>Service Worker: Partitioned Service Workers</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="resources/test-helpers.sub.js"></script>
<script src="/common/get-host-info.sub.js"></script>
<script src="resources/partitioned-utils.js"></script>
<body>
<!-- Debugging text for both test cases -->
The 3p iframe's postMessage:
<p id="iframe_response">No message received</p>
The nested iframe's postMessage:
<p id="nested_iframe_response">No message received</p>
<script>
promise_test(async t => {
const script = './resources/partitioned-storage-sw.js'
const scope = './resources/partitioned-'
// Add service worker to this 1P context. wait_for_state() and
// service_worker_unregister_and_register() are helper functions
// for creating test ServiceWorkers defined in:
// service-workers/service-worker/resources/test-helpers.sub.js
const reg = await service_worker_unregister_and_register(t, script, scope);
t.add_cleanup(() => reg.unregister());
await wait_for_state(t, reg.installing, 'activated');
// Registers the message listener with messageEventHandler(), defined in:
// service-workers/service-worker/resources/partitioned-utils.js
self.addEventListener('message', messageEventHandler);
// Open an iframe that will create a promise within the SW.
// Defined in service-workers/service-worker/resources/partitioned-storage-sw.js:
// `waitUntilResolved.fakehtml`: URL scope that creates the promise.
// `?From1pFrame`: query param that tracks which request the service worker is
// handling.
const wait_frame_url = new URL(
'./resources/partitioned-waitUntilResolved.fakehtml?From1pFrame',
self.location);
// Loads a child iframe with wait_frame_url as the content and returns
// a promise for the data messaged from the loaded iframe.
// loadAndReturnSwData() defined in:
// service-workers/service-worker/resources/partitioned-utils.js:
const wait_frame_1p_data = await loadAndReturnSwData(t, wait_frame_url,
'iframe');
assert_equals(wait_frame_1p_data.source, 'From1pFrame',
'The data for the 1p frame came from the wrong source');
// Now create a 3p iframe that will try to resolve the SW in a 3p context.
const third_party_iframe_url = new URL(
'./resources/partitioned-service-worker-third-party-iframe.html',
get_host_info().HTTPS_ORIGIN + self.location.pathname);
// loadAndReturnSwData() creates a HTTPS_NOTSAMESITE_ORIGIN or 3p `window`
// element which embeds an iframe with the ServiceWorker and returns
// a promise of the data messaged from that frame.
const frame_3p_data = await loadAndReturnSwData(t, third_party_iframe_url, 'window');
assert_equals(frame_3p_data.source, 'From3pFrame',
'The data for the 3p frame came from the wrong source');
// Print some debug info to the main frame.
document.getElementById("iframe_response").innerHTML =
"3p iframe's has_pending: " + frame_3p_data.has_pending + " source: " +
frame_3p_data.source + ". ";
// Now do the same for the 1p iframe.
// Defined in service-workers/service-worker/resources/partitioned-storage-sw.js:
// `resolve.fakehtml`: URL scope that resolves the promise.
const resolve_frame_url = new URL(
'./resources/partitioned-resolve.fakehtml?From1pFrame', self.location);
const frame_1p_data = await loadAndReturnSwData(t, resolve_frame_url,
'iframe');
assert_equals(frame_1p_data.source, 'From1pFrame',
'The data for the 1p frame came from the wrong source');
// Both the 1p frames should have been serviced by the same service worker ID.
// If this isn't the case then that means the SW could have been deactivated
// which invalidates the test.
assert_equals(frame_1p_data.ID, wait_frame_1p_data.ID,
'The 1p frames were serviced by different service workers.');
document.getElementById("iframe_response").innerHTML +=
"1p iframe's has_pending: " + frame_1p_data.has_pending + " source: " +
frame_1p_data.source;
// If partitioning is working correctly then only the 1p iframe should see
// (and resolve) its SW's promise. Additionally the two frames should see
// different IDs.
assert_true(frame_1p_data.has_pending,
'The 1p iframe saw a pending promise in the service worker.');
assert_false(frame_3p_data.has_pending,
'The 3p iframe saw a pending promise in the service worker.');
assert_not_equals(frame_1p_data.ID, frame_3p_data.ID,
'The frames were serviced by the same service worker thread.');
}, 'Services workers under different top-level sites are partitioned.');
// Optional Test: Checking for partitioned ServiceWorkers in an A->B->A
// (nested-iframes with cross-site ancestor) scenario.
promise_test(async t => {
const script = './resources/partitioned-storage-sw.js'
const scope = './resources/partitioned-'
// Add service worker to this 1P context. wait_for_state() and
// service_worker_unregister_and_register() are helper functions
// for creating test ServiceWorkers defined in:
// service-workers/service-worker/resources/test-helpers.sub.js
const reg = await service_worker_unregister_and_register(t, script, scope);
t.add_cleanup(() => reg.unregister());
await wait_for_state(t, reg.installing, 'activated');
// Registers the message listener with messageEventHandler(), defined in:
// service-workers/service-worker/resources/partitioned-utils.js
self.addEventListener('message', messageEventHandler);
// Open an iframe that will create a promise within the SW.
// Defined in service-workers/service-worker/resources/partitioned-storage-sw.js:
// `waitUntilResolved.fakehtml`: URL scope that creates the promise.
// `?From1pFrame`: query param that tracks which request the service worker is
// handling.
const wait_frame_url = new URL(
'./resources/partitioned-waitUntilResolved.fakehtml?From1pFrame',
self.location);
// Load a child iframe with wait_frame_url as the content.
// loadAndReturnSwData() defined in:
// service-workers/service-worker/resources/partitioned-utils.js:
const wait_frame_1p_data = await loadAndReturnSwData(t, wait_frame_url,
'iframe');
assert_equals(wait_frame_1p_data.source, 'From1pFrame',
'The data for the 1p frame came from the wrong source');
// Now create a set of nested iframes in the configuration A1->B->A2
// where B is cross-site and A2 is same-site to this top-level
// site (A1). The innermost iframe of the nested iframes (A2) will
// create an additional iframe to finally resolve the ServiceWorker.
const nested_iframe_url = new URL(
'./resources/partitioned-service-worker-nested-iframe-parent.html',
get_host_info().HTTPS_NOTSAMESITE_ORIGIN + self.location.pathname);
// Create the nested iframes (which will in turn create the iframe
// with the ServiceWorker) and await on receiving its data.
const nested_iframe_data = await loadAndReturnSwData(t, nested_iframe_url, 'iframe');
assert_equals(nested_iframe_data.source, 'FromNestedFrame',
'The data for the nested iframe frame came from the wrong source');
// Print some debug info to the main frame.
document.getElementById("nested_iframe_response").innerHTML =
"Nested iframe's has_pending: " + nested_iframe_data.has_pending + " source: " +
nested_iframe_data.source + ". ";
// Now do the same for the 1p iframe.
// Defined in service-workers/service-worker/resources/partitioned-storage-sw.js:
// `resolve.fakehtml`: URL scope that resolves the promise.
const resolve_frame_url = new URL(
'./resources/partitioned-resolve.fakehtml?From1pFrame', self.location);
const frame_1p_data = await loadAndReturnSwData(t, resolve_frame_url,
'iframe');
assert_equals(frame_1p_data.source, 'From1pFrame',
'The data for the 1p frame came from the wrong source');
// Both the 1p frames should have been serviced by the same service worker ID.
// If this isn't the case then that means the SW could have been deactivated
// which invalidates the test.
assert_equals(frame_1p_data.ID, wait_frame_1p_data.ID,
'The 1p frames were serviced by different service workers.');
document.getElementById("nested_iframe_response").innerHTML +=
"1p iframe's has_pending: " + frame_1p_data.has_pending + " source: " +
frame_1p_data.source;
// If partitioning is working correctly then only the 1p iframe should see
// (and resolve) its SW's promise. Additionally, the innermost iframe of
// the nested iframes (A2 in the configuration A1->B->A2) should have a
// different service worker ID than the 1p (A1) frame.
assert_true(frame_1p_data.has_pending,
'The 1p iframe saw a pending promise in the service worker.');
assert_false(nested_iframe_data.has_pending,
'The 3p iframe saw a pending promise in the service worker.');
assert_not_equals(frame_1p_data.ID, nested_iframe_data.ID,
'The frames were serviced by the same service worker thread.');
}, 'Services workers with cross-site ancestors are partitioned.');
</script>
</body>
|