1/*
2 * Copyright (C) 2017 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27
28#if ENABLE(SERVICE_WORKER)
29#include "ServiceWorkerClients.h"
30
31#include "JSDOMPromiseDeferred.h"
32#include "JSServiceWorkerWindowClient.h"
33#include "SWContextManager.h"
34#include "ServiceWorker.h"
35#include "ServiceWorkerGlobalScope.h"
36#include "ServiceWorkerThread.h"
37
38namespace WebCore {
39
40static inline void didFinishGetRequest(ServiceWorkerGlobalScope& scope, DeferredPromise& promise, ExceptionOr<Optional<ServiceWorkerClientData>>&& clientData)
41{
42 if (clientData.hasException()) {
43 promise.reject(clientData.releaseException());
44 return;
45 }
46 auto data = clientData.releaseReturnValue();
47 if (!data) {
48 promise.resolve();
49 return;
50 }
51
52 promise.resolve<IDLInterface<ServiceWorkerClient>>(ServiceWorkerClient::getOrCreate(scope, WTFMove(data.value())));
53}
54
55void ServiceWorkerClients::get(ScriptExecutionContext& context, const String& id, Ref<DeferredPromise>&& promise)
56{
57 auto identifier = ServiceWorkerClientIdentifier::fromString(id);
58 if (!identifier) {
59 promise->resolve();
60 return;
61 }
62 auto clientIdentifier = identifier.value();
63
64 auto serviceWorkerIdentifier = downcast<ServiceWorkerGlobalScope>(context).thread().identifier();
65
66 auto promisePointer = promise.ptr();
67 m_pendingPromises.add(promisePointer, WTFMove(promise));
68
69 callOnMainThread([promisePointer, serviceWorkerIdentifier, clientIdentifier] () {
70 auto connection = SWContextManager::singleton().connection();
71 connection->findClientByIdentifier(serviceWorkerIdentifier, clientIdentifier, [promisePointer, serviceWorkerIdentifier] (auto&& clientData) {
72 SWContextManager::singleton().postTaskToServiceWorker(serviceWorkerIdentifier, [promisePointer, data = crossThreadCopy(clientData)] (auto& context) mutable {
73 if (auto promise = context.clients().m_pendingPromises.take(promisePointer))
74 didFinishGetRequest(context, *promise, WTFMove(data));
75 });
76 });
77 });
78}
79
80
81static inline void matchAllCompleted(ServiceWorkerGlobalScope& scope, DeferredPromise& promise, Vector<ServiceWorkerClientData>&& clientsData)
82{
83 auto clients = WTF::map(clientsData, [&] (auto&& clientData) {
84 return ServiceWorkerClient::getOrCreate(scope, WTFMove(clientData));
85 });
86 promise.resolve<IDLSequence<IDLInterface<ServiceWorkerClient>>>(WTFMove(clients));
87}
88
89void ServiceWorkerClients::matchAll(ScriptExecutionContext& context, const ClientQueryOptions& options, Ref<DeferredPromise>&& promise)
90{
91 auto promisePointer = promise.ptr();
92 m_pendingPromises.add(promisePointer, WTFMove(promise));
93
94 auto serviceWorkerIdentifier = downcast<ServiceWorkerGlobalScope>(context).thread().identifier();
95
96 callOnMainThread([promisePointer, serviceWorkerIdentifier, options] () mutable {
97 auto connection = SWContextManager::singleton().connection();
98 connection->matchAll(serviceWorkerIdentifier, options, [promisePointer, serviceWorkerIdentifier] (auto&& clientsData) mutable {
99 SWContextManager::singleton().postTaskToServiceWorker(serviceWorkerIdentifier, [promisePointer, clientsData = crossThreadCopy(clientsData)] (auto& scope) mutable {
100 if (auto promise = scope.clients().m_pendingPromises.take(promisePointer))
101 matchAllCompleted(scope, *promise, WTFMove(clientsData));
102 });
103 });
104 });
105}
106
107void ServiceWorkerClients::openWindow(ScriptExecutionContext&, const String& url, Ref<DeferredPromise>&& promise)
108{
109 UNUSED_PARAM(url);
110 promise->reject(Exception { NotSupportedError, "clients.openWindow() is not yet supported"_s });
111}
112
113void ServiceWorkerClients::claim(ScriptExecutionContext& context, Ref<DeferredPromise>&& promise)
114{
115 auto& serviceWorkerGlobalScope = downcast<ServiceWorkerGlobalScope>(context);
116
117 auto serviceWorkerIdentifier = serviceWorkerGlobalScope.thread().identifier();
118
119 if (!serviceWorkerGlobalScope.registration().active() || serviceWorkerGlobalScope.registration().active()->identifier() != serviceWorkerIdentifier) {
120 promise->reject(Exception { InvalidStateError, "Service worker is not active"_s });
121 return;
122 }
123
124 auto promisePointer = promise.ptr();
125 m_pendingPromises.add(promisePointer, WTFMove(promise));
126
127 callOnMainThread([promisePointer, serviceWorkerIdentifier] () mutable {
128 auto connection = SWContextManager::singleton().connection();
129 connection->claim(serviceWorkerIdentifier, [promisePointer, serviceWorkerIdentifier] () mutable {
130 SWContextManager::singleton().postTaskToServiceWorker(serviceWorkerIdentifier, [promisePointer] (auto& scope) mutable {
131 if (auto promise = scope.clients().m_pendingPromises.take(promisePointer))
132 promise.value()->resolve();
133 });
134 });
135 });
136}
137
138} // namespace WebCore
139
140#endif // ENABLE(SERVICE_WORKER)
141