зеркало из https://github.com/mozilla/gecko-dev.git
Backed out 12 changesets (bug 1188545) for test_fetch_cors failures CLOSED TREE
Backed out changeset e04738ee72a3 (bug 1188545) Backed out changeset 1989893b59de (bug 1188545) Backed out changeset 11ff29cc25d8 (bug 1188545) Backed out changeset 4b6bdf859845 (bug 1188545) Backed out changeset 76eb7ffeca2a (bug 1188545) Backed out changeset 4473e036b52e (bug 1188545) Backed out changeset 2a28cb794b23 (bug 1188545) Backed out changeset 1fa2f55727f3 (bug 1188545) Backed out changeset 032f4c24fc34 (bug 1188545) Backed out changeset 4be675dc1b37 (bug 1188545) Backed out changeset d5d05def5b17 (bug 1188545) Backed out changeset e94f12b0bcf3 (bug 1188545)
This commit is contained in:
Родитель
2f2b59e28b
Коммит
6fbdec2422
|
@ -34,7 +34,7 @@ interface nsIServiceWorkerInfo : nsISupports
|
|||
readonly attribute DOMString waitingCacheName;
|
||||
};
|
||||
|
||||
[scriptable, builtinclass, uuid(8fb9db4f-1d04-402b-9c37-542da06e03b9)]
|
||||
[scriptable, builtinclass, uuid(471b2d5d-64c3-4dea-bde1-219853dcaac8)]
|
||||
interface nsIServiceWorkerManager : nsISupports
|
||||
{
|
||||
/**
|
||||
|
@ -93,10 +93,12 @@ interface nsIServiceWorkerManager : nsISupports
|
|||
[noscript] nsISupports GetActive(in nsIDOMWindow aWindow, in DOMString aScope);
|
||||
|
||||
/*
|
||||
* Returns a ServiceWorker object representing the active worker controlling this
|
||||
* window.
|
||||
* Returns a ServiceWorker.
|
||||
* - aLoadFailedRunnable is an optional callback that will fire on main thread if
|
||||
* a ServiceWorker object is returned, but later fails to load for some reason.
|
||||
*/
|
||||
[noscript] nsISupports GetDocumentController(in nsIDOMWindow aWindow);
|
||||
[noscript] nsISupports GetDocumentController(in nsIDOMWindow aWindow,
|
||||
in nsIRunnable aLoadFailedRunnable);
|
||||
|
||||
/*
|
||||
* Clears ServiceWorker registrations from memory and disk for the specified
|
||||
|
|
|
@ -1,73 +0,0 @@
|
|||
var state = "from_scope";
|
||||
var resolvePromiseCallback;
|
||||
|
||||
onfetch = function(event) {
|
||||
if (event.request.url.indexOf("lifetime_frame.html") >= 0) {
|
||||
event.respondWith(new Response("iframe_lifetime"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!event.client) {
|
||||
dump("ERROR: no client to post the message to!\n");
|
||||
dump("request.url=" + event.request.url + "\n");
|
||||
return;
|
||||
}
|
||||
|
||||
event.client.postMessage({type: "fetch", state: state});
|
||||
|
||||
if (event.request.url.indexOf("update") >= 0) {
|
||||
state = "update";
|
||||
} else if (event.request.url.indexOf("wait") >= 0) {
|
||||
event.respondWith(new Promise(function(res, rej) {
|
||||
if (resolvePromiseCallback) {
|
||||
dump("ERROR: service worker was already waiting on a promise.\n");
|
||||
}
|
||||
resolvePromiseCallback = function() {
|
||||
res(new Response("resolve_respondWithPromise"));
|
||||
};
|
||||
}));
|
||||
state = "wait";
|
||||
} else if (event.request.url.indexOf("release") >= 0) {
|
||||
state = "release";
|
||||
resolvePromise();
|
||||
}
|
||||
}
|
||||
|
||||
function resolvePromise() {
|
||||
if (resolvePromiseCallback === undefined || resolvePromiseCallback == null) {
|
||||
dump("ERROR: wait promise was not set.\n");
|
||||
return;
|
||||
}
|
||||
resolvePromiseCallback();
|
||||
resolvePromiseCallback = null;
|
||||
}
|
||||
|
||||
onmessage = function(event) {
|
||||
// FIXME(catalinb): we cannot treat these events as extendable
|
||||
// yet. Bug 1143717
|
||||
event.source.postMessage({type: "message", state: state});
|
||||
state = event.data;
|
||||
if (event.data === "release") {
|
||||
resolvePromise();
|
||||
}
|
||||
}
|
||||
|
||||
onpush = function(event) {
|
||||
// FIXME(catalinb): push message carry no data. So we assume the only
|
||||
// push message we get is "wait"
|
||||
clients.matchAll().then(function(client) {
|
||||
if (client.length == 0) {
|
||||
dump("ERROR: no clients to send the response to.\n");
|
||||
}
|
||||
|
||||
client[0].postMessage({type: "push", state: state});
|
||||
|
||||
state = "wait";
|
||||
event.waitUntil(new Promise(function(res, rej) {
|
||||
if (resolvePromiseCallback) {
|
||||
dump("ERROR: service worker was already waiting on a promise.\n");
|
||||
}
|
||||
resolvePromiseCallback = res;
|
||||
}));
|
||||
});
|
||||
}
|
|
@ -5,7 +5,6 @@ support-files =
|
|||
push-server.sjs
|
||||
frame.html
|
||||
webpush.js
|
||||
lifetime_worker.js
|
||||
|
||||
[test_has_permissions.html]
|
||||
skip-if = os == "android" || toolkit == "gonk"
|
||||
|
@ -26,5 +25,3 @@ skip-if = os == "android" || toolkit == "gonk"
|
|||
# Disabled for too many intermittent failures (bug 1164432)
|
||||
# [test_try_registering_offline_disabled.html]
|
||||
# skip-if = os == "android" || toolkit == "gonk"
|
||||
[test_serviceworker_lifetime.html]
|
||||
skip-if = os == "android" || toolkit == "gonk"
|
||||
|
|
|
@ -1,331 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
Test the lifetime management of service workers. We keep this test in
|
||||
dom/push/tests to pass the external network check when connecting to
|
||||
the mozilla push service.
|
||||
|
||||
How this test works:
|
||||
- the service worker maintains a state variable and a promise used for
|
||||
extending its lifetime. Note that the terminating the worker will reset
|
||||
these variables to their default values.
|
||||
- we send 3 types of requests to the service worker:
|
||||
|update|, |wait| and |release|. All three requests will cause the sw to update
|
||||
its state to the new value and reply with a message containing
|
||||
its previous state. Furthermore, |wait| will set a waitUntil or a respondWith
|
||||
promise that's not resolved until the next |release| message.
|
||||
- Each subtest will use a combination of values for the timeouts and check
|
||||
if the service worker is in the correct state as we send it different
|
||||
events.
|
||||
- We also wait and assert for service worker termination using an event dispatched
|
||||
through nsIObserverService.
|
||||
-->
|
||||
<head>
|
||||
<title>Test for Bug 1188545</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
<meta http-equiv="Content-type" content="text/html;charset=UTF-8">
|
||||
</head>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1188545">Mozilla Bug 118845</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
</pre>
|
||||
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
function start() {
|
||||
return navigator.serviceWorker.register("lifetime_worker.js", {scope: "./"})
|
||||
.then((swr) => ({registration: swr}));
|
||||
}
|
||||
|
||||
function waitForActiveServiceWorker(ctx) {
|
||||
return navigator.serviceWorker.ready.then(function(result) {
|
||||
ok(ctx.registration.active, "Service Worker is active");
|
||||
return ctx;
|
||||
});
|
||||
}
|
||||
|
||||
function unregister(ctx) {
|
||||
return ctx.registration.unregister().then(function(result) {
|
||||
ok(result, "Unregister should return true.");
|
||||
}, function(e) {
|
||||
dump("Unregistering the SW failed with " + e + "\n");
|
||||
});
|
||||
}
|
||||
|
||||
function registerPushNotification(ctx) {
|
||||
var p = new Promise(function(res, rej) {
|
||||
ctx.registration.pushManager.subscribe().then(
|
||||
function(pushSubscription) {
|
||||
ok(true, "successful registered for push notification");
|
||||
ctx.subscription = pushSubscription;
|
||||
res(ctx);
|
||||
}, function(error) {
|
||||
ok(false, "could not register for push notification");
|
||||
res(ctx);
|
||||
});
|
||||
});
|
||||
return p;
|
||||
}
|
||||
|
||||
function sendPushToPushServer(pushEndpoint) {
|
||||
// Work around CORS for now.
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open('GET', "http://mochi.test:8888/tests/dom/push/test/push-server.sjs", true);
|
||||
xhr.setRequestHeader("X-Push-Method", "PUT");
|
||||
xhr.setRequestHeader("X-Push-Server", pushEndpoint);
|
||||
xhr.send("version=24601");
|
||||
}
|
||||
|
||||
function unregisterPushNotification(ctx) {
|
||||
return ctx.subscription.unsubscribe().then(function(result) {
|
||||
ok(result, "unsubscribe should succeed.");
|
||||
ctx.subscription = null;
|
||||
return ctx;
|
||||
});
|
||||
}
|
||||
|
||||
function createIframe(ctx) {
|
||||
var p = new Promise(function(res, rej) {
|
||||
var iframe = document.createElement('iframe');
|
||||
// This file doesn't exist, the service worker will give us an empty
|
||||
// document.
|
||||
iframe.src = "http://mochi.test:8888/tests/dom/push/test/lifetime_frame.html";
|
||||
|
||||
iframe.onload = function() {
|
||||
ctx.iframe = iframe;
|
||||
res(ctx);
|
||||
}
|
||||
document.body.appendChild(iframe);
|
||||
});
|
||||
return p;
|
||||
}
|
||||
|
||||
function closeIframe(ctx) {
|
||||
ctx.iframe.parentNode.removeChild(ctx.iframe);
|
||||
return new Promise(function(res, rej) {
|
||||
// XXXcatalinb: give the worker more time to "notice" it stopped
|
||||
// controlling documents
|
||||
ctx.iframe = null;
|
||||
setTimeout(res, 0);
|
||||
}).then(() => ctx);
|
||||
}
|
||||
|
||||
function waitAndCheckMessage(contentWindow, expected) {
|
||||
function checkMessage(expected, resolve, event) {
|
||||
ok(event.data.type == expected.type, "Received correct message type: " + expected.type);
|
||||
ok(event.data.state == expected.state, "Service worker is in the correct state: " + expected.state);
|
||||
this.navigator.serviceWorker.onmessage = null;
|
||||
resolve();
|
||||
}
|
||||
return new Promise(function(res, rej) {
|
||||
contentWindow.navigator.serviceWorker.onmessage =
|
||||
checkMessage.bind(contentWindow, expected, res);
|
||||
});
|
||||
}
|
||||
|
||||
function fetchEvent(ctx, expected_state, new_state) {
|
||||
var expected = { type: "fetch", state: expected_state };
|
||||
var p = waitAndCheckMessage(ctx.iframe.contentWindow, expected);
|
||||
ctx.iframe.contentWindow.fetch(new_state);
|
||||
return p;
|
||||
}
|
||||
|
||||
function pushEvent(ctx, expected_state, new_state) {
|
||||
var expected = {type: "push", state: expected_state};
|
||||
var p = waitAndCheckMessage(ctx.iframe.contentWindow, expected);
|
||||
sendPushToPushServer(ctx.subscription.endpoint);
|
||||
return p;
|
||||
}
|
||||
|
||||
function messageEventIframe(ctx, expected_state, new_state) {
|
||||
var expected = {type: "message", state: expected_state};
|
||||
var p = waitAndCheckMessage(ctx.iframe.contentWindow, expected);
|
||||
ctx.iframe.contentWindow.navigator.serviceWorker.controller.postMessage(new_state);
|
||||
return p;
|
||||
}
|
||||
|
||||
function messageEvent(ctx, expected_state, new_state) {
|
||||
var expected = {type: "message", state: expected_state};
|
||||
var p = waitAndCheckMessage(window, expected);
|
||||
ctx.registration.active.postMessage(new_state);
|
||||
return p;
|
||||
}
|
||||
|
||||
function checkStateAndUpdate(eventFunction, expected_state, new_state) {
|
||||
return function(ctx) {
|
||||
return eventFunction(ctx, expected_state, new_state)
|
||||
.then(() => ctx);
|
||||
}
|
||||
}
|
||||
|
||||
function setShutdownObserver(expectingEvent) {
|
||||
return function(ctx) {
|
||||
cancelShutdownObserver(ctx);
|
||||
|
||||
ctx.observer_promise = new Promise(function(res, rej) {
|
||||
ctx.observer = {
|
||||
observe: function(subject, topic, data) {
|
||||
ok((topic == "service-worker-shutdown") && expectingEvent, "Service worker was terminated.");
|
||||
this.remove(ctx);
|
||||
},
|
||||
remove: function(ctx) {
|
||||
SpecialPowers.removeObserver(this, "service-worker-shutdown");
|
||||
ctx.observer = null;
|
||||
res(ctx);
|
||||
}
|
||||
}
|
||||
SpecialPowers.addObserver(ctx.observer, "service-worker-shutdown", false);
|
||||
});
|
||||
|
||||
return ctx;
|
||||
}
|
||||
}
|
||||
|
||||
function waitOnShutdownObserver(ctx) {
|
||||
return ctx.observer_promise;
|
||||
}
|
||||
|
||||
function cancelShutdownObserver(ctx) {
|
||||
if (ctx.observer) {
|
||||
ctx.observer.remove(ctx);
|
||||
}
|
||||
return ctx.observer_promise;
|
||||
}
|
||||
|
||||
function subTest(test) {
|
||||
return function(ctx) {
|
||||
return new Promise(function(res, rej) {
|
||||
function run() {
|
||||
test.steps(ctx).catch(function(e) {
|
||||
ok(false, "Some test failed with error: " + e);
|
||||
}).then((ctx) => res(ctx));
|
||||
}
|
||||
|
||||
SpecialPowers.pushPrefEnv({"set" : test.prefs}, run);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
var test1 = {
|
||||
prefs: [
|
||||
["dom.serviceWorkers.idle_timeout", 0],
|
||||
["dom.serviceWorkers.idle_extended_timeout", 2999999]
|
||||
],
|
||||
// Test that service workers are terminated after the grace period expires
|
||||
// when there are no pending waitUntil or respondWith promises.
|
||||
steps: function(ctx) {
|
||||
// Test with fetch events and respondWith promises
|
||||
return createIframe(ctx)
|
||||
.then(setShutdownObserver(true))
|
||||
.then(checkStateAndUpdate(fetchEvent, "from_scope", "update"))
|
||||
.then(waitOnShutdownObserver)
|
||||
.then(setShutdownObserver(false))
|
||||
.then(checkStateAndUpdate(fetchEvent, "from_scope", "wait"))
|
||||
.then(checkStateAndUpdate(fetchEvent, "wait", "update"))
|
||||
.then(checkStateAndUpdate(fetchEvent, "update", "update"))
|
||||
.then(setShutdownObserver(true))
|
||||
// The service worker should be terminated when the promise is resolved.
|
||||
.then(checkStateAndUpdate(fetchEvent, "update", "release"))
|
||||
.then(waitOnShutdownObserver)
|
||||
.then(setShutdownObserver(false))
|
||||
.then(closeIframe)
|
||||
.then(cancelShutdownObserver)
|
||||
|
||||
// Test with push events and message events
|
||||
.then(createIframe)
|
||||
.then(setShutdownObserver(false))
|
||||
.then(checkStateAndUpdate(pushEvent, "from_scope", "wait"))
|
||||
.then(setShutdownObserver(true))
|
||||
.then(checkStateAndUpdate(messageEventIframe, "wait", "update"))
|
||||
.then(waitOnShutdownObserver)
|
||||
.then(closeIframe)
|
||||
}
|
||||
}
|
||||
|
||||
var test2 = {
|
||||
prefs: [
|
||||
["dom.serviceWorkers.idle_timeout", 0],
|
||||
["dom.serviceWorkers.idle_extended_timeout", 2999999]
|
||||
],
|
||||
steps: function(ctx) {
|
||||
// Non push workers are terminated when they stop controlling documents.
|
||||
return createIframe(ctx)
|
||||
.then(setShutdownObserver(true))
|
||||
.then(checkStateAndUpdate(fetchEvent, "from_scope", "wait"))
|
||||
.then(closeIframe)
|
||||
.then(waitOnShutdownObserver)
|
||||
|
||||
// Push workers are exempt from this rule.
|
||||
.then(createIframe)
|
||||
.then(setShutdownObserver(false))
|
||||
.then(checkStateAndUpdate(pushEvent, "from_scope", "wait"))
|
||||
.then(closeIframe)
|
||||
.then(setShutdownObserver(true))
|
||||
.then(checkStateAndUpdate(messageEvent, "wait", "release"))
|
||||
.then(waitOnShutdownObserver)
|
||||
}
|
||||
};
|
||||
|
||||
var test3 = {
|
||||
prefs: [
|
||||
["dom.serviceWorkers.idle_timeout", 2999999],
|
||||
["dom.serviceWorkers.idle_extended_timeout", 0]
|
||||
],
|
||||
steps: function(ctx) {
|
||||
// set the grace period to 0 and dispatch a message which will reset
|
||||
// the internal sw timer to the new value.
|
||||
var test3_1 = {
|
||||
prefs: [
|
||||
["dom.serviceWorkers.idle_timeout", 0]
|
||||
],
|
||||
steps: function(ctx) {
|
||||
return new Promise(function(res, rej) {
|
||||
ctx.registration.active.postMessage("update");
|
||||
res(ctx);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Test that service worker is closed when the extended timeout expired
|
||||
return createIframe(ctx)
|
||||
.then(setShutdownObserver(false))
|
||||
.then(checkStateAndUpdate(messageEvent, "from_scope", "update"))
|
||||
.then(checkStateAndUpdate(messageEventIframe, "update", "update"))
|
||||
.then(checkStateAndUpdate(fetchEvent, "update", "wait"))
|
||||
.then(setShutdownObserver(true))
|
||||
.then(subTest(test3_1)) // This should cause the internal timer to expire.
|
||||
.then(waitOnShutdownObserver)
|
||||
.then(closeIframe)
|
||||
}
|
||||
}
|
||||
|
||||
function runTest() {
|
||||
start()
|
||||
.then(waitForActiveServiceWorker)
|
||||
.then(registerPushNotification)
|
||||
.then(subTest(test1))
|
||||
.then(subTest(test2))
|
||||
.then(subTest(test3))
|
||||
.then(unregisterPushNotification)
|
||||
.then(unregister)
|
||||
.catch(function(e) {
|
||||
ok(false, "Some test failed with error " + e)
|
||||
}).then(SimpleTest.finish);
|
||||
}
|
||||
|
||||
SpecialPowers.pushPrefEnv({"set": [
|
||||
["dom.push.enabled", true],
|
||||
["dom.serviceWorkers.exemptFromPerDomainMax", true],
|
||||
["dom.serviceWorkers.enabled", true],
|
||||
["dom.serviceWorkers.testing.enabled", true],
|
||||
["dom.serviceWorkers.interception.enabled", true]
|
||||
]}, runTest);
|
||||
SpecialPowers.addPermission('push', true, document);
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -278,14 +278,27 @@ GetWorkerPref(const nsACString& aPref,
|
|||
return result;
|
||||
}
|
||||
|
||||
// This function creates a key for a SharedWorker composed by "name|scriptSpec".
|
||||
// This function creates a key for a SharedWorker composed by "shared|name|scriptSpec"
|
||||
// and a key for a ServiceWorker composed by "service|scope|cache|scriptSpec".
|
||||
// If the name contains a '|', this will be replaced by '||'.
|
||||
void
|
||||
GenerateSharedWorkerKey(const nsACString& aScriptSpec, const nsACString& aName,
|
||||
const nsACString& aCacheName, WorkerType aWorkerType,
|
||||
bool aPrivateBrowsing, nsCString& aKey)
|
||||
{
|
||||
aKey.Truncate();
|
||||
aKey.SetCapacity(aScriptSpec.Length() + aName.Length() + 3);
|
||||
NS_NAMED_LITERAL_CSTRING(sharedPrefix, "shared|");
|
||||
NS_NAMED_LITERAL_CSTRING(servicePrefix, "service|");
|
||||
MOZ_ASSERT(servicePrefix.Length() > sharedPrefix.Length());
|
||||
MOZ_ASSERT(aWorkerType == WorkerTypeShared ||
|
||||
aWorkerType == WorkerTypeService);
|
||||
MOZ_ASSERT_IF(aWorkerType == WorkerTypeShared, aCacheName.IsEmpty());
|
||||
MOZ_ASSERT_IF(aWorkerType == WorkerTypeService, !aCacheName.IsEmpty());
|
||||
MOZ_ASSERT_IF(aWorkerType == WorkerTypeService, !aPrivateBrowsing);
|
||||
aKey.SetCapacity(servicePrefix.Length() + aScriptSpec.Length() +
|
||||
aName.Length() + aCacheName.Length() + 3);
|
||||
|
||||
aKey.Append(aWorkerType == WorkerTypeService ? servicePrefix : sharedPrefix);
|
||||
aKey.Append(aPrivateBrowsing ? "1|" : "0|");
|
||||
|
||||
nsACString::const_iterator start, end;
|
||||
|
@ -299,6 +312,11 @@ GenerateSharedWorkerKey(const nsACString& aScriptSpec, const nsACString& aName,
|
|||
}
|
||||
}
|
||||
|
||||
if (aWorkerType == WorkerTypeService) {
|
||||
aKey.Append('|');
|
||||
aKey.Append(aCacheName);
|
||||
}
|
||||
|
||||
aKey.Append('|');
|
||||
aKey.Append(aScriptSpec);
|
||||
}
|
||||
|
@ -1435,15 +1453,16 @@ RuntimeService::RegisterWorker(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
|
|||
}
|
||||
}
|
||||
|
||||
nsCString sharedWorkerScriptSpec;
|
||||
|
||||
const bool isServiceWorker = aWorkerPrivate->IsServiceWorker();
|
||||
const bool isSharedWorker = aWorkerPrivate->IsSharedWorker();
|
||||
if (isServiceWorker) {
|
||||
AssertIsOnMainThread();
|
||||
Telemetry::Accumulate(Telemetry::SERVICE_WORKER_SPAWN_ATTEMPTS, 1);
|
||||
}
|
||||
|
||||
nsCString sharedWorkerScriptSpec;
|
||||
if (isSharedWorker) {
|
||||
const bool isSharedWorker = aWorkerPrivate->IsSharedWorker();
|
||||
if (isSharedWorker || isServiceWorker) {
|
||||
AssertIsOnMainThread();
|
||||
|
||||
nsCOMPtr<nsIURI> scriptURI = aWorkerPrivate->GetResolvedScriptURI();
|
||||
|
@ -1513,10 +1532,16 @@ RuntimeService::RegisterWorker(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
|
|||
domainInfo->mActiveWorkers.AppendElement(aWorkerPrivate);
|
||||
}
|
||||
|
||||
if (isSharedWorker) {
|
||||
const nsCString& sharedWorkerName = aWorkerPrivate->WorkerName();
|
||||
if (isSharedWorker || isServiceWorker) {
|
||||
const nsCString& sharedWorkerName = aWorkerPrivate->SharedWorkerName();
|
||||
const nsCString& cacheName =
|
||||
aWorkerPrivate->IsServiceWorker() ?
|
||||
NS_ConvertUTF16toUTF8(aWorkerPrivate->ServiceWorkerCacheName()) :
|
||||
EmptyCString();
|
||||
|
||||
nsAutoCString key;
|
||||
GenerateSharedWorkerKey(sharedWorkerScriptSpec, sharedWorkerName,
|
||||
cacheName, aWorkerPrivate->Type(),
|
||||
aWorkerPrivate->IsInPrivateBrowsing(), key);
|
||||
MOZ_ASSERT(!domainInfo->mSharedWorkerInfos.Get(key));
|
||||
|
||||
|
@ -1555,20 +1580,16 @@ RuntimeService::RegisterWorker(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
|
|||
|
||||
nsPIDOMWindow* window = aWorkerPrivate->GetWindow();
|
||||
|
||||
if (!isServiceWorker) {
|
||||
// Service workers are excluded since their lifetime is separate from
|
||||
// that of dom windows.
|
||||
nsTArray<WorkerPrivate*>* windowArray;
|
||||
if (!mWindowMap.Get(window, &windowArray)) {
|
||||
windowArray = new nsTArray<WorkerPrivate*>(1);
|
||||
mWindowMap.Put(window, windowArray);
|
||||
}
|
||||
nsTArray<WorkerPrivate*>* windowArray;
|
||||
if (!mWindowMap.Get(window, &windowArray)) {
|
||||
windowArray = new nsTArray<WorkerPrivate*>(1);
|
||||
mWindowMap.Put(window, windowArray);
|
||||
}
|
||||
|
||||
if (!windowArray->Contains(aWorkerPrivate)) {
|
||||
windowArray->AppendElement(aWorkerPrivate);
|
||||
} else {
|
||||
MOZ_ASSERT(aWorkerPrivate->IsSharedWorker());
|
||||
}
|
||||
if (!windowArray->Contains(aWorkerPrivate)) {
|
||||
windowArray->AppendElement(aWorkerPrivate);
|
||||
} else {
|
||||
MOZ_ASSERT(aWorkerPrivate->IsSharedWorker());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1626,15 +1647,21 @@ RuntimeService::UnregisterWorker(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
|
|||
}
|
||||
|
||||
|
||||
if (aWorkerPrivate->IsSharedWorker()) {
|
||||
if (aWorkerPrivate->IsSharedWorker() ||
|
||||
aWorkerPrivate->IsServiceWorker()) {
|
||||
MatchSharedWorkerInfo match(aWorkerPrivate);
|
||||
domainInfo->mSharedWorkerInfos.EnumerateRead(FindSharedWorkerInfo,
|
||||
&match);
|
||||
|
||||
if (match.mSharedWorkerInfo) {
|
||||
nsAutoCString key;
|
||||
const nsCString& cacheName =
|
||||
aWorkerPrivate->IsServiceWorker() ?
|
||||
NS_ConvertUTF16toUTF8(aWorkerPrivate->ServiceWorkerCacheName()) :
|
||||
EmptyCString();
|
||||
GenerateSharedWorkerKey(match.mSharedWorkerInfo->mScriptSpec,
|
||||
match.mSharedWorkerInfo->mName,
|
||||
cacheName, aWorkerPrivate->Type(),
|
||||
aWorkerPrivate->IsInPrivateBrowsing(), key);
|
||||
domainInfo->mSharedWorkerInfos.Remove(key);
|
||||
}
|
||||
|
@ -1678,10 +1705,10 @@ RuntimeService::UnregisterWorker(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
|
|||
if (parent) {
|
||||
parent->RemoveChildWorker(aCx, aWorkerPrivate);
|
||||
}
|
||||
else if (aWorkerPrivate->IsSharedWorker()) {
|
||||
else if (aWorkerPrivate->IsSharedWorker() || aWorkerPrivate->IsServiceWorker()) {
|
||||
mWindowMap.Enumerate(RemoveSharedWorkerFromWindowMap, aWorkerPrivate);
|
||||
}
|
||||
else if (aWorkerPrivate->IsDedicatedWorker()) {
|
||||
else {
|
||||
// May be null.
|
||||
nsPIDOMWindow* window = aWorkerPrivate->GetWindow();
|
||||
|
||||
|
@ -2284,7 +2311,7 @@ RuntimeService::RemoveSharedWorkerFromWindowMap(
|
|||
|
||||
auto workerPrivate = static_cast<WorkerPrivate*>(aUserArg);
|
||||
|
||||
MOZ_ASSERT(workerPrivate->IsSharedWorker());
|
||||
MOZ_ASSERT(workerPrivate->IsSharedWorker() || workerPrivate->IsServiceWorker());
|
||||
|
||||
if (aData->RemoveElement(workerPrivate)) {
|
||||
MOZ_ASSERT(!aData->Contains(workerPrivate), "Added worker more than once!");
|
||||
|
@ -2347,7 +2374,7 @@ RuntimeService::CancelWorkersForWindow(nsPIDOMWindow* aWindow)
|
|||
for (uint32_t index = 0; index < workers.Length(); index++) {
|
||||
WorkerPrivate*& worker = workers[index];
|
||||
|
||||
if (worker->IsSharedWorker()) {
|
||||
if (worker->IsSharedWorker() || worker->IsServiceWorker()) {
|
||||
worker->CloseSharedWorkersForWindow(aWindow);
|
||||
} else if (!worker->Cancel(cx)) {
|
||||
JS_ReportPendingException(cx);
|
||||
|
@ -2405,12 +2432,14 @@ RuntimeService::ThawWorkersForWindow(nsPIDOMWindow* aWindow)
|
|||
}
|
||||
|
||||
nsresult
|
||||
RuntimeService::CreateSharedWorker(const GlobalObject& aGlobal,
|
||||
const nsAString& aScriptURL,
|
||||
const nsACString& aName,
|
||||
SharedWorker** aSharedWorker)
|
||||
RuntimeService::CreateSharedWorkerInternal(const GlobalObject& aGlobal,
|
||||
const nsAString& aScriptURL,
|
||||
const nsACString& aName,
|
||||
WorkerType aType,
|
||||
SharedWorker** aSharedWorker)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
MOZ_ASSERT(aType == WorkerTypeShared || aType == WorkerTypeService);
|
||||
|
||||
nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobal.GetAsSupports());
|
||||
MOZ_ASSERT(window);
|
||||
|
@ -2421,10 +2450,10 @@ RuntimeService::CreateSharedWorker(const GlobalObject& aGlobal,
|
|||
nsresult rv = WorkerPrivate::GetLoadInfo(cx, window, nullptr, aScriptURL,
|
||||
false,
|
||||
WorkerPrivate::OverrideLoadGroup,
|
||||
WorkerTypeShared, &loadInfo);
|
||||
aType, &loadInfo);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return CreateSharedWorkerFromLoadInfo(cx, &loadInfo, aScriptURL, aName,
|
||||
return CreateSharedWorkerFromLoadInfo(cx, &loadInfo, aScriptURL, aName, aType,
|
||||
aSharedWorker);
|
||||
}
|
||||
|
||||
|
@ -2433,11 +2462,13 @@ RuntimeService::CreateSharedWorkerFromLoadInfo(JSContext* aCx,
|
|||
WorkerLoadInfo* aLoadInfo,
|
||||
const nsAString& aScriptURL,
|
||||
const nsACString& aName,
|
||||
WorkerType aType,
|
||||
SharedWorker** aSharedWorker)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
MOZ_ASSERT(aLoadInfo);
|
||||
MOZ_ASSERT(aLoadInfo->mResolvedScriptURI);
|
||||
MOZ_ASSERT_IF(aType == WorkerTypeService, aLoadInfo->mServiceWorkerID > 0);
|
||||
|
||||
nsRefPtr<WorkerPrivate> workerPrivate;
|
||||
{
|
||||
|
@ -2452,7 +2483,8 @@ RuntimeService::CreateSharedWorkerFromLoadInfo(JSContext* aCx,
|
|||
|
||||
nsAutoCString key;
|
||||
GenerateSharedWorkerKey(scriptSpec, aName,
|
||||
aLoadInfo->mPrivateBrowsing, key);
|
||||
NS_ConvertUTF16toUTF8(aLoadInfo->mServiceWorkerCacheName),
|
||||
aType, aLoadInfo->mPrivateBrowsing, key);
|
||||
|
||||
if (mDomainMap.Get(aLoadInfo->mDomain, &domainInfo) &&
|
||||
domainInfo->mSharedWorkerInfos.Get(key, &sharedWorkerInfo)) {
|
||||
|
@ -2471,7 +2503,7 @@ RuntimeService::CreateSharedWorkerFromLoadInfo(JSContext* aCx,
|
|||
if (!workerPrivate) {
|
||||
workerPrivate =
|
||||
WorkerPrivate::Constructor(aCx, aScriptURL, false,
|
||||
WorkerTypeShared, aName, aLoadInfo, rv);
|
||||
aType, aName, aLoadInfo, rv);
|
||||
NS_ENSURE_TRUE(workerPrivate, rv.StealNSResult());
|
||||
|
||||
created = true;
|
||||
|
@ -2522,7 +2554,8 @@ RuntimeService::ForgetSharedWorker(WorkerPrivate* aWorkerPrivate)
|
|||
{
|
||||
AssertIsOnMainThread();
|
||||
MOZ_ASSERT(aWorkerPrivate);
|
||||
MOZ_ASSERT(aWorkerPrivate->IsSharedWorker());
|
||||
MOZ_ASSERT(aWorkerPrivate->IsSharedWorker() ||
|
||||
aWorkerPrivate->IsServiceWorker());
|
||||
|
||||
MutexAutoLock lock(mMutex);
|
||||
|
||||
|
@ -2534,8 +2567,13 @@ RuntimeService::ForgetSharedWorker(WorkerPrivate* aWorkerPrivate)
|
|||
|
||||
if (match.mSharedWorkerInfo) {
|
||||
nsAutoCString key;
|
||||
const nsCString& cacheName =
|
||||
aWorkerPrivate->IsServiceWorker() ?
|
||||
NS_ConvertUTF16toUTF8(aWorkerPrivate->ServiceWorkerCacheName()) :
|
||||
EmptyCString();
|
||||
GenerateSharedWorkerKey(match.mSharedWorkerInfo->mScriptSpec,
|
||||
match.mSharedWorkerInfo->mName,
|
||||
cacheName, aWorkerPrivate->Type(),
|
||||
aWorkerPrivate->IsInPrivateBrowsing(), key);
|
||||
domainInfo->mSharedWorkerInfos.Remove(key);
|
||||
}
|
||||
|
|
|
@ -152,7 +152,22 @@ public:
|
|||
CreateSharedWorker(const GlobalObject& aGlobal,
|
||||
const nsAString& aScriptURL,
|
||||
const nsACString& aName,
|
||||
SharedWorker** aSharedWorker);
|
||||
SharedWorker** aSharedWorker)
|
||||
{
|
||||
return CreateSharedWorkerInternal(aGlobal, aScriptURL, aName,
|
||||
WorkerTypeShared, aSharedWorker);
|
||||
}
|
||||
|
||||
nsresult
|
||||
CreateSharedWorkerForServiceWorkerFromLoadInfo(JSContext* aCx,
|
||||
WorkerLoadInfo* aLoadInfo,
|
||||
const nsAString& aScriptURL,
|
||||
const nsACString& aScope,
|
||||
SharedWorker** aSharedWorker)
|
||||
{
|
||||
return CreateSharedWorkerFromLoadInfo(aCx, aLoadInfo, aScriptURL, aScope,
|
||||
WorkerTypeService, aSharedWorker);
|
||||
}
|
||||
|
||||
void
|
||||
ForgetSharedWorker(WorkerPrivate* aWorkerPrivate);
|
||||
|
@ -293,11 +308,19 @@ private:
|
|||
static void
|
||||
JSVersionChanged(const char* aPrefName, void* aClosure);
|
||||
|
||||
nsresult
|
||||
CreateSharedWorkerInternal(const GlobalObject& aGlobal,
|
||||
const nsAString& aScriptURL,
|
||||
const nsACString& aName,
|
||||
WorkerType aType,
|
||||
SharedWorker** aSharedWorker);
|
||||
|
||||
nsresult
|
||||
CreateSharedWorkerFromLoadInfo(JSContext* aCx,
|
||||
WorkerLoadInfo* aLoadInfo,
|
||||
const nsAString& aScriptURL,
|
||||
const nsACString& aName,
|
||||
WorkerType aType,
|
||||
SharedWorker** aSharedWorker);
|
||||
};
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
#include "nsPIDOMWindow.h"
|
||||
#include "ServiceWorkerClient.h"
|
||||
#include "ServiceWorkerManager.h"
|
||||
#include "ServiceWorkerPrivate.h"
|
||||
#include "SharedWorker.h"
|
||||
#include "WorkerPrivate.h"
|
||||
|
||||
#include "mozilla/Preferences.h"
|
||||
|
@ -42,12 +42,15 @@ ServiceWorkerVisible(JSContext* aCx, JSObject* aObj)
|
|||
}
|
||||
|
||||
ServiceWorker::ServiceWorker(nsPIDOMWindow* aWindow,
|
||||
ServiceWorkerInfo* aInfo)
|
||||
ServiceWorkerInfo* aInfo,
|
||||
SharedWorker* aSharedWorker)
|
||||
: DOMEventTargetHelper(aWindow),
|
||||
mInfo(aInfo)
|
||||
mInfo(aInfo),
|
||||
mSharedWorker(aSharedWorker)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
MOZ_ASSERT(aInfo);
|
||||
MOZ_ASSERT(mSharedWorker);
|
||||
|
||||
// This will update our state too.
|
||||
mInfo->AppendWorker(this);
|
||||
|
@ -65,6 +68,9 @@ NS_IMPL_RELEASE_INHERITED(ServiceWorker, DOMEventTargetHelper)
|
|||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(ServiceWorker)
|
||||
NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_INHERITED(ServiceWorker, DOMEventTargetHelper,
|
||||
mSharedWorker)
|
||||
|
||||
JSObject*
|
||||
ServiceWorker::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
|
@ -96,9 +102,23 @@ ServiceWorker::PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
|
|||
return;
|
||||
}
|
||||
|
||||
UniquePtr<ServiceWorkerClientInfo> clientInfo(new ServiceWorkerClientInfo(window->GetExtantDoc()));
|
||||
ServiceWorkerPrivate* workerPrivate = mInfo->WorkerPrivate();
|
||||
aRv = workerPrivate->SendMessageEvent(aCx, aMessage, aTransferable, Move(clientInfo));
|
||||
WorkerPrivate* workerPrivate = GetWorkerPrivate();
|
||||
MOZ_ASSERT(workerPrivate);
|
||||
|
||||
nsAutoPtr<ServiceWorkerClientInfo> clientInfo(new ServiceWorkerClientInfo(window->GetExtantDoc()));
|
||||
|
||||
workerPrivate->PostMessageToServiceWorker(aCx, aMessage, aTransferable,
|
||||
clientInfo, aRv);
|
||||
}
|
||||
|
||||
WorkerPrivate*
|
||||
ServiceWorker::GetWorkerPrivate() const
|
||||
{
|
||||
// At some point in the future, this may be optimized to terminate a worker
|
||||
// that hasn't been used in a certain amount of time or when there is memory
|
||||
// pressure or similar.
|
||||
MOZ_ASSERT(mSharedWorker);
|
||||
return mSharedWorker->GetWorkerPrivate();
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -30,6 +30,7 @@ class ServiceWorker final : public DOMEventTargetHelper
|
|||
friend class ServiceWorkerManager;
|
||||
public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(ServiceWorker, DOMEventTargetHelper)
|
||||
|
||||
IMPL_EVENT_HANDLER(statechange)
|
||||
IMPL_EVENT_HANDLER(error)
|
||||
|
@ -52,6 +53,8 @@ public:
|
|||
void
|
||||
GetScriptURL(nsString& aURL) const;
|
||||
|
||||
const ServiceWorkerInfo* Info() const { return mInfo; }
|
||||
|
||||
void
|
||||
DispatchStateChange(ServiceWorkerState aState)
|
||||
{
|
||||
|
@ -71,15 +74,25 @@ public:
|
|||
const Optional<Sequence<JS::Value>>& aTransferable,
|
||||
ErrorResult& aRv);
|
||||
|
||||
WorkerPrivate*
|
||||
GetWorkerPrivate() const;
|
||||
|
||||
private:
|
||||
// This class can only be created from the ServiceWorkerManager.
|
||||
ServiceWorker(nsPIDOMWindow* aWindow, ServiceWorkerInfo* aInfo);
|
||||
ServiceWorker(nsPIDOMWindow* aWindow, ServiceWorkerInfo* aInfo,
|
||||
SharedWorker* aSharedWorker);
|
||||
|
||||
// This class is reference-counted and will be destroyed from Release().
|
||||
~ServiceWorker();
|
||||
|
||||
ServiceWorkerState mState;
|
||||
const nsRefPtr<ServiceWorkerInfo> mInfo;
|
||||
|
||||
// To allow ServiceWorkers to potentially drop the backing DOMEventTargetHelper and
|
||||
// re-instantiate it later, they simply own a SharedWorker member that
|
||||
// can be released and recreated as required rather than re-implement some of
|
||||
// the SharedWorker logic.
|
||||
nsRefPtr<SharedWorker> mSharedWorker;
|
||||
};
|
||||
|
||||
} // namespace workers
|
||||
|
|
|
@ -240,6 +240,7 @@ ServiceWorkerContainer::GetController()
|
|||
// thread running, but it seems our design does not expect that.
|
||||
nsCOMPtr<nsISupports> serviceWorker;
|
||||
rv = swm->GetDocumentController(GetOwner(),
|
||||
nullptr, // aLoadFailedRunnable
|
||||
getter_AddRefs(serviceWorker));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return nullptr;
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
#include "ServiceWorkerEvents.h"
|
||||
#include "ServiceWorkerClient.h"
|
||||
#include "ServiceWorkerManager.h"
|
||||
|
||||
#include "nsIHttpChannelInternal.h"
|
||||
#include "nsINetworkInterceptController.h"
|
||||
|
@ -72,12 +73,12 @@ FetchEvent::~FetchEvent()
|
|||
|
||||
void
|
||||
FetchEvent::PostInit(nsMainThreadPtrHandle<nsIInterceptedChannel>& aChannel,
|
||||
const nsACString& aScriptSpec,
|
||||
UniquePtr<ServiceWorkerClientInfo>&& aClientInfo)
|
||||
nsMainThreadPtrHandle<ServiceWorker>& aServiceWorker,
|
||||
nsAutoPtr<ServiceWorkerClientInfo>& aClientInfo)
|
||||
{
|
||||
mChannel = aChannel;
|
||||
mScriptSpec.Assign(aScriptSpec);
|
||||
mClientInfo = Move(aClientInfo);
|
||||
mServiceWorker = aServiceWorker;
|
||||
mClientInfo = aClientInfo;
|
||||
}
|
||||
|
||||
/*static*/ already_AddRefed<FetchEvent>
|
||||
|
@ -106,19 +107,19 @@ namespace {
|
|||
class FinishResponse final : public nsRunnable
|
||||
{
|
||||
nsMainThreadPtrHandle<nsIInterceptedChannel> mChannel;
|
||||
nsMainThreadPtrHandle<ServiceWorker> mServiceWorker;
|
||||
nsRefPtr<InternalResponse> mInternalResponse;
|
||||
ChannelInfo mWorkerChannelInfo;
|
||||
const nsCString mScriptSpec;
|
||||
|
||||
public:
|
||||
FinishResponse(nsMainThreadPtrHandle<nsIInterceptedChannel>& aChannel,
|
||||
nsMainThreadPtrHandle<ServiceWorker> aServiceWorker,
|
||||
InternalResponse* aInternalResponse,
|
||||
const ChannelInfo& aWorkerChannelInfo,
|
||||
const nsACString& aScriptSpec)
|
||||
const ChannelInfo& aWorkerChannelInfo)
|
||||
: mChannel(aChannel)
|
||||
, mServiceWorker(aServiceWorker)
|
||||
, mInternalResponse(aInternalResponse)
|
||||
, mWorkerChannelInfo(aWorkerChannelInfo)
|
||||
, mScriptSpec(aScriptSpec)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -169,7 +170,7 @@ public:
|
|||
mInternalResponse->GetUnfilteredUrl(url);
|
||||
if (url.IsEmpty()) {
|
||||
// Synthetic response. The buck stops at the worker script.
|
||||
url = mScriptSpec;
|
||||
url = mServiceWorker->Info()->ScriptSpec();
|
||||
}
|
||||
rv = NS_NewURI(getter_AddRefs(uri), url, nullptr, nullptr);
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
|
@ -191,24 +192,22 @@ public:
|
|||
class RespondWithHandler final : public PromiseNativeHandler
|
||||
{
|
||||
nsMainThreadPtrHandle<nsIInterceptedChannel> mInterceptedChannel;
|
||||
nsMainThreadPtrHandle<ServiceWorker> mServiceWorker;
|
||||
const RequestMode mRequestMode;
|
||||
const DebugOnly<bool> mIsClientRequest;
|
||||
const bool mIsNavigationRequest;
|
||||
const nsCString mScriptSpec;
|
||||
bool mRequestWasHandled;
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
RespondWithHandler(nsMainThreadPtrHandle<nsIInterceptedChannel>& aChannel,
|
||||
nsMainThreadPtrHandle<ServiceWorker>& aServiceWorker,
|
||||
RequestMode aRequestMode, bool aIsClientRequest,
|
||||
bool aIsNavigationRequest,
|
||||
const nsACString& aScriptSpec)
|
||||
bool aIsNavigationRequest)
|
||||
: mInterceptedChannel(aChannel)
|
||||
, mServiceWorker(aServiceWorker)
|
||||
, mRequestMode(aRequestMode)
|
||||
, mIsClientRequest(aIsClientRequest)
|
||||
, mIsNavigationRequest(aIsNavigationRequest)
|
||||
, mScriptSpec(aScriptSpec)
|
||||
, mRequestWasHandled(false)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -218,29 +217,24 @@ public:
|
|||
|
||||
void CancelRequest(nsresult aStatus);
|
||||
private:
|
||||
~RespondWithHandler()
|
||||
{
|
||||
if (!mRequestWasHandled) {
|
||||
CancelRequest(NS_ERROR_INTERCEPTION_FAILED);
|
||||
}
|
||||
}
|
||||
~RespondWithHandler() {}
|
||||
};
|
||||
|
||||
struct RespondWithClosure
|
||||
{
|
||||
nsMainThreadPtrHandle<nsIInterceptedChannel> mInterceptedChannel;
|
||||
nsMainThreadPtrHandle<ServiceWorker> mServiceWorker;
|
||||
nsRefPtr<InternalResponse> mInternalResponse;
|
||||
ChannelInfo mWorkerChannelInfo;
|
||||
const nsCString mScriptSpec;
|
||||
|
||||
RespondWithClosure(nsMainThreadPtrHandle<nsIInterceptedChannel>& aChannel,
|
||||
nsMainThreadPtrHandle<ServiceWorker>& aServiceWorker,
|
||||
InternalResponse* aInternalResponse,
|
||||
const ChannelInfo& aWorkerChannelInfo,
|
||||
const nsCString& aScriptSpec)
|
||||
const ChannelInfo& aWorkerChannelInfo)
|
||||
: mInterceptedChannel(aChannel)
|
||||
, mServiceWorker(aServiceWorker)
|
||||
, mInternalResponse(aInternalResponse)
|
||||
, mWorkerChannelInfo(aWorkerChannelInfo)
|
||||
, mScriptSpec(aScriptSpec)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
@ -251,9 +245,9 @@ void RespondWithCopyComplete(void* aClosure, nsresult aStatus)
|
|||
nsCOMPtr<nsIRunnable> event;
|
||||
if (NS_SUCCEEDED(aStatus)) {
|
||||
event = new FinishResponse(data->mInterceptedChannel,
|
||||
data->mServiceWorker,
|
||||
data->mInternalResponse,
|
||||
data->mWorkerChannelInfo,
|
||||
data->mScriptSpec);
|
||||
data->mWorkerChannelInfo);
|
||||
} else {
|
||||
event = new CancelChannelRunnable(data->mInterceptedChannel,
|
||||
NS_ERROR_INTERCEPTION_FAILED);
|
||||
|
@ -356,9 +350,8 @@ RespondWithHandler::ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValu
|
|||
return;
|
||||
}
|
||||
|
||||
nsAutoPtr<RespondWithClosure> closure(new RespondWithClosure(mInterceptedChannel, ir,
|
||||
worker->GetChannelInfo(),
|
||||
mScriptSpec));
|
||||
nsAutoPtr<RespondWithClosure> closure(
|
||||
new RespondWithClosure(mInterceptedChannel, mServiceWorker, ir, worker->GetChannelInfo()));
|
||||
nsCOMPtr<nsIInputStream> body;
|
||||
ir->GetUnfilteredBody(getter_AddRefs(body));
|
||||
// Errors and redirects may not have a body.
|
||||
|
@ -389,7 +382,6 @@ RespondWithHandler::ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValu
|
|||
|
||||
MOZ_ASSERT(!closure);
|
||||
autoCancel.Reset();
|
||||
mRequestWasHandled = true;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -404,7 +396,6 @@ RespondWithHandler::CancelRequest(nsresult aStatus)
|
|||
nsCOMPtr<nsIRunnable> runnable =
|
||||
new CancelChannelRunnable(mInterceptedChannel, aStatus);
|
||||
NS_DispatchToMainThread(runnable);
|
||||
mRequestWasHandled = true;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
@ -417,14 +408,11 @@ FetchEvent::RespondWith(Promise& aArg, ErrorResult& aRv)
|
|||
return;
|
||||
}
|
||||
|
||||
if (!mPromise) {
|
||||
mPromise = &aArg;
|
||||
}
|
||||
nsRefPtr<InternalRequest> ir = mRequest->GetInternalRequest();
|
||||
mWaitToRespond = true;
|
||||
nsRefPtr<RespondWithHandler> handler =
|
||||
new RespondWithHandler(mChannel, mRequest->Mode(), ir->IsClientRequest(),
|
||||
ir->IsNavigationRequest(), mScriptSpec);
|
||||
new RespondWithHandler(mChannel, mServiceWorker, mRequest->Mode(),
|
||||
ir->IsClientRequest(), ir->IsNavigationRequest());
|
||||
aArg.AppendNativeHandler(handler);
|
||||
}
|
||||
|
||||
|
@ -452,8 +440,7 @@ NS_IMPL_RELEASE_INHERITED(FetchEvent, Event)
|
|||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(FetchEvent)
|
||||
NS_INTERFACE_MAP_END_INHERITING(Event)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_INHERITED(FetchEvent, Event, mRequest, mClient,
|
||||
mPromise)
|
||||
NS_IMPL_CYCLE_COLLECTION_INHERITED(FetchEvent, Event, mRequest, mClient)
|
||||
|
||||
ExtendableEvent::ExtendableEvent(EventTarget* aOwner)
|
||||
: Event(aOwner, nullptr, nullptr)
|
||||
|
|
|
@ -51,11 +51,10 @@ public:
|
|||
class FetchEvent final : public Event
|
||||
{
|
||||
nsMainThreadPtrHandle<nsIInterceptedChannel> mChannel;
|
||||
nsMainThreadPtrHandle<ServiceWorker> mServiceWorker;
|
||||
nsRefPtr<ServiceWorkerClient> mClient;
|
||||
nsRefPtr<Request> mRequest;
|
||||
nsCString mScriptSpec;
|
||||
UniquePtr<ServiceWorkerClientInfo> mClientInfo;
|
||||
nsRefPtr<Promise> mPromise;
|
||||
nsAutoPtr<ServiceWorkerClientInfo> mClientInfo;
|
||||
bool mIsReload;
|
||||
bool mWaitToRespond;
|
||||
protected:
|
||||
|
@ -73,8 +72,8 @@ public:
|
|||
}
|
||||
|
||||
void PostInit(nsMainThreadPtrHandle<nsIInterceptedChannel>& aChannel,
|
||||
const nsACString& aScriptSpec,
|
||||
UniquePtr<ServiceWorkerClientInfo>&& aClientInfo);
|
||||
nsMainThreadPtrHandle<ServiceWorker>& aServiceWorker,
|
||||
nsAutoPtr<ServiceWorkerClientInfo>& aClientInfo);
|
||||
|
||||
static already_AddRefed<FetchEvent>
|
||||
Constructor(const GlobalObject& aGlobal,
|
||||
|
@ -106,13 +105,6 @@ public:
|
|||
void
|
||||
RespondWith(Promise& aArg, ErrorResult& aRv);
|
||||
|
||||
already_AddRefed<Promise>
|
||||
GetPromise() const
|
||||
{
|
||||
nsRefPtr<Promise> p = mPromise;
|
||||
return p.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
ForwardTo(const nsAString& aUrl);
|
||||
|
||||
|
@ -211,6 +203,7 @@ private:
|
|||
class PushEvent final : public ExtendableEvent
|
||||
{
|
||||
nsRefPtr<PushMessageData> mData;
|
||||
nsMainThreadPtrHandle<ServiceWorker> mServiceWorker;
|
||||
|
||||
protected:
|
||||
explicit PushEvent(mozilla::dom::EventTarget* aOwner);
|
||||
|
@ -242,8 +235,12 @@ public:
|
|||
return Constructor(owner, aType, aOptions, aRv);
|
||||
}
|
||||
|
||||
PushMessageData*
|
||||
GetData() const
|
||||
void PostInit(nsMainThreadPtrHandle<ServiceWorker>& aServiceWorker)
|
||||
{
|
||||
mServiceWorker = aServiceWorker;
|
||||
}
|
||||
|
||||
PushMessageData* GetData() const
|
||||
{
|
||||
return mData;
|
||||
}
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -49,7 +49,6 @@ class ServiceWorkerInfo;
|
|||
class ServiceWorkerJob;
|
||||
class ServiceWorkerJobQueue;
|
||||
class ServiceWorkerManagerChild;
|
||||
class ServiceWorkerPrivate;
|
||||
|
||||
// Needs to inherit from nsISupports because NS_ProxyRelease() does not support
|
||||
// non-ISupports classes.
|
||||
|
@ -176,11 +175,10 @@ private:
|
|||
// There is a high chance of there being at least one ServiceWorker
|
||||
// associated with this all the time.
|
||||
nsAutoTArray<ServiceWorker*, 1> mInstances;
|
||||
|
||||
nsRefPtr<ServiceWorkerPrivate> mServiceWorkerPrivate;
|
||||
bool mSkipWaitingFlag;
|
||||
|
||||
~ServiceWorkerInfo();
|
||||
~ServiceWorkerInfo()
|
||||
{ }
|
||||
|
||||
// Generates a unique id for the service worker, with zero being treated as
|
||||
// invalid.
|
||||
|
@ -190,19 +188,6 @@ private:
|
|||
public:
|
||||
NS_INLINE_DECL_REFCOUNTING(ServiceWorkerInfo)
|
||||
|
||||
class ServiceWorkerPrivate*
|
||||
WorkerPrivate() const
|
||||
{
|
||||
MOZ_ASSERT(mServiceWorkerPrivate);
|
||||
return mServiceWorkerPrivate;
|
||||
}
|
||||
|
||||
nsIPrincipal*
|
||||
GetPrincipal() const
|
||||
{
|
||||
return mRegistration->mPrincipal;
|
||||
}
|
||||
|
||||
const nsCString&
|
||||
ScriptSpec() const
|
||||
{
|
||||
|
@ -235,7 +220,17 @@ public:
|
|||
|
||||
ServiceWorkerInfo(ServiceWorkerRegistrationInfo* aReg,
|
||||
const nsACString& aScriptSpec,
|
||||
const nsAString& aCacheName);
|
||||
const nsAString& aCacheName)
|
||||
: mRegistration(aReg)
|
||||
, mScriptSpec(aScriptSpec)
|
||||
, mCacheName(aCacheName)
|
||||
, mState(ServiceWorkerState::EndGuard_)
|
||||
, mServiceWorkerID(GetNextID())
|
||||
, mSkipWaitingFlag(false)
|
||||
{
|
||||
MOZ_ASSERT(mRegistration);
|
||||
MOZ_ASSERT(!aCacheName.IsEmpty());
|
||||
}
|
||||
|
||||
ServiceWorkerState
|
||||
State() const
|
||||
|
@ -459,18 +454,28 @@ private:
|
|||
nsresult
|
||||
GetDocumentRegistration(nsIDocument* aDoc, ServiceWorkerRegistrationInfo** aRegistrationInfo);
|
||||
|
||||
NS_IMETHOD
|
||||
CreateServiceWorkerForWindow(nsPIDOMWindow* aWindow,
|
||||
ServiceWorkerInfo* aInfo,
|
||||
nsIRunnable* aLoadFailedRunnable,
|
||||
ServiceWorker** aServiceWorker);
|
||||
|
||||
NS_IMETHOD
|
||||
CreateServiceWorker(nsIPrincipal* aPrincipal,
|
||||
ServiceWorkerInfo* aInfo,
|
||||
nsIRunnable* aLoadFailedRunnable,
|
||||
ServiceWorker** aServiceWorker);
|
||||
|
||||
NS_IMETHODIMP
|
||||
GetServiceWorkerForScope(nsIDOMWindow* aWindow,
|
||||
const nsAString& aScope,
|
||||
WhichServiceWorker aWhichWorker,
|
||||
nsISupports** aServiceWorker);
|
||||
|
||||
ServiceWorkerInfo*
|
||||
GetActiveWorkerInfoForScope(const OriginAttributes& aOriginAttributes,
|
||||
const nsACString& aScope);
|
||||
|
||||
ServiceWorkerInfo*
|
||||
GetActiveWorkerInfoForDocument(nsIDocument* aDocument);
|
||||
already_AddRefed<ServiceWorker>
|
||||
CreateServiceWorkerForScope(const OriginAttributes& aOriginAttributes,
|
||||
const nsACString& aScope,
|
||||
nsIRunnable* aLoadFailedRunnable);
|
||||
|
||||
void
|
||||
InvalidateServiceWorkerRegistrationWorker(ServiceWorkerRegistrationInfo* aRegistration,
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -1,186 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_dom_workers_serviceworkerprivate_h
|
||||
#define mozilla_dom_workers_serviceworkerprivate_h
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
|
||||
#include "WorkerPrivate.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
namespace workers {
|
||||
|
||||
class ServiceWorkerInfo;
|
||||
class KeepAliveToken;
|
||||
|
||||
class LifeCycleEventCallback : public nsRunnable
|
||||
{
|
||||
public:
|
||||
// Called on the worker thread.
|
||||
virtual void
|
||||
SetResult(bool aResult) = 0;
|
||||
};
|
||||
|
||||
// ServiceWorkerPrivate is a wrapper for managing the on-demand aspect of
|
||||
// service workers. It handles all event dispatching to the worker and ensures
|
||||
// the worker thread is running when needed.
|
||||
//
|
||||
// Lifetime management: To spin up the worker thread we own a |WorkerPrivate|
|
||||
// object which can be cancelled if no events are received for a certain
|
||||
// amount of time. The worker is kept alive by holding a |KeepAliveToken|
|
||||
// reference.
|
||||
//
|
||||
// Extendable events hold tokens for the duration of their handler execution
|
||||
// and until their waitUntil promise is resolved, while ServiceWorkerPrivate
|
||||
// will hold a token for |dom.serviceWorkers.idle_timeout| seconds after each
|
||||
// new event.
|
||||
//
|
||||
// Note: All timer events must be handled on the main thread because the
|
||||
// worker may block indefinitely the worker thread (e. g. infinite loop in the
|
||||
// script).
|
||||
//
|
||||
// There are 3 cases where we may ignore keep alive tokens:
|
||||
// 1. When ServiceWorkerPrivate's token expired, if there are still waitUntil
|
||||
// handlers holding tokens, we wait another |dom.serviceWorkers.idle_extended_timeout|
|
||||
// seconds before forcibly terminating the worker.
|
||||
// 2. If the worker stopped controlling documents and it is not handling push
|
||||
// events.
|
||||
// 3. The content process is shutting down.
|
||||
//
|
||||
// Adding an API function for a new event requires calling |SpawnWorkerIfNeeded|
|
||||
// with an appropriate reason before any runnable is dispatched to the worker.
|
||||
// If the event is extendable then the runnable should inherit
|
||||
// ExtendableEventWorkerRunnable.
|
||||
class ServiceWorkerPrivate final : public nsISupports
|
||||
{
|
||||
friend class KeepAliveToken;
|
||||
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
explicit ServiceWorkerPrivate(ServiceWorkerInfo* aInfo);
|
||||
|
||||
nsresult
|
||||
SendMessageEvent(JSContext* aCx, JS::Handle<JS::Value> aMessage,
|
||||
const Optional<Sequence<JS::Value>>& aTransferable,
|
||||
UniquePtr<ServiceWorkerClientInfo>&& aClientInfo);
|
||||
|
||||
// This is used to validate the worker script and continue the installation
|
||||
// process. Note that the callback is dispatched to the main thread
|
||||
// ONLY if the evaluation was successful. Failure is handled by the JS
|
||||
// exception handler which will call ServiceWorkerManager::HandleError.
|
||||
nsresult
|
||||
ContinueOnSuccessfulScriptEvaluation(nsRunnable* aCallback);
|
||||
|
||||
nsresult
|
||||
SendLifeCycleEvent(const nsAString& aEventType,
|
||||
LifeCycleEventCallback* aCallback,
|
||||
nsIRunnable* aLoadFailure);
|
||||
|
||||
nsresult
|
||||
SendPushEvent(const Maybe<nsTArray<uint8_t>>& aData);
|
||||
|
||||
nsresult
|
||||
SendPushSubscriptionChangeEvent();
|
||||
|
||||
nsresult
|
||||
SendNotificationClickEvent(const nsAString& aID,
|
||||
const nsAString& aTitle,
|
||||
const nsAString& aDir,
|
||||
const nsAString& aLang,
|
||||
const nsAString& aBody,
|
||||
const nsAString& aTag,
|
||||
const nsAString& aIcon,
|
||||
const nsAString& aData,
|
||||
const nsAString& aBehavior,
|
||||
const nsAString& aScope);
|
||||
|
||||
nsresult
|
||||
SendFetchEvent(nsIInterceptedChannel* aChannel,
|
||||
nsILoadGroup* aLoadGroup,
|
||||
UniquePtr<ServiceWorkerClientInfo>&& aClientInfo,
|
||||
bool aIsReload);
|
||||
|
||||
// This will terminate the current running worker thread and drop the
|
||||
// workerPrivate reference.
|
||||
// Called by ServiceWorkerInfo when [[Clear Registration]] is invoked
|
||||
// or whenever the spec mandates that we terminate the worker.
|
||||
// This is a no-op if the worker has already been stopped.
|
||||
void
|
||||
TerminateWorker();
|
||||
|
||||
void
|
||||
NoteDeadServiceWorkerInfo();
|
||||
|
||||
void
|
||||
NoteStoppedControllingDocuments();
|
||||
|
||||
private:
|
||||
enum WakeUpReason {
|
||||
FetchEvent = 0,
|
||||
PushEvent,
|
||||
PushSubscriptionChangeEvent,
|
||||
MessageEvent,
|
||||
NotificationClickEvent,
|
||||
LifeCycleEvent
|
||||
};
|
||||
|
||||
// Timer callbacks
|
||||
static void
|
||||
NoteIdleWorkerCallback(nsITimer* aTimer, void* aPrivate);
|
||||
|
||||
static void
|
||||
TerminateWorkerCallback(nsITimer* aTimer, void *aPrivate);
|
||||
|
||||
void
|
||||
ResetIdleTimeout(WakeUpReason aWhy);
|
||||
|
||||
void
|
||||
AddToken();
|
||||
|
||||
void
|
||||
ReleaseToken();
|
||||
|
||||
// |aLoadFailedRunnable| is a runnable dispatched to the main thread
|
||||
// if the script loader failed for some reason, but can be null.
|
||||
nsresult
|
||||
SpawnWorkerIfNeeded(WakeUpReason aWhy,
|
||||
nsIRunnable* aLoadFailedRunnable,
|
||||
nsILoadGroup* aLoadGroup = nullptr);
|
||||
|
||||
~ServiceWorkerPrivate();
|
||||
|
||||
// The info object owns us. It is possible to outlive it for a brief period
|
||||
// of time if there are pending waitUntil promises, in which case it
|
||||
// will be null and |SpawnWorkerIfNeeded| will always fail.
|
||||
ServiceWorkerInfo* MOZ_NON_OWNING_REF mInfo;
|
||||
|
||||
// The WorkerPrivate object can only be closed by this class or by the
|
||||
// RuntimeService class if gecko is shutting down. Closing the worker
|
||||
// multiple times is OK, since the second attempt will be a no-op.
|
||||
nsRefPtr<WorkerPrivate> mWorkerPrivate;
|
||||
|
||||
nsCOMPtr<nsITimer> mIdleWorkerTimer;
|
||||
|
||||
// We keep track if this worker received any push events since it was last
|
||||
// woken up. The flag is reset to false every time a new WorkerPrivate
|
||||
// is created.
|
||||
bool mIsPushWorker;
|
||||
|
||||
// We keep a token for |dom.serviceWorkers.idle_timeout| seconds to give the
|
||||
// worker a grace period after each event.
|
||||
nsRefPtr<KeepAliveToken> mKeepAliveToken;
|
||||
|
||||
uint64_t mTokenCount;
|
||||
};
|
||||
|
||||
} // namespace workers
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_workers_serviceworkerprivate_h
|
|
@ -602,7 +602,7 @@ class MessageEventRunnable final : public WorkerRunnable
|
|||
, public StructuredCloneHolder
|
||||
{
|
||||
// This is only used for messages dispatched to a service worker.
|
||||
UniquePtr<ServiceWorkerClientInfo> mEventSource;
|
||||
nsAutoPtr<ServiceWorkerClientInfo> mEventSource;
|
||||
|
||||
public:
|
||||
MessageEventRunnable(WorkerPrivate* aWorkerPrivate,
|
||||
|
@ -614,9 +614,9 @@ public:
|
|||
}
|
||||
|
||||
void
|
||||
SetMessageSource(UniquePtr<ServiceWorkerClientInfo>&& aSource)
|
||||
SetMessageSource(ServiceWorkerClientInfo* aSource)
|
||||
{
|
||||
mEventSource = Move(aSource);
|
||||
mEventSource = aSource;
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -1016,7 +1016,7 @@ private:
|
|||
nsRefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
|
||||
MOZ_ASSERT(swm);
|
||||
bool handled = swm->HandleError(aCx, aWorkerPrivate->GetPrincipal(),
|
||||
aWorkerPrivate->WorkerName(),
|
||||
aWorkerPrivate->SharedWorkerName(),
|
||||
aWorkerPrivate->ScriptURL(),
|
||||
mMessage,
|
||||
mFilename, mLine, mLineNumber,
|
||||
|
@ -2100,13 +2100,13 @@ WorkerPrivateParent<Derived>::WorkerPrivateParent(
|
|||
const nsAString& aScriptURL,
|
||||
bool aIsChromeWorker,
|
||||
WorkerType aWorkerType,
|
||||
const nsACString& aWorkerName,
|
||||
const nsACString& aSharedWorkerName,
|
||||
WorkerLoadInfo& aLoadInfo)
|
||||
: mMutex("WorkerPrivateParent Mutex"),
|
||||
mCondVar(mMutex, "WorkerPrivateParent CondVar"),
|
||||
mMemoryReportCondVar(mMutex, "WorkerPrivateParent Memory Report CondVar"),
|
||||
mParent(aParent), mScriptURL(aScriptURL),
|
||||
mWorkerName(aWorkerName), mLoadingWorkerScript(false),
|
||||
mSharedWorkerName(aSharedWorkerName), mLoadingWorkerScript(false),
|
||||
mBusyCount(0), mParentStatus(Pending), mParentFrozen(false),
|
||||
mIsChromeWorker(aIsChromeWorker), mMainThreadObjectsForgotten(false),
|
||||
mWorkerType(aWorkerType),
|
||||
|
@ -2114,8 +2114,8 @@ WorkerPrivateParent<Derived>::WorkerPrivateParent(
|
|||
mCreationTimeHighRes((double)PR_Now() / PR_USEC_PER_MSEC)
|
||||
{
|
||||
MOZ_ASSERT_IF(!IsDedicatedWorker(),
|
||||
!aWorkerName.IsVoid() && NS_IsMainThread());
|
||||
MOZ_ASSERT_IF(IsDedicatedWorker(), aWorkerName.IsEmpty());
|
||||
!aSharedWorkerName.IsVoid() && NS_IsMainThread());
|
||||
MOZ_ASSERT_IF(IsDedicatedWorker(), aSharedWorkerName.IsEmpty());
|
||||
|
||||
if (aLoadInfo.mWindow) {
|
||||
AssertIsOnMainThread();
|
||||
|
@ -2422,7 +2422,7 @@ WorkerPrivateParent<Derived>::NotifyPrivate(JSContext* aCx, Status aStatus)
|
|||
mParentStatus = aStatus;
|
||||
}
|
||||
|
||||
if (IsSharedWorker()) {
|
||||
if (IsSharedWorker() || IsServiceWorker()) {
|
||||
RuntimeService* runtime = RuntimeService::GetService();
|
||||
MOZ_ASSERT(runtime);
|
||||
|
||||
|
@ -2694,7 +2694,7 @@ WorkerPrivateParent<Derived>::PostMessageInternal(
|
|||
JSContext* aCx,
|
||||
JS::Handle<JS::Value> aMessage,
|
||||
const Optional<Sequence<JS::Value>>& aTransferable,
|
||||
UniquePtr<ServiceWorkerClientInfo>&& aClientInfo,
|
||||
ServiceWorkerClientInfo* aClientInfo,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
AssertIsOnParentThread();
|
||||
|
@ -2734,33 +2734,23 @@ WorkerPrivateParent<Derived>::PostMessageInternal(
|
|||
return;
|
||||
}
|
||||
|
||||
runnable->SetMessageSource(Move(aClientInfo));
|
||||
runnable->SetMessageSource(aClientInfo);
|
||||
|
||||
if (!runnable->Dispatch(aCx)) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
template <class Derived>
|
||||
void
|
||||
WorkerPrivateParent<Derived>::PostMessage(
|
||||
JSContext* aCx, JS::Handle<JS::Value> aMessage,
|
||||
const Optional<Sequence<JS::Value>>& aTransferable,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
PostMessageInternal(aCx, aMessage, aTransferable, nullptr, aRv);
|
||||
}
|
||||
|
||||
template <class Derived>
|
||||
void
|
||||
WorkerPrivateParent<Derived>::PostMessageToServiceWorker(
|
||||
JSContext* aCx, JS::Handle<JS::Value> aMessage,
|
||||
const Optional<Sequence<JS::Value>>& aTransferable,
|
||||
UniquePtr<ServiceWorkerClientInfo>&& aClientInfo,
|
||||
nsAutoPtr<ServiceWorkerClientInfo>& aClientInfo,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
PostMessageInternal(aCx, aMessage, aTransferable, Move(aClientInfo), aRv);
|
||||
PostMessageInternal(aCx, aMessage, aTransferable, aClientInfo.forget(), aRv);
|
||||
}
|
||||
|
||||
template <class Derived>
|
||||
|
@ -2953,7 +2943,7 @@ WorkerPrivateParent<Derived>::RegisterSharedWorker(JSContext* aCx,
|
|||
{
|
||||
AssertIsOnMainThread();
|
||||
MOZ_ASSERT(aSharedWorker);
|
||||
MOZ_ASSERT(IsSharedWorker());
|
||||
MOZ_ASSERT(IsSharedWorker() || IsServiceWorker());
|
||||
MOZ_ASSERT(!mSharedWorkers.Contains(aSharedWorker));
|
||||
|
||||
if (IsSharedWorker()) {
|
||||
|
@ -3831,11 +3821,11 @@ WorkerPrivate::WorkerPrivate(JSContext* aCx,
|
|||
WorkerPrivate* aParent,
|
||||
const nsAString& aScriptURL,
|
||||
bool aIsChromeWorker, WorkerType aWorkerType,
|
||||
const nsACString& aWorkerName,
|
||||
const nsACString& aSharedWorkerName,
|
||||
WorkerLoadInfo& aLoadInfo)
|
||||
: WorkerPrivateParent<WorkerPrivate>(aCx, aParent, aScriptURL,
|
||||
aIsChromeWorker, aWorkerType,
|
||||
aWorkerName, aLoadInfo)
|
||||
aSharedWorkerName, aLoadInfo)
|
||||
, mJSContext(nullptr)
|
||||
, mPRThread(nullptr)
|
||||
, mDebuggerEventLoopLevel(0)
|
||||
|
@ -3855,8 +3845,8 @@ WorkerPrivate::WorkerPrivate(JSContext* aCx,
|
|||
, mIdleGCTimerRunning(false)
|
||||
, mWorkerScriptExecutedSuccessfully(false)
|
||||
{
|
||||
MOZ_ASSERT_IF(!IsDedicatedWorker(), !aWorkerName.IsVoid());
|
||||
MOZ_ASSERT_IF(IsDedicatedWorker(), aWorkerName.IsEmpty());
|
||||
MOZ_ASSERT_IF(!IsDedicatedWorker(), !aSharedWorkerName.IsVoid());
|
||||
MOZ_ASSERT_IF(IsDedicatedWorker(), aSharedWorkerName.IsEmpty());
|
||||
|
||||
if (aParent) {
|
||||
aParent->AssertIsOnWorkerThread();
|
||||
|
@ -3935,12 +3925,12 @@ already_AddRefed<WorkerPrivate>
|
|||
WorkerPrivate::Constructor(const GlobalObject& aGlobal,
|
||||
const nsAString& aScriptURL,
|
||||
bool aIsChromeWorker, WorkerType aWorkerType,
|
||||
const nsACString& aWorkerName,
|
||||
const nsACString& aSharedWorkerName,
|
||||
WorkerLoadInfo* aLoadInfo, ErrorResult& aRv)
|
||||
{
|
||||
JSContext* cx = aGlobal.Context();
|
||||
return Constructor(cx, aScriptURL, aIsChromeWorker, aWorkerType,
|
||||
aWorkerName, aLoadInfo, aRv);
|
||||
aSharedWorkerName, aLoadInfo, aRv);
|
||||
}
|
||||
|
||||
// static
|
||||
|
@ -3948,7 +3938,7 @@ already_AddRefed<WorkerPrivate>
|
|||
WorkerPrivate::Constructor(JSContext* aCx,
|
||||
const nsAString& aScriptURL,
|
||||
bool aIsChromeWorker, WorkerType aWorkerType,
|
||||
const nsACString& aWorkerName,
|
||||
const nsACString& aSharedWorkerName,
|
||||
WorkerLoadInfo* aLoadInfo, ErrorResult& aRv)
|
||||
{
|
||||
WorkerPrivate* parent = NS_IsMainThread() ?
|
||||
|
@ -3960,11 +3950,10 @@ WorkerPrivate::Constructor(JSContext* aCx,
|
|||
AssertIsOnMainThread();
|
||||
}
|
||||
|
||||
// Only service and shared workers can have names.
|
||||
MOZ_ASSERT_IF(aWorkerType != WorkerTypeDedicated,
|
||||
!aWorkerName.IsVoid());
|
||||
!aSharedWorkerName.IsVoid());
|
||||
MOZ_ASSERT_IF(aWorkerType == WorkerTypeDedicated,
|
||||
aWorkerName.IsEmpty());
|
||||
aSharedWorkerName.IsEmpty());
|
||||
|
||||
Maybe<WorkerLoadInfo> stackLoadInfo;
|
||||
if (!aLoadInfo) {
|
||||
|
@ -4004,7 +3993,7 @@ WorkerPrivate::Constructor(JSContext* aCx,
|
|||
|
||||
nsRefPtr<WorkerPrivate> worker =
|
||||
new WorkerPrivate(aCx, parent, aScriptURL, aIsChromeWorker,
|
||||
aWorkerType, aWorkerName, *aLoadInfo);
|
||||
aWorkerType, aSharedWorkerName, *aLoadInfo);
|
||||
|
||||
if (!runtimeService->RegisterWorker(aCx, worker)) {
|
||||
aRv.Throw(NS_ERROR_UNEXPECTED);
|
||||
|
@ -4314,10 +4303,6 @@ WorkerPrivate::OverrideLoadInfoLoadGroup(WorkerLoadInfo& aLoadInfo)
|
|||
aLoadInfo.mLoadGroup);
|
||||
aLoadInfo.mInterfaceRequestor->MaybeAddTabChild(aLoadInfo.mLoadGroup);
|
||||
|
||||
// NOTE: this defaults the load context to:
|
||||
// - private browsing = false
|
||||
// - content = true
|
||||
// - use remote tabs = false
|
||||
nsCOMPtr<nsILoadGroup> loadGroup =
|
||||
do_CreateInstance(NS_LOADGROUP_CONTRACTID);
|
||||
|
||||
|
@ -6313,9 +6298,9 @@ WorkerPrivate::GetOrCreateGlobalScope(JSContext* aCx)
|
|||
if (!mScope) {
|
||||
nsRefPtr<WorkerGlobalScope> globalScope;
|
||||
if (IsSharedWorker()) {
|
||||
globalScope = new SharedWorkerGlobalScope(this, WorkerName());
|
||||
globalScope = new SharedWorkerGlobalScope(this, SharedWorkerName());
|
||||
} else if (IsServiceWorker()) {
|
||||
globalScope = new ServiceWorkerGlobalScope(this, WorkerName());
|
||||
globalScope = new ServiceWorkerGlobalScope(this, SharedWorkerName());
|
||||
} else {
|
||||
globalScope = new DedicatedWorkerGlobalScope(this);
|
||||
}
|
||||
|
|
|
@ -162,9 +162,7 @@ protected:
|
|||
private:
|
||||
WorkerPrivate* mParent;
|
||||
nsString mScriptURL;
|
||||
// This is the worker name for shared workers or the worker scope
|
||||
// for service workers.
|
||||
nsCString mWorkerName;
|
||||
nsCString mSharedWorkerName;
|
||||
LocationInfo mLocationInfo;
|
||||
// The lifetime of these objects within LoadInfo is managed explicitly;
|
||||
// they do not need to be cycle collected.
|
||||
|
@ -228,7 +226,7 @@ private:
|
|||
void
|
||||
PostMessageInternal(JSContext* aCx, JS::Handle<JS::Value> aMessage,
|
||||
const Optional<Sequence<JS::Value>>& aTransferable,
|
||||
UniquePtr<ServiceWorkerClientInfo>&& aClientInfo,
|
||||
ServiceWorkerClientInfo* aClientInfo,
|
||||
ErrorResult& aRv);
|
||||
|
||||
nsresult
|
||||
|
@ -326,13 +324,16 @@ public:
|
|||
|
||||
void
|
||||
PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
|
||||
const Optional<Sequence<JS::Value>>& aTransferable,
|
||||
ErrorResult& aRv);
|
||||
const Optional<Sequence<JS::Value> >& aTransferable,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
PostMessageInternal(aCx, aMessage, aTransferable, nullptr, aRv);
|
||||
}
|
||||
|
||||
void
|
||||
PostMessageToServiceWorker(JSContext* aCx, JS::Handle<JS::Value> aMessage,
|
||||
const Optional<Sequence<JS::Value>>& aTransferable,
|
||||
UniquePtr<ServiceWorkerClientInfo>&& aClientInfo,
|
||||
nsAutoPtr<ServiceWorkerClientInfo>& aClientInfo,
|
||||
ErrorResult& aRv);
|
||||
|
||||
void
|
||||
|
@ -736,10 +737,9 @@ public:
|
|||
}
|
||||
|
||||
const nsCString&
|
||||
WorkerName() const
|
||||
SharedWorkerName() const
|
||||
{
|
||||
MOZ_ASSERT(IsServiceWorker() || IsSharedWorker());
|
||||
return mWorkerName;
|
||||
return mSharedWorkerName;
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
|
@ -73,7 +73,6 @@ UNIFIED_SOURCES += [
|
|||
'ServiceWorkerManagerService.cpp',
|
||||
'ServiceWorkerMessageEvent.cpp',
|
||||
'ServiceWorkerPeriodicUpdater.cpp',
|
||||
'ServiceWorkerPrivate.cpp',
|
||||
'ServiceWorkerRegistrar.cpp',
|
||||
'ServiceWorkerRegistration.cpp',
|
||||
'ServiceWorkerScriptCache.cpp',
|
||||
|
|
|
@ -4,7 +4,6 @@ support-files =
|
|||
app/*
|
||||
app2/*
|
||||
|
||||
[test_aboutserviceworkers.html]
|
||||
skip-if = true #bug 1193319
|
||||
[test_app_installation.html]
|
||||
[test_privateBrowsing.html]
|
||||
[test_aboutserviceworkers.html]
|
||||
|
|
|
@ -164,7 +164,6 @@ support-files =
|
|||
redirect_post.sjs
|
||||
xslt_worker.js
|
||||
xslt/*
|
||||
unresolved_fetch_worker.js
|
||||
|
||||
[test_app_protocol.html]
|
||||
skip-if = release_build
|
||||
|
@ -258,4 +257,3 @@ skip-if = toolkit == "android" || toolkit == "gonk"
|
|||
[test_eventsource_intercept.html]
|
||||
[test_not_intercept_plugin.html]
|
||||
[test_file_blob_upload.html]
|
||||
[test_unresolved_fetch_interception.html]
|
||||
|
|
|
@ -1,95 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
Test that an unresolved respondWith promise will reset the channel when
|
||||
the service worker is terminated due to idling.
|
||||
-->
|
||||
<head>
|
||||
<title>Test for Bug 1188545</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
<meta http-equiv="Content-type" content="text/html;charset=UTF-8">
|
||||
</head>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1188545">Mozilla Bug 118845</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
</pre>
|
||||
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
function start() {
|
||||
return navigator.serviceWorker.register("unresolved_fetch_worker.js", {scope: "./"})
|
||||
.then((swr) => ({registration: swr}));
|
||||
}
|
||||
|
||||
function waitControlled(ctx) {
|
||||
var p = new Promise(function(res, rej) {
|
||||
if (navigator.serviceWorker.controller) {
|
||||
res(ctx);
|
||||
} else {
|
||||
navigator.serviceWorker.oncontrollerchange = function() {
|
||||
res(ctx);
|
||||
navigator.serviceWorker.oncontrollerchange = null;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
function unregister(ctx) {
|
||||
return ctx.registration.unregister().then(function(result) {
|
||||
ok(result, "Unregister should return true.");
|
||||
}, function(e) {
|
||||
dump("Unregistering the SW failed with " + e + "\n");
|
||||
});
|
||||
}
|
||||
|
||||
function testFetch(ctx) {
|
||||
ok(navigator.serviceWorker.controller, "Controlled");
|
||||
|
||||
var p = fetch("something_that_doesnt_exist_abcd.html")
|
||||
.catch(function() {
|
||||
ok(true, "channel was reset");
|
||||
}).then(function() { return ctx; });
|
||||
|
||||
navigator.serviceWorker.onmessage = function(event) {
|
||||
ok(event.data == "continue", "Got continue message from worker.");
|
||||
// close worker
|
||||
SpecialPowers.pushPrefEnv({"set": [
|
||||
["dom.serviceWorkers.idle_extended_timeout", 0]
|
||||
]}, function() {
|
||||
navigator.serviceWorker.controller.postMessage("shutdown");
|
||||
});
|
||||
|
||||
navigator.serviceWorker.onmessage = null;
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
function runTest() {
|
||||
start()
|
||||
.then(waitControlled)
|
||||
.then(testFetch)
|
||||
.then(unregister)
|
||||
.catch(function(e) {
|
||||
ok(false, "Some test failed with error " + e)
|
||||
}).then(SimpleTest.finish);
|
||||
}
|
||||
|
||||
SpecialPowers.pushPrefEnv({"set": [
|
||||
["dom.serviceWorkers.idle_timeout", 0],
|
||||
["dom.serviceWorkers.idle_extended_timeout", 299999],
|
||||
["dom.serviceWorkers.exemptFromPerDomainMax", true],
|
||||
["dom.serviceWorkers.enabled", true],
|
||||
["dom.serviceWorkers.testing.enabled", true],
|
||||
["dom.serviceWorkers.interception.enabled", true]
|
||||
]}, runTest);
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -1,14 +0,0 @@
|
|||
onfetch = function(event) {
|
||||
if (!event.client) {
|
||||
dump("ERROR: event doesnt have a client");
|
||||
}
|
||||
|
||||
event.client.postMessage("continue");
|
||||
|
||||
// never resolve
|
||||
event.respondWith(new Promise(function(res, rej) {}));
|
||||
}
|
||||
|
||||
onactivate = function(event) {
|
||||
event.waitUntil(clients.claim());
|
||||
}
|
|
@ -154,12 +154,6 @@ pref("dom.serviceWorkers.interception.enabled", false);
|
|||
// Allow service workers to intercept opaque (cross origin) responses
|
||||
pref("dom.serviceWorkers.interception.opaque.enabled", false);
|
||||
|
||||
// The amount of time (milliseconds) service workers keep running after each event.
|
||||
pref("dom.serviceWorkers.idle_timeout", 30000);
|
||||
|
||||
// The amount of time (milliseconds) service workers can be kept running using waitUntil promises.
|
||||
pref("dom.serviceWorkers.idle_extended_timeout", 300000);
|
||||
|
||||
// Whether nonzero values can be returned from performance.timing.*
|
||||
pref("dom.enable_performance", true);
|
||||
|
||||
|
|
|
@ -145,7 +145,6 @@
|
|||
"service-workers/service-worker/fetch-event-redirect.https.html": [
|
||||
{
|
||||
"path": "service-workers/service-worker/fetch-event-redirect.https.html",
|
||||
"timeout": "long",
|
||||
"url": "/_mozilla/service-workers/service-worker/fetch-event-redirect.https.html"
|
||||
}
|
||||
],
|
||||
|
@ -176,14 +175,12 @@
|
|||
"service-workers/service-worker/fetch-mixed-content-to-inscope.https.html": [
|
||||
{
|
||||
"path": "service-workers/service-worker/fetch-mixed-content-to-inscope.https.html",
|
||||
"timeout": "long",
|
||||
"url": "/_mozilla/service-workers/service-worker/fetch-mixed-content-to-inscope.https.html"
|
||||
}
|
||||
],
|
||||
"service-workers/service-worker/fetch-mixed-content-to-outscope.https.html": [
|
||||
{
|
||||
"path": "service-workers/service-worker/fetch-mixed-content-to-outscope.https.html",
|
||||
"timeout": "long",
|
||||
"url": "/_mozilla/service-workers/service-worker/fetch-mixed-content-to-outscope.https.html"
|
||||
}
|
||||
],
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[registration-attribute.https.html]
|
||||
type: testharness
|
||||
expected: TIMEOUT
|
||||
expected: ERROR
|
||||
[Verify registration attribute on ServiceWorkerGlobalScope]
|
||||
expected: TIMEOUT
|
||||
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
[fetch-request-no-freshness-headers.https.html]
|
||||
type: testharness
|
||||
expected: ERROR
|
|
@ -0,0 +1,3 @@
|
|||
[onactivate-script-error.https.html]
|
||||
type: testharness
|
||||
expected: ERROR
|
|
@ -1,6 +1,6 @@
|
|||
[oninstall-script-error.https.html]
|
||||
type: testharness
|
||||
expected: OK
|
||||
expected: ERROR
|
||||
[install handler throws an error that is cancelled]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[request-end-to-end.https.html]
|
||||
type: testharness
|
||||
expected: TIMEOUT
|
||||
expected: ERROR
|
||||
[Request: end-to-end]
|
||||
expected: TIMEOUT
|
||||
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
[sync-xhr-doesnt-deadlock.https.html]
|
||||
type: testharness
|
||||
expected: OK
|
||||
expected:
|
||||
if debug and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): CRASH
|
||||
if debug and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): CRASH
|
||||
if debug and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): CRASH
|
||||
if debug and (os == "win") and (version == "10.0.10240") and (processor == "x86_64") and (bits == 64): CRASH
|
||||
[Verify SyncXHR does not deadlock]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -67,7 +67,7 @@ promise_test(function(t) {
|
|||
|
||||
promise_test(function(t) {
|
||||
var script = 'resources/unregister-worker.js';
|
||||
var scope = 'resources/unregister-controlling-worker.html';
|
||||
var scope = 'resources/unregister-controlling-worker';
|
||||
|
||||
var controller;
|
||||
var frame;
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
<!DOCTYPE html>
|
||||
<title>Service Worker: Fetch Event Redirect Handling</title>
|
||||
<meta name=timeout content=long>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="resources/testharness-helpers.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
<!DOCTYPE html>
|
||||
<title>Service Worker: Mixed content of fetch()</title>
|
||||
<meta name=timeout content=long>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="resources/get-host-info.sub.js"></script>
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
<!DOCTYPE html>
|
||||
<title>Service Worker: Mixed content of fetch()</title>
|
||||
<meta name=timeout content=long>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="resources/get-host-info.sub.js"></script>
|
||||
|
|
|
@ -50,9 +50,7 @@ promise_test(function(t) {
|
|||
return saw_controllerchanged;
|
||||
})
|
||||
.then(function() {
|
||||
// XXXcatalinb: Removing the iframe here would terminate the worker
|
||||
// discarding inflight events.
|
||||
// frame.remove();
|
||||
frame.remove();
|
||||
assert_not_equals(sw_registration.active, null,
|
||||
'Registration active worker should not be null');
|
||||
fetch_tests_from_worker(sw_registration.active);
|
||||
|
|
Загрузка…
Ссылка в новой задаче