blob: 21e132d80b432e39dace6b0be843246bd9cd4ab7 [file] [log] [blame]
<!DOCTYPE html>
<title>Service Worker: basic Foreign Fetch functionality</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="resources/get-host-info.sub.js"></script>
<script src="resources/test-helpers.sub.js"></script>
<script src="resources/foreign-fetch-helpers.js"></script>
<body>
<script>
var host_info = get_host_info();
var resource_path = new URL('resources/', location).pathname;
function worker_for_origins(origins) {
var worker = 'foreign-fetch-worker.js?';
var params = {origins: origins, relscopes: ['/intercept']};
return worker + encodeURIComponent(JSON.stringify(params));
}
function worker_for_scopes(relative_scopes) {
var worker = 'foreign-fetch-worker.js?';
var params = {relscopes: relative_scopes};
return worker + encodeURIComponent(JSON.stringify(params));
}
function intercepted_url(scope) {
return host_info.HTTPS_REMOTE_ORIGIN + resource_path + scope + '/intercept/foo?basic';
}
function non_intercepted_url(scope) {
return host_info.HTTPS_REMOTE_ORIGIN + resource_path + scope + '/foo?basic';
}
promise_test(t => {
var scope = 'foreign-fetch/scope/wildcard';
return install_cross_origin_worker(t, worker_for_origins(['*']), scope)
.then(() => promise_rejects(t, new TypeError(),
fetch(non_intercepted_url(scope))))
.then(() => fetch(intercepted_url(scope)))
.then(response => response.text())
.then(response_text => {
assert_equals(response_text, 'Foreign Fetch');
});
}, 'Service Worker intercepts fetches in scope with wildcard origin.');
promise_test(t => {
var scope = 'foreign-fetch/scope/match-origin';
return install_cross_origin_worker(
t, worker_for_origins([location.origin]), scope)
.then(() => fetch(intercepted_url(scope)))
.then(response => response.text())
.then(response_text => {
assert_equals(response_text, 'Foreign Fetch');
});
}, 'Service Worker intercepts fetches in scope with explicit origin.');
promise_test(t => {
var scope = 'foreign-fetch/scope/nomatch-origin';
return install_cross_origin_worker(
t, worker_for_origins(['https://example.com']), scope)
.then(() => promise_rejects(t, new TypeError(),
fetch(non_intercepted_url(scope))));
}, 'Service Worker doesn\'t intercept fetches with non matching origin.');
promise_test(t => {
var scope = 'foreign-fetch/scope/origin-list';
return install_cross_origin_worker(
t, worker_for_origins([location.origin, 'https://example.com']), scope)
.then(() => fetch(intercepted_url(scope)))
.then(response => response.text())
.then(response_text => {
assert_equals(response_text, 'Foreign Fetch');
});
}, 'Service Worker intercepts fetches in scope with explicit origin list.');
promise_test(t => {
var scope = 'resources/foreign-fetch/same-origin';
return service_worker_unregister_and_register(
t, 'resources/' + worker_for_origins(['*']), scope)
.then(r => {
add_completion_callback(() => r.unregister());
return wait_for_state(t, r.installing, 'activated');
})
.then(() => fetch(scope + '/intercept/foo?basic'))
.then(response => {
assert_equals(response.status, 404);
});
}, 'Service Worker does not intercept same origin fetches.');
promise_test(t => {
var scope = 'reply-to-message.html?onmessage';
var remote_url =
host_info.HTTPS_REMOTE_ORIGIN + resource_path + scope;
return install_cross_origin_worker(t, worker_for_scopes(['']), scope)
.then(() => with_iframe(remote_url))
.then(frame => new Promise(resolve => {
var channel = new MessageChannel();
frame.contentWindow.postMessage('ping', '*', [channel.port1]);
channel.port2.onmessage = reply => resolve(reply.data);
}))
.then(reply => {
assert_equals(reply, 'ping');
});
}, 'Service Worker does not intercept navigations.');
promise_test(t => {
var scope = 'fetch-access-control.py?fallback&ACAOrigin=*';
var remote_url =
host_info.HTTPS_REMOTE_ORIGIN + resource_path + scope;
return install_cross_origin_worker(t, worker_for_scopes(['']), scope)
.then(() => fetch(remote_url))
.then(response => response.text())
.then(response_text => assert_true(response_text.startsWith('report(')));
}, 'Service Worker that fallback to network should fallback to network.');
promise_test(t => {
var scope = 'fetch-access-control.py?fetch&ACAOrigin=*';
var remote_url =
host_info.HTTPS_REMOTE_ORIGIN + resource_path + scope;
return install_cross_origin_worker(t, worker_for_scopes(['']), scope)
.then(() => fetch(remote_url))
.then(response => response.text())
.then(response_text => assert_true(response_text.startsWith('report(')));
}, 'Service Worker that fetch from the network should fallback to network.');
promise_test(t => {
var scope = 'simple.txt?fallback';
var remote_url =
host_info.HTTPS_REMOTE_ORIGIN + resource_path + scope;
return install_cross_origin_worker(t, worker_for_scopes(['']), scope)
.then(() => fetch(remote_url, {mode: 'no-cors'}))
.then(response => assert_equals(response.type, 'opaque'))
.then(() => promise_rejects(t, new TypeError(), fetch(remote_url)));
}, 'Falling back to network should still respect CORS.');
promise_test(t => {
var ff_scope = 'foreign-fetch/scope/controlled?basic';
var remote_url =
host_info.HTTPS_REMOTE_ORIGIN + resource_path + ff_scope;
var scope = 'resources/simple.html?fetch';
var worker = 'resources/empty-worker.js';
return install_cross_origin_worker(t, worker_for_scopes(['']), ff_scope)
.then(() => service_worker_unregister_and_register(t, worker, scope))
.then(r => {
add_completion_callback(() => r.unregister());
return wait_for_state(t, r.installing, 'activated');
})
.then(() => with_iframe(scope))
.then(frame => frame.contentWindow.fetch(remote_url))
.then(response => response.text())
.then(response_text => {
assert_equals(response_text, 'Foreign Fetch');
});
}, 'Foreign fetch can intercept fetch requests from SW controlled pages.');
promise_test(t => {
var ff_scope = 'foreign-fetch/scope/controlled?script';
var remote_url =
host_info.HTTPS_REMOTE_ORIGIN + resource_path + ff_scope;
var scope = 'resources/simple.html?script';
var worker = 'resources/empty-worker.js';
return install_cross_origin_worker(t, worker_for_scopes(['']), ff_scope)
.then(() => service_worker_unregister_and_register(t, worker, scope))
.then(r => {
add_completion_callback(() => r.unregister());
return wait_for_state(t, r.installing, 'activated');
})
.then(() => with_iframe(scope))
.then(frame => new Promise(resolve => {
frame.contentWindow.DidLoad = resolve;
let script = frame.contentWindow.document.createElement('script');
script.setAttribute('src', remote_url);
script.setAttribute('crossorigin', 'use-credentials');
frame.contentWindow.document.head.appendChild(script);
}))
.then(response_text => {
assert_equals(response_text, 'Foreign Fetch');
});
}, 'Foreign fetch can intercept resource requests from SW controlled pages.');
promise_test(t => {
var scope = 'simple.txt?meta';
var remote_url =
host_info.HTTPS_REMOTE_ORIGIN + resource_path + scope;
return install_cross_origin_worker(t, worker_for_scopes(['']), scope)
.then(() => fetch(remote_url, {mode: 'no-cors'}))
.then(response => response.json())
.then(response_data => {
assert_equals(self.location.href, response_data.referrer);
assert_equals(self.location.origin, response_data.origin);
})
.then(() => with_iframe('resources/blank.html'))
.then(frame => {
var meta = frame.contentDocument.createElement('meta');
meta.setAttribute('name', 'referrer');
meta.setAttribute('content', 'no-referrer');
frame.contentDocument.head.appendChild(meta);
return frame.contentWindow.fetch(remote_url, {mode: 'no-cors'});
})
.then(response => response.json())
.then(response_data => {
assert_equals('', response_data.referrer);
assert_equals('null', response_data.origin);
});
}, 'Referrer and origin are set correctly in ForeignFetchEvent.');
promise_test(t => {
var scope = 'simple.txt?basic_insecure';
var remote_url =
host_info.AUTHENTICATED_ORIGIN + resource_path + scope;
return install_cross_origin_worker(t, worker_for_scopes(['']), scope,
host_info.AUTHENTICATED_ORIGIN)
.then(() => fetch_from_different_origin(host_info.HTTPS_REMOTE_ORIGIN, remote_url))
.then(response => assert_equals(response, 'Success: Foreign Fetch'))
.then(() => fetch_from_different_origin(host_info.UNAUTHENTICATED_ORIGIN,
remote_url))
.then(response => assert_true(response.startsWith('Error: TypeError')));
}, 'Service Worker does not intercept fetches from an insecure context.');
promise_test(t => {
var scope = 'fetch-access-control.py?basic&ACAOrigin=*&ACAMethods=SPECIAL';
var remote_url =
host_info.HTTPS_REMOTE_ORIGIN + resource_path + scope;
return install_cross_origin_worker(t, worker_for_scopes(['']), scope)
.then(() => fetch(remote_url, {method: 'SPECIAL'}))
.then(response => response.text())
.then(response_text => assert_true(response_text.startsWith('report(')))
// Do the whole thing twice to test CORS preflight cache behavior.
.then(() => fetch(remote_url, {method: 'SPECIAL'}))
.then(response => response.text())
.then(response_text => assert_true(response_text.startsWith('report(')));
}, 'Service Worker does not intercept fetches with CORS preflight');
promise_test(t => {
var scope = 'simple.txt?null';
var remote_url =
host_info.HTTPS_REMOTE_ORIGIN + resource_path + scope;
return install_cross_origin_worker(t, worker_for_scopes(['']), scope)
.then(() => promise_rejects(t, new TypeError(), fetch(remote_url)));
}, 'Foreign fetch rejects if resolved with a null response.');
</script>
</body>