Update ANGLE
[WebKit-https.git] / Source / WebCore / workers / service / ServiceWorker.cpp
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 #include "ServiceWorker.h"
28
29 #if ENABLE(SERVICE_WORKER)
30
31 #include "Document.h"
32 #include "EventNames.h"
33 #include "Logging.h"
34 #include "MessagePort.h"
35 #include "SWClientConnection.h"
36 #include "ScriptExecutionContext.h"
37 #include "SerializedScriptValue.h"
38 #include "ServiceWorkerClientData.h"
39 #include "ServiceWorkerContainer.h"
40 #include "ServiceWorkerGlobalScope.h"
41 #include "ServiceWorkerProvider.h"
42 #include "ServiceWorkerThread.h"
43 #include <JavaScriptCore/JSCJSValueInlines.h>
44 #include <wtf/IsoMallocInlines.h>
45 #include <wtf/NeverDestroyed.h>
46
47 #define WORKER_RELEASE_LOG_IF_ALLOWED(fmt, ...) RELEASE_LOG_IF(isAlwaysOnLoggingAllowed(), ServiceWorker, "%p - ServiceWorker::" fmt, this, ##__VA_ARGS__)
48 #define WORKER_RELEASE_LOG_ERROR_IF_ALLOWED(fmt, ...) RELEASE_LOG_ERROR_IF(isAlwaysOnLoggingAllowed(), ServiceWorker, "%p - ServiceWorker::" fmt, this, ##__VA_ARGS__)
49
50 namespace WebCore {
51
52 WTF_MAKE_ISO_ALLOCATED_IMPL(ServiceWorker);
53
54 Ref<ServiceWorker> ServiceWorker::getOrCreate(ScriptExecutionContext& context, ServiceWorkerData&& data)
55 {
56     if (auto existingServiceWorker = context.serviceWorker(data.identifier))
57         return *existingServiceWorker;
58     return adoptRef(*new ServiceWorker(context, WTFMove(data)));
59 }
60
61 ServiceWorker::ServiceWorker(ScriptExecutionContext& context, ServiceWorkerData&& data)
62     : ActiveDOMObject(&context)
63     , m_data(WTFMove(data))
64 {
65     suspendIfNeeded();
66
67     context.registerServiceWorker(*this);
68
69     relaxAdoptionRequirement();
70     updatePendingActivityForEventDispatch();
71
72     WORKER_RELEASE_LOG_IF_ALLOWED("ServiceWorker: ID: %llu, state: %hhu", identifier().toUInt64(), m_data.state);
73 }
74
75 ServiceWorker::~ServiceWorker()
76 {
77     if (auto* context = scriptExecutionContext())
78         context->unregisterServiceWorker(*this);
79 }
80
81 void ServiceWorker::updateState(State state)
82 {
83     WORKER_RELEASE_LOG_IF_ALLOWED("updateState: Updating service worker %llu state from %hhu to %hhu. Registration ID: %llu", identifier().toUInt64(), m_data.state, state, registrationIdentifier().toUInt64());
84     m_data.state = state;
85     if (state != State::Installing && !m_isStopped) {
86         ASSERT(m_pendingActivityForEventDispatch);
87         dispatchEvent(Event::create(eventNames().statechangeEvent, Event::CanBubble::No, Event::IsCancelable::No));
88     }
89
90     updatePendingActivityForEventDispatch();
91 }
92
93 ExceptionOr<void> ServiceWorker::postMessage(ScriptExecutionContext& context, JSC::JSValue messageValue, Vector<JSC::Strong<JSC::JSObject>>&& transfer)
94 {
95     if (m_isStopped || !context.sessionID().isValid())
96         return Exception { InvalidStateError };
97
98     auto* execState = context.execState();
99     ASSERT(execState);
100
101     Vector<RefPtr<MessagePort>> ports;
102     auto messageData = SerializedScriptValue::create(*execState, messageValue, WTFMove(transfer), ports, SerializationContext::WorkerPostMessage);
103     if (messageData.hasException())
104         return messageData.releaseException();
105
106     // Disentangle the port in preparation for sending it to the remote context.
107     auto portsOrException = MessagePort::disentanglePorts(WTFMove(ports));
108     if (portsOrException.hasException())
109         return portsOrException.releaseException();
110
111     ServiceWorkerOrClientIdentifier sourceIdentifier;
112     if (is<ServiceWorkerGlobalScope>(context))
113         sourceIdentifier = downcast<ServiceWorkerGlobalScope>(context).thread().identifier();
114     else {
115         auto& connection = ServiceWorkerProvider::singleton().serviceWorkerConnectionForSession(context.sessionID());
116         sourceIdentifier = ServiceWorkerClientIdentifier { connection.serverConnectionIdentifier(), downcast<Document>(context).identifier() };
117     }
118
119     MessageWithMessagePorts message = { messageData.releaseReturnValue(), portsOrException.releaseReturnValue() };
120     callOnMainThread([sessionID = context.sessionID(), destinationIdentifier = identifier(), message = WTFMove(message), sourceIdentifier = WTFMove(sourceIdentifier)]() mutable {
121         auto& connection = ServiceWorkerProvider::singleton().serviceWorkerConnectionForSession(sessionID);
122         connection.postMessageToServiceWorker(destinationIdentifier, WTFMove(message), sourceIdentifier);
123     });
124     return { };
125 }
126
127 EventTargetInterface ServiceWorker::eventTargetInterface() const
128 {
129     return ServiceWorkerEventTargetInterfaceType;
130 }
131
132 ScriptExecutionContext* ServiceWorker::scriptExecutionContext() const
133 {
134     return ContextDestructionObserver::scriptExecutionContext();
135 }
136
137 const char* ServiceWorker::activeDOMObjectName() const
138 {
139     return "ServiceWorker";
140 }
141
142 bool ServiceWorker::canSuspendForDocumentSuspension() const
143 {
144     // FIXME: We should do better as this prevents the page from entering PageCache when there is a Service Worker.
145     return !hasPendingActivity();
146 }
147
148 void ServiceWorker::stop()
149 {
150     m_isStopped = true;
151     removeAllEventListeners();
152     scriptExecutionContext()->unregisterServiceWorker(*this);
153     updatePendingActivityForEventDispatch();
154 }
155
156 void ServiceWorker::updatePendingActivityForEventDispatch()
157 {
158     // ServiceWorkers can dispatch events until they become redundant or they are stopped.
159     if (m_isStopped || state() == State::Redundant) {
160         m_pendingActivityForEventDispatch = nullptr;
161         return;
162     }
163     if (m_pendingActivityForEventDispatch)
164         return;
165     m_pendingActivityForEventDispatch = makePendingActivity(*this);
166 }
167
168 bool ServiceWorker::isAlwaysOnLoggingAllowed() const
169 {
170     auto* context = scriptExecutionContext();
171     if (!context)
172         return false;
173
174     auto* container = context->serviceWorkerContainer();
175     if (!container)
176         return false;
177
178     return container->isAlwaysOnLoggingAllowed();
179 }
180
181 } // namespace WebCore
182
183 #endif // ENABLE(SERVICE_WORKER)