Remove unnecessary includes
[WebKit-https.git] / Source / WebCore / dom / MessagePort.cpp
1 /*
2  * Copyright (C) 2008 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. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  *
25  */
26
27 #include "config.h"
28 #include "MessagePort.h"
29
30 #include "Document.h"
31 #include "EventNames.h"
32 #include "ExceptionCode.h"
33 #include "MessageEvent.h"
34 #include "WorkerGlobalScope.h"
35
36 namespace WebCore {
37
38 MessagePort::MessagePort(ScriptExecutionContext& scriptExecutionContext)
39     : m_scriptExecutionContext(&scriptExecutionContext)
40 {
41     m_scriptExecutionContext->createdMessagePort(*this);
42
43     // Don't need to call processMessagePortMessagesSoon() here, because the port will not be opened until start() is invoked.
44 }
45
46 MessagePort::~MessagePort()
47 {
48     close();
49     if (m_scriptExecutionContext)
50         m_scriptExecutionContext->destroyedMessagePort(*this);
51 }
52
53 ExceptionOr<void> MessagePort::postMessage(JSC::ExecState& state, JSC::JSValue messageValue, Vector<JSC::Strong<JSC::JSObject>>&& transfer)
54 {
55     Vector<RefPtr<MessagePort>> ports;
56     auto message = SerializedScriptValue::create(state, messageValue, WTFMove(transfer), ports);
57     if (message.hasException())
58         return message.releaseException();
59
60     if (!isEntangled())
61         return { };
62     ASSERT(m_scriptExecutionContext);
63
64     std::unique_ptr<MessagePortChannelArray> channels;
65     // Make sure we aren't connected to any of the passed-in ports.
66     if (!ports.isEmpty()) {
67         for (auto& dataPort : ports) {
68             if (dataPort == this || m_entangledChannel->isConnectedTo(dataPort.get()))
69                 return Exception { DATA_CLONE_ERR };
70         }
71         auto disentangleResult = MessagePort::disentanglePorts(WTFMove(ports));
72         if (disentangleResult.hasException())
73             return disentangleResult.releaseException();
74         channels = disentangleResult.releaseReturnValue();
75     }
76     m_entangledChannel->postMessageToRemote(message.releaseReturnValue(), WTFMove(channels));
77     return { };
78 }
79
80 std::unique_ptr<MessagePortChannel> MessagePort::disentangle()
81 {
82     ASSERT(m_entangledChannel);
83
84     m_entangledChannel->disentangle();
85
86     // We can't receive any messages or generate any events after this, so remove ourselves from the list of active ports.
87     ASSERT(m_scriptExecutionContext);
88     m_scriptExecutionContext->destroyedMessagePort(*this);
89     m_scriptExecutionContext = nullptr;
90
91     return WTFMove(m_entangledChannel);
92 }
93
94 // Invoked to notify us that there are messages available for this port.
95 // This code may be called from another thread, and so should not call any non-threadsafe APIs (i.e. should not call into the entangled channel or access mutable variables).
96 void MessagePort::messageAvailable()
97 {
98     ASSERT(m_scriptExecutionContext);
99     m_scriptExecutionContext->processMessagePortMessagesSoon();
100 }
101
102 void MessagePort::start()
103 {
104     // Do nothing if we've been cloned or closed.
105     if (!isEntangled())
106         return;
107
108     ASSERT(m_scriptExecutionContext);
109     if (m_started)
110         return;
111
112     m_started = true;
113     m_scriptExecutionContext->processMessagePortMessagesSoon();
114 }
115
116 void MessagePort::close()
117 {
118     if (isEntangled())
119         m_entangledChannel->close();
120     m_closed = true;
121 }
122
123 void MessagePort::entangle(std::unique_ptr<MessagePortChannel>&& remote)
124 {
125     // Only invoked to set our initial entanglement.
126     ASSERT(!m_entangledChannel);
127     ASSERT(m_scriptExecutionContext);
128
129     // Don't entangle the ports if the channel is closed.
130     if (remote->entangleIfOpen(this))
131         m_entangledChannel = WTFMove(remote);
132 }
133
134 void MessagePort::contextDestroyed()
135 {
136     ASSERT(m_scriptExecutionContext);
137     // Must be closed before blowing away the cached context, to ensure that we get no more calls to messageAvailable().
138     // ScriptExecutionContext::closeMessagePorts() takes care of that.
139     ASSERT(m_closed);
140     m_scriptExecutionContext = nullptr;
141 }
142
143 void MessagePort::dispatchMessages()
144 {
145     // Messages for contexts that are not fully active get dispatched too, but JSAbstractEventListener::handleEvent() doesn't call handlers for these.
146     // The HTML5 spec specifies that any messages sent to a document that is not fully active should be dropped, so this behavior is OK.
147     ASSERT(started());
148
149     RefPtr<SerializedScriptValue> message;
150     std::unique_ptr<MessagePortChannelArray> channels;
151     while (m_entangledChannel && m_entangledChannel->tryGetMessageFromRemote(message, channels)) {
152
153         // close() in Worker onmessage handler should prevent next message from dispatching.
154         if (is<WorkerGlobalScope>(*m_scriptExecutionContext) && downcast<WorkerGlobalScope>(*m_scriptExecutionContext).isClosing())
155             return;
156
157         auto ports = MessagePort::entanglePorts(*m_scriptExecutionContext, WTFMove(channels));
158         dispatchEvent(MessageEvent::create(WTFMove(ports), WTFMove(message)));
159     }
160 }
161
162 bool MessagePort::hasPendingActivity()
163 {
164     // The spec says that entangled message ports should always be treated as if they have a strong reference.
165     // We'll also stipulate that the queue needs to be open (if the app drops its reference to the port before start()-ing it, then it's not really entangled as it's unreachable).
166     if (m_started && m_entangledChannel && m_entangledChannel->hasPendingActivity())
167         return true;
168     if (isEntangled() && !locallyEntangledPort())
169         return true;
170     return false;
171 }
172
173 MessagePort* MessagePort::locallyEntangledPort()
174 {
175     return m_entangledChannel ? m_entangledChannel->locallyEntangledPort(m_scriptExecutionContext) : nullptr;
176 }
177
178 ExceptionOr<std::unique_ptr<MessagePortChannelArray>> MessagePort::disentanglePorts(Vector<RefPtr<MessagePort>>&& ports)
179 {
180     if (ports.isEmpty())
181         return nullptr;
182
183     // Walk the incoming array - if there are any duplicate ports, or null ports or cloned ports, throw an error (per section 8.3.3 of the HTML5 spec).
184     HashSet<MessagePort*> portSet;
185     for (auto& port : ports) {
186         if (!port || port->isNeutered() || !portSet.add(port.get()).isNewEntry)
187             return Exception { DATA_CLONE_ERR };
188     }
189
190     // Passed-in ports passed validity checks, so we can disentangle them.
191     auto portArray = std::make_unique<MessagePortChannelArray>(ports.size());
192     for (unsigned i = 0 ; i < ports.size(); ++i)
193         (*portArray)[i] = ports[i]->disentangle();
194     return WTFMove(portArray);
195 }
196
197 Vector<RefPtr<MessagePort>> MessagePort::entanglePorts(ScriptExecutionContext& context, std::unique_ptr<MessagePortChannelArray>&& channels)
198 {
199     if (!channels || !channels->size())
200         return { };
201
202     Vector<RefPtr<MessagePort>> portArray;
203     portArray.reserveInitialCapacity(channels->size());
204     for (unsigned int i = 0; i < channels->size(); ++i) {
205         auto port = MessagePort::create(context);
206         port->entangle(WTFMove((*channels)[i]));
207         portArray.uncheckedAppend(WTFMove(port));
208     }
209     return portArray;
210 }
211
212 bool MessagePort::addEventListener(const AtomicString& eventType, Ref<EventListener>&& listener, const AddEventListenerOptions& options)
213 {
214     if (listener->isAttribute() && eventType == eventNames().messageEvent)
215         start();
216     return EventTargetWithInlineData::addEventListener(eventType, WTFMove(listener), options);
217 }
218
219 } // namespace WebCore