static void messageHandlerInMainThread(v8::Handle<v8::Message> message, v8::Handle<v8::Value> data) { ASSERT(isMainThread()); // It's possible that messageHandlerInMainThread() is invoked while we're initializing a window. // In that half-baked situation, we don't have a valid context nor a valid world, // so just return immediately. if (DOMWrapperWorld::windowIsBeingInitialized()) return; v8::Isolate* isolate = v8::Isolate::GetCurrent(); // If called during context initialization, there will be no entered window. LocalDOMWindow* enteredWindow = enteredDOMWindow(isolate); if (!enteredWindow) return; String errorMessage = toCoreString(message->Get()); v8::Handle<v8::StackTrace> stackTrace = message->GetStackTrace(); RefPtr<ScriptCallStack> callStack = nullptr; int scriptId = message->GetScriptOrigin().ScriptID()->Value(); // Currently stack trace is only collected when inspector is open. if (!stackTrace.IsEmpty() && stackTrace->GetFrameCount() > 0) { callStack = createScriptCallStack(stackTrace, ScriptCallStack::maxCallStackSizeToCapture, isolate); bool success = false; int topScriptId = callStack->at(0).scriptId().toInt(&success); if (success && topScriptId == scriptId) scriptId = 0; } else { Vector<ScriptCallFrame> callFrames; callStack = ScriptCallStack::create(callFrames); } v8::Handle<v8::Value> resourceName = message->GetScriptOrigin().ResourceName(); bool shouldUseDocumentURL = resourceName.IsEmpty() || !resourceName->IsString(); String resource = shouldUseDocumentURL ? enteredWindow->document()->url() : toCoreString(resourceName.As<v8::String>()); ScriptState* scriptState = ScriptState::current(isolate); RefPtr<ErrorEvent> event = ErrorEvent::create(errorMessage, resource, message->GetLineNumber(), message->GetStartColumn() + 1, &scriptState->world()); if (V8DOMWrapper::isDOMWrapper(data)) { v8::Handle<v8::Object> obj = v8::Handle<v8::Object>::Cast(data); const WrapperTypeInfo* type = toWrapperTypeInfo(obj); if (V8DOMException::wrapperTypeInfo.isSubclass(type)) { DOMException* exception = V8DOMException::toNative(obj); if (exception && !exception->messageForConsole().isEmpty()) event->setUnsanitizedMessage("Uncaught " + exception->toStringForConsole()); } } // This method might be called while we're creating a new context. In this case, we // avoid storing the exception object, as we can't create a wrapper during context creation. // FIXME: Can we even get here during initialization now that we bail out when GetEntered returns an empty handle? LocalFrame* frame = enteredWindow->document()->frame(); if (frame && frame->script().existingWindowProxy(scriptState->world())) { V8ErrorHandler::storeExceptionOnErrorEventWrapper(event.get(), data, scriptState->context()->Global(), isolate); } enteredWindow->document()->reportException(event.release(), scriptId, callStack); }
static void messageHandlerInMainThread(v8::Local<v8::Message> message, v8::Local<v8::Value> data) { ASSERT(isMainThread()); v8::Isolate* isolate = v8::Isolate::GetCurrent(); // If called during context initialization, there will be no entered window. LocalDOMWindow* enteredWindow = enteredDOMWindow(isolate); if (!enteredWindow || !enteredWindow->isCurrentlyDisplayedInFrame()) return; int scriptId = 0; RefPtrWillBeRawPtr<ScriptCallStack> callStack = extractCallStack(isolate, message, &scriptId); String resourceName = extractResourceName(message, enteredWindow->document()); AccessControlStatus accessControlStatus = NotSharableCrossOrigin; if (message->IsOpaque()) accessControlStatus = OpaqueResource; else if (message->IsSharedCrossOrigin()) accessControlStatus = SharableCrossOrigin; ScriptState* scriptState = ScriptState::current(isolate); String errorMessage = toCoreStringWithNullCheck(message->Get()); int lineNumber = 0; int columnNumber = 0; if (v8Call(message->GetLineNumber(scriptState->context()), lineNumber) && v8Call(message->GetStartColumn(scriptState->context()), columnNumber)) ++columnNumber; RefPtrWillBeRawPtr<ErrorEvent> event = ErrorEvent::create(errorMessage, resourceName, lineNumber, columnNumber, &scriptState->world()); String messageForConsole = extractMessageForConsole(isolate, data); if (!messageForConsole.isEmpty()) event->setUnsanitizedMessage("Uncaught " + messageForConsole); // This method might be called while we're creating a new context. In this case, we // avoid storing the exception object, as we can't create a wrapper during context creation. // FIXME: Can we even get here during initialization now that we bail out when GetEntered returns an empty handle? LocalFrame* frame = enteredWindow->document()->frame(); if (frame && frame->script().existingWindowProxy(scriptState->world())) { V8ErrorHandler::storeExceptionOnErrorEventWrapper(isolate, event.get(), data, scriptState->context()->Global()); } if (scriptState->world().isPrivateScriptIsolatedWorld()) { // We allow a private script to dispatch error events even in a EventDispatchForbiddenScope scope. // Without having this ability, it's hard to debug the private script because syntax errors // in the private script are not reported to console (the private script just crashes silently). // Allowing error events in private scripts is safe because error events don't propagate to // other isolated worlds (which means that the error events won't fire any event listeners // in user's scripts). EventDispatchForbiddenScope::AllowUserAgentEvents allowUserAgentEvents; enteredWindow->document()->reportException(event.release(), scriptId, callStack, accessControlStatus); } else { enteredWindow->document()->reportException(event.release(), scriptId, callStack, accessControlStatus); } }
static void promiseRejectHandlerInMainThread(v8::PromiseRejectMessage data) { ASSERT(isMainThread()); v8::Local<v8::Promise> promise = data.GetPromise(); v8::Isolate* isolate = promise->GetIsolate(); // There is no entered window during microtask callbacks from V8, // thus we call toDOMWindow() instead of enteredDOMWindow(). LocalDOMWindow* window = currentDOMWindow(isolate); if (!window || !window->isCurrentlyDisplayedInFrame()) return; promiseRejectHandler(data, rejectedPromisesOnMainThread(), window->document() ? window->document()->url() : String()); }
static void promiseRejectHandlerInMainThread(v8::PromiseRejectMessage data) { ASSERT(isMainThread()); if (data.GetEvent() == v8::kPromiseHandlerAddedAfterReject) { rejectedPromisesOnMainThread().handlerAdded(data); return; } ASSERT(data.GetEvent() == v8::kPromiseRejectWithNoHandler); v8::Local<v8::Promise> promise = data.GetPromise(); v8::Isolate* isolate = promise->GetIsolate(); // There is no entered window during microtask callbacks from V8, // thus we call toDOMWindow() instead of enteredDOMWindow(). LocalDOMWindow* window = currentDOMWindow(isolate); if (!window || !window->isCurrentlyDisplayedInFrame()) return; v8::Local<v8::Value> exception = data.GetValue(); if (V8DOMWrapper::isWrapper(isolate, exception)) { // Try to get the stack & location from a wrapped exception object (e.g. DOMException). ASSERT(exception->IsObject()); v8::Local<v8::Object> obj = v8::Local<v8::Object>::Cast(exception); v8::Local<v8::Value> error = V8HiddenValue::getHiddenValue(isolate, obj, V8HiddenValue::error(isolate)); if (!error.IsEmpty()) exception = error; } int scriptId = 0; int lineNumber = 0; int columnNumber = 0; String resourceName; String errorMessage; RefPtrWillBeRawPtr<ScriptCallStack> callStack = nullptr; v8::Local<v8::Message> message = v8::Exception::CreateMessage(exception); if (!message.IsEmpty()) { if (v8Call(message->GetLineNumber(isolate->GetCurrentContext()), lineNumber) && v8Call(message->GetStartColumn(isolate->GetCurrentContext()), columnNumber)) ++columnNumber; resourceName = extractResourceName(message, window->document()); errorMessage = toCoreStringWithNullCheck(message->Get()); callStack = extractCallStack(isolate, message, &scriptId); } else if (!exception.IsEmpty() && exception->IsInt32()) { // For Smi's the message would be empty. errorMessage = "Uncaught " + String::number(exception.As<v8::Integer>()->Value()); } String messageForConsole = extractMessageForConsole(isolate, data.GetValue()); if (!messageForConsole.isEmpty()) errorMessage = "Uncaught " + messageForConsole; ScriptState* scriptState = ScriptState::current(isolate); rejectedPromisesOnMainThread().rejectedWithNoHandler(scriptState, data, errorMessage, resourceName, scriptId, lineNumber, columnNumber, callStack); }
PostMessageTimer(LocalDOMWindow& window, PassRefPtrWillBeRawPtr<MessageEvent> event, PassRefPtrWillBeRawPtr<LocalDOMWindow> source, SecurityOrigin* targetOrigin, PassRefPtrWillBeRawPtr<ScriptCallStack> stackTrace, UserGestureToken* userGestureToken) : SuspendableTimer(window.document()) , m_event(event) , m_window(&window) , m_targetOrigin(targetOrigin) , m_stackTrace(stackTrace) , m_userGestureToken(userGestureToken) , m_preventDestruction(false) { m_asyncOperationId = InspectorInstrumentation::traceAsyncOperationStarting(executionContext(), "postMessage"); }
void V8HTMLElement::HTMLConstructor( const v8::FunctionCallbackInfo<v8::Value>& info) { DCHECK(info.IsConstructCall()); v8::Isolate* isolate = info.GetIsolate(); ScriptState* scriptState = ScriptState::current(isolate); if (!RuntimeEnabledFeatures::customElementsV1Enabled() || !scriptState->world().isMainWorld()) { V8ThrowException::throwTypeError(info.GetIsolate(), "Illegal constructor"); return; } LocalDOMWindow* window = scriptState->domWindow(); ScriptCustomElementDefinition* definition = ScriptCustomElementDefinition::forConstructor( scriptState, window->customElements(), info.NewTarget()); if (!definition) { V8ThrowException::throwTypeError(isolate, "Illegal constructor"); return; } ExceptionState exceptionState(ExceptionState::ConstructionContext, "HTMLElement", info.Holder(), isolate); Element* element; if (definition->constructionStack().isEmpty()) { // This is an element being created with 'new' from script element = definition->createElementForConstructor(*window->document()); } else { element = definition->constructionStack().last(); if (element) { // This is an element being upgraded that has called super definition->constructionStack().last().clear(); } else { // During upgrade an element has invoked the same constructor // before calling 'super' and that invocation has poached the // element. exceptionState.throwDOMException(InvalidStateError, "this instance is already constructed"); return; } } const WrapperTypeInfo* wrapperType = element->wrapperTypeInfo(); v8::Local<v8::Object> wrapper = V8DOMWrapper::associateObjectWithWrapper( isolate, element, wrapperType, info.Holder()); // If the element had a wrapper, we now update and return that // instead. v8SetReturnValue(info, wrapper); wrapper->SetPrototype(scriptState->context(), definition->prototype()) .ToChecked(); }
void WebDOMMessageEvent::initMessageEvent(const WebString& type, bool canBubble, bool cancelable, const WebSerializedScriptValue& messageData, const WebString& origin, const WebFrame* sourceFrame, const WebString& lastEventId, const WebMessagePortChannelArray& webChannels) { ASSERT(m_private.get()); ASSERT(isMessageEvent()); LocalDOMWindow* window = 0; if (sourceFrame) window = toWebLocalFrameImpl(sourceFrame)->frame()->domWindow(); OwnPtr<MessagePortArray> ports; if (sourceFrame) ports = MessagePort::toMessagePortArray(window->document(), webChannels); unwrap<MessageEvent>()->initMessageEvent(type, canBubble, cancelable, messageData, origin, lastEventId, window, ports.release()); }
void DevToolsHost::showContextMenu(Event* event, const Vector<ContextMenuItem>& items) { if (!event) return; ASSERT(m_frontendFrame); ScriptState* frontendScriptState = ScriptState::forMainWorld(m_frontendFrame); ScriptValue devtoolsApiObject = frontendScriptState->getFromGlobalObject("DevToolsAPI"); ASSERT(devtoolsApiObject.isObject()); Page* targetPage = m_frontendFrame->page(); if (event->target() && event->target()->executionContext() && event->target()->executionContext()->executingWindow()) { LocalDOMWindow* window = event->target()->executionContext()->executingWindow(); if (window->document() && window->document()->page()) targetPage = window->document()->page(); } RefPtrWillBeRawPtr<FrontendMenuProvider> menuProvider = FrontendMenuProvider::create(this, devtoolsApiObject, items); targetPage->contextMenuController().showContextMenu(event, menuProvider); m_menuProvider = menuProvider.get(); }
void DOMWindowFileSystem::webkitRequestFileSystem(LocalDOMWindow& window, int type, long long size, PassOwnPtr<FileSystemCallback> successCallback, PassOwnPtr<ErrorCallback> errorCallback) { if (!window.isCurrentlyDisplayedInFrame()) return; Document* document = window.document(); if (!document) return; if (!document->securityOrigin()->canAccessFileSystem()) { DOMFileSystem::scheduleCallback(document, errorCallback, FileError::create(FileError::SECURITY_ERR)); return; } FileSystemType fileSystemType = static_cast<FileSystemType>(type); if (!DOMFileSystemBase::isValidType(fileSystemType)) { DOMFileSystem::scheduleCallback(document, errorCallback, FileError::create(FileError::INVALID_MODIFICATION_ERR)); return; } LocalFileSystem::from(*document)->requestFileSystem(document, fileSystemType, size, FileSystemCallbacks::create(successCallback, errorCallback, document, fileSystemType)); }
void DOMWindowFileSystem::webkitResolveLocalFileSystemURL(LocalDOMWindow& window, const String& url, PassOwnPtr<EntryCallback> successCallback, PassOwnPtr<ErrorCallback> errorCallback) { if (!window.isCurrentlyDisplayedInFrame()) return; Document* document = window.document(); if (!document) return; SecurityOrigin* securityOrigin = document->securityOrigin(); KURL completedURL = document->completeURL(url); if (!securityOrigin->canAccessFileSystem() || !securityOrigin->canRequest(completedURL)) { DOMFileSystem::scheduleCallback(document, errorCallback, FileError::create(FileError::SECURITY_ERR)); return; } if (!completedURL.isValid()) { DOMFileSystem::scheduleCallback(document, errorCallback, FileError::create(FileError::ENCODING_ERR)); return; } LocalFileSystem::from(*document)->resolveURL(document, completedURL, ResolveURICallbacks::create(successCallback, errorCallback, document)); }
// https://html.spec.whatwg.org/multipage/dom.html#html-element-constructors void V8HTMLConstructor::htmlConstructor( const v8::FunctionCallbackInfo<v8::Value>& info, const WrapperTypeInfo& wrapperTypeInfo, const HTMLElementType elementInterfaceName) { TRACE_EVENT0("blink", "HTMLConstructor"); DCHECK(info.IsConstructCall()); v8::Isolate* isolate = info.GetIsolate(); ScriptState* scriptState = ScriptState::current(isolate); v8::Local<v8::Value> newTarget = info.NewTarget(); if (!scriptState->contextIsValid()) { V8ThrowException::throwError(isolate, "The context has been destroyed"); return; } if (!RuntimeEnabledFeatures::customElementsV1Enabled() || !scriptState->world().isMainWorld()) { V8ThrowException::throwTypeError(isolate, "Illegal constructor"); return; } // 2. If NewTarget is equal to the active function object, then // throw a TypeError and abort these steps. v8::Local<v8::Function> activeFunctionObject = scriptState->perContextData()->constructorForType( &V8HTMLElement::wrapperTypeInfo); if (newTarget == activeFunctionObject) { V8ThrowException::throwTypeError(isolate, "Illegal constructor"); return; } LocalDOMWindow* window = scriptState->domWindow(); CustomElementRegistry* registry = window->customElements(); // 3. Let definition be the entry in registry with constructor equal to // NewTarget. // If there is no such definition, then throw a TypeError and abort these // steps. ScriptCustomElementDefinition* definition = ScriptCustomElementDefinition::forConstructor(scriptState, registry, newTarget); if (!definition) { V8ThrowException::throwTypeError(isolate, "Illegal constructor"); return; } const AtomicString& localName = definition->descriptor().localName(); const AtomicString& name = definition->descriptor().name(); if (localName == name) { // Autonomous custom element // 4.1. If the active function object is not HTMLElement, then throw a // TypeError if (!V8HTMLElement::wrapperTypeInfo.equals(&wrapperTypeInfo)) { V8ThrowException::throwTypeError(isolate, "Illegal constructor: autonomous custom " "elements must extend HTMLElement"); return; } } else { // Customized built-in element // 5. If local name is not valid for interface, throw TypeError if (htmlElementTypeForTag(localName) != elementInterfaceName) { V8ThrowException::throwTypeError(isolate, "Illegal constructor: localName does " "not match the HTML element interface"); return; } } ExceptionState exceptionState(isolate, ExceptionState::ConstructionContext, "HTMLElement"); v8::TryCatch tryCatch(isolate); // 6. Let prototype be Get(NewTarget, "prototype"). Rethrow any exceptions. v8::Local<v8::Value> prototype; v8::Local<v8::String> prototypeString = v8AtomicString(isolate, "prototype"); if (!v8Call(newTarget.As<v8::Object>()->Get(scriptState->context(), prototypeString), prototype)) { return; } // 7. If Type(prototype) is not Object, then: ... if (!prototype->IsObject()) { if (V8PerContextData* perContextData = V8PerContextData::from( newTarget.As<v8::Object>()->CreationContext())) { prototype = perContextData->prototypeForType(&V8HTMLElement::wrapperTypeInfo); } else { V8ThrowException::throwError(isolate, "The context has been destroyed"); return; } } // 8. If definition's construction stack is empty... Element* element; if (definition->constructionStack().isEmpty()) { // This is an element being created with 'new' from script element = definition->createElementForConstructor(*window->document()); } else { element = definition->constructionStack().last(); if (element) { // This is an element being upgraded that has called super definition->constructionStack().last().clear(); } else { // During upgrade an element has invoked the same constructor // before calling 'super' and that invocation has poached the // element. exceptionState.throwDOMException(InvalidStateError, "this instance is already constructed"); return; } } const WrapperTypeInfo* wrapperType = element->wrapperTypeInfo(); v8::Local<v8::Object> wrapper = V8DOMWrapper::associateObjectWithWrapper( isolate, element, wrapperType, info.Holder()); // If the element had a wrapper, we now update and return that // instead. v8SetReturnValue(info, wrapper); // 11. Perform element.[[SetPrototypeOf]](prototype). Rethrow any exceptions. // Note: I don't think this prototype set *can* throw exceptions. wrapper->SetPrototype(scriptState->context(), prototype.As<v8::Object>()) .ToChecked(); }