| // Copyright 2014 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "config.h" |
| #include "ServiceWorkerRegistration.h" |
| |
| #include "bindings/core/v8/CallbackPromiseAdapter.h" |
| #include "bindings/core/v8/ScriptPromise.h" |
| #include "bindings/core/v8/ScriptPromiseResolver.h" |
| #include "bindings/core/v8/ScriptState.h" |
| #include "core/dom/DOMException.h" |
| #include "core/dom/ExceptionCode.h" |
| #include "core/dom/ExecutionContext.h" |
| #include "core/events/Event.h" |
| #include "modules/EventTargetModules.h" |
| #include "modules/serviceworkers/ServiceWorkerContainerClient.h" |
| #include "modules/serviceworkers/ServiceWorkerError.h" |
| #include "public/platform/WebServiceWorkerProvider.h" |
| |
| namespace blink { |
| |
| class UndefinedValue { |
| public: |
| typedef WebServiceWorkerRegistration WebType; |
| static V8UndefinedType take(ScriptPromiseResolver* resolver, WebType* registration) |
| { |
| ASSERT(!registration); // Anything passed here will be leaked. |
| return V8UndefinedType(); |
| } |
| static void dispose(WebType* registration) |
| { |
| ASSERT(!registration); // Anything passed here will be leaked. |
| } |
| |
| private: |
| UndefinedValue(); |
| }; |
| |
| static void deleteIfNoExistingOwner(WebServiceWorker* serviceWorker) |
| { |
| if (serviceWorker && !serviceWorker->proxy()) |
| delete serviceWorker; |
| } |
| |
| const AtomicString& ServiceWorkerRegistration::interfaceName() const |
| { |
| return EventTargetNames::ServiceWorkerRegistration; |
| } |
| |
| void ServiceWorkerRegistration::dispatchUpdateFoundEvent() |
| { |
| dispatchEvent(Event::create(EventTypeNames::updatefound)); |
| } |
| |
| void ServiceWorkerRegistration::setInstalling(WebServiceWorker* serviceWorker) |
| { |
| if (!executionContext()) { |
| deleteIfNoExistingOwner(serviceWorker); |
| return; |
| } |
| m_installing = ServiceWorker::from(executionContext(), serviceWorker); |
| } |
| |
| void ServiceWorkerRegistration::setWaiting(WebServiceWorker* serviceWorker) |
| { |
| if (!executionContext()) { |
| deleteIfNoExistingOwner(serviceWorker); |
| return; |
| } |
| m_waiting = ServiceWorker::from(executionContext(), serviceWorker); |
| } |
| |
| void ServiceWorkerRegistration::setActive(WebServiceWorker* serviceWorker) |
| { |
| if (!executionContext()) { |
| deleteIfNoExistingOwner(serviceWorker); |
| return; |
| } |
| m_active = ServiceWorker::from(executionContext(), serviceWorker); |
| } |
| |
| PassRefPtrWillBeRawPtr<ServiceWorkerRegistration> ServiceWorkerRegistration::take(ScriptPromiseResolver* resolver, WebType* registration) |
| { |
| if (!registration) |
| return nullptr; |
| return getOrCreate(resolver->scriptState()->executionContext(), registration); |
| } |
| |
| void ServiceWorkerRegistration::dispose(WebType* registration) |
| { |
| delete registration; |
| } |
| |
| String ServiceWorkerRegistration::scope() const |
| { |
| return m_outerRegistration->scope().string(); |
| } |
| |
| ScriptPromise ServiceWorkerRegistration::unregister(ScriptState* scriptState) |
| { |
| RefPtr<ScriptPromiseResolver> resolver = ScriptPromiseResolver::create(scriptState); |
| ScriptPromise promise = resolver->promise(); |
| |
| if (!m_provider) { |
| resolver->reject(DOMException::create(InvalidStateError, "No associated provider is available")); |
| return promise; |
| } |
| |
| RefPtr<SecurityOrigin> documentOrigin = scriptState->executionContext()->securityOrigin(); |
| KURL scopeURL = scriptState->executionContext()->completeURL(scope()); |
| scopeURL.removeFragmentIdentifier(); |
| if (!scope().isEmpty() && !documentOrigin->canRequest(scopeURL)) { |
| resolver->reject(DOMException::create(SecurityError, "Can only unregister for scopes in the document's origin.")); |
| return promise; |
| } |
| |
| m_provider->unregisterServiceWorker(scopeURL, new CallbackPromiseAdapter<UndefinedValue, ServiceWorkerError>(resolver)); |
| return promise; |
| } |
| |
| PassRefPtrWillBeRawPtr<ServiceWorkerRegistration> ServiceWorkerRegistration::getOrCreate(ExecutionContext* executionContext, WebServiceWorkerRegistration* outerRegistration) |
| { |
| if (!outerRegistration) |
| return nullptr; |
| |
| WebServiceWorkerRegistrationProxy* proxy = outerRegistration->proxy(); |
| if (proxy) { |
| ServiceWorkerRegistration* existingRegistration = *proxy; |
| if (existingRegistration) { |
| ASSERT(existingRegistration->executionContext() == executionContext); |
| return existingRegistration; |
| } |
| } |
| |
| RefPtrWillBeRawPtr<ServiceWorkerRegistration> registration = adoptRefWillBeRefCountedGarbageCollected(new ServiceWorkerRegistration(executionContext, adoptPtr(outerRegistration))); |
| registration->suspendIfNeeded(); |
| return registration.release(); |
| } |
| |
| ServiceWorkerRegistration::ServiceWorkerRegistration(ExecutionContext* executionContext, PassOwnPtr<WebServiceWorkerRegistration> outerRegistration) |
| : ActiveDOMObject(executionContext) |
| , WebServiceWorkerRegistrationProxy(this) |
| , m_outerRegistration(outerRegistration) |
| , m_provider(0) |
| , m_stopped(false) |
| { |
| ASSERT(m_outerRegistration); |
| ScriptWrappable::init(this); |
| |
| if (!executionContext) |
| return; |
| if (ServiceWorkerContainerClient* client = ServiceWorkerContainerClient::from(executionContext)) |
| m_provider = client->provider(); |
| m_outerRegistration->setProxy(this); |
| } |
| |
| void ServiceWorkerRegistration::trace(Visitor* visitor) |
| { |
| visitor->trace(m_installing); |
| visitor->trace(m_waiting); |
| visitor->trace(m_active); |
| EventTargetWithInlineData::trace(visitor); |
| } |
| |
| bool ServiceWorkerRegistration::hasPendingActivity() const |
| { |
| return !m_stopped; |
| } |
| |
| void ServiceWorkerRegistration::stop() |
| { |
| if (m_stopped) |
| return; |
| m_stopped = true; |
| m_outerRegistration->proxyStopped(); |
| } |
| |
| } // namespace blink |