void MessagePort::postMessage(RefPtr<SerializedScriptValue>&& message, MessagePort* port, ExceptionCode& ec) { MessagePortArray ports; if (port) ports.append(port); postMessage(WTFMove(message), &ports, ec); }
void fillMessagePortArray(JSC::ExecState* exec, JSC::JSValue value, MessagePortArray& portArray) { // Convert from the passed-in JS array-like object to a MessagePortArray. // Also validates the elements per sections 4.1.13 and 4.1.15 of the WebIDL spec and section 8.3.3 of the HTML5 spec. if (value.isUndefinedOrNull()) { portArray.resize(0); return; } // Validation of sequence types, per WebIDL spec 4.1.13. unsigned length; JSObject* object = toJSSequence(exec, value, length); if (exec->hadException()) return; portArray.resize(length); for (unsigned i = 0 ; i < length; ++i) { JSValue value = object->get(exec, i); if (exec->hadException()) return; // Validation of non-null objects, per HTML5 spec 8.3.3. if (value.isUndefinedOrNull()) { setDOMException(exec, INVALID_STATE_ERR); return; } // Validation of Objects implementing an interface, per WebIDL spec 4.1.15. RefPtr<MessagePort> port = toMessagePort(value); if (!port) { throwTypeError(exec); return; } portArray[i] = port.release(); } }
// FIXME: remove this when we update the ObjC bindings (bug #28774). void Worker::postMessage(PassRefPtr<SerializedScriptValue> message, MessagePort* port, ExceptionCode& ec) { MessagePortArray ports; if (port) ports.append(port); postMessage(message, &ports, ec); }
void MessageEvent::initMessageEvent(const AtomicString& type, bool canBubble, bool cancelable, PassRefPtr<SerializedScriptValue> data, const String& origin, const String& lastEventId, DOMWindow* source, MessagePort* port) { MessagePortArray* ports = 0; if (port) { ports = new MessagePortArray(); ports->append(port); } initMessageEvent(type, canBubble, cancelable, data, origin, lastEventId, source, ports); }
JSValue JSMessageEvent::ports(ExecState* exec) const { MessagePortArray* ports = static_cast<MessageEvent*>(impl())->ports(); if (!ports) return constructEmptyArray(exec, globalObject()); MarkedArgumentBuffer list; for (size_t i = 0; i < ports->size(); i++) list.append(toJS(exec, globalObject(), (*ports)[i].get())); return constructArray(exec, globalObject(), list); }
void fillMessagePortArray(JSC::ExecState* exec, JSC::JSValue value, MessagePortArray& portArray, ArrayBufferArray& arrayBuffers) { // Convert from the passed-in JS array-like object to a MessagePortArray. // Also validates the elements per sections 4.1.13 and 4.1.15 of the WebIDL spec and section 8.3.3 of the HTML5 spec. if (value.isUndefinedOrNull()) { portArray.resize(0); arrayBuffers.resize(0); return; } // Validation of sequence types, per WebIDL spec 4.1.13. unsigned length = 0; JSObject* object = toJSSequence(exec, value, length); if (exec->hadException()) return; for (unsigned i = 0 ; i < length; ++i) { JSValue value = object->get(exec, i); if (exec->hadException()) return; // Validation of non-null objects, per HTML5 spec 10.3.3. if (value.isUndefinedOrNull()) { setDOMException(exec, INVALID_STATE_ERR); return; } // Validation of Objects implementing an interface, per WebIDL spec 4.1.15. RefPtr<MessagePort> port = toMessagePort(value); if (port) { // Check for duplicate ports. if (portArray.contains(port)) { #if MODIFY(ENGINE) //[2014.03.05][infraware][jungong16] : fix to issue. http://www.w3.org/TR/webmessaging/#dom-window-postmessage setDOMException(exec, DATA_CLONE_ERR); #else setDOMException(exec, INVALID_STATE_ERR); #endif return; } portArray.append(port.release()); } else { RefPtr<ArrayBuffer> arrayBuffer = toArrayBuffer(value); if (arrayBuffer) arrayBuffers.append(arrayBuffer); else { throwTypeError(exec); return; } } } }
bool extractTransferables(v8::Local<v8::Value> value, int argumentIndex, MessagePortArray& ports, ArrayBufferArray& arrayBuffers, ExceptionState& exceptionState, v8::Isolate* isolate) { if (isUndefinedOrNull(value)) { ports.resize(0); arrayBuffers.resize(0); return true; } uint32_t length = 0; if (value->IsArray()) { v8::Local<v8::Array> array = v8::Local<v8::Array>::Cast(value); length = array->Length(); } else if (toV8Sequence(value, length, isolate).IsEmpty()) { exceptionState.throwTypeError(ExceptionMessages::notAnArrayTypeArgumentOrValue(argumentIndex + 1)); return false; } v8::Local<v8::Object> transferrables = v8::Local<v8::Object>::Cast(value); // Validate the passed array of transferrables. for (unsigned int i = 0; i < length; ++i) { v8::Local<v8::Value> transferrable = transferrables->Get(i); // Validation of non-null objects, per HTML5 spec 10.3.3. if (isUndefinedOrNull(transferrable)) { exceptionState.throwDOMException(DataCloneError, "Value at index " + String::number(i) + " is an untransferable " + (transferrable->IsUndefined() ? "'undefined'" : "'null'") + " value."); return false; } // Validation of Objects implementing an interface, per WebIDL spec 4.1.15. if (V8MessagePort::hasInstance(transferrable, isolate)) { RefPtr<MessagePort> port = V8MessagePort::toNative(v8::Handle<v8::Object>::Cast(transferrable)); // Check for duplicate MessagePorts. if (ports.contains(port)) { exceptionState.throwDOMException(DataCloneError, "Message port at index " + String::number(i) + " is a duplicate of an earlier port."); return false; } ports.append(port.release()); } else if (V8ArrayBuffer::hasInstance(transferrable, isolate)) { RefPtr<ArrayBuffer> arrayBuffer = V8ArrayBuffer::toNative(v8::Handle<v8::Object>::Cast(transferrable)); if (arrayBuffers.contains(arrayBuffer)) { exceptionState.throwDOMException(DataCloneError, "ArrayBuffer at index " + String::number(i) + " is a duplicate of an earlier ArrayBuffer."); return false; } arrayBuffers.append(arrayBuffer.release()); } else { exceptionState.throwDOMException(DataCloneError, "Value at index " + String::number(i) + " does not have a transferable type."); return false; } } return true; }
v8::Handle<v8::Value> V8MessageEvent::portsAccessorGetter(v8::Local<v8::String> name, const v8::AccessorInfo& info) { INC_STATS("DOM.MessageEvent.ports"); MessageEvent* event = V8MessageEvent::toNative(info.Holder()); MessagePortArray* ports = event->ports(); if (!ports || ports->isEmpty()) return v8::Null(); v8::Local<v8::Array> portArray = v8::Array::New(ports->size()); for (size_t i = 0; i < ports->size(); ++i) portArray->Set(v8::Integer::New(i), toV8((*ports)[i].get())); return portArray; }
bool extractTransferables(v8::Local<v8::Value> value, MessagePortArray& ports, ArrayBufferArray& arrayBuffers) { if (isUndefinedOrNull(value)) { ports.resize(0); arrayBuffers.resize(0); return true; } if (!value->IsObject()) { throwError("TransferArray argument must be an object"); return false; } uint32_t length = 0; v8::Local<v8::Object> transferrables = v8::Local<v8::Object>::Cast(value); if (value->IsArray()) { v8::Local<v8::Array> array = v8::Local<v8::Array>::Cast(value); length = array->Length(); } else { // Sequence-type object - get the length attribute v8::Local<v8::Value> sequenceLength = transferrables->Get(v8::String::New("length")); if (!sequenceLength->IsNumber()) { throwError("TransferArray argument has no length attribute"); return false; } length = sequenceLength->Uint32Value(); } // Validate the passed array of transferrables. for (unsigned int i = 0; i < length; ++i) { v8::Local<v8::Value> transferrable = transferrables->Get(i); // Validation of non-null objects, per HTML5 spec 10.3.3. if (isUndefinedOrNull(transferrable)) { throwError(DATA_CLONE_ERR); return false; } // Validation of Objects implementing an interface, per WebIDL spec 4.1.15. if (V8MessagePort::HasInstance(transferrable)) ports.append(V8MessagePort::toNative(v8::Handle<v8::Object>::Cast(transferrable))); else if (V8ArrayBuffer::HasInstance(transferrable)) arrayBuffers.append(V8ArrayBuffer::toNative(v8::Handle<v8::Object>::Cast(transferrable))); else { throwError("TransferArray argument must contain only Transferables"); return false; } } return true; }
void MessagePort::postMessage(ExecutionContext* context, PassRefPtr<SerializedScriptValue> message, const MessagePortArray& ports, ExceptionState& exceptionState) { if (!isEntangled()) return; DCHECK(getExecutionContext()); DCHECK(m_entangledChannel); // Make sure we aren't connected to any of the passed-in ports. for (unsigned i = 0; i < ports.size(); ++i) { if (ports[i] == this) { exceptionState.throwDOMException( DataCloneError, "Port at index " + String::number(i) + " contains the source port."); return; } } std::unique_ptr<MessagePortChannelArray> channels = MessagePort::disentanglePorts(context, ports, exceptionState); if (exceptionState.hadException()) return; if (message->containsTransferableArrayBuffer()) getExecutionContext()->addConsoleMessage(ConsoleMessage::create( JSMessageSource, WarningMessageLevel, "MessagePort cannot send an ArrayBuffer as a transferable object yet. " "See http://crbug.com/334408")); WebString messageString = message->toWireString(); std::unique_ptr<WebMessagePortChannelArray> webChannels = toWebMessagePortChannelArray(std::move(channels)); m_entangledChannel->postMessage(messageString, webChannels.release()); }
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 fillMessagePortArray(JSC::ExecState* exec, JSC::JSValue value, MessagePortArray& portArray, ArrayBufferArray& arrayBuffers) { // Convert from the passed-in JS array-like object to a MessagePortArray. // Also validates the elements per sections 4.1.13 and 4.1.15 of the WebIDL spec and section 8.3.3 of the HTML5 spec. if (value.isUndefinedOrNull()) { portArray.resize(0); arrayBuffers.resize(0); return; } // Validation of sequence types, per WebIDL spec 4.1.13. unsigned length = 0; JSObject* object = toJSSequence(exec, value, length); if (exec->hadException()) return; for (unsigned i = 0 ; i < length; ++i) { JSValue value = object->get(exec, i); if (exec->hadException()) return; // Validation of non-null objects, per HTML5 spec 10.3.3. if (value.isUndefinedOrNull()) { setDOMException(exec, INVALID_STATE_ERR); return; } // Validation of Objects implementing an interface, per WebIDL spec 4.1.15. RefPtr<MessagePort> port = JSMessagePort::toWrapped(value); if (port) { // Check for duplicate ports. if (portArray.contains(port)) { setDOMException(exec, INVALID_STATE_ERR); return; } portArray.append(port.release()); } else { RefPtr<ArrayBuffer> arrayBuffer = toArrayBuffer(value); if (arrayBuffer) arrayBuffers.append(arrayBuffer); else { throwTypeError(exec); return; } } } }
bool extractTransferables(v8::Local<v8::Value> value, MessagePortArray& ports, ArrayBufferArray& arrayBuffers, v8::Isolate* isolate) { if (isUndefinedOrNull(value)) { ports.resize(0); arrayBuffers.resize(0); return true; } uint32_t length = 0; if (value->IsArray()) { v8::Local<v8::Array> array = v8::Local<v8::Array>::Cast(value); length = array->Length(); } else { if (toV8Sequence(value, length).IsEmpty()) return false; } v8::Local<v8::Object> transferrables = v8::Local<v8::Object>::Cast(value); // Validate the passed array of transferrables. for (unsigned int i = 0; i < length; ++i) { v8::Local<v8::Value> transferrable = transferrables->Get(i); // Validation of non-null objects, per HTML5 spec 10.3.3. if (isUndefinedOrNull(transferrable)) { setDOMException(INVALID_STATE_ERR, isolate); return false; } // Validation of Objects implementing an interface, per WebIDL spec 4.1.15. if (V8MessagePort::HasInstance(transferrable)) { RefPtr<MessagePort> port = V8MessagePort::toNative(v8::Handle<v8::Object>::Cast(transferrable)); // Check for duplicate MessagePorts. if (ports.contains(port)) { setDOMException(INVALID_STATE_ERR, isolate); return false; } ports.append(port.release()); } else if (V8ArrayBuffer::HasInstance(transferrable)) arrayBuffers.append(V8ArrayBuffer::toNative(v8::Handle<v8::Object>::Cast(transferrable))); else { throwTypeError(); return false; } } return true; }
bool getMessagePortArray(v8::Local<v8::Value> value, MessagePortArray& portArray) { if (isUndefinedOrNull(value)) { portArray.resize(0); return true; } if (!value->IsObject()) { throwError("MessagePortArray argument must be an object"); return false; } uint32_t length = 0; v8::Local<v8::Object> ports = v8::Local<v8::Object>::Cast(value); if (value->IsArray()) { v8::Local<v8::Array> array = v8::Local<v8::Array>::Cast(value); length = array->Length(); } else { // Sequence-type object - get the length attribute v8::Local<v8::Value> sequenceLength = ports->Get(v8::String::New("length")); if (!sequenceLength->IsNumber()) { throwError("MessagePortArray argument has no length attribute"); return false; } length = sequenceLength->Uint32Value(); } portArray.resize(length); for (unsigned int i = 0; i < length; ++i) { v8::Local<v8::Value> port = ports->Get(v8::Integer::New(i)); // Validation of non-null objects, per HTML5 spec 8.3.3. if (isUndefinedOrNull(port)) { throwError(INVALID_STATE_ERR); return false; } // Validation of Objects implementing an interface, per WebIDL spec 4.1.15. if (!V8MessagePort::HasInstance(port)) { throwError("MessagePortArray argument must contain only MessagePorts"); return false; } portArray[i] = V8DOMWrapper::convertToNativeObject<MessagePort>(V8ClassIndex::MESSAGEPORT, v8::Handle<v8::Object>::Cast(port)); } return true; }
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; }
bool getMessagePortArray(v8::Local<v8::Value> value, const String& propertyName, MessagePortArray& ports, v8::Isolate* isolate) { if (isUndefinedOrNull(value)) { ports.resize(0); return true; } if (!value->IsArray()) { throwTypeError(ExceptionMessages::notASequenceTypeProperty(propertyName), isolate); return false; } bool success = false; ports = toRefPtrNativeArray<MessagePort, V8MessagePort>(value, propertyName, isolate, &success); return success; }
bool getMessagePortArray(v8::Local<v8::Value> value, int argumentIndex, MessagePortArray& ports, v8::Isolate* isolate) { if (isUndefinedOrNull(value)) { ports.resize(0); return true; } if (!value->IsArray()) { throwTypeError(ExceptionMessages::notAnArrayTypeArgumentOrValue(argumentIndex), isolate); return false; } bool success = false; ports = toRefPtrNativeArray<MessagePort, V8MessagePort>(value, argumentIndex, isolate, &success); return success; }