PassOwnPtr<MessagePortChannelArray> MessagePort::disentanglePorts(const MessagePortArray* ports, ExceptionCode& ec) { if (!ports || !ports->size()) return 0; // HashSet used to efficiently check for duplicates in the passed-in array. HashSet<MessagePort*> portSet; // 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). for (unsigned int i = 0; i < ports->size(); ++i) { MessagePort* port = (*ports)[i].get(); if (!port || port->isCloned() || portSet.contains(port)) { ec = INVALID_STATE_ERR; return 0; } portSet.add(port); } // Passed-in ports passed validity checks, so we can disentangle them. MessagePortChannelArray* portArray = new MessagePortChannelArray(ports->size()); for (unsigned int i = 0 ; i < ports->size() ; ++i) { OwnPtr<MessagePortChannel> channel = (*ports)[i]->disentangle(ec); ASSERT(!ec); // Can't generate exception here if passed above checks. (*portArray)[i] = channel.release(); } return portArray; }
PassOwnPtr<MessagePortChannelArray> MessagePort::disentanglePorts(const MessagePortArray* ports, ExceptionState& exceptionState) { if (!ports || !ports->size()) return nullptr; // HashSet used to efficiently check for duplicates in the passed-in array. HashSet<MessagePort*> portSet; // 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). for (unsigned i = 0; i < ports->size(); ++i) { MessagePort* port = (*ports)[i].get(); if (!port || port->isNeutered() || portSet.contains(port)) { String type; if (!port) type = "null"; else if (port->isNeutered()) type = "already neutered"; else type = "a duplicate"; exceptionState.throwDOMException(DataCloneError, "Port at index " + String::number(i) + " is " + type + "."); return nullptr; } portSet.add(port); } // Passed-in ports passed validity checks, so we can disentangle them. OwnPtr<MessagePortChannelArray> portArray = adoptPtr(new MessagePortChannelArray(ports->size())); for (unsigned i = 0; i < ports->size(); ++i) (*portArray)[i] = (*ports)[i]->disentangle(); return portArray.release(); }
static v8::Handle<v8::Value> closeCallback(const v8::Arguments& args) { INC_STATS("DOM.MessagePort.close"); MessagePort* imp = V8MessagePort::toNative(args.Holder()); imp->close(); return v8::Handle<v8::Value>(); }
void setJSMessagePortOnmessage(ExecState* exec, JSObject* thisObject, JSValue value) { UNUSED_PARAM(exec); JSMessagePort* castedThis = static_cast<JSMessagePort*>(thisObject); MessagePort* imp = static_cast<MessagePort*>(castedThis->impl()); imp->setOnmessage(createJSAttributeEventListener(exec, value, thisObject)); }
static void onmessageAttrSetter(v8::Local<v8::String> name, v8::Local<v8::Value> value, const v8::AccessorInfo& info) { MessagePort* imp = V8MessagePort::toNative(info.Holder()); transferHiddenDependency(info.Holder(), imp->onmessage(), value, V8MessagePort::eventListenerCacheIndex); imp->setOnmessage(V8DOMWrapper::getEventListener(value, true, ListenerFindOrCreate)); return; }
std::unique_ptr<MessagePortChannelArray> MessagePort::disentanglePorts(const MessagePortArray* ports, ExceptionCode& ec) { if (!ports || !ports->size()) return nullptr; // HashSet used to efficiently check for duplicates in the passed-in array. HashSet<MessagePort*> portSet; // 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). for (unsigned int i = 0; i < ports->size(); ++i) { MessagePort* port = (*ports)[i].get(); if (!port || port->isNeutered() || portSet.contains(port)) { ec = DATA_CLONE_ERR; return nullptr; } portSet.add(port); } // Passed-in ports passed validity checks, so we can disentangle them. auto portArray = std::make_unique<MessagePortChannelArray>(ports->size()); for (unsigned int i = 0 ; i < ports->size() ; ++i) { std::unique_ptr<MessagePortChannel> channel = (*ports)[i]->disentangle(); (*portArray)[i] = std::move(channel); } return portArray; }
void WebSharedWorkerImpl::connectTask(PassOwnPtr<WebMessagePortChannel> channel, ExecutionContext* context) { // Wrap the passed-in channel in a MessagePort, and send it off via a connect event. MessagePort* port = MessagePort::create(*context); port->entangle(channel); WorkerGlobalScope* workerGlobalScope = toWorkerGlobalScope(context); ASSERT_WITH_SECURITY_IMPLICATION(workerGlobalScope->isSharedWorkerGlobalScope()); workerGlobalScope->dispatchEvent(createConnectEvent(port)); }
void WebSharedWorkerImpl::connectTask(WebMessagePortChannelUniquePtr channel, ExecutionContext* context) { // Wrap the passed-in channel in a MessagePort, and send it off via a connect // event. MessagePort* port = MessagePort::create(*context); port->entangle(std::move(channel)); WorkerGlobalScope* workerGlobalScope = toWorkerGlobalScope(context); SECURITY_DCHECK(workerGlobalScope->isSharedWorkerGlobalScope()); workerGlobalScope->dispatchEvent(createConnectEvent(port)); }
JSValue JSC_HOST_CALL jsMessagePortPrototypeFunctionClose(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) { UNUSED_PARAM(args); if (!thisValue.inherits(&JSMessagePort::s_info)) return throwError(exec, TypeError); JSMessagePort* castedThisObj = static_cast<JSMessagePort*>(asObject(thisValue)); MessagePort* imp = static_cast<MessagePort*>(castedThisObj->impl()); imp->close(); return jsUndefined(); }
EncodedJSValue JSC_HOST_CALL jsMessagePortPrototypeFunctionClose(ExecState* exec) { JSValue thisValue = exec->hostThisValue(); if (!thisValue.inherits(&JSMessagePort::s_info)) return throwVMTypeError(exec); JSMessagePort* castedThis = static_cast<JSMessagePort*>(asObject(thisValue)); ASSERT_GC_OBJECT_INHERITS(castedThis, &JSMessagePort::s_info); MessagePort* imp = static_cast<MessagePort*>(castedThis->impl()); imp->close(); return JSValue::encode(jsUndefined()); }
JSValue jsMessagePortOnmessage(ExecState* exec, JSValue slotBase, const Identifier&) { JSMessagePort* castedThis = static_cast<JSMessagePort*>(asObject(slotBase)); UNUSED_PARAM(exec); MessagePort* imp = static_cast<MessagePort*>(castedThis->impl()); if (EventListener* listener = imp->onmessage()) { if (const JSEventListener* jsListener = JSEventListener::cast(listener)) { if (JSObject* jsFunction = jsListener->jsFunction(imp->scriptExecutionContext())) return jsFunction; } } return jsNull(); }
v8::Handle<v8::Value> V8MessagePort::addEventListenerCallback(const v8::Arguments& args) { INC_STATS("DOM.MessagePort.addEventListener()"); MessagePort* messagePort = V8DOMWrapper::convertToNativeObject<MessagePort>(V8ClassIndex::MESSAGEPORT, args.Holder()); RefPtr<EventListener> listener = V8DOMWrapper::getEventListener(messagePort, args[1], false, ListenerFindOrCreate); if (listener) { String type = toWebCoreString(args[0]); bool useCapture = args[2]->BooleanValue(); messagePort->addEventListener(type, listener, useCapture); createHiddenDependency(args.Holder(), args[1], V8Custom::kMessagePortRequestCacheIndex); } return v8::Undefined(); }
v8::Handle<v8::Value> V8MessagePort::postMessageCallback(const v8::Arguments& args) { INC_STATS("DOM.MessagePort.postMessage"); MessagePort* messagePort = V8DOMWrapper::convertToNativeObject<MessagePort>(V8ClassIndex::MESSAGEPORT, args.Holder()); RefPtr<SerializedScriptValue> message = SerializedScriptValue::create(toWebCoreString(args[0])); MessagePortArray portArray; if (args.Length() > 1) { if (!getMessagePortArray(args[1], portArray)) return v8::Undefined(); } ExceptionCode ec = 0; messagePort->postMessage(message.release(), &portArray, ec); return throwError(ec); }
JSValue JSC_HOST_CALL jsMessagePortPrototypeFunctionDispatchEvent(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) { UNUSED_PARAM(args); if (!thisValue.inherits(&JSMessagePort::s_info)) return throwError(exec, TypeError); JSMessagePort* castedThisObj = static_cast<JSMessagePort*>(asObject(thisValue)); MessagePort* imp = static_cast<MessagePort*>(castedThisObj->impl()); ExceptionCode ec = 0; Event* evt = toEvent(args.at(0)); JSC::JSValue result = jsBoolean(imp->dispatchEvent(evt, ec)); setDOMException(exec, ec); return result; }
static v8::Handle<v8::Value> dispatchEventCallback(const v8::Arguments& args) { if (args.Length() < 1) return throwNotEnoughArgumentsError(args.GetIsolate()); MessagePort* imp = V8MessagePort::toNative(args.Holder()); ExceptionCode ec = 0; { V8TRYCATCH(Event*, evt, V8Event::HasInstance(MAYBE_MISSING_PARAMETER(args, 0, DefaultIsUndefined)) ? V8Event::toNative(v8::Handle<v8::Object>::Cast(MAYBE_MISSING_PARAMETER(args, 0, DefaultIsUndefined))) : 0); bool result = imp->dispatchEvent(evt, ec); if (UNLIKELY(ec)) goto fail; return v8Boolean(result, args.GetIsolate()); } fail: return setDOMException(ec, args.GetIsolate()); }
static v8::Handle<v8::Value> dispatchEventCallback(const v8::Arguments& args) { INC_STATS("DOM.MessagePort.dispatchEvent"); MessagePort* imp = V8MessagePort::toNative(args.Holder()); ExceptionCode ec = 0; { EXCEPTION_BLOCK(Event*, evt, V8Event::HasInstance(args[0]) ? V8Event::toNative(v8::Handle<v8::Object>::Cast(args[0])) : 0); bool result = imp->dispatchEvent(evt, ec); if (UNLIKELY(ec)) goto fail; return v8Boolean(result); } fail: V8Proxy::setDOMException(ec); return v8::Handle<v8::Value>(); }
EncodedJSValue JSC_HOST_CALL jsMessagePortPrototypeFunctionRemoveEventListener(ExecState* exec) { JSValue thisValue = exec->hostThisValue(); if (!thisValue.inherits(&JSMessagePort::s_info)) return throwVMTypeError(exec); JSMessagePort* castedThis = static_cast<JSMessagePort*>(asObject(thisValue)); ASSERT_GC_OBJECT_INHERITS(castedThis, &JSMessagePort::s_info); MessagePort* imp = static_cast<MessagePort*>(castedThis->impl()); if (exec->argumentCount() < 2) return throwVMError(exec, createTypeError(exec, "Not enough arguments")); JSValue listener = exec->argument(1); if (!listener.isObject()) return JSValue::encode(jsUndefined()); imp->removeEventListener(ustringToAtomicString(exec->argument(0).toString(exec)), JSEventListener::create(asObject(listener), castedThis, false, currentWorld(exec)).get(), exec->argument(2).toBoolean(exec)); return JSValue::encode(jsUndefined()); }
MessagePortArray* MessagePort::entanglePorts( ExecutionContext& context, std::unique_ptr<MessagePortChannelArray> channels) { // https://html.spec.whatwg.org/multipage/comms.html#message-ports // |ports| should be an empty array, not null even when there is no ports. if (!channels || !channels->size()) return new MessagePortArray; MessagePortArray* portArray = new MessagePortArray(channels->size()); for (unsigned i = 0; i < channels->size(); ++i) { MessagePort* port = MessagePort::create(context); port->entangle(std::move((*channels)[i])); (*portArray)[i] = port; } return portArray; }
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { // Odd sizes are handled in various ways, depending how they arrive. // Let's not worry about that case here. if (size % sizeof(UChar)) return 0; // Used to control what kind of extra data is provided to the deserializer. unsigned hash = StringHasher::hashMemory(data, size); // If message ports are requested, make some. MessagePortArray* messagePorts = nullptr; if (hash & kFuzzMessagePorts) { messagePorts = new MessagePortArray(3); std::generate(messagePorts->begin(), messagePorts->end(), []() { WebMessagePortChannelUniquePtr channel(new WebMessagePortChannelImpl()); MessagePort* port = MessagePort::create(pageHolder->document()); port->entangle(std::move(channel)); return port; }); } // If blobs are requested, supply blob info. const auto* blobs = (hash & kFuzzBlobInfo) ? blobInfoArray : nullptr; // Set up. ScriptState* scriptState = ScriptState::forMainWorld(&pageHolder->frame()); v8::Isolate* isolate = scriptState->isolate(); ScriptState::Scope scope(scriptState); v8::TryCatch tryCatch(isolate); // Deserialize. RefPtr<SerializedScriptValue> serializedScriptValue = SerializedScriptValue::create(reinterpret_cast<const char*>(data), size); serializedScriptValue->deserialize(isolate, messagePorts, blobs); CHECK(!tryCatch.HasCaught()) << "deserialize() should return null rather than throwing an exception."; // Clean up. We have to periodically run pending tasks so that scheduled // Oilpan GC occurs. static int iterations = 0; if (iterations++ == 2048) { testing::runPendingTasks(); iterations = 0; } return 0; }
void ScriptExecutionContext::dispatchMessagePortEvents() { RefPtr<ScriptExecutionContext> protect(this); // Make a frozen copy. Vector<MessagePort*> ports; copyToVector(m_messagePorts, ports); unsigned portCount = ports.size(); for (unsigned i = 0; i < portCount; ++i) { MessagePort* port = ports[i]; // The port may be destroyed, and another one created at the same address, but this is safe, as the worst that can happen // as a result is that dispatchMessages() will be called needlessly. if (m_messagePorts.contains(port) && port->started()) port->dispatchMessages(); } }
void V8MessagePort::postMessageMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info) { ExceptionState exceptionState(ExceptionState::ExecutionContext, "postMessage", "MessagePort", info.Holder(), info.GetIsolate()); MessagePort* messagePort = V8MessagePort::toNative(info.Holder()); MessagePortArray portArray; ArrayBufferArray arrayBufferArray; if (info.Length() > 1) { const int transferablesArgIndex = 1; if (!SerializedScriptValue::extractTransferables(info[transferablesArgIndex], transferablesArgIndex, portArray, arrayBufferArray, exceptionState, info.GetIsolate())) { exceptionState.throwIfNeeded(); return; } } RefPtr<SerializedScriptValue> message = SerializedScriptValue::create(info[0], &portArray, &arrayBufferArray, exceptionState, info.GetIsolate()); if (exceptionState.throwIfNeeded()) return; messagePort->postMessage(message.release(), &portArray, exceptionState); exceptionState.throwIfNeeded(); }
EncodedJSValue JSC_HOST_CALL jsMessagePortPrototypeFunctionDispatchEvent(ExecState* exec) { JSValue thisValue = exec->hostThisValue(); if (!thisValue.inherits(&JSMessagePort::s_info)) return throwVMTypeError(exec); JSMessagePort* castedThis = static_cast<JSMessagePort*>(asObject(thisValue)); ASSERT_GC_OBJECT_INHERITS(castedThis, &JSMessagePort::s_info); MessagePort* imp = static_cast<MessagePort*>(castedThis->impl()); if (exec->argumentCount() < 1) return throwVMError(exec, createTypeError(exec, "Not enough arguments")); ExceptionCode ec = 0; Event* evt(toEvent(exec->argument(0))); if (exec->hadException()) return JSValue::encode(jsUndefined()); JSC::JSValue result = jsBoolean(imp->dispatchEvent(evt, ec)); setDOMException(exec, ec); return JSValue::encode(result); }
v8::Handle<v8::Value> V8MessagePort::postMessageCallback(const v8::Arguments& args) { INC_STATS("DOM.MessagePort.postMessage"); MessagePort* messagePort = V8MessagePort::toNative(args.Holder()); MessagePortArray portArray; ArrayBufferArray arrayBufferArray; if (args.Length() > 1) { if (!extractTransferables(args[1], portArray, arrayBufferArray)) return v8::Undefined(); } bool didThrow = false; RefPtr<SerializedScriptValue> message = SerializedScriptValue::create(args[0], &portArray, didThrow); if (didThrow) return v8::Undefined(); ExceptionCode ec = 0; messagePort->postMessage(message.release(), &portArray, ec); return throwError(ec); }
std::unique_ptr<MessagePortChannelArray> MessagePort::disentanglePorts( ExecutionContext* context, const MessagePortArray& ports, ExceptionState& exceptionState) { if (!ports.size()) return nullptr; HeapHashSet<Member<MessagePort>> visited; // 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). for (unsigned i = 0; i < ports.size(); ++i) { MessagePort* port = ports[i]; if (!port || port->isNeutered() || visited.contains(port)) { String type; if (!port) type = "null"; else if (port->isNeutered()) type = "already neutered"; else type = "a duplicate"; exceptionState.throwDOMException( DataCloneError, "Port at index " + String::number(i) + " is " + type + "."); return nullptr; } visited.add(port); } UseCounter::count(context, UseCounter::MessagePortsTransferred); // Passed-in ports passed validity checks, so we can disentangle them. std::unique_ptr<MessagePortChannelArray> portArray = wrapUnique(new MessagePortChannelArray(ports.size())); for (unsigned i = 0; i < ports.size(); ++i) (*portArray)[i] = ports[i]->disentangle(); return portArray; }
MessagePort* MessagePort::create(ExecutionContext& executionContext) { MessagePort* port = new MessagePort(executionContext); port->suspendIfNeeded(); return port; }
static v8::Handle<v8::Value> onmessageAttrGetter(v8::Local<v8::String> name, const v8::AccessorInfo& info) { MessagePort* imp = V8MessagePort::toNative(info.Holder()); return imp->onmessage() ? v8::Handle<v8::Value>(static_cast<V8AbstractEventListener*>(imp->onmessage())->getListenerObject(imp->scriptExecutionContext())) : v8::Handle<v8::Value>(v8Null(info.GetIsolate())); }
static v8::Handle<v8::Value> closeCallback(const v8::Arguments& args) { MessagePort* imp = V8MessagePort::toNative(args.Holder()); imp->close(); return v8Undefined(); }