OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2008 Apple Inc. All Rights Reserved. | 2 * Copyright (C) 2008 Apple Inc. All Rights Reserved. |
3 * | 3 * |
4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
5 * modification, are permitted provided that the following conditions | 5 * modification, are permitted provided that the following conditions |
6 * are met: | 6 * are met: |
7 * 1. Redistributions of source code must retain the above copyright | 7 * 1. Redistributions of source code must retain the above copyright |
8 * notice, this list of conditions and the following disclaimer. | 8 * notice, this list of conditions and the following disclaimer. |
9 * 2. Redistributions in binary form must reproduce the above copyright | 9 * 2. Redistributions in binary form must reproduce the above copyright |
10 * notice, this list of conditions and the following disclaimer in the | 10 * notice, this list of conditions and the following disclaimer in the |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
69 | 69 |
70 // Make sure we aren't connected to any of the passed-in ports. | 70 // Make sure we aren't connected to any of the passed-in ports. |
71 for (unsigned i = 0; i < ports.size(); ++i) { | 71 for (unsigned i = 0; i < ports.size(); ++i) { |
72 if (ports[i] == this) { | 72 if (ports[i] == this) { |
73 exceptionState.throwDOMException( | 73 exceptionState.throwDOMException( |
74 DataCloneError, | 74 DataCloneError, |
75 "Port at index " + String::number(i) + " contains the source port."); | 75 "Port at index " + String::number(i) + " contains the source port."); |
76 return; | 76 return; |
77 } | 77 } |
78 } | 78 } |
79 std::unique_ptr<MessagePortChannelArray> channels = | 79 MessagePortChannelArray channels = |
80 MessagePort::disentanglePorts(scriptState->getExecutionContext(), ports, | 80 MessagePort::disentanglePorts(scriptState->getExecutionContext(), ports, |
81 exceptionState); | 81 exceptionState); |
82 if (exceptionState.hadException()) | 82 if (exceptionState.hadException()) |
83 return; | 83 return; |
84 | 84 |
85 WebString messageString = message->toWireString(); | 85 WebString messageString = message->toWireString(); |
86 std::unique_ptr<WebMessagePortChannelArray> webChannels = | 86 WebMessagePortChannelArray webChannels = |
87 toWebMessagePortChannelArray(std::move(channels)); | 87 toWebMessagePortChannelArray(std::move(channels)); |
88 m_entangledChannel->postMessage(messageString, webChannels.release()); | 88 m_entangledChannel->postMessage(messageString, std::move(webChannels)); |
89 } | 89 } |
90 | 90 |
91 // static | 91 // static |
92 std::unique_ptr<WebMessagePortChannelArray> | 92 WebMessagePortChannelArray MessagePort::toWebMessagePortChannelArray( |
93 MessagePort::toWebMessagePortChannelArray( | 93 MessagePortChannelArray channels) { |
94 std::unique_ptr<MessagePortChannelArray> channels) { | 94 WebMessagePortChannelArray webChannels(channels.size()); |
95 std::unique_ptr<WebMessagePortChannelArray> webChannels; | 95 for (size_t i = 0; i < channels.size(); ++i) |
96 if (channels && channels->size()) { | 96 webChannels[i] = std::move(channels[i]); |
97 webChannels = | |
98 WTF::wrapUnique(new WebMessagePortChannelArray(channels->size())); | |
99 for (size_t i = 0; i < channels->size(); ++i) | |
100 (*webChannels)[i] = (*channels)[i].release(); | |
101 } | |
102 return webChannels; | 97 return webChannels; |
103 } | 98 } |
104 | 99 |
105 // static | 100 // static |
106 MessagePortArray* MessagePort::toMessagePortArray( | 101 MessagePortArray* MessagePort::toMessagePortArray( |
107 ExecutionContext* context, | 102 ExecutionContext* context, |
108 const WebMessagePortChannelArray& webChannels) { | 103 WebMessagePortChannelArray webChannels) { |
109 std::unique_ptr<MessagePortChannelArray> channels = | 104 MessagePortChannelArray channels(webChannels.size()); |
110 WTF::wrapUnique(new MessagePortChannelArray(webChannels.size())); | |
111 for (size_t i = 0; i < webChannels.size(); ++i) | 105 for (size_t i = 0; i < webChannels.size(); ++i) |
112 (*channels)[i] = WebMessagePortChannelUniquePtr(webChannels[i]); | 106 channels[i] = std::move(webChannels[i]); |
113 return MessagePort::entanglePorts(*context, std::move(channels)); | 107 return MessagePort::entanglePorts(*context, std::move(channels)); |
114 } | 108 } |
115 | 109 |
116 WebMessagePortChannelUniquePtr MessagePort::disentangle() { | 110 WebMessagePortChannelUniquePtr MessagePort::disentangle() { |
117 DCHECK(m_entangledChannel); | 111 DCHECK(m_entangledChannel); |
118 m_entangledChannel->setClient(nullptr); | 112 m_entangledChannel->setClient(nullptr); |
119 return std::move(m_entangledChannel); | 113 return std::move(m_entangledChannel); |
120 } | 114 } |
121 | 115 |
122 // Invoked to notify us that there are messages available for this port. | 116 // Invoked to notify us that there are messages available for this port. |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
158 DCHECK(!m_entangledChannel); | 152 DCHECK(!m_entangledChannel); |
159 DCHECK(getExecutionContext()); | 153 DCHECK(getExecutionContext()); |
160 | 154 |
161 m_entangledChannel = std::move(remote); | 155 m_entangledChannel = std::move(remote); |
162 } | 156 } |
163 | 157 |
164 const AtomicString& MessagePort::interfaceName() const { | 158 const AtomicString& MessagePort::interfaceName() const { |
165 return EventTargetNames::MessagePort; | 159 return EventTargetNames::MessagePort; |
166 } | 160 } |
167 | 161 |
168 static bool tryGetMessageFrom( | 162 static bool tryGetMessageFrom(WebMessagePortChannel& webChannel, |
169 WebMessagePortChannel& webChannel, | 163 RefPtr<SerializedScriptValue>& message, |
170 RefPtr<SerializedScriptValue>& message, | 164 MessagePortChannelArray& channels) { |
171 std::unique_ptr<MessagePortChannelArray>& channels) { | |
172 WebString messageString; | 165 WebString messageString; |
173 WebMessagePortChannelArray webChannels; | 166 WebMessagePortChannelArray webChannels; |
174 if (!webChannel.tryGetMessage(&messageString, webChannels)) | 167 if (!webChannel.tryGetMessage(&messageString, webChannels)) |
175 return false; | 168 return false; |
176 | 169 |
177 if (webChannels.size()) { | 170 if (webChannels.size()) { |
178 channels = WTF::wrapUnique(new MessagePortChannelArray(webChannels.size())); | 171 channels.resize(webChannels.size()); |
179 for (size_t i = 0; i < webChannels.size(); ++i) | 172 for (size_t i = 0; i < webChannels.size(); ++i) |
180 (*channels)[i] = WebMessagePortChannelUniquePtr(webChannels[i]); | 173 channels[i] = std::move(webChannels[i]); |
181 } | 174 } |
182 message = SerializedScriptValue::create(messageString); | 175 message = SerializedScriptValue::create(messageString); |
183 return true; | 176 return true; |
184 } | 177 } |
185 | 178 |
186 bool MessagePort::tryGetMessage( | 179 bool MessagePort::tryGetMessage(RefPtr<SerializedScriptValue>& message, |
187 RefPtr<SerializedScriptValue>& message, | 180 MessagePortChannelArray& channels) { |
188 std::unique_ptr<MessagePortChannelArray>& channels) { | |
189 if (!m_entangledChannel) | 181 if (!m_entangledChannel) |
190 return false; | 182 return false; |
191 return tryGetMessageFrom(*m_entangledChannel, message, channels); | 183 return tryGetMessageFrom(*m_entangledChannel, message, channels); |
192 } | 184 } |
193 | 185 |
194 void MessagePort::dispatchMessages() { | 186 void MessagePort::dispatchMessages() { |
195 // Messages for contexts that are not fully active get dispatched too, but | 187 // Messages for contexts that are not fully active get dispatched too, but |
196 // JSAbstractEventListener::handleEvent() doesn't call handlers for these. | 188 // JSAbstractEventListener::handleEvent() doesn't call handlers for these. |
197 // The HTML5 spec specifies that any messages sent to a document that is not | 189 // The HTML5 spec specifies that any messages sent to a document that is not |
198 // fully active should be dropped, so this behavior is OK. | 190 // fully active should be dropped, so this behavior is OK. |
199 if (!started()) | 191 if (!started()) |
200 return; | 192 return; |
201 | 193 |
202 while (true) { | 194 while (true) { |
203 // Because close() doesn't cancel any in flight calls to dispatchMessages(), | 195 // Because close() doesn't cancel any in flight calls to dispatchMessages(), |
204 // and can be triggered by the onmessage event handler, we need to check if | 196 // and can be triggered by the onmessage event handler, we need to check if |
205 // the port is still open before each dispatch. | 197 // the port is still open before each dispatch. |
206 if (m_closed) | 198 if (m_closed) |
207 break; | 199 break; |
208 | 200 |
209 // WorkerGlobalScope::close() in Worker onmessage handler should prevent | 201 // WorkerGlobalScope::close() in Worker onmessage handler should prevent |
210 // the next message from dispatching. | 202 // the next message from dispatching. |
211 if (getExecutionContext()->isWorkerGlobalScope() && | 203 if (getExecutionContext()->isWorkerGlobalScope() && |
212 toWorkerGlobalScope(getExecutionContext())->isClosing()) { | 204 toWorkerGlobalScope(getExecutionContext())->isClosing()) { |
213 break; | 205 break; |
214 } | 206 } |
215 | 207 |
216 RefPtr<SerializedScriptValue> message; | 208 RefPtr<SerializedScriptValue> message; |
217 std::unique_ptr<MessagePortChannelArray> channels; | 209 MessagePortChannelArray channels; |
218 if (!tryGetMessage(message, channels)) | 210 if (!tryGetMessage(message, channels)) |
219 break; | 211 break; |
220 | 212 |
221 MessagePortArray* ports = | 213 MessagePortArray* ports = |
222 MessagePort::entanglePorts(*getExecutionContext(), std::move(channels)); | 214 MessagePort::entanglePorts(*getExecutionContext(), std::move(channels)); |
223 Event* evt = MessageEvent::create(ports, std::move(message)); | 215 Event* evt = MessageEvent::create(ports, std::move(message)); |
224 | 216 |
225 dispatchEvent(evt); | 217 dispatchEvent(evt); |
226 } | 218 } |
227 } | 219 } |
228 | 220 |
229 bool MessagePort::hasPendingActivity() const { | 221 bool MessagePort::hasPendingActivity() const { |
230 // The spec says that entangled message ports should always be treated as if | 222 // The spec says that entangled message ports should always be treated as if |
231 // they have a strong reference. | 223 // they have a strong reference. |
232 // We'll also stipulate that the queue needs to be open (if the app drops its | 224 // We'll also stipulate that the queue needs to be open (if the app drops its |
233 // reference to the port before start()-ing it, then it's not really entangled | 225 // reference to the port before start()-ing it, then it's not really entangled |
234 // as it's unreachable). | 226 // as it's unreachable). |
235 return m_started && isEntangled(); | 227 return m_started && isEntangled(); |
236 } | 228 } |
237 | 229 |
238 std::unique_ptr<MessagePortChannelArray> MessagePort::disentanglePorts( | 230 MessagePortChannelArray MessagePort::disentanglePorts( |
239 ExecutionContext* context, | 231 ExecutionContext* context, |
240 const MessagePortArray& ports, | 232 const MessagePortArray& ports, |
241 ExceptionState& exceptionState) { | 233 ExceptionState& exceptionState) { |
242 if (!ports.size()) | 234 if (!ports.size()) |
243 return nullptr; | 235 return MessagePortChannelArray(); |
244 | 236 |
245 HeapHashSet<Member<MessagePort>> visited; | 237 HeapHashSet<Member<MessagePort>> visited; |
246 | 238 |
247 // Walk the incoming array - if there are any duplicate ports, or null ports | 239 // Walk the incoming array - if there are any duplicate ports, or null ports |
248 // or cloned ports, throw an error (per section 8.3.3 of the HTML5 spec). | 240 // or cloned ports, throw an error (per section 8.3.3 of the HTML5 spec). |
249 for (unsigned i = 0; i < ports.size(); ++i) { | 241 for (unsigned i = 0; i < ports.size(); ++i) { |
250 MessagePort* port = ports[i]; | 242 MessagePort* port = ports[i]; |
251 if (!port || port->isNeutered() || visited.contains(port)) { | 243 if (!port || port->isNeutered() || visited.contains(port)) { |
252 String type; | 244 String type; |
253 if (!port) | 245 if (!port) |
254 type = "null"; | 246 type = "null"; |
255 else if (port->isNeutered()) | 247 else if (port->isNeutered()) |
256 type = "already neutered"; | 248 type = "already neutered"; |
257 else | 249 else |
258 type = "a duplicate"; | 250 type = "a duplicate"; |
259 exceptionState.throwDOMException( | 251 exceptionState.throwDOMException( |
260 DataCloneError, | 252 DataCloneError, |
261 "Port at index " + String::number(i) + " is " + type + "."); | 253 "Port at index " + String::number(i) + " is " + type + "."); |
262 return nullptr; | 254 return MessagePortChannelArray(); |
263 } | 255 } |
264 visited.insert(port); | 256 visited.insert(port); |
265 } | 257 } |
266 | 258 |
267 UseCounter::count(context, UseCounter::MessagePortsTransferred); | 259 UseCounter::count(context, UseCounter::MessagePortsTransferred); |
268 | 260 |
269 // Passed-in ports passed validity checks, so we can disentangle them. | 261 // Passed-in ports passed validity checks, so we can disentangle them. |
270 std::unique_ptr<MessagePortChannelArray> portArray = | 262 MessagePortChannelArray portArray(ports.size()); |
271 WTF::wrapUnique(new MessagePortChannelArray(ports.size())); | |
272 for (unsigned i = 0; i < ports.size(); ++i) | 263 for (unsigned i = 0; i < ports.size(); ++i) |
273 (*portArray)[i] = ports[i]->disentangle(); | 264 portArray[i] = ports[i]->disentangle(); |
274 return portArray; | 265 return portArray; |
275 } | 266 } |
276 | 267 |
277 MessagePortArray* MessagePort::entanglePorts( | 268 MessagePortArray* MessagePort::entanglePorts(ExecutionContext& context, |
278 ExecutionContext& context, | 269 MessagePortChannelArray channels) { |
279 std::unique_ptr<MessagePortChannelArray> channels) { | |
280 // https://html.spec.whatwg.org/multipage/comms.html#message-ports | 270 // https://html.spec.whatwg.org/multipage/comms.html#message-ports |
281 // |ports| should be an empty array, not null even when there is no ports. | 271 // |ports| should be an empty array, not null even when there is no ports. |
282 if (!channels || !channels->size()) | 272 MessagePortArray* portArray = new MessagePortArray(channels.size()); |
283 return new MessagePortArray; | 273 for (unsigned i = 0; i < channels.size(); ++i) { |
284 | |
285 MessagePortArray* portArray = new MessagePortArray(channels->size()); | |
286 for (unsigned i = 0; i < channels->size(); ++i) { | |
287 MessagePort* port = MessagePort::create(context); | 274 MessagePort* port = MessagePort::create(context); |
288 port->entangle(std::move((*channels)[i])); | 275 port->entangle(std::move(channels[i])); |
289 (*portArray)[i] = port; | 276 (*portArray)[i] = port; |
290 } | 277 } |
291 return portArray; | 278 return portArray; |
292 } | 279 } |
293 | 280 |
294 DEFINE_TRACE(MessagePort) { | 281 DEFINE_TRACE(MessagePort) { |
295 ContextLifecycleObserver::trace(visitor); | 282 ContextLifecycleObserver::trace(visitor); |
296 EventTargetWithInlineData::trace(visitor); | 283 EventTargetWithInlineData::trace(visitor); |
297 } | 284 } |
298 | 285 |
299 } // namespace blink | 286 } // namespace blink |
OLD | NEW |