☠☠ backed out by c6e5013e0b7f ☠ ☠ | |
author | Catalin Badea <cbadea@mozilla.com> |
Mon, 27 Oct 2014 12:03:00 +0100 | |
changeset 212603 | 062c0a4db943f57d3904c232c7dbd0d4d26c7897 |
parent 212602 | 0d6feb092943f048312191dd1d2e854122ff1c41 |
child 212604 | 26cd857611b8a662f005c2b7975955a69ca9549a |
push id | 27721 |
push user | cbook@mozilla.com |
push date | Tue, 28 Oct 2014 14:55:05 +0000 |
treeherder | mozilla-central@c0ddb1b098ec [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | baku |
bugs | 982726 |
milestone | 36.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/dom/bindings/Bindings.conf +++ b/dom/bindings/Bindings.conf @@ -926,16 +926,26 @@ DOMInterfaces = { 'nativeType': 'nsScreen', }, 'ServiceWorker': { 'nativeType': 'mozilla::dom::workers::ServiceWorker', 'headerFile': 'mozilla/dom/workers/bindings/ServiceWorker.h', }, +'ServiceWorkerClient': { + 'nativeType': 'mozilla::dom::workers::ServiceWorkerClient', + 'headerFile': 'mozilla/dom/workers/bindings/ServiceWorkerClient.h', +}, + +'ServiceWorkerClients': { + 'nativeType': 'mozilla::dom::workers::ServiceWorkerClients', + 'headerFile': 'mozilla/dom/workers/bindings/ServiceWorkerClients.h', +}, + 'ServiceWorkerGlobalScope': { 'headerFile': 'mozilla/dom/WorkerScope.h', 'workers': True, }, 'SharedWorker': { 'nativeType': 'mozilla::dom::workers::SharedWorker', 'headerFile': 'mozilla/dom/workers/bindings/SharedWorker.h',
new file mode 100644 --- /dev/null +++ b/dom/webidl/ServiceWorkerClient.webidl @@ -0,0 +1,14 @@ +/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* 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/. + * + * The origin of this IDL file is + * http://slightlyoff.github.io/ServiceWorker/spec/service_worker/index.html + * + */ + +[Exposed=ServiceWorker] +interface ServiceWorkerClient { + readonly attribute unsigned long id; +};
new file mode 100644 --- /dev/null +++ b/dom/webidl/ServiceWorkerClients.webidl @@ -0,0 +1,19 @@ +/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* 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/. + * + * The origin of this IDL file is + * http://slightlyoff.github.io/ServiceWorker/spec/service_worker/index.html + * + */ + +[Exposed=ServiceWorker] +interface ServiceWorkerClients { + // A list of client objects, identifiable by ID, that correspond to windows + // (or workers) that are "controlled" by this SW + [Throws] + Promise<sequence<ServiceWorkerClient>?> getServiced(); + [Throws] + Promise<any> reloadAll(); +};
--- a/dom/webidl/ServiceWorkerGlobalScope.webidl +++ b/dom/webidl/ServiceWorkerGlobalScope.webidl @@ -11,20 +11,17 @@ */ [Global=(Worker,ServiceWorker), Exposed=ServiceWorker] interface ServiceWorkerGlobalScope : WorkerGlobalScope { // FIXME(nsm): Bug 982725 // readonly attribute CacheList caches; - // FIXME(nsm): Bug 982726 - // A container for a list of window objects, identifiable by ID, that - // correspond to windows (or workers) that are "controlled" by this SW - // readonly attribute ServiceWorkerClients clients; + readonly attribute ServiceWorkerClients clients; [Unforgeable] readonly attribute DOMString scope; // FIXME(nsm): Bug 995484 // ResponsePromise<any> fetch((Request or [EnsureUTF16] DOMString) request); void update();
--- a/dom/webidl/moz.build +++ b/dom/webidl/moz.build @@ -349,16 +349,18 @@ WEBIDL_FILES = [ 'RTCSessionDescription.webidl', 'RTCStatsReport.webidl', 'Screen.webidl', 'ScriptProcessorNode.webidl', 'ScrollAreaEvent.webidl', 'ScrollBoxObject.webidl', 'Selection.webidl', 'ServiceWorker.webidl', + 'ServiceWorkerClient.webidl', + 'ServiceWorkerClients.webidl', 'ServiceWorkerContainer.webidl', 'ServiceWorkerGlobalScope.webidl', 'ServiceWorkerRegistration.webidl', 'SettingChangeNotification.webidl', 'SettingsManager.webidl', 'ShadowRoot.webidl', 'SharedWorker.webidl', 'SharedWorkerGlobalScope.webidl',
new file mode 100644 --- /dev/null +++ b/dom/workers/ServiceWorkerClient.cpp @@ -0,0 +1,29 @@ +/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* 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/. + */ + +#include "ServiceWorkerClient.h" + +#include "mozilla/dom/ServiceWorkerClientBinding.h" + +using namespace mozilla::dom; +using namespace mozilla::dom::workers; + +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(ServiceWorkerClient, mOwner) + +NS_IMPL_CYCLE_COLLECTING_ADDREF(ServiceWorkerClient) +NS_IMPL_CYCLE_COLLECTING_RELEASE(ServiceWorkerClient) + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ServiceWorkerClient) + NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY + NS_INTERFACE_MAP_ENTRY(nsISupports) +NS_INTERFACE_MAP_END + +JSObject* +ServiceWorkerClient::WrapObject(JSContext* aCx) +{ + return ServiceWorkerClientBinding::Wrap(aCx, this); +} +
new file mode 100644 --- /dev/null +++ b/dom/workers/ServiceWorkerClient.h @@ -0,0 +1,58 @@ +/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* 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_serviceworkerclient_h +#define mozilla_dom_workers_serviceworkerclient_h + +#include "nsCOMPtr.h" +#include "nsWrapperCache.h" + +namespace mozilla { +namespace dom { + +class Promise; + +namespace workers { + +class ServiceWorkerClient MOZ_FINAL : public nsISupports, + public nsWrapperCache +{ +public: + NS_DECL_CYCLE_COLLECTING_ISUPPORTS + NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(ServiceWorkerClient) + + ServiceWorkerClient(nsISupports* aOwner, uint64_t aId) + : mOwner(aOwner), + mId(aId) + { + } + + uint32_t Id() const + { + return mId; + } + + nsISupports* GetParentObject() const + { + return mOwner; + } + + JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE; + +private: + ~ServiceWorkerClient() + { + } + + nsCOMPtr<nsISupports> mOwner; + uint64_t mId; +}; + +} // namespace workers +} // namespace dom +} // namespace mozilla + +#endif // mozilla_dom_workers_serviceworkerclient_h
new file mode 100644 --- /dev/null +++ b/dom/workers/ServiceWorkerClients.cpp @@ -0,0 +1,228 @@ +/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ +/* 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/. */ + +#include "ServiceWorkerClient.h" +#include "ServiceWorkerClients.h" +#include "ServiceWorkerManager.h" + +#include "WorkerPrivate.h" +#include "WorkerRunnable.h" +#include "WorkerScope.h" + +#include "mozilla/dom/Promise.h" +#include "mozilla/dom/ServiceWorkerClientsBinding.h" + +using namespace mozilla; +using namespace mozilla::dom; +using namespace mozilla::dom::workers; + +NS_IMPL_CYCLE_COLLECTING_ADDREF(ServiceWorkerClients) +NS_IMPL_CYCLE_COLLECTING_RELEASE(ServiceWorkerClients) +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(ServiceWorkerClients, mWorkerScope) + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ServiceWorkerClients) + NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY + NS_INTERFACE_MAP_ENTRY(nsISupports) +NS_INTERFACE_MAP_END + +ServiceWorkerClients::ServiceWorkerClients(ServiceWorkerGlobalScope* aWorkerScope) + : mWorkerScope(aWorkerScope) +{ + MOZ_ASSERT(mWorkerScope); +} + +JSObject* +ServiceWorkerClients::WrapObject(JSContext* aCx) +{ + return ServiceWorkerClientsBinding::Wrap(aCx, this); +} + +namespace { + +// Helper class used for passing the promise between threads while +// keeping the worker alive. +class PromiseHolder MOZ_FINAL : public WorkerFeature +{ + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(PromiseHolder) + +public: + PromiseHolder(WorkerPrivate* aWorkerPrivate, + Promise* aPromise) + : mWorkerPrivate(aWorkerPrivate), + mPromise(aPromise), + mClean(false) + { + MOZ_ASSERT(mWorkerPrivate); + mWorkerPrivate->AssertIsOnWorkerThread(); + MOZ_ASSERT(mPromise); + + if (NS_WARN_IF(!mWorkerPrivate->AddFeature(mWorkerPrivate->GetJSContext(), this))) { + // Worker has been canceled and will go away. + // The ResolvePromiseWorkerRunnable won't run, so we can set mPromise to + // nullptr. + mPromise = nullptr; + mClean = true; + } + } + + Promise* + Get() const + { + return mPromise; + } + + void + Clean() + { + mWorkerPrivate->AssertIsOnWorkerThread(); + + if (mClean) { + return; + } + + mPromise = nullptr; + mWorkerPrivate->RemoveFeature(mWorkerPrivate->GetJSContext(), this); + mClean = true; + } + + bool + Notify(JSContext* aCx, Status aStatus) + { + mWorkerPrivate->AssertIsOnWorkerThread(); + + if (aStatus > Running) { + Clean(); + } + + return true; + } + +private: + ~PromiseHolder() + { + MOZ_ASSERT(mClean); + } + + WorkerPrivate* mWorkerPrivate; + nsRefPtr<Promise> mPromise; + + bool mClean; +}; + +class ResolvePromiseWorkerRunnable MOZ_FINAL : public WorkerRunnable +{ + nsRefPtr<PromiseHolder> mPromiseHolder; + nsAutoPtr<nsTArray<uint64_t>> mValue; + +public: + ResolvePromiseWorkerRunnable(WorkerPrivate* aWorkerPrivate, + PromiseHolder* aPromiseHolder, + nsAutoPtr<nsTArray<uint64_t>>& aValue) + : WorkerRunnable(aWorkerPrivate, WorkerThreadModifyBusyCount), + mPromiseHolder(aPromiseHolder), + mValue(aValue) + { + AssertIsOnMainThread(); + } + + bool + WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) + { + MOZ_ASSERT(aWorkerPrivate); + aWorkerPrivate->AssertIsOnWorkerThread(); + + Promise* promise = mPromiseHolder->Get(); + MOZ_ASSERT(promise); + + nsTArray<nsRefPtr<ServiceWorkerClient>> ret; + for (size_t i = 0; i < mValue->Length(); i++) { + ret.AppendElement(nsRefPtr<ServiceWorkerClient>( + new ServiceWorkerClient(promise->GetParentObject(), + mValue->ElementAt(i)))); + } + promise->MaybeResolve(ret); + + // release the reference on the worker thread. + mPromiseHolder->Clean(); + + return true; + } +}; + +class GetServicedRunnable MOZ_FINAL : public nsRunnable +{ + WorkerPrivate* mWorkerPrivate; + nsCString mScope; + nsRefPtr<PromiseHolder> mPromiseHolder; +public: + GetServicedRunnable(WorkerPrivate* aWorkerPrivate, + Promise* aPromise, + const nsCString& aScope) + : mWorkerPrivate(aWorkerPrivate), + mScope(aScope) + { + MOZ_ASSERT(aWorkerPrivate); + aWorkerPrivate->AssertIsOnWorkerThread(); + mPromiseHolder = new PromiseHolder(aWorkerPrivate, aPromise); + } + + NS_IMETHOD + Run() MOZ_OVERRIDE + { + AssertIsOnMainThread(); + + nsRefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance(); + nsAutoPtr<nsTArray<uint64_t>> result(new nsTArray<uint64_t>()); + + swm->GetServicedClients(mScope, result); + nsRefPtr<ResolvePromiseWorkerRunnable> r = + new ResolvePromiseWorkerRunnable(mWorkerPrivate, mPromiseHolder, result); + + AutoSafeJSContext cx; + r->Dispatch(cx); + return NS_OK; + } +}; + +} // anonymous namespace + +already_AddRefed<Promise> +ServiceWorkerClients::GetServiced(ErrorResult& aRv) +{ + WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate(); + MOZ_ASSERT(workerPrivate); + workerPrivate->AssertIsOnWorkerThread(); + + DOMString scope; + mWorkerScope->GetScope(scope); + + nsRefPtr<Promise> promise = Promise::Create(mWorkerScope, aRv); + if (NS_WARN_IF(aRv.Failed())) { + return nullptr; + } + + nsRefPtr<GetServicedRunnable> r = + new GetServicedRunnable(workerPrivate, promise, NS_ConvertUTF16toUTF8(scope)); + nsresult rv = NS_DispatchToMainThread(r); + + if (NS_WARN_IF(NS_FAILED(rv))) { + promise->MaybeReject(NS_ERROR_NOT_AVAILABLE); + } + + return promise.forget(); +} + +// FIXME(catalinb): Bug 1045257 - Implement ReloadAll +already_AddRefed<Promise> +ServiceWorkerClients::ReloadAll(ErrorResult& aRv) +{ + nsRefPtr<Promise> promise = Promise::Create(mWorkerScope, aRv); + if (NS_WARN_IF(aRv.Failed())) { + return nullptr; + } + promise->MaybeReject(NS_ERROR_NOT_AVAILABLE); + return promise.forget(); +} +
new file mode 100644 --- /dev/null +++ b/dom/workers/ServiceWorkerClients.h @@ -0,0 +1,56 @@ +/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* 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_serviceworkerclients_h +#define mozilla_dom_workers_serviceworkerclients_h + +#include "nsAutoPtr.h" +#include "nsWrapperCache.h" + +namespace mozilla { + +class ErrorResult; + +namespace dom { + +class Promise; + +namespace workers { + +class ServiceWorkerGlobalScope; + +class ServiceWorkerClients MOZ_FINAL : public nsISupports, + public nsWrapperCache +{ +public: + NS_DECL_CYCLE_COLLECTING_ISUPPORTS + NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(ServiceWorkerClients) + + ServiceWorkerClients(ServiceWorkerGlobalScope* aWorkerScope); + + already_AddRefed<Promise> GetServiced(ErrorResult& aRv); + already_AddRefed<Promise> ReloadAll(ErrorResult& aRv); + + JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE; + + ServiceWorkerGlobalScope* GetParentObject() const + { + return mWorkerScope; + } + +private: + ~ServiceWorkerClients() + { + } + + nsRefPtr<ServiceWorkerGlobalScope> mWorkerScope; +}; + +} // namespace workers +} // namespace dom +} // namespace mozilla + +#endif // mozilla_dom_workers_serviceworkerclients_h
--- a/dom/workers/ServiceWorkerManager.cpp +++ b/dom/workers/ServiceWorkerManager.cpp @@ -19,16 +19,17 @@ #include "nsContentUtils.h" #include "nsNetUtil.h" #include "nsProxyRelease.h" #include "nsTArray.h" #include "RuntimeService.h" #include "ServiceWorker.h" +#include "ServiceWorkerClient.h" #include "ServiceWorkerRegistration.h" #include "ServiceWorkerEvents.h" #include "WorkerInlines.h" #include "WorkerPrivate.h" #include "WorkerRunnable.h" #include "WorkerScope.h" using namespace mozilla; @@ -65,16 +66,17 @@ UpdatePromise::ResolveAllPromises(const RuntimeService* rs = RuntimeService::GetOrCreateService(); MOZ_ASSERT(rs); nsTArray<WeakPtr<Promise>> array; array.SwapElements(mPromises); for (uint32_t i = 0; i < array.Length(); ++i) { WeakPtr<Promise>& pendingPromise = array.ElementAt(i); if (pendingPromise) { + nsRefPtr<Promise> kungfuDeathGrip = pendingPromise.get(); nsCOMPtr<nsIGlobalObject> go = do_QueryInterface(pendingPromise->GetParentObject()); MOZ_ASSERT(go); AutoSafeJSContext cx; JS::Rooted<JSObject*> global(cx, go->GetGlobalJSObject()); JSAutoCompartment ac(cx, global); @@ -88,18 +90,17 @@ UpdatePromise::ResolveAllPromises(const getter_AddRefs(serviceWorker)); if (NS_WARN_IF(NS_FAILED(rv))) { pendingPromise->MaybeReject(NS_ERROR_DOM_ABORT_ERR); continue; } // Since ServiceWorkerRegistration is only exposed to windows we can be // certain about this cast. - nsCOMPtr<nsPIDOMWindow> window = - do_QueryInterface(pendingPromise->GetParentObject()); + nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(go); nsRefPtr<ServiceWorkerRegistration> swr = new ServiceWorkerRegistration(window, NS_ConvertUTF8toUTF16(aScope)); pendingPromise->MaybeResolve(swr); } } } @@ -2136,9 +2137,59 @@ ServiceWorkerManager::InvalidateServiceW continue; } target->InvalidateWorkerReference(aWhichOnes); } } } +namespace { + +class MOZ_STACK_CLASS FilterRegistrationData +{ +public: + FilterRegistrationData(nsTArray<uint64_t>* aDocuments, + ServiceWorkerRegistrationInfo* aRegistration) + : mDocuments(aDocuments), + mRegistration(aRegistration) + { + } + + nsTArray<uint64_t>* mDocuments; + nsRefPtr<ServiceWorkerRegistrationInfo> mRegistration; +}; + +static PLDHashOperator +EnumControlledDocuments(nsISupports* aKey, + ServiceWorkerRegistrationInfo* aRegistration, + void* aData) +{ + FilterRegistrationData* data = static_cast<FilterRegistrationData*>(aData); + if (data->mRegistration != aRegistration) { + return PL_DHASH_NEXT; + } + nsCOMPtr<nsIDocument> document = do_QueryInterface(aKey); + if (!document || !document->GetInnerWindow()) { + return PL_DHASH_NEXT; + } + + data->mDocuments->AppendElement(document->GetInnerWindow()->WindowID()); + return PL_DHASH_NEXT; +} + +} // anonymous namespace + +void +ServiceWorkerManager::GetServicedClients(const nsCString& aScope, + nsTArray<uint64_t>* aControlledDocuments) +{ + nsRefPtr<ServiceWorkerDomainInfo> domainInfo = GetDomainInfo(aScope); + nsRefPtr<ServiceWorkerRegistrationInfo> registration = + domainInfo->GetRegistration(aScope); + MOZ_ASSERT(registration); + FilterRegistrationData data(aControlledDocuments, registration); + + domainInfo->mControlledDocuments.EnumerateRead(EnumControlledDocuments, + &data); +} + END_WORKERS_NAMESPACE
--- a/dom/workers/ServiceWorkerManager.h +++ b/dom/workers/ServiceWorkerManager.h @@ -312,16 +312,20 @@ public: const nsAString& aWorkerURL, nsString aMessage, nsString aFilename, nsString aLine, uint32_t aLineNumber, uint32_t aColumnNumber, uint32_t aFlags); + void + GetServicedClients(const nsCString& aScope, + nsTArray<uint64_t>* aControlledDocuments); + static already_AddRefed<ServiceWorkerManager> GetInstance(); private: ServiceWorkerManager(); ~ServiceWorkerManager(); void
--- a/dom/workers/WorkerScope.cpp +++ b/dom/workers/WorkerScope.cpp @@ -354,16 +354,24 @@ SharedWorkerGlobalScope::WrapGlobalObjec JS::CompartmentOptions options; mWorkerPrivate->CopyJSCompartmentOptions(options); return SharedWorkerGlobalScopeBinding_workers::Wrap(aCx, this, this, options, GetWorkerPrincipal(), true); } +NS_IMPL_CYCLE_COLLECTION_INHERITED(ServiceWorkerGlobalScope, WorkerGlobalScope, + mClients) +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(ServiceWorkerGlobalScope) +NS_INTERFACE_MAP_END_INHERITING(WorkerGlobalScope) + +NS_IMPL_ADDREF_INHERITED(ServiceWorkerGlobalScope, WorkerGlobalScope) +NS_IMPL_RELEASE_INHERITED(ServiceWorkerGlobalScope, WorkerGlobalScope) + ServiceWorkerGlobalScope::ServiceWorkerGlobalScope(WorkerPrivate* aWorkerPrivate, const nsACString& aScope) : WorkerGlobalScope(aWorkerPrivate), mScope(NS_ConvertUTF8toUTF16(aScope)) { } JSObject*
--- a/dom/workers/WorkerScope.h +++ b/dom/workers/WorkerScope.h @@ -6,16 +6,18 @@ #ifndef mozilla_dom_workerscope_h__ #define mozilla_dom_workerscope_h__ #include "Workers.h" #include "mozilla/DOMEventTargetHelper.h" #include "mozilla/dom/Headers.h" #include "mozilla/dom/RequestBinding.h" +#include "ServiceWorkerClients.h" + namespace mozilla { namespace dom { class Console; class Function; class Promise; class RequestOrScalarValueString; @@ -165,19 +167,25 @@ public: } IMPL_EVENT_HANDLER(connect) }; class ServiceWorkerGlobalScope MOZ_FINAL : public WorkerGlobalScope { const nsString mScope; + nsRefPtr<ServiceWorkerClients> mClients; + ~ServiceWorkerGlobalScope() { } public: + NS_DECL_ISUPPORTS_INHERITED + NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(ServiceWorkerGlobalScope, + WorkerGlobalScope) + ServiceWorkerGlobalScope(WorkerPrivate* aWorkerPrivate, const nsACString& aScope); virtual JSObject* WrapGlobalObject(JSContext* aCx) MOZ_OVERRIDE; void GetScope(DOMString& aScope) const { @@ -194,16 +202,25 @@ public: Update() { // FIXME(nsm): Bug 982728 } already_AddRefed<Promise> Unregister(ErrorResult& aRv); + ServiceWorkerClients* + Clients() { + if (!mClients) { + mClients = new ServiceWorkerClients(this); + } + + return mClients; + } + IMPL_EVENT_HANDLER(activate) IMPL_EVENT_HANDLER(beforeevicted) IMPL_EVENT_HANDLER(evicted) IMPL_EVENT_HANDLER(fetch) IMPL_EVENT_HANDLER(install) IMPL_EVENT_HANDLER(message) };
--- a/dom/workers/moz.build +++ b/dom/workers/moz.build @@ -25,16 +25,18 @@ EXPORTS.mozilla.dom.workers.bindings += 'DataStore.h', 'DataStoreCursor.h', 'FileReaderSync.h', 'Location.h', 'MessagePort.h', 'Navigator.h', 'Performance.h', 'ServiceWorker.h', + 'ServiceWorkerClient.h', + 'ServiceWorkerClients.h', 'SharedWorker.h', 'URL.h', 'WorkerFeature.h', 'XMLHttpRequest.h', 'XMLHttpRequestUpload.h', ] XPIDL_MODULE = 'dom_workers' @@ -53,16 +55,18 @@ UNIFIED_SOURCES += [ 'MessagePort.cpp', 'Navigator.cpp', 'Performance.cpp', 'Principal.cpp', 'RegisterBindings.cpp', 'RuntimeService.cpp', 'ScriptLoader.cpp', 'ServiceWorker.cpp', + 'ServiceWorkerClient.cpp', + 'ServiceWorkerClients.cpp', 'ServiceWorkerContainer.cpp', 'ServiceWorkerEvents.cpp', 'ServiceWorkerManager.cpp', 'ServiceWorkerRegistration.cpp', 'SharedWorker.cpp', 'URL.cpp', 'WorkerDebuggerManager.cpp', 'WorkerPrivate.cpp',
new file mode 100644 --- /dev/null +++ b/dom/workers/test/serviceworkers/get_serviced_worker.js @@ -0,0 +1,16 @@ +function loop() { + self.clients.getServiced().then(function(result) { + setTimeout(loop, 0); + }); +} + +onactivate = function(e) { + // spam getServiced until the worker is closed. + loop(); +} + +onclose = function(e) { + for (var i = 0; i < 100; ++i) { + self.clients.getServiced(); + } +}
--- a/dom/workers/test/serviceworkers/mochitest.ini +++ b/dom/workers/test/serviceworkers/mochitest.ini @@ -5,15 +5,18 @@ support-files = worker2.js worker3.js parse_error_worker.js install_event_worker.js simpleregister/index.html simpleregister/ready.html controller/index.html unregister/index.html + sw_clients/simple.html + get_serviced_worker.js +[test_get_serviced.html] [test_installation_simple.html] [test_install_event.html] [test_navigator.html] [test_scopes.html] [test_controller.html] [test_unregister.html]
new file mode 100644 --- /dev/null +++ b/dom/workers/test/serviceworkers/sw_clients/simple.html @@ -0,0 +1,25 @@ +<!-- + Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ +--> +<!DOCTYPE HTML> +<html> +<head> + <title>Bug 982726 - test get_serviced not crashing</title> + <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<p id="display"></p> +<div id="content" style="display: none"></div> +<pre id="test"></pre> +<script class="testbody" type="text/javascript"> + + window.onload = function() { + opener.postMessage("READY", "*"); + } +</script> +</pre> +</body> +</html> +
new file mode 100644 --- /dev/null +++ b/dom/workers/test/serviceworkers/test_get_serviced.html @@ -0,0 +1,57 @@ +<!-- + Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ +--> +<!DOCTYPE HTML> +<html> +<head> + <title>Bug 982726 - test get_serviced not crashing</title> + <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<p id="display"></p> +<div id="content" style="display: none"></div> +<pre id="test"></pre> +<script class="testbody" type="text/javascript"> + // get_serviced_worker will call getServiced until the worker shuts down. + // Test passes if the browser doesn't crash on leaked promise objects. + var controlled_window; + function simpleRegister() { + return navigator.serviceWorker.register("get_serviced_worker.js", { scope: "./sw_clients/" }); + } + + function openWindow() { + var p = new Promise(function(resolve, reject) { + window.onmessage = function(e) { + if (e.data === "READY") { + resolve(); + } + } + }); + + controlled_window = window.open("sw_clients/simple.html"); + return p; + } + + function runTest() { + simpleRegister() + .then(openWindow).catch(function(e) { + ok(false, "Some test failed with error " + e); + }).then(function() { + ok(true, "Didn't crash on resolving getServiced promises while worker shuts down."); + SimpleTest.finish(); + controlled_window.close(); + }); + } + + SimpleTest.waitForExplicitFinish(); + SpecialPowers.pushPrefEnv({"set": [ + ["dom.serviceWorkers.enabled", true], + ["dom.serviceWorkers.testing.enabled", true] + ]}, runTest); +</script> +</pre> +</body> +</html> +
--- a/dom/workers/test/serviceworkers/test_unregister.html +++ b/dom/workers/test/serviceworkers/test_unregister.html @@ -11,16 +11,17 @@ </head> <body> <p id="display"></p> <div id="content" style="display: none"></div> <pre id="test"></pre> <script class="testbody" type="text/javascript"> function simpleRegister() { + info("simpleRegister() just before calling register"); return navigator.serviceWorker.register("worker.js", { scope: "unregister/" }); } function testControlled() { var testPromise = new Promise(function(res, rej) { window.onmessage = function(e) { if (!("controlled" in e.data)) { ok(false, "Something went wrong."); @@ -43,16 +44,17 @@ return testPromise.then(function() { div.removeChild(ifr); }); } function unregister() { return navigator.serviceWorker.getRegistration("unregister/") .then(function(reg) { + info("getRegistration() succeeded " + reg.scope); return reg.unregister().then(function(v) { ok(v, "Unregister should resolve to true"); }, function(e) { ok(false, "Unregister failed with " + e.name); }); }); } @@ -79,19 +81,35 @@ return testPromise.then(function() { div.removeChild(ifr); }); } function runTest() { simpleRegister() + .then(function(v) { + info("simpleRegister() promise resolved"); + }) .then(testControlled) + .then(function(v) { + info("testControlled() promise resolved"); + }, function(e) { + info("testControlled() promise rejected " + e); + }) .then(unregister) + .then(function(v) { + info("unregister() promise resolved"); + }) .then(testUncontrolled) + .then(function(v) { + info("testUncontrolled() promise resolved"); + }, function(e) { + info("testUncontrolled() promise rejected " + e); + }) .then(function() { SimpleTest.finish(); }).catch(function(e) { ok(false, "Some test failed with error " + e); SimpleTest.finish(); }); }
--- a/dom/workers/test/serviceworkers/unregister/index.html +++ b/dom/workers/test/serviceworkers/unregister/index.html @@ -15,26 +15,30 @@ <pre id="test"></pre> <script class="testbody" type="text/javascript"> if (!parent) { info("unregister/index.html should not to be launched directly!"); } var tId = setTimeout(function() { + info("tId timeout!"); parent.postMessage({ controlled: false }, "*"); tId = null; }, 2000); navigator.serviceWorker.ready.then(function() { + info("Got ready"); if (tId == null) { + info("tId was null"); parent.postMessage("FAIL!!!", "*"); return; } clearTimeout(tId); + info("tId was non-null"); parent.postMessage({ controlled: true }, "*"); }); </script> </pre> </body> </html>