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
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
|
<!DOCTYPE html>
<title>Service Worker: intercepting Worker script loads</title>
<meta name="timeout" content="long">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="resources/test-helpers.sub.js"></script>
<body>
<script>
// ========== Worker main resource interception tests ==========
async function setup_service_worker(t, service_worker_url, scope) {
const r = await service_worker_unregister_and_register(
t, service_worker_url, scope);
t.add_cleanup(() => service_worker_unregister(t, scope));
await wait_for_state(t, r.installing, 'activated');
return r.active;
}
promise_test(async t => {
const worker_url = 'resources/sample-synthesized-worker.js?dedicated';
const service_worker_url = 'resources/sample-worker-interceptor.js';
const scope = worker_url;
const serviceWorker = await setup_service_worker(t, service_worker_url, scope);
const channels = new MessageChannel();
serviceWorker.postMessage({port: channels.port1}, [channels.port1]);
const clientId = await new Promise(resolve => channels.port2.onmessage = (e) => resolve(e.data.id));
const resultPromise = new Promise(resolve => channels.port2.onmessage = (e) => resolve(e.data));
const w = new Worker(worker_url);
const data = await new Promise((resolve, reject) => {
w.onmessage = e => resolve(e.data);
w.onerror = e => reject(e.message);
});
assert_equals(data, 'worker loading intercepted by service worker');
const results = await resultPromise;
assert_equals(results.clientId, clientId);
assert_true(!!results.resultingClientId.length);
channels.port2.postMessage("done");
}, `Verify a dedicated worker script request gets correct client Ids`);
promise_test(async t => {
const worker_url = 'resources/sample-synthesized-worker.js?dedicated';
const service_worker_url = 'resources/sample-worker-interceptor.js';
const scope = worker_url;
await setup_service_worker(t, service_worker_url, scope);
const w = new Worker(worker_url);
const data = await new Promise((resolve, reject) => {
w.onmessage = e => resolve(e.data);
w.onerror = e => reject(e.message);
});
assert_equals(data, 'worker loading intercepted by service worker');
}, `Verify a dedicated worker script request issued from a uncontrolled ` +
`document is intercepted by worker's own service worker.`);
promise_test(async t => {
const frame_url = 'resources/create-out-of-scope-worker.html';
const service_worker_url = 'resources/sample-worker-interceptor.js';
const scope = frame_url;
const registration = await service_worker_unregister_and_register(
t, service_worker_url, scope);
t.add_cleanup(() => service_worker_unregister(t, scope));
await wait_for_state(t, registration.installing, 'activated');
const frame = await with_iframe(frame_url);
t.add_cleanup(_ => frame.remove());
assert_equals(
frame.contentWindow.navigator.serviceWorker.controller.scriptURL,
get_newest_worker(registration).scriptURL,
'the frame should be controlled by a service worker'
);
const result = await frame.contentWindow.getWorkerPromise();
assert_equals(result,
'worker loading was not intercepted by service worker');
}, `Verify an out-of-scope dedicated worker script request issued from a ` +
`controlled document should not be intercepted by document's service ` +
`worker.`);
promise_test(async t => {
const worker_url = 'resources/sample-synthesized-worker.js?shared';
const service_worker_url = 'resources/sample-worker-interceptor.js';
const scope = worker_url;
await setup_service_worker(t, service_worker_url, scope);
const w = new SharedWorker(worker_url);
const data = await new Promise((resolve, reject) => {
w.port.onmessage = e => resolve(e.data);
w.onerror = e => reject(e.message);
});
assert_equals(data, 'worker loading intercepted by service worker');
}, `Verify a shared worker script request issued from a uncontrolled ` +
`document is intercepted by worker's own service worker.`);
promise_test(async t => {
const worker_url = 'resources/sample-same-origin-worker.js?dedicated';
const service_worker_url = 'resources/sample-worker-interceptor.js';
const scope = worker_url;
await setup_service_worker(t, service_worker_url, scope);
const w = new Worker(worker_url);
const data = await new Promise((resolve, reject) => {
w.onmessage = e => resolve(e.data);
w.onerror = e => reject(e.message);
});
assert_equals(data, 'dedicated worker script loaded');
}, 'Verify a same-origin worker script served by a service worker succeeds ' +
'in starting a dedicated worker.');
promise_test(async t => {
const worker_url = 'resources/sample-same-origin-worker.js?shared';
const service_worker_url = 'resources/sample-worker-interceptor.js';
const scope = worker_url;
await setup_service_worker(t, service_worker_url, scope);
const w = new SharedWorker(worker_url);
const data = await new Promise((resolve, reject) => {
w.port.onmessage = e => resolve(e.data);
w.onerror = e => reject(e.message);
});
assert_equals(data, 'shared worker script loaded');
}, 'Verify a same-origin worker script served by a service worker succeeds ' +
'in starting a shared worker.');
promise_test(async t => {
const worker_url = 'resources/sample-cors-worker.js?dedicated';
const service_worker_url = 'resources/sample-worker-interceptor.js';
const scope = worker_url;
await setup_service_worker(t, service_worker_url, scope);
const w = new Worker(worker_url);
const watcher = new EventWatcher(t, w, ['message', 'error']);
await watcher.wait_for('error');
}, 'Verify a cors worker script served by a service worker fails dedicated ' +
'worker start.');
promise_test(async t => {
const worker_url = 'resources/sample-cors-worker.js?shared';
const service_worker_url = 'resources/sample-worker-interceptor.js';
const scope = worker_url;
await setup_service_worker(t, service_worker_url, scope);
const w = new SharedWorker(worker_url);
const watcher = new EventWatcher(t, w, ['message', 'error']);
await watcher.wait_for('error');
}, 'Verify a cors worker script served by a service worker fails shared ' +
'worker start.');
promise_test(async t => {
const worker_url = 'resources/sample-no-cors-worker.js?dedicated';
const service_worker_url = 'resources/sample-worker-interceptor.js';
const scope = worker_url;
await setup_service_worker(t, service_worker_url, scope);
const w = new Worker(worker_url);
const watcher = new EventWatcher(t, w, ['message', 'error']);
await watcher.wait_for('error');
}, 'Verify a no-cors cross-origin worker script served by a service worker ' +
'fails dedicated worker start.');
promise_test(async t => {
const worker_url = 'resources/sample-no-cors-worker.js?shared';
const service_worker_url = 'resources/sample-worker-interceptor.js';
const scope = worker_url;
await setup_service_worker(t, service_worker_url, scope);
const w = new SharedWorker(worker_url);
const watcher = new EventWatcher(t, w, ['message', 'error']);
await watcher.wait_for('error');
}, 'Verify a no-cors cross-origin worker script served by a service worker ' +
'fails shared worker start.');
// ========== Worker subresource interception tests ==========
const scope_for_subresource_interception = 'resources/load_worker.js';
promise_test(async t => {
const service_worker_url = 'resources/worker-load-interceptor.js';
const r = await service_worker_unregister_and_register(
t, service_worker_url, scope_for_subresource_interception);
await wait_for_state(t, r.installing, 'activated');
}, 'Register a service worker for worker subresource interception tests.');
// Do not call this function multiple times without waiting for the promise
// resolution because this sets new event handlers on |worker|.
// TODO(nhiroki): To isolate multiple function calls, use MessagePort instead of
// worker's onmessage event handler.
async function request_on_worker(worker, resource_type) {
const data = await new Promise((resolve, reject) => {
if (worker instanceof Worker) {
worker.onmessage = e => resolve(e.data);
worker.onerror = e => reject(e);
worker.postMessage(resource_type);
} else if (worker instanceof SharedWorker) {
worker.port.onmessage = e => resolve(e.data);
worker.onerror = e => reject(e);
worker.port.postMessage(resource_type);
} else {
reject('Unexpected worker type!');
}
});
assert_equals(data, 'This load was successfully intercepted.');
}
async function subresource_test(worker) {
await request_on_worker(worker, 'xhr');
await request_on_worker(worker, 'fetch');
await request_on_worker(worker, 'importScripts');
}
promise_test(async t => {
await subresource_test(new Worker('resources/load_worker.js'));
}, 'Requests on a dedicated worker controlled by a service worker.');
promise_test(async t => {
await subresource_test(new SharedWorker('resources/load_worker.js'));
}, 'Requests on a shared worker controlled by a service worker.');
promise_test(async t => {
await subresource_test(new Worker('resources/nested_load_worker.js'));
}, 'Requests on a dedicated worker nested in a dedicated worker and ' +
'controlled by a service worker');
promise_test(async t => {
await subresource_test(new SharedWorker('resources/nested_load_worker.js'));
}, 'Requests on a dedicated worker nested in a shared worker and controlled ' +
'by a service worker');
promise_test(async t => {
await service_worker_unregister(t, scope_for_subresource_interception);
}, 'Unregister a service worker for subresource interception tests.');
</script>
</body>
|