Beispiel #1
0
static void messageHandlerInMainThread(v8::Local<v8::Message> message,
                                       v8::Local<v8::Value> data) {
  ASSERT(isMainThread());
  v8::Isolate* isolate = v8::Isolate::GetCurrent();

  if (isolate->GetEnteredContext().IsEmpty())
    return;

  // If called during context initialization, there will be no entered context.
  ScriptState* scriptState = ScriptState::current(isolate);
  if (!scriptState->contextIsValid())
    return;

  ExecutionContext* context = scriptState->getExecutionContext();
  std::unique_ptr<SourceLocation> location =
      SourceLocation::fromMessage(isolate, message, context);

  AccessControlStatus accessControlStatus = NotSharableCrossOrigin;
  if (message->IsOpaque())
    accessControlStatus = OpaqueResource;
  else if (message->IsSharedCrossOrigin())
    accessControlStatus = SharableCrossOrigin;

  ErrorEvent* event =
      ErrorEvent::create(toCoreStringWithNullCheck(message->Get()),
                         std::move(location), &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?
  if (context->isDocument()) {
    LocalFrame* frame = toDocument(context)->frame();
    if (frame && frame->script().existingWindowProxy(scriptState->world())) {
      V8ErrorHandler::storeExceptionOnErrorEventWrapper(
          scriptState, event, 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;
    context->dispatchErrorEvent(event, accessControlStatus);
  } else {
    context->dispatchErrorEvent(event, accessControlStatus);
  }
}
Beispiel #2
0
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);
    }
}
Beispiel #3
0
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);
}
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();
}
V8DOMActivityLogger* V8DOMActivityLogger::currentActivityLoggerIfIsolatedWorld()
{
    v8::Isolate* isolate = v8::Isolate::GetCurrent();
    if (!isolate->InContext())
        return 0;

    ScriptState* scriptState = ScriptState::current(isolate);
    if (!scriptState->world().isIsolatedWorld())
        return 0;

    V8PerContextData* contextData = scriptState->perContextData();
    if (!contextData)
        return 0;

    return contextData->activityLogger();
}
V8DOMActivityLogger* V8DOMActivityLogger::currentActivityLoggerIfIsolatedWorld()
{
    v8::Isolate* isolate = v8::Isolate::GetCurrent();
    if (!isolate->InContext())
        return 0;

    v8::HandleScope handleScope(isolate);
    v8::Local<v8::Context> context = isolate->GetCurrentContext();
    if (context.IsEmpty() || !toDOMWindow(context))
        return 0;

    ScriptState* scriptState = ScriptState::from(context);
    if (!scriptState->world().isIsolatedWorld())
        return 0;

    V8PerContextData* contextData = scriptState->perContextData();
    if (!contextData)
        return 0;

    return contextData->activityLogger();
}
Beispiel #7
0
static void messageHandlerInWorker(v8::Local<v8::Message> message,
                                   v8::Local<v8::Value> data) {
  v8::Isolate* isolate = v8::Isolate::GetCurrent();
  V8PerIsolateData* perIsolateData = V8PerIsolateData::from(isolate);

  // During the frame teardown, there may not be a valid context.
  ScriptState* scriptState = ScriptState::current(isolate);
  if (!scriptState->contextIsValid())
    return;

  // Exceptions that occur in error handler should be ignored since in that case
  // WorkerGlobalScope::dispatchErrorEvent will send the exception to the worker
  // object.
  if (perIsolateData->isReportingException())
    return;

  perIsolateData->setReportingException(true);

  ExecutionContext* context = scriptState->getExecutionContext();
  std::unique_ptr<SourceLocation> location =
      SourceLocation::fromMessage(isolate, message, context);
  ErrorEvent* event =
      ErrorEvent::create(toCoreStringWithNullCheck(message->Get()),
                         std::move(location), &scriptState->world());

  AccessControlStatus corsStatus = message->IsSharedCrossOrigin()
                                       ? SharableCrossOrigin
                                       : NotSharableCrossOrigin;

  // If execution termination has been triggered as part of constructing
  // the error event from the v8::Message, quietly leave.
  if (!isolate->IsExecutionTerminating()) {
    V8ErrorHandler::storeExceptionOnErrorEventWrapper(
        scriptState, event, data, scriptState->context()->Global());
    scriptState->getExecutionContext()->dispatchErrorEvent(event, corsStatus);
  }

  perIsolateData->setReportingException(false);
}
Beispiel #8
0
// 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();
}