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:
Wes Kocher 2015-09-30 11:11:47 -07:00
Родитель 2f2b59e28b
Коммит 6fbdec2422
36 изменённых файлов: 1500 добавлений и 2391 удалений

Просмотреть файл

@ -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);