Implement "UpdateWorkerState" and use it
[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 "EventNames.h"
32 #include "MessagePort.h"
33 #include "SWClientConnection.h"
34 #include "ScriptExecutionContext.h"
35 #include "SerializedScriptValue.h"
36 #include "ServiceWorkerProvider.h"
37 #include <runtime/JSCJSValueInlines.h>
38 #include <wtf/NeverDestroyed.h>
39
40 namespace WebCore {
41
42 const HashMap<ServiceWorkerIdentifier, HashSet<ServiceWorker*>>& ServiceWorker::allWorkers()
43 {
44     return mutableAllWorkers();
45 }
46
47 HashMap<ServiceWorkerIdentifier, HashSet<ServiceWorker*>>& ServiceWorker::mutableAllWorkers()
48 {
49     // FIXME: Once we support service workers from workers, this will need to change.
50     RELEASE_ASSERT(isMainThread());
51     
52     static NeverDestroyed<HashMap<ServiceWorkerIdentifier, HashSet<ServiceWorker*>>> allWorkersMap;
53     return allWorkersMap;
54 }
55
56 ServiceWorker::ServiceWorker(ScriptExecutionContext& context, ServiceWorkerIdentifier identifier, const URL& scriptURL)
57     : ContextDestructionObserver(&context)
58     , m_identifier(identifier)
59     , m_scriptURL(scriptURL)
60 {
61     auto result = mutableAllWorkers().ensure(identifier, [] {
62         return HashSet<ServiceWorker*>();
63     });
64     result.iterator->value.add(this);
65 }
66
67 ServiceWorker::~ServiceWorker()
68 {
69     auto iterator = mutableAllWorkers().find(m_identifier);
70
71     ASSERT(iterator->value.contains(this));
72     iterator->value.remove(this);
73
74     if (iterator->value.isEmpty())
75         mutableAllWorkers().remove(iterator);
76 }
77
78 void ServiceWorker::updateWorkerState(State state, ShouldFireStateChangeEvent shouldFire)
79 {
80     // FIXME: Once we support service workers from workers, this might need to change.
81     RELEASE_ASSERT(isMainThread());
82
83     m_state = state;
84     
85     if (shouldFire == FireStateChangeEvent)
86         dispatchEvent(Event::create(eventNames().statechangeEvent, false, false));
87 }
88
89 ExceptionOr<void> ServiceWorker::postMessage(ScriptExecutionContext& context, JSC::JSValue messageValue, Vector<JSC::Strong<JSC::JSObject>>&& transfer)
90 {
91     if (state() == State::Redundant)
92         return Exception { InvalidStateError, ASCIILiteral("Service Worker state is redundant") };
93
94     // FIXME: Invoke Run Service Worker algorithm with serviceWorker as the argument.
95
96     auto* execState = context.execState();
97     ASSERT(execState);
98
99     Vector<RefPtr<MessagePort>> ports;
100     auto message = SerializedScriptValue::create(*execState, messageValue, WTFMove(transfer), ports, SerializationContext::WorkerPostMessage);
101     if (message.hasException())
102         return message.releaseException();
103
104     // Disentangle the port in preparation for sending it to the remote context.
105     auto channelsOrException = MessagePort::disentanglePorts(WTFMove(ports));
106     if (channelsOrException.hasException())
107         return channelsOrException.releaseException();
108
109     // FIXME: Support sending the channels.
110     auto channels = channelsOrException.releaseReturnValue();
111     if (channels && !channels->isEmpty())
112         return Exception { NotSupportedError, ASCIILiteral("Passing MessagePort objects to postMessage is not yet supported") };
113
114     auto& swConnection = ServiceWorkerProvider::singleton().serviceWorkerConnectionForSession(context.sessionID());
115     swConnection.postMessageToServiceWorkerGlobalScope(m_identifier, message.releaseReturnValue(), context);
116
117     return { };
118 }
119
120 EventTargetInterface ServiceWorker::eventTargetInterface() const
121 {
122     return ServiceWorkerEventTargetInterfaceType;
123 }
124
125 ScriptExecutionContext* ServiceWorker::scriptExecutionContext() const
126 {
127     return ContextDestructionObserver::scriptExecutionContext();
128 }
129
130 } // namespace WebCore
131
132 #endif // ENABLE(SERVICE_WORKER)