| 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 |