Commit 378d85a4 authored by falken@chromium.org's avatar falken@chromium.org

Service Worker: FetchEvent.preventDefault() results in a network error

Since the default behavior is to fallback to network, preventDefault()
should cause a network error.

As per spec: https://github.com/slightlyoff/ServiceWorker/issues/51
(see commit f022c3a6d)

Also add a test for calling FetchEvent.respondWith() with a rejected
promise; this must also produce a network error.

BUG=432825

Review URL: https://codereview.chromium.org/733983002

git-svn-id: svn://svn.chromium.org/blink/trunk@185451 bbb929c8-8fbe-4397-9dbb-9b2b20218538
parent 8cd4dc5c
<!DOCTYPE html>
<title>Service Worker: Fetch event network error</title>
<script src="../resources/testharness.js"></script>
<script src="../resources/testharness-helpers.js"></script>
<script src="../resources/testharnessreport.js"></script>
<script src="resources/test-helpers.js"></script>
<script>
var resolve_test_done;
var test_done_promise = new Promise(function(resolve) {
resolve_test_done = resolve;
});
// Called by the child frame.
function notify_test_done(result) {
resolve_test_done(result);
}
promise_test(function(t) {
var scope = 'resources/fetch-event-network-error-controllee-iframe.html';
var script = 'resources/fetch-event-network-error-worker.js';
var frame;
return service_worker_unregister_and_register(t, script, scope)
.then(function(registration) {
return wait_for_activated(t, registration);
})
.then(function() {
return with_iframe(scope);
})
.then(function(f) {
frame = f;
return test_done_promise;
})
.then(function(result) {
frame.remove();
assert_equals(result, 'PASS');
return service_worker_unregister_and_done(t, scope);
});
}, 'Rejecting the fetch event or using preventDefault() causes a network ' +
'error');
</script>
<!DOCTYPE html>
<script>
function fetch_url(url) {
return new Promise(function(resolve, reject) {
var request = new XMLHttpRequest();
request.addEventListener('load', function(event) {
resolve();
});
request.addEventListener('error', function(event) {
reject();
});
request.open('GET', url);
request.send();
});
}
function make_test(testcase) {
var name = testcase.name;
return fetch_url(window.location.href + '?' + name)
.then(
function() {
if (testcase.expect_load)
return Promise.resolve();
return Promise.reject(new Error(
name + ': expected network error but loaded'));
},
function() {
if (!testcase.expect_load)
return Promise.resolve();
return Promise.reject(new Error(
name + ': expected to load but got network error'));
});
}
function run_tests() {
var tests = [
{ name: 'prevent-default-and-respond-with', expect_load: true },
{ name: 'prevent-default', expect_load: false },
{ name: 'reject', expect_load: false }
].map(make_test);
Promise.all(tests)
.then(function() {
window.parent.notify_test_done('PASS');
})
.catch(function(error) {
window.parent.notify_test_done('FAIL: ' + error.message);
});
}
if (!navigator.serviceWorker.controller)
window.parent.notify_done('FAIL: no controller');
else
run_tests();
</script>
// Test that multiple fetch handlers do not confuse the implementation.
self.addEventListener('fetch', function(event) {});
self.addEventListener('fetch', function(event) {
var testcase = new URL(event.request.url).search;
switch (testcase) {
case '?reject':
event.respondWith(Promise.reject());
break;
case '?prevent-default':
event.preventDefault();
break;
case '?prevent-default-and-respond-with':
event.preventDefault();
break;
}
});
self.addEventListener('fetch', function(event) {});
self.addEventListener('fetch', function(event) {
var testcase = new URL(event.request.url).search;
if (testcase == '?prevent-default-and-respond-with')
event.respondWith(new Response('responding!'));
});
self.addEventListener('fetch', function(event) {});
......@@ -195,9 +195,9 @@ bool EventTarget::dispatchEvent(PassRefPtrWillBeRawPtr<Event> event)
event->setTarget(this);
event->setCurrentTarget(this);
event->setEventPhase(Event::AT_TARGET);
bool defaultPrevented = fireEventListeners(event.get());
bool defaultWasNotPrevented = fireEventListeners(event.get());
event->setEventPhase(0);
return defaultPrevented;
return defaultWasNotPrevented;
}
void EventTarget::uncaughtExceptionInEventHandler()
......
......@@ -74,11 +74,17 @@ void RespondWithObserver::contextDestroyed()
m_state = Done;
}
void RespondWithObserver::didDispatchEvent()
void RespondWithObserver::didDispatchEvent(bool defaultPrevented)
{
ASSERT(executionContext());
if (m_state != Initial)
return;
if (defaultPrevented) {
responseWasRejected();
return;
}
ServiceWorkerGlobalScopeClient::from(executionContext())->didHandleFetchEvent(m_eventID);
m_state = Done;
}
......
......@@ -24,7 +24,7 @@ public:
virtual void contextDestroyed() override;
void didDispatchEvent();
void didDispatchEvent(bool defaultPrevented);
// Observes the promise and delays calling didHandleFetchEvent() until the
// given promise is resolved or rejected.
......
......@@ -82,8 +82,9 @@ void ServiceWorkerGlobalScopeProxy::dispatchFetchEvent(int eventID, const WebSer
{
ASSERT(m_workerGlobalScope);
RespondWithObserver* observer = RespondWithObserver::create(m_workerGlobalScope, eventID, webRequest.mode(), webRequest.frameType());
bool defaultPrevented = false;
if (!RuntimeEnabledFeatures::serviceWorkerOnFetchEnabled()) {
observer->didDispatchEvent();
observer->didDispatchEvent(defaultPrevented);
return;
}
......@@ -91,8 +92,8 @@ void ServiceWorkerGlobalScopeProxy::dispatchFetchEvent(int eventID, const WebSer
request->headers()->setGuard(Headers::ImmutableGuard);
RefPtrWillBeRawPtr<FetchEvent> fetchEvent(FetchEvent::create(observer, request));
fetchEvent->setIsReload(webRequest.isReload());
m_workerGlobalScope->dispatchEvent(fetchEvent.release());
observer->didDispatchEvent();
defaultPrevented = !m_workerGlobalScope->dispatchEvent(fetchEvent.release());
observer->didDispatchEvent(defaultPrevented);
}
void ServiceWorkerGlobalScopeProxy::dispatchGeofencingEvent(int eventID, WebGeofencingEventType eventType, const WebString& regionID, const WebCircularGeofencingRegion& region)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment