mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-11 01:57:00 +00:00
Bug 1025077 - Implement ServiceWorkerContainer.ready, r=nsm
This commit is contained in:
parent
f980f5fb99
commit
51c5e60fe1
@ -8,7 +8,7 @@
|
||||
interface nsIDocument;
|
||||
interface nsIURI;
|
||||
|
||||
[uuid(c7132f91-c46c-4e01-b75a-43babb254d93)]
|
||||
[uuid(91b9d3fc-1654-44da-b438-15123cdbe7aa)]
|
||||
interface nsIServiceWorkerManager : nsISupports
|
||||
{
|
||||
/**
|
||||
@ -36,6 +36,12 @@ interface nsIServiceWorkerManager : nsISupports
|
||||
// Returns a Promise
|
||||
nsISupports getRegistration(in nsIDOMWindow aWindow, in DOMString aScope);
|
||||
|
||||
// Returns a Promise
|
||||
nsISupports getReadyPromise(in nsIDOMWindow aWindow);
|
||||
|
||||
// Remove ready pending Promise
|
||||
void removeReadyPromise(in nsIDOMWindow aWindow);
|
||||
|
||||
// aTarget MUST be a ServiceWorkerRegistration.
|
||||
[noscript] void AddRegistrationEventListener(in nsIURI aPageURI, in nsIDOMEventTarget aTarget);
|
||||
[noscript] void RemoveRegistrationEventListener(in nsIURI aPageURI, in nsIDOMEventTarget aTarget);
|
||||
|
@ -30,18 +30,28 @@ NS_IMPL_ADDREF_INHERITED(ServiceWorkerContainer, DOMEventTargetHelper)
|
||||
NS_IMPL_RELEASE_INHERITED(ServiceWorkerContainer, DOMEventTargetHelper)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_INHERITED(ServiceWorkerContainer, DOMEventTargetHelper,
|
||||
mControllerWorker)
|
||||
mControllerWorker, mReadyPromise)
|
||||
|
||||
ServiceWorkerContainer::ServiceWorkerContainer(nsPIDOMWindow* aWindow)
|
||||
: mWindow(aWindow)
|
||||
: DOMEventTargetHelper(aWindow)
|
||||
{
|
||||
SetIsDOMBinding();
|
||||
}
|
||||
|
||||
ServiceWorkerContainer::~ServiceWorkerContainer()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
ServiceWorkerContainer::DisconnectFromOwner()
|
||||
{
|
||||
nsCOMPtr<nsIServiceWorkerManager> swm = mozilla::services::GetServiceWorkerManager();
|
||||
MOZ_ASSERT(swm);
|
||||
|
||||
swm->RemoveReadyPromise(GetOwner());
|
||||
|
||||
DOMEventTargetHelper::DisconnectFromOwner();
|
||||
}
|
||||
|
||||
JSObject*
|
||||
ServiceWorkerContainer::WrapObject(JSContext* aCx)
|
||||
{
|
||||
@ -82,7 +92,7 @@ ServiceWorkerContainer::GetController()
|
||||
}
|
||||
|
||||
nsCOMPtr<nsISupports> serviceWorker;
|
||||
rv = swm->GetDocumentController(mWindow, getter_AddRefs(serviceWorker));
|
||||
rv = swm->GetDocumentController(GetOwner(), getter_AddRefs(serviceWorker));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return nullptr;
|
||||
}
|
||||
@ -106,7 +116,7 @@ ServiceWorkerContainer::GetRegistrations(ErrorResult& aRv)
|
||||
}
|
||||
|
||||
nsCOMPtr<nsISupports> promise;
|
||||
aRv = swm->GetRegistrations(mWindow, getter_AddRefs(promise));
|
||||
aRv = swm->GetRegistrations(GetOwner(), getter_AddRefs(promise));
|
||||
if (aRv.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
@ -128,7 +138,7 @@ ServiceWorkerContainer::GetRegistration(const nsAString& aDocumentURL,
|
||||
}
|
||||
|
||||
nsCOMPtr<nsISupports> promise;
|
||||
aRv = swm->GetRegistration(mWindow, aDocumentURL, getter_AddRefs(promise));
|
||||
aRv = swm->GetRegistration(GetOwner(), aDocumentURL, getter_AddRefs(promise));
|
||||
if (aRv.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
@ -138,12 +148,24 @@ ServiceWorkerContainer::GetRegistration(const nsAString& aDocumentURL,
|
||||
return ret.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
Promise*
|
||||
ServiceWorkerContainer::GetReady(ErrorResult& aRv)
|
||||
{
|
||||
// FIXME(nsm): Bug 1025077
|
||||
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(mWindow);
|
||||
return Promise::Create(global, aRv);
|
||||
if (mReadyPromise) {
|
||||
return mReadyPromise;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIServiceWorkerManager> swm = mozilla::services::GetServiceWorkerManager();
|
||||
if (!swm) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsISupports> promise;
|
||||
aRv = swm->GetReadyPromise(GetOwner(), getter_AddRefs(promise));
|
||||
|
||||
mReadyPromise = static_cast<Promise*>(promise.get());
|
||||
return mReadyPromise;
|
||||
}
|
||||
|
||||
// Testing only.
|
||||
|
@ -34,12 +34,6 @@ public:
|
||||
|
||||
explicit ServiceWorkerContainer(nsPIDOMWindow* aWindow);
|
||||
|
||||
nsPIDOMWindow*
|
||||
GetParentObject() const
|
||||
{
|
||||
return mWindow;
|
||||
}
|
||||
|
||||
JSObject*
|
||||
WrapObject(JSContext* aCx);
|
||||
|
||||
@ -58,7 +52,7 @@ public:
|
||||
already_AddRefed<Promise>
|
||||
GetRegistrations(ErrorResult& aRv);
|
||||
|
||||
already_AddRefed<Promise>
|
||||
Promise*
|
||||
GetReady(ErrorResult& aRv);
|
||||
|
||||
// Testing only.
|
||||
@ -74,15 +68,19 @@ public:
|
||||
GetControllingWorkerScriptURLForPath(const nsAString& aPath,
|
||||
nsString& aScriptURL,
|
||||
ErrorResult& aRv);
|
||||
|
||||
// DOMEventTargetHelper
|
||||
void DisconnectFromOwner() MOZ_OVERRIDE;
|
||||
|
||||
private:
|
||||
~ServiceWorkerContainer();
|
||||
|
||||
nsCOMPtr<nsPIDOMWindow> mWindow;
|
||||
|
||||
// This only changes when a worker hijacks everything in its scope by calling
|
||||
// replace().
|
||||
// FIXME(nsm): Bug 982711. Provide API to let SWM invalidate this.
|
||||
nsRefPtr<workers::ServiceWorker> mControllerWorker;
|
||||
|
||||
nsRefPtr<Promise> mReadyPromise;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
@ -820,6 +820,142 @@ ServiceWorkerManager::GetRegistration(nsIDOMWindow* aWindow,
|
||||
return NS_DispatchToCurrentThread(runnable);
|
||||
}
|
||||
|
||||
class GetReadyPromiseRunnable : public nsRunnable
|
||||
{
|
||||
nsCOMPtr<nsPIDOMWindow> mWindow;
|
||||
nsRefPtr<Promise> mPromise;
|
||||
|
||||
public:
|
||||
GetReadyPromiseRunnable(nsPIDOMWindow* aWindow, Promise* aPromise)
|
||||
: mWindow(aWindow), mPromise(aPromise)
|
||||
{ }
|
||||
|
||||
NS_IMETHODIMP
|
||||
Run()
|
||||
{
|
||||
nsRefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
|
||||
|
||||
nsIDocument* doc = mWindow->GetExtantDoc();
|
||||
if (!doc) {
|
||||
mPromise->MaybeReject(NS_ERROR_UNEXPECTED);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIURI> docURI = doc->GetDocumentURI();
|
||||
if (!docURI) {
|
||||
mPromise->MaybeReject(NS_ERROR_UNEXPECTED);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (!swm->CheckReadyPromise(mWindow, docURI, mPromise)) {
|
||||
swm->StorePendingReadyPromise(mWindow, docURI, mPromise);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
};
|
||||
|
||||
NS_IMETHODIMP
|
||||
ServiceWorkerManager::GetReadyPromise(nsIDOMWindow* aWindow,
|
||||
nsISupports** aPromise)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
MOZ_ASSERT(aWindow);
|
||||
|
||||
// XXXnsm Don't allow chrome callers for now, we don't support chrome
|
||||
// ServiceWorkers.
|
||||
MOZ_ASSERT(!nsContentUtils::IsCallerChrome());
|
||||
|
||||
nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aWindow);
|
||||
if (!window) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(!mPendingReadyPromises.Contains(window));
|
||||
|
||||
nsCOMPtr<nsIGlobalObject> sgo = do_QueryInterface(window);
|
||||
ErrorResult result;
|
||||
nsRefPtr<Promise> promise = Promise::Create(sgo, result);
|
||||
if (result.Failed()) {
|
||||
return result.ErrorCode();
|
||||
}
|
||||
|
||||
nsRefPtr<nsIRunnable> runnable =
|
||||
new GetReadyPromiseRunnable(window, promise);
|
||||
promise.forget(aPromise);
|
||||
return NS_DispatchToCurrentThread(runnable);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ServiceWorkerManager::RemoveReadyPromise(nsIDOMWindow* aWindow)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
MOZ_ASSERT(aWindow);
|
||||
|
||||
nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aWindow);
|
||||
if (!window) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
mPendingReadyPromises.Remove(aWindow);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
ServiceWorkerManager::StorePendingReadyPromise(nsPIDOMWindow* aWindow,
|
||||
nsIURI* aURI,
|
||||
Promise* aPromise)
|
||||
{
|
||||
PendingReadyPromise* data;
|
||||
|
||||
// We should not have 2 pending promises for the same window.
|
||||
MOZ_ASSERT(!mPendingReadyPromises.Get(aWindow, &data));
|
||||
|
||||
data = new PendingReadyPromise(aURI, aPromise);
|
||||
mPendingReadyPromises.Put(aWindow, data);
|
||||
}
|
||||
|
||||
void
|
||||
ServiceWorkerManager::CheckPendingReadyPromises()
|
||||
{
|
||||
mPendingReadyPromises.Enumerate(CheckPendingReadyPromisesEnumerator, this);
|
||||
}
|
||||
|
||||
PLDHashOperator
|
||||
ServiceWorkerManager::CheckPendingReadyPromisesEnumerator(
|
||||
nsISupports* aSupports,
|
||||
nsAutoPtr<PendingReadyPromise>& aData,
|
||||
void* aPtr)
|
||||
{
|
||||
ServiceWorkerManager* aSwm = static_cast<ServiceWorkerManager*>(aPtr);
|
||||
|
||||
nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aSupports);
|
||||
|
||||
if (aSwm->CheckReadyPromise(window, aData->mURI, aData->mPromise)) {
|
||||
return PL_DHASH_REMOVE;
|
||||
}
|
||||
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
bool
|
||||
ServiceWorkerManager::CheckReadyPromise(nsPIDOMWindow* aWindow,
|
||||
nsIURI* aURI, Promise* aPromise)
|
||||
{
|
||||
nsRefPtr<ServiceWorkerRegistrationInfo> registration =
|
||||
GetServiceWorkerRegistrationInfo(aURI);
|
||||
|
||||
if (registration && registration->mCurrentWorker) {
|
||||
NS_ConvertUTF8toUTF16 scope(registration->mScope);
|
||||
nsRefPtr<ServiceWorkerRegistration> swr =
|
||||
new ServiceWorkerRegistration(aWindow, scope);
|
||||
aPromise->MaybeResolve(swr);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
ServiceWorkerManager::RejectUpdatePromiseObservers(ServiceWorkerRegistrationInfo* aRegistration,
|
||||
nsresult aRv)
|
||||
@ -1406,6 +1542,8 @@ public:
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
swm->CheckPendingReadyPromises();
|
||||
|
||||
// FIXME(nsm): Steps 7 of the algorithm.
|
||||
|
||||
swm->FireEventOnServiceWorkerRegistrations(mRegistration,
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include "nsRefPtrHashtable.h"
|
||||
#include "nsTArrayForwardDeclare.h"
|
||||
#include "nsTObserverArray.h"
|
||||
#include "nsClassHashtable.h"
|
||||
|
||||
class nsIScriptError;
|
||||
|
||||
@ -199,6 +200,7 @@ class ServiceWorkerManager MOZ_FINAL : public nsIServiceWorkerManager
|
||||
friend class CancelServiceWorkerInstallationRunnable;
|
||||
friend class ServiceWorkerRegistrationInfo;
|
||||
friend class ServiceWorkerUpdateInstance;
|
||||
friend class GetReadyPromiseRunnable;
|
||||
friend class GetRegistrationsRunnable;
|
||||
friend class GetRegistrationRunnable;
|
||||
friend class UnregisterRunnable;
|
||||
@ -389,6 +391,31 @@ private:
|
||||
FireEventOnServiceWorkerRegistrations(ServiceWorkerRegistrationInfo* aRegistration,
|
||||
const nsAString& aName);
|
||||
|
||||
void
|
||||
StorePendingReadyPromise(nsPIDOMWindow* aWindow, nsIURI* aURI, Promise* aPromise);
|
||||
|
||||
void
|
||||
CheckPendingReadyPromises();
|
||||
|
||||
bool
|
||||
CheckReadyPromise(nsPIDOMWindow* aWindow, nsIURI* aURI, Promise* aPromise);
|
||||
|
||||
struct PendingReadyPromise
|
||||
{
|
||||
PendingReadyPromise(nsIURI* aURI, Promise* aPromise)
|
||||
: mURI(aURI), mPromise(aPromise)
|
||||
{ }
|
||||
|
||||
nsCOMPtr<nsIURI> mURI;
|
||||
nsRefPtr<Promise> mPromise;
|
||||
};
|
||||
|
||||
static PLDHashOperator
|
||||
CheckPendingReadyPromisesEnumerator(nsISupports* aSupports,
|
||||
nsAutoPtr<PendingReadyPromise>& aData,
|
||||
void* aUnused);
|
||||
|
||||
nsClassHashtable<nsISupportsHashKey, PendingReadyPromise> mPendingReadyPromises;
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(ServiceWorkerManager,
|
||||
|
@ -7,6 +7,7 @@ support-files =
|
||||
parse_error_worker.js
|
||||
install_event_worker.js
|
||||
simpleregister/index.html
|
||||
simpleregister/ready.html
|
||||
controller/index.html
|
||||
unregister/index.html
|
||||
|
||||
|
15
dom/workers/test/serviceworkers/simpleregister/ready.html
Normal file
15
dom/workers/test/serviceworkers/simpleregister/ready.html
Normal file
@ -0,0 +1,15 @@
|
||||
<html>
|
||||
<head></head>
|
||||
<body>
|
||||
<script type="text/javascript">
|
||||
|
||||
window.addEventListener('message', function(evt) {
|
||||
navigator.serviceWorker.ready.then(function() {
|
||||
evt.ports[0].postMessage("WOW!");
|
||||
});
|
||||
}, false);
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -141,8 +141,34 @@
|
||||
return p;
|
||||
}
|
||||
|
||||
var readyPromiseResolved = false;
|
||||
|
||||
function readyPromise() {
|
||||
var frame = document.createElement("iframe");
|
||||
frame.setAttribute("id", "simpleregister-frame-ready");
|
||||
frame.setAttribute("src", new URL("simpleregister/ready.html", document.baseURI).href);
|
||||
document.body.appendChild(frame);
|
||||
|
||||
var channel = new MessageChannel();
|
||||
frame.addEventListener('load', function() {
|
||||
frame.contentWindow.postMessage('your port!', '*', [channel.port2]);
|
||||
}, false);
|
||||
|
||||
channel.port1.onmessage = function() {
|
||||
readyPromiseResolved = true;
|
||||
}
|
||||
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
function checkReadyPromise() {
|
||||
ok(readyPromiseResolved, "The ready promise has been resolved!");
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
function runTest() {
|
||||
simpleRegister()
|
||||
.then(readyPromise)
|
||||
.then(sameOriginWorker)
|
||||
.then(sameOriginScope)
|
||||
.then(httpsOnly)
|
||||
@ -151,6 +177,7 @@
|
||||
.then(networkError404)
|
||||
.then(parseError)
|
||||
.then(updatefound)
|
||||
.then(checkReadyPromise)
|
||||
// put more tests here.
|
||||
.then(function() {
|
||||
SimpleTest.finish();
|
||||
@ -162,6 +189,7 @@
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SpecialPowers.pushPrefEnv({"set": [
|
||||
["dom.messageChannel.enabled", true],
|
||||
["dom.serviceWorkers.enabled", true],
|
||||
["dom.serviceWorkers.testing.enabled", true]
|
||||
]}, runTest);
|
||||
|
Loading…
x
Reference in New Issue
Block a user