| <!DOCTYPE html> |
| <title>Service Worker: Tainting of responses fetched via SW.</title> |
| <!-- This test makes a large number of requests sequentially. --> |
| <meta name="timeout" content="long"> |
| <script src="/resources/testharness.js"></script> |
| <script src="/resources/testharnessreport.js"></script> |
| <script src="/common/get-host-info.sub.js"></script> |
| <script src="resources/test-helpers.sub.js"></script> |
| <body> |
| <script> |
| var host_info = get_host_info(); |
| var BASE_ORIGIN = host_info.HTTPS_ORIGIN; |
| var OTHER_ORIGIN = host_info.HTTPS_REMOTE_ORIGIN; |
| var BASE_URL = BASE_ORIGIN + base_path() + |
| 'resources/fetch-access-control.py?'; |
| var OTHER_BASE_URL = OTHER_ORIGIN + base_path() + |
| 'resources/fetch-access-control.py?'; |
| |
| function frame_fetch(frame, url, mode, credentials) { |
| var foreignPromise = frame.contentWindow.fetch( |
| new Request(url, {mode: mode, credentials: credentials})) |
| |
| // Event loops should be shared between contexts of similar origin, not all |
| // browsers adhere to this expectation at the time of this writing. Incorrect |
| // behavior in this regard can interfere with test execution when the |
| // provided iframe is removed from the document. |
| // |
| // WPT maintains a test dedicated the expected treatment of event loops, so |
| // the following workaround is acceptable in this context. |
| return Promise.resolve(foreignPromise); |
| } |
| |
| var login_and_register; |
| promise_test(function(t) { |
| var SCOPE = 'resources/fetch-response-taint-iframe.html'; |
| var SCRIPT = 'resources/fetch-rewrite-worker.js'; |
| var registration; |
| |
| login_and_register = login_https(t, host_info.HTTPS_ORIGIN, host_info.HTTPS_REMOTE_ORIGIN) |
| .then(function() { |
| return service_worker_unregister_and_register(t, SCRIPT, SCOPE); |
| }) |
| .then(function(r) { |
| registration = r; |
| return wait_for_state(t, registration.installing, 'activated'); |
| }) |
| .then(function() { return with_iframe(SCOPE); }) |
| .then(function(f) { |
| // This test should not be considered complete until after the |
| // service worker has been unregistered. Currently, `testharness.js` |
| // does not support asynchronous global "tear down" logic, so this |
| // must be expressed using a dedicated `promise_test`. Because the |
| // other sub-tests in this file are declared synchronously, this |
| // test will be the final test executed. |
| promise_test(function(t) { |
| f.remove(); |
| return registration.unregister(); |
| }, 'restore global state'); |
| |
| return f; |
| }); |
| return login_and_register; |
| }, 'initialize global state'); |
| |
| function ng_test(url, mode, credentials) { |
| promise_test(function(t) { |
| return login_and_register |
| .then(function(frame) { |
| var fetchRequest = frame_fetch(frame, url, mode, credentials); |
| return promise_rejects_js(t, frame.contentWindow.TypeError, fetchRequest); |
| }); |
| }, 'url:\"' + url + '\" mode:\"' + mode + |
| '\" credentials:\"' + credentials + '\" should fail.'); |
| } |
| |
| function ok_test(url, mode, credentials, expected_type, expected_username) { |
| promise_test(function() { |
| return login_and_register.then(function(frame) { |
| return frame_fetch(frame, url, mode, credentials) |
| }) |
| .then(function(res) { |
| assert_equals(res.type, expected_type, 'response type'); |
| return res.text(); |
| }) |
| .then(function(text) { |
| if (expected_type == 'opaque') { |
| assert_equals(text, ''); |
| } else { |
| return new Promise(function(resolve) { |
| var report = resolve; |
| // text must contain report() call. |
| eval(text); |
| }) |
| .then(function(result) { |
| assert_equals(result.username, expected_username); |
| }); |
| } |
| }); |
| }, 'fetching url:\"' + url + '\" mode:\"' + mode + |
| '\" credentials:\"' + credentials + '\" should ' + |
| 'succeed.'); |
| } |
| |
| function build_rewrite_url(origin, url, mode, credentials) { |
| return origin + '/?url=' + encodeURIComponent(url) + '&mode=' + mode + |
| '&credentials=' + credentials + '&'; |
| } |
| |
| function for_each_origin_mode_credentials(callback) { |
| [BASE_ORIGIN, OTHER_ORIGIN].forEach(function(origin) { |
| ['same-origin', 'no-cors', 'cors'].forEach(function(mode) { |
| ['omit', 'same-origin', 'include'].forEach(function(credentials) { |
| callback(origin, mode, credentials); |
| }); |
| }); |
| }); |
| } |
| |
| ok_test(BASE_URL, 'same-origin', 'omit', 'basic', 'undefined'); |
| ok_test(BASE_URL, 'same-origin', 'same-origin', 'basic', 'username2s'); |
| ok_test(BASE_URL, 'same-origin', 'include', 'basic', 'username2s'); |
| ok_test(BASE_URL, 'no-cors', 'omit', 'basic', 'undefined'); |
| ok_test(BASE_URL, 'no-cors', 'same-origin', 'basic', 'username2s'); |
| ok_test(BASE_URL, 'no-cors', 'include', 'basic', 'username2s'); |
| ok_test(BASE_URL, 'cors', 'omit', 'basic', 'undefined'); |
| ok_test(BASE_URL, 'cors', 'same-origin', 'basic', 'username2s'); |
| ok_test(BASE_URL, 'cors', 'include', 'basic', 'username2s'); |
| ng_test(OTHER_BASE_URL, 'same-origin', 'omit'); |
| ng_test(OTHER_BASE_URL, 'same-origin', 'same-origin'); |
| ng_test(OTHER_BASE_URL, 'same-origin', 'include'); |
| ok_test(OTHER_BASE_URL, 'no-cors', 'omit', 'opaque'); |
| ok_test(OTHER_BASE_URL, 'no-cors', 'same-origin', 'opaque'); |
| ok_test(OTHER_BASE_URL, 'no-cors', 'include', 'opaque'); |
| ng_test(OTHER_BASE_URL, 'cors', 'omit'); |
| ng_test(OTHER_BASE_URL, 'cors', 'same-origin'); |
| ng_test(OTHER_BASE_URL, 'cors', 'include'); |
| ok_test(OTHER_BASE_URL + 'ACAOrigin=*', 'cors', 'omit', 'cors', 'undefined'); |
| ok_test(OTHER_BASE_URL + 'ACAOrigin=*', 'cors', 'same-origin', 'cors', |
| 'undefined'); |
| ng_test(OTHER_BASE_URL + 'ACAOrigin=*', 'cors', 'include'); |
| ok_test(OTHER_BASE_URL + 'ACAOrigin=' + BASE_ORIGIN + '&ACACredentials=true', |
| 'cors', 'include', 'cors', 'username1s') |
| |
| for_each_origin_mode_credentials(function(origin, mode, credentials) { |
| var url = build_rewrite_url( |
| origin, BASE_URL, 'same-origin', 'omit'); |
| // Fetch to the other origin with same-origin mode should fail. |
| if (origin == OTHER_ORIGIN && mode == 'same-origin') { |
| ng_test(url, mode, credentials); |
| } else { |
| // The response type from the SW should be basic |
| ok_test(url, mode, credentials, 'basic', 'undefined'); |
| } |
| }); |
| |
| for_each_origin_mode_credentials(function(origin, mode, credentials) { |
| var url = build_rewrite_url( |
| origin, BASE_URL, 'same-origin', 'same-origin'); |
| |
| // Fetch to the other origin with same-origin mode should fail. |
| if (origin == OTHER_ORIGIN && mode == 'same-origin') { |
| ng_test(url, mode, credentials); |
| } else { |
| // The response type from the SW should be basic. |
| ok_test(url, mode, credentials, 'basic', 'username2s'); |
| } |
| }); |
| |
| for_each_origin_mode_credentials(function(origin, mode, credentials) { |
| var url = build_rewrite_url( |
| origin, OTHER_BASE_URL, 'same-origin', 'omit'); |
| // The response from the SW should be an error. |
| ng_test(url, mode, credentials); |
| }); |
| |
| for_each_origin_mode_credentials(function(origin, mode, credentials) { |
| var url = build_rewrite_url( |
| origin, OTHER_BASE_URL, 'no-cors', 'omit'); |
| |
| // SW can respond only to no-cors requests. |
| if (mode != 'no-cors') { |
| ng_test(url, mode, credentials); |
| } else { |
| // The response type from the SW should be opaque. |
| ok_test(url, mode, credentials, 'opaque'); |
| } |
| }); |
| |
| for_each_origin_mode_credentials(function(origin, mode, credentials) { |
| var url = build_rewrite_url( |
| origin, OTHER_BASE_URL + 'ACAOrigin=*', 'cors', 'omit'); |
| |
| // Fetch to the other origin with same-origin mode should fail. |
| if (origin == OTHER_ORIGIN && mode == 'same-origin') { |
| ng_test(url, mode, credentials); |
| } else if (origin == BASE_ORIGIN && mode == 'same-origin') { |
| // Cors type response to a same-origin mode request should fail |
| ng_test(url, mode, credentials); |
| } else { |
| // The response from the SW should be cors. |
| ok_test(url, mode, credentials, 'cors', 'undefined'); |
| } |
| }); |
| |
| for_each_origin_mode_credentials(function(origin, mode, credentials) { |
| var url = build_rewrite_url( |
| origin, |
| OTHER_BASE_URL + 'ACAOrigin=' + BASE_ORIGIN + |
| '&ACACredentials=true', |
| 'cors', 'include'); |
| // Fetch to the other origin with same-origin mode should fail. |
| if (origin == OTHER_ORIGIN && mode == 'same-origin') { |
| ng_test(url, mode, credentials); |
| } else if (origin == BASE_ORIGIN && mode == 'same-origin') { |
| // Cors type response to a same-origin mode request should fail |
| ng_test(url, mode, credentials); |
| } else { |
| // The response from the SW should be cors. |
| ok_test(url, mode, credentials, 'cors', 'username1s'); |
| } |
| }); |
| </script> |
| </body> |