| OLD | NEW |
| (Empty) |
| 1 var SCOPE = BASE_ORIGIN + | |
| 2 '/fetch/resources/fetch-access-control-iframe.html?' + TEST_OPTIONS; | |
| 3 var IFRAME_ORIGIN = BASE_ORIGIN; | |
| 4 var BASE_URL = BASE_ORIGIN + | |
| 5 '/serviceworker/resources/fetch-access-control.php?'; | |
| 6 var OTHER_BASE_URL = OTHER_ORIGIN + | |
| 7 '/serviceworker/resources/fetch-access-control.php?'; | |
| 8 var REDIRECT_URL = BASE_ORIGIN + | |
| 9 '/serviceworker/resources/redirect.php?Redirect='; | |
| 10 var OTHER_REDIRECT_URL = OTHER_ORIGIN + | |
| 11 '/serviceworker/resources/redirect.php?Redirect='; | |
| 12 var REDIRECT_LOOP_URL = BASE_ORIGIN + | |
| 13 '/fetch/resources/redirect-loop.php?Redirect='; | |
| 14 var OTHER_REDIRECT_LOOP_URL = OTHER_ORIGIN + | |
| 15 '/fetch/resources/redirect-loop.php?Redirect='; | |
| 16 var IFRAME_URL = SCOPE; | |
| 17 var WORKER_URL = BASE_ORIGIN + | |
| 18 '/fetch/resources/fetch-access-control-worker.js?' + | |
| 19 TEST_OPTIONS; | |
| 20 | |
| 21 function onlyOnServiceWorkerProxiedTest(checkFuncs) { | |
| 22 return []; | |
| 23 } | |
| 24 | |
| 25 // Functions to check the result from the ServiceWorker. | |
| 26 var checkFetchResult = function(expected, url, data) { | |
| 27 assert_equals(data.fetchResult, expected, url + ' should be ' + expected); | |
| 28 }; | |
| 29 var checkFetchResponseBody = function(hasBody, url, data) { | |
| 30 assert_equals(data.fetchResult, | |
| 31 'resolved', | |
| 32 'fetchResult must be resolved. url: ' + url); | |
| 33 if (hasBody) { | |
| 34 assert_not_equals(data.body, '', | |
| 35 'response must have body. url: ' + url); | |
| 36 } else { | |
| 37 assert_equals(data.body, '', | |
| 38 'response must not have body. url: ' + url); | |
| 39 } | |
| 40 }; | |
| 41 var checkFetchResponseHeader = function(name, expected, url, data) { | |
| 42 assert_equals(data.fetchResult, | |
| 43 'resolved', | |
| 44 'fetchResult must be resolved. url: ' + url); | |
| 45 var exist = false; | |
| 46 for (var i = 0; i < data.headers.length; ++i) { | |
| 47 if (data.headers[i][0] === name) { | |
| 48 exist = true; | |
| 49 } | |
| 50 } | |
| 51 assert_equals(exist, | |
| 52 expected, | |
| 53 'header check failed url: ' + url + ' name: ' + name); | |
| 54 }; | |
| 55 var checkFetchResponseType = function(type, url, data) { | |
| 56 assert_equals(data.fetchResult, | |
| 57 'resolved', | |
| 58 'fetchResult must be resolved. url = ' + url); | |
| 59 assert_equals(data.type, | |
| 60 type, | |
| 61 'type must match. url: ' + url); | |
| 62 }; | |
| 63 | |
| 64 var showComment = function(url, data) { | |
| 65 assert_true(!data.comment, 'Show comment: ' + data.comment + ' url: ' + url); | |
| 66 } | |
| 67 | |
| 68 var fetchIgnored = checkFetchResult.bind(this, 'ignored'); | |
| 69 var fetchResolved = checkFetchResult.bind(this, 'resolved'); | |
| 70 var fetchRejected = checkFetchResult.bind(this, 'rejected'); | |
| 71 var fetchError = checkFetchResult.bind(this, 'error'); | |
| 72 var hasBody = checkFetchResponseBody.bind(this, true); | |
| 73 var noBody = checkFetchResponseBody.bind(this, false); | |
| 74 var hasContentLength = | |
| 75 checkFetchResponseHeader.bind(this, 'content-length', true); | |
| 76 var noContentLength = | |
| 77 checkFetchResponseHeader.bind(this, 'content-length', false); | |
| 78 var hasServerHeader = | |
| 79 checkFetchResponseHeader.bind(this, 'x-serviceworker-serverheader', true); | |
| 80 var noServerHeader = | |
| 81 checkFetchResponseHeader.bind(this, 'x-serviceworker-serverheader', false); | |
| 82 var typeBasic = checkFetchResponseType.bind(this, 'basic'); | |
| 83 var typeCors = checkFetchResponseType.bind(this, 'cors'); | |
| 84 var typeOpaque = checkFetchResponseType.bind(this, 'opaque'); | |
| 85 | |
| 86 // Functions to check the result of JSONP which is evaluated in | |
| 87 // fetch-access-control-iframe.html by appending <script> element. | |
| 88 var checkJsonpResult = function(expected, url, data) { | |
| 89 assert_equals(data.jsonpResult, | |
| 90 expected, | |
| 91 url + ' jsonpResult should match'); | |
| 92 }; | |
| 93 var checkJsonpHeader = function(name, value, url, data) { | |
| 94 assert_equals(data.jsonpResult, | |
| 95 'success', | |
| 96 url + ' jsonpResult must be success'); | |
| 97 assert_equals(data.headers[name], | |
| 98 value, | |
| 99 'Request header check failed url:' + url + ' name:' + name); | |
| 100 }; | |
| 101 var checkJsonpMethod = function(method, url, data) { | |
| 102 assert_equals(data.jsonpResult, | |
| 103 'success', | |
| 104 url + ' jsonpResult must be success'); | |
| 105 assert_equals(data.method, | |
| 106 method, | |
| 107 'Method must match url:' + url); | |
| 108 }; | |
| 109 var checkJsonpAuth = function(username, password, cookie, url, data) { | |
| 110 assert_equals(data.jsonpResult, | |
| 111 'success', | |
| 112 url + ' jsonpResult must be success'); | |
| 113 assert_equals(data.username, | |
| 114 username, | |
| 115 'Username must match. url: ' + url); | |
| 116 assert_equals(data.password, | |
| 117 password, | |
| 118 'Password must match. url: ' + url); | |
| 119 assert_equals(data.cookie, | |
| 120 cookie, | |
| 121 'Cookie must match. url: ' + url); | |
| 122 }; | |
| 123 var checkJsonpCookie = function(cookie, url, data) { | |
| 124 assert_equals(data.jsonpResult, | |
| 125 'success', | |
| 126 url + ' jsonpResult must be success'); | |
| 127 assert_equals(data.cookie, | |
| 128 cookie, | |
| 129 'Cookie must match. url: ' + url); | |
| 130 }; | |
| 131 var checkJsonpError = checkJsonpResult.bind(this, 'error'); | |
| 132 var checkJsonpSuccess = checkJsonpResult.bind(this, 'success'); | |
| 133 var checkJsonpNoRedirect = checkJsonpResult.bind(this, 'noredirect'); | |
| 134 var hasCustomHeader = | |
| 135 checkJsonpHeader.bind(this, 'x-serviceworker-test', 'test'); | |
| 136 var hasCustomHeader2 = function(url, data) { | |
| 137 checkJsonpHeader('x-serviceworker-s', 'test1', url, data); | |
| 138 checkJsonpHeader('x-serviceworker-test', 'test2,test3', url, data); | |
| 139 checkJsonpHeader('x-serviceworker-ua', 'test4', url, data); | |
| 140 checkJsonpHeader('x-serviceworker-u', 'test5', url, data); | |
| 141 checkJsonpHeader('x-serviceworker-v', 'test6', url, data); | |
| 142 }; | |
| 143 var noCustomHeader = | |
| 144 checkJsonpHeader.bind(this, 'x-serviceworker-test', undefined); | |
| 145 var methodIsGET = checkJsonpMethod.bind(this, 'GET'); | |
| 146 var methodIsPOST = checkJsonpMethod.bind(this, 'POST'); | |
| 147 var methodIsPUT = checkJsonpMethod.bind(this, 'PUT'); | |
| 148 var methodIsXXX = checkJsonpMethod.bind(this, 'XXX'); | |
| 149 var authCheckNone = | |
| 150 checkJsonpAuth.bind(this, 'undefined', 'undefined', 'undefined'); | |
| 151 var authCheck1 = checkJsonpAuth.bind(this, 'username1', 'password1', 'cookie1'); | |
| 152 var authCheck2 = checkJsonpAuth.bind(this, 'username2', 'password2', 'cookie2'); | |
| 153 | |
| 154 var cookieCheck1 = checkJsonpCookie.bind(this, 'cookie1'); | |
| 155 var cookieCheck2 = checkJsonpCookie.bind(this, 'cookie2'); | |
| 156 var cookieCheckA = checkJsonpCookie.bind(this, 'cookieA'); | |
| 157 var cookieCheckB = checkJsonpCookie.bind(this, 'cookieB'); | |
| 158 var cookieCheckC = checkJsonpCookie.bind(this, 'cookieC'); | |
| 159 var cookieCheckNone = checkJsonpCookie.bind(this, 'undefined'); | |
| 160 | |
| 161 if (location.href.indexOf('base-https') >= 0) | |
| 162 authCheck1 = checkJsonpAuth.bind(this, 'username1s', 'password1s', 'cookie1'); | |
| 163 | |
| 164 if (location.href.indexOf('other-https') >= 0) | |
| 165 authCheck2 = checkJsonpAuth.bind(this, 'username2s', 'password2s', 'cookie2'); | |
| 166 | |
| 167 function executeServiceWorkerProxiedTests(test_targets) { | |
| 168 var test = async_test('Verify access control of fetch() in a Service Worker'); | |
| 169 test.step(function() { | |
| 170 var worker = undefined; | |
| 171 var frameWindow = {}; | |
| 172 var counter = 0; | |
| 173 window.addEventListener('message', test.step_func(onMessage), false); | |
| 174 | |
| 175 Promise.resolve() | |
| 176 .then(function() { | |
| 177 return service_worker_unregister_and_register(test, | |
| 178 WORKER_URL, | |
| 179 SCOPE); | |
| 180 }) | |
| 181 .then(function(registration) { | |
| 182 worker = registration.installing; | |
| 183 var messageChannel = new MessageChannel(); | |
| 184 messageChannel.port1.onmessage = test.step_func(onWorkerMessage); | |
| 185 worker.postMessage( | |
| 186 {port: messageChannel.port2}, [messageChannel.port2]); | |
| 187 return wait_for_state(test, worker, 'activated'); | |
| 188 }) | |
| 189 .then(function() { | |
| 190 return with_iframe(SCOPE); | |
| 191 }) | |
| 192 .then(function(frame) { | |
| 193 frameWindow = frame.contentWindow; | |
| 194 // Start tests. | |
| 195 loadNext(); | |
| 196 }) | |
| 197 .catch(unreached_rejection(test)); | |
| 198 | |
| 199 var readyFromWorkerReceived = undefined; | |
| 200 var resultFromWorkerReceived = undefined; | |
| 201 var resultFromIframeReceived = undefined; | |
| 202 | |
| 203 function onMessage(e) { | |
| 204 // The message is sent from fetch-access-control-iframe.html in report() | |
| 205 // which is called by appending <script> element which source code is | |
| 206 // generated by fetch-access-control.php. | |
| 207 if (test_targets[counter][2]) { | |
| 208 test_targets[counter][2].forEach(function(checkFunc) { | |
| 209 checkFunc.call(this, test_targets[counter][0], e.data); | |
| 210 }); | |
| 211 } | |
| 212 resultFromIframeReceived(); | |
| 213 } | |
| 214 | |
| 215 function onWorkerMessage(e) { | |
| 216 // The message is sent from the ServiceWorker. | |
| 217 var message = e.data; | |
| 218 if (message.msg === 'READY') { | |
| 219 readyFromWorkerReceived(); | |
| 220 return; | |
| 221 } | |
| 222 var checks = test_targets[counter][1].concat(showComment); | |
| 223 checks.forEach(function(checkFunc) { | |
| 224 checkFunc.call(this, test_targets[counter][0], message); | |
| 225 }); | |
| 226 resultFromWorkerReceived(); | |
| 227 } | |
| 228 | |
| 229 function loadNext() { | |
| 230 var workerPromise = new Promise(function(resolve, reject) { | |
| 231 resultFromWorkerReceived = resolve; | |
| 232 }); | |
| 233 var iframePromise = new Promise(function(resolve, reject) { | |
| 234 resultFromIframeReceived = resolve; | |
| 235 }); | |
| 236 Promise.all([workerPromise, iframePromise]) | |
| 237 .then(test.step_func(function() { | |
| 238 ++counter; | |
| 239 if (counter === test_targets.length) { | |
| 240 service_worker_unregister_and_done(test, SCOPE); | |
| 241 } else { | |
| 242 loadNext(); | |
| 243 } | |
| 244 })); | |
| 245 (new Promise(function(resolve, reject) { | |
| 246 readyFromWorkerReceived = resolve; | |
| 247 worker.postMessage({msg: 'START TEST CASE'}); | |
| 248 })) | |
| 249 .then(test.step_func(function() { | |
| 250 frameWindow.postMessage( | |
| 251 {url: test_targets[counter][0]}, | |
| 252 IFRAME_ORIGIN); | |
| 253 })); | |
| 254 } | |
| 255 }); | |
| 256 } | |
| 257 | |
| 258 function getQueryParams(url) { | |
| 259 var search = (new URL(url)).search; | |
| 260 if (!search) { | |
| 261 return {}; | |
| 262 } | |
| 263 var ret = {}; | |
| 264 var params = search.substring(1).split('&'); | |
| 265 params.forEach(function(param) { | |
| 266 var element = param.split('='); | |
| 267 ret[decodeURIComponent(element[0])] = decodeURIComponent(element[1]); | |
| 268 }); | |
| 269 return ret; | |
| 270 } | |
| 271 | |
| 272 function getRequestInit(params) { | |
| 273 var init = {}; | |
| 274 if (params['method']) { | |
| 275 init['method'] = params['method']; | |
| 276 } | |
| 277 if (params['mode']) { | |
| 278 init['mode'] = params['mode']; | |
| 279 } | |
| 280 if (params['credentials']) { | |
| 281 init['credentials'] = params['credentials']; | |
| 282 } | |
| 283 if (params['headers'] === 'CUSTOM') { | |
| 284 init['headers'] = {'X-ServiceWorker-Test': 'test'}; | |
| 285 } else if (params['headers'] === 'CUSTOM2') { | |
| 286 init['headers'] = [['X-ServiceWorker-Test', 'test2'], | |
| 287 ['X-ServiceWorker-ua', 'test4'], | |
| 288 ['X-ServiceWorker-V', 'test6'], | |
| 289 ['X-ServiceWorker-s', 'test1'], | |
| 290 ['X-ServiceWorker-Test', 'test3'], | |
| 291 ['X-ServiceWorker-U', 'test5']]; | |
| 292 } else if (params['headers'] === '{}') { | |
| 293 init['headers'] = {}; | |
| 294 } | |
| 295 return init; | |
| 296 } | |
| 297 | |
| 298 function headersToArray(headers) { | |
| 299 var ret = []; | |
| 300 | |
| 301 // Workaround for Firefox. iterable is not implemented yet. | |
| 302 // This is used only by checkFetchResponseHeader, and | |
| 303 // checkFetchResponseHeader is used only for the header names listed below. | |
| 304 // FIXME: Replace it with the original code below when Firefox supports | |
| 305 // iterable. | |
| 306 ['content-length', 'x-serviceworker-serverheader'].forEach(function(name) { | |
| 307 for (var value of headers.getAll(name)) | |
| 308 ret.push([name, value]); | |
| 309 }); | |
| 310 | |
| 311 // Original code: | |
| 312 // for (var header of headers) { | |
| 313 // ret.push(header); | |
| 314 // } | |
| 315 | |
| 316 return ret; | |
| 317 } | |
| 318 | |
| 319 function doFetch(request) { | |
| 320 var originalURL = request.url; | |
| 321 var params = getQueryParams(originalURL); | |
| 322 var init = getRequestInit(params); | |
| 323 var url = params['url']; | |
| 324 try { | |
| 325 if (url) { | |
| 326 request = new Request(url, init); | |
| 327 } else { | |
| 328 request = new Request(request, init); | |
| 329 } | |
| 330 var response; | |
| 331 return fetch(request) | |
| 332 .then(function(res) { | |
| 333 response = res; | |
| 334 return res.clone().text() | |
| 335 .then(function(body) { | |
| 336 return Promise.resolve({ | |
| 337 // Setting a comment will fail the test and show the | |
| 338 // comment in the result. Use this for debugging | |
| 339 // tests. | |
| 340 comment: undefined, | |
| 341 | |
| 342 fetchResult: 'resolved', | |
| 343 body: body, | |
| 344 status: response.status, | |
| 345 headers: headersToArray(response.headers), | |
| 346 type: response.type, | |
| 347 response: response, | |
| 348 originalURL: originalURL | |
| 349 }); | |
| 350 }) | |
| 351 .catch(function(e) { | |
| 352 return Promise.resolve({fetchResult: 'error'}); | |
| 353 }); | |
| 354 }) | |
| 355 .catch(function(e) { | |
| 356 return Promise.resolve({fetchResult: 'rejected'}); | |
| 357 }); | |
| 358 } catch (e) { | |
| 359 return Promise.resolve({fetchResult: 'error'}); | |
| 360 } | |
| 361 } | |
| 362 | |
| 363 var report_data = {}; | |
| 364 function report(data) { | |
| 365 report_data = data; | |
| 366 } | |
| 367 | |
| 368 function executeTest(test_target) { | |
| 369 if (test_target.length == 0) { | |
| 370 return Promise.resolve(); | |
| 371 } | |
| 372 return doFetch(new Request(test_target[0], | |
| 373 {credentials: 'same-origin', mode: 'no-cors'})) | |
| 374 .then(function(message) { | |
| 375 var checks = test_target[1].concat(showComment); | |
| 376 checks.forEach(function(checkFunc) { | |
| 377 checkFunc.call(this, test_target[0], message); | |
| 378 }); | |
| 379 | |
| 380 if (test_target[2]) { | |
| 381 report_data = {}; | |
| 382 if (message.fetchResult !== 'resolved' || | |
| 383 message.body === '' || | |
| 384 400 <= message.status) { | |
| 385 report({jsonpResult:'error'}); | |
| 386 } else { | |
| 387 eval(message.body); | |
| 388 } | |
| 389 assert_not_equals(report_data, {}, 'data should be set'); | |
| 390 | |
| 391 test_target[2].forEach(function(checkFunc) { | |
| 392 checkFunc.call(this, test_target[0], report_data); | |
| 393 }); | |
| 394 } | |
| 395 }); | |
| 396 } | |
| 397 | |
| 398 function executeTests(test_targets) { | |
| 399 for (var i = 0; i < test_targets.length; ++i) { | |
| 400 sequential_promise_test( | |
| 401 function(counter, t) { | |
| 402 return executeTest(test_targets[counter]); | |
| 403 }.bind(this, i), | |
| 404 "executeTest-" + i); | |
| 405 } | |
| 406 } | |
| OLD | NEW |