OLD | NEW |
---|---|
1 <!DOCTYPE html> | 1 <!DOCTYPE html> |
2 <title>Service Worker: Tainting of responses fetched via SW.</title> | 2 <title>Service Worker: Tainting of responses fetched via SW.</title> |
3 <script src="../resources/testharness.js"></script> | 3 <!-- This test makes a large number of requests sequentially. --> |
4 <script src="../resources/testharnessreport.js"></script> | 4 <meta name="timeout" content="long"> |
5 <script src="../resources/get-host-info.js?pipe=sub"></script> | 5 <script src="/resources/testharness.js"></script> |
6 <script src="resources/test-helpers.js"></script> | 6 <script src="/resources/testharnessreport.js"></script> |
7 <script src="/common/get-host-info.sub.js"></script> | |
8 <script src="resources/test-helpers.sub.js"></script> | |
7 <body> | 9 <body> |
8 <script> | 10 <script> |
9 var host_info = get_host_info(); | 11 var host_info = get_host_info(); |
10 var BASE_ORIGIN = host_info.HTTP_ORIGIN; | 12 var BASE_ORIGIN = host_info.HTTPS_ORIGIN; |
11 var OTHER_ORIGIN = host_info.HTTP_REMOTE_ORIGIN; | 13 var OTHER_ORIGIN = host_info.HTTPS_REMOTE_ORIGIN; |
12 var BASE_URL = BASE_ORIGIN + base_path() + | 14 var BASE_URL = BASE_ORIGIN + base_path() + |
13 'resources/fetch-access-control.php?'; | 15 'resources/fetch-access-control.py?'; |
14 var OTHER_BASE_URL = OTHER_ORIGIN + base_path() + | 16 var OTHER_BASE_URL = OTHER_ORIGIN + base_path() + |
15 'resources/fetch-access-control.php?'; | 17 'resources/fetch-access-control.py?'; |
16 | 18 |
17 function frame_fetch(frame, url, mode, credentials) { | 19 function frame_fetch(frame, url, mode, credentials) { |
18 return frame.contentWindow.fetch( | 20 var foreignPromise = frame.contentWindow.fetch( |
19 new Request(url, {mode: mode, credentials: credentials})); | 21 new Request(url, {mode: mode, credentials: credentials})) |
22 | |
23 // Event loops should be shared between contexts of similar origin, not all | |
24 // browsers adhere to this expectation at the time of this writing. Incorrect | |
25 // behavior in this regard can interfere with test execution when the | |
26 // provided iframe is removed from the document. | |
27 // | |
28 // WPT maintains a test dedicated the expected treatment of event loops, so | |
29 // the following workaround is acceptable in this context. | |
30 return Promise.resolve(foreignPromise); | |
20 } | 31 } |
21 | 32 |
22 function ng_test(frame, url, mode, credentials) { | 33 var login_and_register; |
23 return frame_fetch(frame, url, mode, credentials).then( | 34 promise_test(function(t) { |
24 function() { | 35 var SCOPE = 'resources/fetch-response-taint-iframe.html'; |
25 throw new Error('fetching url:\"' + url + '\" mode:\"' + mode + | 36 var SCRIPT = 'resources/fetch-rewrite-worker.js'; |
26 '\" credentials:\"' + credentials + '\" should fail.'); | 37 login_and_register = login_https(t, host_info.HTTPS_ORIGIN, host_info.HTTPS_ REMOTE_ORIGIN) |
27 }, | 38 .then(function() { |
28 function() {}); | 39 return service_worker_unregister_and_register(t, SCRIPT, SCOPE); |
40 }) | |
41 .then(function(registration) { | |
42 return wait_for_state(t, registration.installing, 'activated'); | |
43 }) | |
44 .then(function() { return with_iframe(SCOPE); }) | |
45 .then(function(f) { | |
46 promise_test(function(t) { | |
Marijn Kruisselbrink
2017/05/04 00:08:05
Could you add a comment explaining:
1) why this is
mike3
2017/05/05 16:21:38
Acknowledged.
| |
47 f.remove(); | |
48 return service_worker_unregister_and_done(t, SCOPE); | |
Marijn Kruisselbrink
2017/05/04 00:08:05
calling unregister_and_done in a promise test alwa
mike3
2017/05/05 16:21:38
Acknowledged.
| |
49 }, 'restore global state'); | |
50 | |
51 return f; | |
52 }); | |
53 return login_and_register; | |
54 }, 'initialize global state'); | |
55 | |
56 function ng_test(url, mode, credentials) { | |
57 promise_test(function() { | |
58 return login_and_register.then(function(frame) { | |
59 return frame_fetch(frame, url, mode, credentials); | |
Marijn Kruisselbrink
2017/05/04 00:08:05
return promise_rejects(t, null, frame_fetch(...))
mike3
2017/05/05 16:21:37
I wasn't aware of that helper. Thanks for the tip.
Marijn Kruisselbrink
2017/05/05 17:32:42
I think using 'null' might make annevk sad (https:
| |
60 }) | |
61 .then(function() { | |
62 throw new Error('Expected request to fail, but it succeeded.'); | |
63 }, function() {}); | |
64 }, 'url:\"' + url + '\" mode:\"' + mode + | |
65 '\" credentials:\"' + credentials + '\" should fail.'); | |
29 } | 66 } |
30 | 67 |
31 function ok_test(frame, url, mode, credentials, expected_type, | 68 function ok_test(url, mode, credentials, expected_type, expected_username) { |
32 expected_username) { | 69 promise_test(function() { |
33 return frame_fetch(frame, url, mode, credentials) | 70 return login_and_register.then(function(frame) { |
34 .then(function(res) { | 71 return frame_fetch(frame, url, mode, credentials) |
35 assert_equals(res.type, expected_type); | 72 }) |
36 return res.text(); | 73 .then(function(res) { |
37 }) | 74 assert_equals(res.type, expected_type, 'response type'); |
38 .then(function(text) { | 75 return res.text(); |
39 if (expected_type == 'opaque') { | 76 }) |
40 assert_equals(text, ''); | 77 .then(function(text) { |
41 } else { | 78 if (expected_type == 'opaque') { |
42 return new Promise(function(resolve) { | 79 assert_equals(text, ''); |
43 var report = resolve; | 80 } else { |
44 // text must contain report() call. | 81 return new Promise(function(resolve) { |
45 eval(text); | 82 var report = resolve; |
46 }) | 83 // text must contain report() call. |
47 .then(function(result) { | 84 eval(text); |
48 assert_equals(result.username, expected_username); | 85 }) |
49 }); | 86 .then(function(result) { |
50 } | 87 assert_equals(result.username, expected_username); |
51 }) | 88 }); |
52 .catch(function(reason) { | 89 } |
53 throw new Error('fetching url:\"' + url + '\" mode:\"' + mode + | 90 }); |
91 }, 'fetching url:\"' + url + '\" mode:\"' + mode + | |
54 '\" credentials:\"' + credentials + '\" should ' + | 92 '\" credentials:\"' + credentials + '\" should ' + |
55 'success. - ' + reason.message); | 93 'succeed.'); |
56 }); | |
57 } | 94 } |
58 | 95 |
59 function build_rewrite_url(origin, url, mode, credentials) { | 96 function build_rewrite_url(origin, url, mode, credentials) { |
60 return origin + '/?url=' + encodeURIComponent(url) + '&mode=' + mode + | 97 return origin + '/?url=' + encodeURIComponent(url) + '&mode=' + mode + |
61 '&credentials=' + credentials + '&'; | 98 '&credentials=' + credentials + '&'; |
62 } | 99 } |
63 | 100 |
64 function for_each_origin_mode_credentials(callback) { | 101 function for_each_origin_mode_credentials(callback) { |
65 [BASE_ORIGIN, OTHER_ORIGIN].forEach(function(origin) { | 102 [BASE_ORIGIN, OTHER_ORIGIN].forEach(function(origin) { |
66 ['same-origin', 'no-cors', 'cors'].forEach(function(mode) { | 103 ['same-origin', 'no-cors', 'cors'].forEach(function(mode) { |
67 ['omit', 'same-origin', 'include'].forEach(function(credentials) { | 104 ['omit', 'same-origin', 'include'].forEach(function(credentials) { |
68 callback(origin, mode, credentials); | 105 callback(origin, mode, credentials); |
69 }); | 106 }); |
70 }); | 107 }); |
71 }); | 108 }); |
72 } | 109 } |
73 | 110 |
74 promise_test(function(t) { | 111 ok_test(BASE_URL, 'same-origin', 'omit', 'basic', 'undefined'); |
75 var SCOPE = 'resources/fetch-response-taint-iframe.html'; | 112 ok_test(BASE_URL, 'same-origin', 'same-origin', 'basic', 'username2s'); |
76 var SCRIPT = 'resources/fetch-rewrite-worker.js'; | 113 ok_test(BASE_URL, 'same-origin', 'include', 'basic', 'username2s'); |
77 var frame = undefined; | 114 ok_test(BASE_URL, 'no-cors', 'omit', 'basic', 'undefined'); |
115 ok_test(BASE_URL, 'no-cors', 'same-origin', 'basic', 'username2s'); | |
116 ok_test(BASE_URL, 'no-cors', 'include', 'basic', 'username2s'); | |
117 ok_test(BASE_URL, 'cors', 'omit', 'basic', 'undefined'); | |
118 ok_test(BASE_URL, 'cors', 'same-origin', 'basic', 'username2s'); | |
119 ok_test(BASE_URL, 'cors', 'include', 'basic', 'username2s'); | |
120 ng_test(OTHER_BASE_URL, 'same-origin', 'omit'); | |
121 ng_test(OTHER_BASE_URL, 'same-origin', 'same-origin'); | |
122 ng_test(OTHER_BASE_URL, 'same-origin', 'include'); | |
123 ok_test(OTHER_BASE_URL, 'no-cors', 'omit', 'opaque'); | |
124 ok_test(OTHER_BASE_URL, 'no-cors', 'same-origin', 'opaque'); | |
125 ok_test(OTHER_BASE_URL, 'no-cors', 'include', 'opaque'); | |
126 ng_test(OTHER_BASE_URL, 'cors', 'omit'); | |
127 ng_test(OTHER_BASE_URL, 'cors', 'same-origin'); | |
128 ng_test(OTHER_BASE_URL, 'cors', 'include'); | |
129 ok_test(OTHER_BASE_URL + 'ACAOrigin=*', 'cors', 'omit', 'cors', 'undefined'); | |
130 ok_test(OTHER_BASE_URL + 'ACAOrigin=*', 'cors', 'same-origin', 'cors', | |
131 'undefined'); | |
132 ng_test(OTHER_BASE_URL + 'ACAOrigin=*', 'cors', 'include'); | |
133 ok_test( | |
Marijn Kruisselbrink
2017/05/04 00:08:05
nit: why the line-break?
mike3
2017/05/05 16:21:38
A vestige from the prior version. Fixed.
| |
134 OTHER_BASE_URL + 'ACAOrigin=' + BASE_ORIGIN + '&ACACredentials=true', | |
135 'cors', 'include', 'cors', 'username1s') | |
78 | 136 |
79 return login(t, host_info.HTTP_ORIGIN, host_info.HTTP_REMOTE_ORIGIN) | 137 for_each_origin_mode_credentials(function(origin, mode, credentials) { |
80 .then(function() { | 138 var url = build_rewrite_url( |
81 return service_worker_unregister_and_register(t, SCRIPT, SCOPE); | 139 origin, BASE_URL, 'same-origin', 'omit'); |
82 }) | 140 // Fetch to the other origin with same-origin mode should fail. |
83 .then(function(registration) { | 141 if (origin == OTHER_ORIGIN && mode == 'same-origin') { |
84 return wait_for_state(t, registration.installing, 'activated'); | 142 ng_test(url, mode, credentials); |
85 }) | 143 } else { |
86 .then(function() { return with_iframe(SCOPE); }) | 144 // The response type from the SW should be basic |
87 .then(function(f) { | 145 ok_test(url, mode, credentials, 'basic', 'undefined'); |
88 frame = f; | 146 } |
89 var promises = [ | 147 }); |
90 ok_test(f, BASE_URL, 'same-origin', 'omit', 'basic', 'undefined'), | |
91 ok_test(f, BASE_URL, 'same-origin', 'same-origin', 'basic', | |
92 'username1'), | |
93 ok_test(f, BASE_URL, 'same-origin', 'include', 'basic', | |
94 'username1'), | |
95 ok_test(f, BASE_URL, 'no-cors', 'omit', 'basic', 'undefined'), | |
96 ok_test(f, BASE_URL, 'no-cors', 'same-origin', 'basic', | |
97 'username1'), | |
98 ok_test(f, BASE_URL, 'no-cors', 'include', 'basic', 'username1'), | |
99 ok_test(f, BASE_URL, 'cors', 'omit', 'basic', 'undefined'), | |
100 ok_test(f, BASE_URL, 'cors', 'same-origin', 'basic', 'username1'), | |
101 ok_test(f, BASE_URL, 'cors', 'include', 'basic', 'username1'), | |
102 ng_test(f, OTHER_BASE_URL, 'same-origin', 'omit'), | |
103 ng_test(f, OTHER_BASE_URL, 'same-origin', 'same-origin'), | |
104 ng_test(f, OTHER_BASE_URL, 'same-origin', 'include'), | |
105 ok_test(f, OTHER_BASE_URL, 'no-cors', 'omit', 'opaque'), | |
106 ok_test(f, OTHER_BASE_URL, 'no-cors', 'same-origin', 'opaque'), | |
107 ok_test(f, OTHER_BASE_URL, 'no-cors', 'include', 'opaque'), | |
108 ng_test(f, OTHER_BASE_URL, 'cors', 'omit'), | |
109 ng_test(f, OTHER_BASE_URL, 'cors', 'same-origin'), | |
110 ng_test(f, OTHER_BASE_URL, 'cors', 'include'), | |
111 ok_test(f, OTHER_BASE_URL + 'ACAOrigin=*', 'cors', 'omit', 'cors', | |
112 'undefined'), | |
113 ok_test(f, OTHER_BASE_URL + 'ACAOrigin=*', 'cors', 'same-origin', | |
114 'cors', 'undefined'), | |
115 ng_test(f, OTHER_BASE_URL + 'ACAOrigin=*', 'cors', 'include'), | |
116 ok_test(f, | |
117 OTHER_BASE_URL + 'ACAOrigin=' + BASE_ORIGIN + | |
118 '&ACACredentials=true', | |
119 'cors', 'include', 'cors', 'username2') | |
120 ]; | |
121 | 148 |
122 for_each_origin_mode_credentials(function(origin, mode, credentials) { | 149 for_each_origin_mode_credentials(function(origin, mode, credentials) { |
123 var url = build_rewrite_url( | 150 var url = build_rewrite_url( |
124 origin, BASE_URL, 'same-origin', 'omit'); | 151 origin, BASE_URL, 'same-origin', 'same-origin'); |
125 // Fetch to the other origin with same-origin mode should fail. | |
126 if (origin == OTHER_ORIGIN && mode == 'same-origin') | |
127 return promises.push(ng_test(f, url, mode, credentials)); | |
128 // The response type from the SW should be basic | |
129 promises.push( | |
130 ok_test(f, url, mode, credentials, 'basic', 'undefined')); | |
131 }); | |
132 | 152 |
133 for_each_origin_mode_credentials(function(origin, mode, credentials) { | 153 // Fetch to the other origin with same-origin mode should fail. |
134 var url = build_rewrite_url( | 154 if (origin == OTHER_ORIGIN && mode == 'same-origin') { |
135 origin, BASE_URL, 'same-origin', 'same-origin'); | 155 ng_test(url, mode, credentials); |
136 // Fetch to the other origin with same-origin mode should fail. | 156 // The response type from the SW should be basic. |
137 if (origin == OTHER_ORIGIN && mode == 'same-origin') | 157 } else { |
138 return promises.push(ng_test(f, url, mode, credentials)); | 158 ok_test(url, mode, credentials, 'basic', 'username2s'); |
139 // The response type from the SW should be basic. | 159 } |
140 promises.push( | 160 }); |
141 ok_test(f, url, mode, credentials, 'basic', 'username1')); | |
142 }); | |
143 | 161 |
144 for_each_origin_mode_credentials(function(origin, mode, credentials) { | 162 for_each_origin_mode_credentials(function(origin, mode, credentials) { |
145 var url = build_rewrite_url( | 163 var url = build_rewrite_url( |
146 origin, OTHER_BASE_URL, 'same-origin', 'omit'); | 164 origin, OTHER_BASE_URL, 'same-origin', 'omit'); |
147 // The response from the SW should be an error. | 165 // The response from the SW should be an error. |
148 promises.push(ng_test(f, url, mode, credentials)); | 166 ng_test(url, mode, credentials); |
149 }); | 167 }); |
150 | 168 |
151 for_each_origin_mode_credentials(function(origin, mode, credentials) { | 169 for_each_origin_mode_credentials(function(origin, mode, credentials) { |
152 var url = build_rewrite_url( | 170 var url = build_rewrite_url( |
153 origin, OTHER_BASE_URL, 'no-cors', 'omit'); | 171 origin, OTHER_BASE_URL, 'no-cors', 'omit'); |
154 // SW can respond only to no-cors requests. | |
155 if (mode != 'no-cors') | |
156 return promises.push(ng_test(f, url, mode, credentials)); | |
157 // The response type from the SW should be opaque. | |
158 promises.push(ok_test(f, url, mode, credentials, 'opaque')); | |
159 }); | |
160 | 172 |
161 for_each_origin_mode_credentials(function(origin, mode, credentials) { | 173 // SW can respond only to no-cors requests. |
162 var url = build_rewrite_url( | 174 if (mode != 'no-cors') { |
163 origin, OTHER_BASE_URL + 'ACAOrigin=*', 'cors', 'omit'); | 175 ng_test(url, mode, credentials); |
164 // Fetch to the other origin with same-origin mode should fail. | 176 } else { |
165 if (origin == OTHER_ORIGIN && mode == 'same-origin') | 177 // The response type from the SW should be opaque. |
166 return promises.push(ng_test(f, url, mode, credentials)); | 178 ok_test(url, mode, credentials, 'opaque'); |
167 // The response from the SW should be cors. | 179 } |
168 promises.push( | 180 }); |
169 ok_test(f, url, mode, credentials, 'cors', 'undefined')); | |
170 }); | |
171 | 181 |
172 for_each_origin_mode_credentials(function(origin, mode, credentials) { | 182 for_each_origin_mode_credentials(function(origin, mode, credentials) { |
173 var url = build_rewrite_url( | 183 var url = build_rewrite_url( |
174 origin, | 184 origin, OTHER_BASE_URL + 'ACAOrigin=*', 'cors', 'omit'); |
175 OTHER_BASE_URL + 'ACAOrigin=' + BASE_ORIGIN + | 185 |
176 '&ACACredentials=true', | 186 // Fetch to the other origin with same-origin mode should fail. |
177 'cors', 'include'); | 187 if (origin == OTHER_ORIGIN && mode == 'same-origin') { |
178 // Fetch to the other origin with same-origin mode should fail. | 188 ng_test(url, mode, credentials); |
179 if (origin == OTHER_ORIGIN && mode == 'same-origin') | 189 } else { |
180 return promises.push(ng_test(f, url, mode, credentials)); | 190 // The response from the SW should be cors. |
181 // The response from the SW should be cors. | 191 ok_test(url, mode, credentials, 'cors', 'undefined'); |
182 promises.push( | 192 } |
183 ok_test(f, url, mode, credentials, 'cors', 'username2')); | 193 }); |
184 }); | 194 |
185 return Promise.all(promises); | 195 for_each_origin_mode_credentials(function(origin, mode, credentials) { |
186 }) | 196 var url = build_rewrite_url( |
187 .then(function(f) { | 197 origin, |
188 frame.remove() | 198 OTHER_BASE_URL + 'ACAOrigin=' + BASE_ORIGIN + |
189 }) | 199 '&ACACredentials=true', |
190 .catch(unreached_rejection(t)); | 200 'cors', 'include'); |
191 }, 'Verify the tainting of responses fetched via SW'); | 201 // Fetch to the other origin with same-origin mode should fail. |
202 if (origin == OTHER_ORIGIN && mode == 'same-origin') { | |
203 ng_test(url, mode, credentials); | |
204 } else { | |
205 // The response from the SW should be cors. | |
206 ok_test(url, mode, credentials, 'cors', 'username1s'); | |
207 } | |
208 }); | |
192 </script> | 209 </script> |
193 </body> | 210 </body> |
OLD | NEW |