Пример #1
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::reportException 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()->reportException(event, corsStatus);
    }

    perIsolateData->setReportingException(false);
}
PassRefPtr<JSONValue> toJSONValue(const ScriptValue& value)
{
    ScriptState* scriptState = value.scriptState();
    ASSERT(scriptState->contextIsValid());
    ScriptState::Scope scope(scriptState);
    NonThrowableExceptionState exceptionState;
    return ScriptValue::to<JSONValuePtr>(scriptState->isolate(), value, exceptionState);
}
Пример #3
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);
  }
}
Пример #4
0
ScriptState* ScriptState::forWorld(LocalFrame* frame, DOMWrapperWorld& world) {
  ASSERT(frame);
  v8::HandleScope handleScope(toIsolate(frame));
  v8::Local<v8::Context> context = toV8Context(frame, world);
  if (context.IsEmpty())
    return nullptr;
  ScriptState* scriptState = ScriptState::from(context);
  ASSERT(scriptState->contextIsValid());
  return scriptState;
}
Пример #5
0
// Create a V8 object with an interceptor of NPObjectPropertyGetter.
bool ScriptController::bindToWindowObject(LocalFrame* frame, const String& key, NPObject* object)
{
    ScriptState* scriptState = ScriptState::forMainWorld(frame);
    if (!scriptState->contextIsValid())
        return false;

    ScriptState::Scope scope(scriptState);
    v8::Local<v8::Object> value = createV8ObjectForNPObject(isolate(), object, 0);

    // Attach to the global object.
    return v8CallBoolean(scriptState->context()->Global()->Set(scriptState->context(), v8String(isolate(), key), value));
}
Пример #6
0
// Create a V8 object with an interceptor of NPObjectPropertyGetter.
void ScriptController::bindToWindowObject(LocalFrame* frame, const String& key, NPObject* object)
{
    ScriptState* scriptState = ScriptState::forMainWorld(frame);
    if (!scriptState->contextIsValid())
        return;

    ScriptState::Scope scope(scriptState);
    v8::Handle<v8::Object> value = createV8ObjectForNPObject(m_isolate, object, 0);

    // Attach to the global object.
    scriptState->context()->Global()->Set(v8String(m_isolate, key), value);
}
Пример #7
0
static void promiseRejectHandlerInWorker(v8::PromiseRejectMessage data)
{
    v8::Local<v8::Promise> promise = data.GetPromise();

    // Bail out if called during context initialization.
    v8::Isolate* isolate = promise->GetIsolate();
    ScriptState* scriptState = ScriptState::current(isolate);
    if (!scriptState->contextIsValid())
        return;

    ExecutionContext* executionContext = scriptState->executionContext();
    if (!executionContext)
        return;

    ASSERT(executionContext->isWorkerGlobalScope());
    WorkerScriptController* scriptController = toWorkerGlobalScope(executionContext)->script();
    ASSERT(scriptController);

    if (data.GetEvent() == v8::kPromiseHandlerAddedAfterReject) {
        scriptController->rejectedPromises()->handlerAdded(data);
        return;
    }

    ASSERT(data.GetEvent() == v8::kPromiseRejectWithNoHandler);

    int scriptId = 0;
    int lineNumber = 0;
    int columnNumber = 0;
    String resourceName;
    String errorMessage;

    v8::Local<v8::Message> message = v8::Exception::CreateMessage(data.GetValue());
    if (!message.IsEmpty()) {
        TOSTRING_VOID(V8StringResource<>, resourceName, message->GetScriptOrigin().ResourceName());
        scriptId = message->GetScriptOrigin().ScriptID()->Value();
        if (v8Call(message->GetLineNumber(scriptState->context()), lineNumber)
            && v8Call(message->GetStartColumn(scriptState->context()), columnNumber))
            ++columnNumber;
        // message->Get() can be empty here. https://crbug.com/450330
        errorMessage = toCoreStringWithNullCheck(message->Get());
    }
    scriptController->rejectedPromises()->rejectedWithNoHandler(scriptState, data, errorMessage, resourceName, scriptId, lineNumber, columnNumber, nullptr);
}
Пример #8
0
void MainThreadDebugger::exceptionThrown(ExecutionContext* context,
                                         ErrorEvent* event) {
  LocalFrame* frame = nullptr;
  ScriptState* scriptState = nullptr;
  if (context->isDocument()) {
    frame = toDocument(context)->frame();
    if (!frame)
      return;
    scriptState = event->world() ? ScriptState::forWorld(frame, *event->world())
                                 : nullptr;
  } else if (context->isMainThreadWorkletGlobalScope()) {
    frame = toMainThreadWorkletGlobalScope(context)->frame();
    if (!frame)
      return;
    scriptState = toMainThreadWorkletGlobalScope(context)
                      ->scriptController()
                      ->getScriptState();
  } else {
    NOTREACHED();
  }

  frame->console().reportMessageToClient(JSMessageSource, ErrorMessageLevel,
                                         event->messageForConsole(),
                                         event->location());

  const String defaultMessage = "Uncaught";
  if (scriptState && scriptState->contextIsValid()) {
    ScriptState::Scope scope(scriptState);
    v8::Local<v8::Value> exception =
        V8ErrorHandler::loadExceptionFromErrorEventWrapper(
            scriptState, event, scriptState->context()->Global());
    SourceLocation* location = event->location();
    String message = event->messageForConsole();
    String url = location->url();
    v8Inspector()->exceptionThrown(
        scriptState->context(), toV8InspectorStringView(defaultMessage),
        exception, toV8InspectorStringView(message),
        toV8InspectorStringView(url), location->lineNumber(),
        location->columnNumber(), location->takeStackTrace(),
        location->scriptId());
  }
}
Пример #9
0
static void promiseRejectHandlerInWorker(v8::PromiseRejectMessage data)
{
    v8::Local<v8::Promise> promise = data.GetPromise();

    // Bail out if called during context initialization.
    v8::Isolate* isolate = promise->GetIsolate();
    ScriptState* scriptState = ScriptState::current(isolate);
    if (!scriptState->contextIsValid())
        return;

    ExecutionContext* executionContext = scriptState->getExecutionContext();
    if (!executionContext)
        return;

    ASSERT(executionContext->isWorkerGlobalScope());
    WorkerOrWorkletScriptController* scriptController = toWorkerGlobalScope(executionContext)->scriptController();
    ASSERT(scriptController);

    promiseRejectHandler(data, *scriptController->getRejectedPromises(), scriptState);
}
Пример #10
0
static void promiseRejectHandlerInMainThread(v8::PromiseRejectMessage data) {
  ASSERT(isMainThread());

  v8::Local<v8::Promise> promise = data.GetPromise();

  v8::Isolate* isolate = promise->GetIsolate();

  // TODO(ikilpatrick): Remove this check, extensions tests that use
  // extensions::ModuleSystemTest incorrectly don't have a valid script state.
  LocalDOMWindow* window = currentDOMWindow(isolate);
  if (!window || !window->isCurrentlyDisplayedInFrame())
    return;

  // Bail out if called during context initialization.
  ScriptState* scriptState = ScriptState::current(isolate);
  if (!scriptState->contextIsValid())
    return;

  promiseRejectHandler(data, rejectedPromisesOnMainThread(), scriptState);
}
void V8AbstractEventListener::handleEvent(ExecutionContext* executionContext, Event* event)
{
    if (!executionContext)
        return;
    // Don't reenter V8 if execution was terminated in this instance of V8.
    if (executionContext->isJSExecutionForbidden())
        return;

    // A ScriptState used by the event listener needs to be calculated based on
    // the ExecutionContext that fired the the event listener and the world
    // that installed the event listener.
    ASSERT(event);
    v8::HandleScope handleScope(toIsolate(executionContext));
    v8::Local<v8::Context> v8Context = toV8Context(executionContext, world());
    if (v8Context.IsEmpty())
        return;
    ScriptState* scriptState = ScriptState::from(v8Context);
    if (!scriptState->contextIsValid())
        return;
    handleEvent(scriptState, event);
}
Пример #12
0
// http://dev.w3.org/html5/spec/Overview.html#prepare-a-script
bool ScriptLoader::prepareScript(const TextPosition& scriptStartPosition, LegacyTypeSupport supportLegacyTypes)
{
    if (m_alreadyStarted)
        return false;

    ScriptLoaderClient* client = this->client();

    bool wasParserInserted;
    if (m_parserInserted) {
        wasParserInserted = true;
        m_parserInserted = false;
    } else {
        wasParserInserted = false;
    }

    if (wasParserInserted && !client->asyncAttributeValue())
        m_forceAsync = true;

    // FIXME: HTML5 spec says we should check that all children are either comments or empty text nodes.
    if (!client->hasSourceAttribute() && !m_element->hasChildren())
        return false;

    if (!m_element->inDocument())
        return false;

    if (!isScriptTypeSupported(supportLegacyTypes))
        return false;

    if (wasParserInserted) {
        m_parserInserted = true;
        m_forceAsync = false;
    }

    m_alreadyStarted = true;

    // FIXME: If script is parser inserted, verify it's still in the original document.
    Document& elementDocument = m_element->document();
    Document* contextDocument = elementDocument.contextDocument().get();

    if (!contextDocument || !contextDocument->allowExecutingScripts(m_element))
        return false;

    if (!isScriptForEventSupported())
        return false;

    if (!client->charsetAttributeValue().isEmpty())
        m_characterEncoding = client->charsetAttributeValue();
    else
        m_characterEncoding = elementDocument.characterSet();

    if (client->hasSourceAttribute()) {
        FetchRequest::DeferOption defer = FetchRequest::NoDefer;
        if (!m_parserInserted || client->asyncAttributeValue() || client->deferAttributeValue())
            defer = FetchRequest::LazyLoad;
        if (!fetchScript(client->sourceAttributeValue(), defer))
            return false;
    }

    if (client->hasSourceAttribute() && client->deferAttributeValue() && m_parserInserted && !client->asyncAttributeValue()) {
        m_willExecuteWhenDocumentFinishedParsing = true;
        m_willBeParserExecuted = true;
    } else if (client->hasSourceAttribute() && m_parserInserted && !client->asyncAttributeValue()) {
        m_willBeParserExecuted = true;
    } else if (!client->hasSourceAttribute() && m_parserInserted && !elementDocument.isRenderingReady()) {
        m_willBeParserExecuted = true;
        m_readyToBeParserExecuted = true;
    } else if (client->hasSourceAttribute() && !client->asyncAttributeValue() && !m_forceAsync) {
        m_willExecuteInOrder = true;
        m_pendingScript = PendingScript(m_element, m_resource.get());
        contextDocument->scriptRunner()->queueScriptForExecution(this, ScriptRunner::IN_ORDER_EXECUTION);
        // Note that watchForLoad can immediately call notifyFinished.
        m_pendingScript.watchForLoad(this);
    } else if (client->hasSourceAttribute()) {
        m_pendingScript = PendingScript(m_element, m_resource.get());
        LocalFrame* frame = m_element->document().frame();
        if (frame) {
            ScriptState* scriptState = ScriptState::forMainWorld(frame);
            if (scriptState->contextIsValid())
                ScriptStreamer::startStreaming(m_pendingScript, PendingScript::Async, frame->settings(), scriptState, frame->frameScheduler()->loadingTaskRunner());
        }
        contextDocument->scriptRunner()->queueScriptForExecution(this, ScriptRunner::ASYNC_EXECUTION);
        // Note that watchForLoad can immediately call notifyFinished.
        m_pendingScript.watchForLoad(this);
    } else {
        // Reset line numbering for nested writes.
        TextPosition position = elementDocument.isInDocumentWrite() ? TextPosition() : scriptStartPosition;
        KURL scriptURL = (!elementDocument.isInDocumentWrite() && m_parserInserted) ? elementDocument.url() : KURL();
        if (!executeScript(ScriptSourceCode(scriptContent(), scriptURL, position))) {
            dispatchErrorEvent();
            return false;
        }
    }

    return true;
}
Пример #13
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();
}
Пример #14
0
void V8LazyEventListener::prepareListenerObject(ExecutionContext* executionContext)
{
    if (!executionContext)
        return;

    // A ScriptState used by the event listener needs to be calculated based on
    // the ExecutionContext that fired the the event listener and the world
    // that installed the event listener.
    v8::HandleScope handleScope(toIsolate(executionContext));
    v8::Local<v8::Context> v8Context = toV8Context(executionContext, world());
    if (v8Context.IsEmpty())
        return;
    ScriptState* scriptState = ScriptState::from(v8Context);
    if (!scriptState->contextIsValid())
        return;

    if (!executionContext->isDocument())
        return;

    if (!toDocument(executionContext)->allowInlineEventHandlers(m_node, this, m_sourceURL, m_position.m_line)) {
        clearListenerObject();
        return;
    }

    if (hasExistingListenerObject())
        return;

    ScriptState::Scope scope(scriptState);

    // FIXME: Remove the following 'with' hack.
    //
    // Nodes other than the document object, when executing inline event
    // handlers push document, form owner, and the target node on the scope chain.
    // We do this by using 'with' statement.
    // See chrome/fast/forms/form-action.html
    //     chrome/fast/forms/selected-index-value.html
    //     base/fast/overflow/onscroll-layer-self-destruct.html
    //
    // Don't use new lines so that lines in the modified handler
    // have the same numbers as in the original code.
    // FIXME: V8 does not allow us to programmatically create object environments so
    //        we have to do this hack! What if m_code escapes to run arbitrary script?
    //
    // Call with 4 arguments instead of 3, pass additional null as the last parameter.
    // By calling the function with 4 arguments, we create a setter on arguments object
    // which would shadow property "3" on the prototype.
    String code = "(function() {"
        "with (this[2]) {"
        "with (this[1]) {"
        "with (this[0]) {"
            "return function(" + m_eventParameterName + ") {" +
                m_code + "\n" // Insert '\n' otherwise //-style comments could break the handler.
            "};"
        "}}}})";

    v8::Local<v8::String> codeExternalString = v8String(isolate(), code);

    v8::Local<v8::Value> result;
    if (!V8ScriptRunner::compileAndRunInternalScript(codeExternalString, isolate(), m_sourceURL, m_position).ToLocal(&result))
        return;

    // Call the outer function to get the inner function.
    if (!result->IsFunction())
        return;
    v8::Local<v8::Function> intermediateFunction = result.As<v8::Function>();

    HTMLFormElement* formElement = 0;
    if (m_node && m_node->isHTMLElement())
        formElement = toHTMLElement(m_node)->formOwner();

    v8::Local<v8::Object> nodeWrapper = toObjectWrapper<Node>(m_node, scriptState);
    v8::Local<v8::Object> formWrapper = toObjectWrapper<HTMLFormElement>(formElement, scriptState);
    v8::Local<v8::Object> documentWrapper = toObjectWrapper<Document>(m_node ? m_node->ownerDocument() : 0, scriptState);

    v8::Local<v8::Object> thisObject = v8::Object::New(isolate());
    if (thisObject.IsEmpty())
        return;
    if (!v8CallBoolean(thisObject->ForceSet(scriptState->context(), v8::Integer::New(isolate(), 0), nodeWrapper)))
        return;
    if (!v8CallBoolean(thisObject->ForceSet(scriptState->context(), v8::Integer::New(isolate(), 1), formWrapper)))
        return;
    if (!v8CallBoolean(thisObject->ForceSet(scriptState->context(), v8::Integer::New(isolate(), 2), documentWrapper)))
        return;

    // FIXME: Remove this code when we stop doing the 'with' hack above.
    v8::Local<v8::Value> innerValue;
    if (!V8ScriptRunner::callInternalFunction(intermediateFunction, thisObject, 0, 0, isolate()).ToLocal(&innerValue) || !innerValue->IsFunction())
        return;

    v8::Local<v8::Function> wrappedFunction = innerValue.As<v8::Function>();

    // Change the toString function on the wrapper function to avoid it
    // returning the source for the actual wrapper function. Instead it
    // returns source for a clean wrapper function with the event
    // argument wrapping the event source code. The reason for this is
    // that some web sites use toString on event functions and eval the
    // source returned (sometimes a RegExp is applied as well) for some
    // other use. That fails miserably if the actual wrapper source is
    // returned.
    v8::Local<v8::Function> toStringFunction = v8::Function::New(isolate(), V8LazyEventListenerToString);
    if (toStringFunction.IsEmpty())
        return;
    String toStringString = "function " + m_functionName + "(" + m_eventParameterName + ") {\n  " + m_code + "\n}";
    V8HiddenValue::setHiddenValue(isolate(), wrappedFunction, V8HiddenValue::toStringString(isolate()), v8String(isolate(), toStringString));
    if (!v8CallBoolean(wrappedFunction->Set(scriptState->context(), v8AtomicString(isolate(), "toString"), toStringFunction)))
        return;
    wrappedFunction->SetName(v8String(isolate(), m_functionName));

    // FIXME: Remove the following comment-outs.
    // See https://bugs.webkit.org/show_bug.cgi?id=85152 for more details.
    //
    // For the time being, we comment out the following code since the
    // second parsing can happen.
    // // Since we only parse once, there's no need to keep data used for parsing around anymore.
    // m_functionName = String();
    // m_code = String();
    // m_eventParameterName = String();
    // m_sourceURL = String();

    setListenerObject(wrappedFunction);
}
Пример #15
0
void V8LazyEventListener::prepareListenerObject(ExecutionContext* executionContext)
{
    if (!executionContext)
        return;

    // A ScriptState used by the event listener needs to be calculated based on
    // the ExecutionContext that fired the the event listener and the world
    // that installed the event listener.
    v8::HandleScope handleScope(toIsolate(executionContext));
    v8::Local<v8::Context> v8Context = toV8Context(executionContext, world());
    if (v8Context.IsEmpty())
        return;
    ScriptState* scriptState = ScriptState::from(v8Context);
    if (!scriptState->contextIsValid())
        return;

    if (!executionContext->isDocument())
        return;

    if (!toDocument(executionContext)->allowInlineEventHandlers(m_node, this, m_sourceURL, m_position.m_line)) {
        clearListenerObject();
        return;
    }

    if (hasExistingListenerObject())
        return;

    ScriptState::Scope scope(scriptState);

    // Nodes other than the document object, when executing inline event
    // handlers push document, form owner, and the target node on the scope chain.
    // We do this by using 'with' statement.
    // See fast/forms/form-action.html
    //     fast/forms/selected-index-value.html
    //     fast/overflow/onscroll-layer-self-destruct.html
    HTMLFormElement* formElement = 0;
    if (m_node && m_node->isHTMLElement())
        formElement = toHTMLElement(m_node)->formOwner();

    v8::Local<v8::Object> scopes[3];

    scopes[2] = toObjectWrapper<Node>(m_node, scriptState);
    scopes[1] = toObjectWrapper<HTMLFormElement>(formElement, scriptState);
    scopes[0] = toObjectWrapper<Document>(m_node ? m_node->ownerDocument() : 0, scriptState);

    v8::Local<v8::String> parameterName = v8String(isolate(), m_eventParameterName);
    v8::ScriptOrigin origin(
        v8String(isolate(), m_sourceURL),
        v8::Integer::New(isolate(), m_position.m_line.zeroBasedInt()),
        v8::Integer::New(isolate(), m_position.m_column.zeroBasedInt()),
        v8::True(isolate()),
        v8::Local<v8::Integer>(),
        v8::True(isolate()));
    v8::ScriptCompiler::Source source(v8String(isolate(), m_code), origin);

    v8::Local<v8::Function> wrappedFunction;
    {
        // JavaScript compilation error shouldn't be reported as a runtime
        // exception because we're not running any program code.  Instead,
        // it should be reported as an ErrorEvent.
        v8::TryCatch block(isolate());
        wrappedFunction = v8::ScriptCompiler::CompileFunctionInContext(isolate(), &source, v8Context, 1, &parameterName, 3, scopes);
        if (block.HasCaught()) {
            fireErrorEvent(v8Context, executionContext, block.Message());
            return;
        }
    }

    // Change the toString function on the wrapper function to avoid it
    // returning the source for the actual wrapper function. Instead it
    // returns source for a clean wrapper function with the event
    // argument wrapping the event source code. The reason for this is
    // that some web sites use toString on event functions and eval the
    // source returned (sometimes a RegExp is applied as well) for some
    // other use. That fails miserably if the actual wrapper source is
    // returned.
    v8::Local<v8::Function> toStringFunction = v8::Function::New(isolate(), V8LazyEventListenerToString);
    if (toStringFunction.IsEmpty())
        return;
    String toStringString = "function " + m_functionName + "(" + m_eventParameterName + ") {\n  " + m_code + "\n}";
    V8HiddenValue::setHiddenValue(scriptState, wrappedFunction, V8HiddenValue::toStringString(isolate()), v8String(isolate(), toStringString));
    if (!v8CallBoolean(wrappedFunction->Set(scriptState->context(), v8AtomicString(isolate(), "toString"), toStringFunction)))
        return;
    wrappedFunction->SetName(v8String(isolate(), m_functionName));

    // FIXME: Remove the following comment-outs.
    // See https://bugs.webkit.org/show_bug.cgi?id=85152 for more details.
    //
    // For the time being, we comment out the following code since the
    // second parsing can happen.
    // // Since we only parse once, there's no need to keep data used for parsing around anymore.
    // m_functionName = String();
    // m_code = String();
    // m_eventParameterName = String();
    // m_sourceURL = String();
    setListenerObject(wrappedFunction, scriptState);
}