PassRefPtr<JSLazyEventListener> createAttributeEventListener(Node* node, Attribute* attr)
{
    ASSERT(node);
    ASSERT(attr);
    if (attr->isNull())
        return 0;

    int lineNumber = 1;
    String sourceURL;
    JSObject* wrapper = 0;
    
    // FIXME: We should be able to provide accurate source information for frameless documents, too (e.g. for importing nodes from XMLHttpRequest.responseXML).
    if (Frame* frame = node->document()->frame()) {
        ScriptController* scriptController = frame->script();
        if (!scriptController->canExecuteScripts())
            return 0;

        if (!scriptController->xssAuditor()->canCreateInlineEventListener(attr->localName().string(), attr->value())) {
            // This script is not safe to execute.
            return 0;
        }

        lineNumber = scriptController->eventHandlerLineNumber();
        sourceURL = node->document()->url().string();

        JSC::JSLock lock(SilenceAssertionsOnly);
        JSDOMGlobalObject* globalObject = toJSDOMGlobalObject(node->document(), mainThreadNormalWorld());
        wrapper = asObject(toJS(globalObject->globalExec(), globalObject, node));
    }

    return JSLazyEventListener::create(attr->localName().string(), eventParameterName(node->isSVGElement()), attr->value(), node, sourceURL, lineNumber, wrapper, mainThreadNormalWorld());
}
void JSWorkerContextErrorHandler::handleEvent(ScriptExecutionContext* scriptExecutionContext, Event* event)
{
    ASSERT(scriptExecutionContext);
    if (!scriptExecutionContext)
        return;

    JSLock lock(SilenceAssertionsOnly);

    JSObject* jsFunction = this->jsFunction(scriptExecutionContext);
    if (!jsFunction)
        return;

    JSDOMGlobalObject* globalObject = toJSDOMGlobalObject(scriptExecutionContext, isolatedWorld());
    if (!globalObject)
        return;

    ExecState* exec = globalObject->globalExec();

    CallData callData;
    CallType callType = jsFunction->getCallData(callData);

    if (callType != CallTypeNone) {

        ref();

        Event* savedEvent = globalObject->currentEvent();
        globalObject->setCurrentEvent(event);

        ASSERT(event->isErrorEvent());
        ErrorEvent* errorEvent = static_cast<ErrorEvent*>(event);

        MarkedArgumentBuffer args;
        args.append(jsString(exec, errorEvent->message()));
        args.append(jsString(exec, errorEvent->filename()));
        args.append(jsNumber(exec, errorEvent->lineno()));

        JSGlobalData* globalData = globalObject->globalData();
        DynamicGlobalObjectScope globalObjectScope(exec, globalData->dynamicGlobalObject ? globalData->dynamicGlobalObject : globalObject);    

        JSValue thisValue = globalObject->toThisObject(exec);

        globalData->timeoutChecker.start();
        JSValue returnValue = JSC::call(exec, jsFunction, callType, callData, thisValue, args);
        globalData->timeoutChecker.stop();

        globalObject->setCurrentEvent(savedEvent);

        if (exec->hadException())
            reportCurrentException(exec);
        else {
            bool retvalbool;
            if (returnValue.getBoolean(retvalbool) && !retvalbool)
                event->preventDefault();
        }

        deref();
    }
}
void JSErrorHandler::handleEvent(ScriptExecutionContext* scriptExecutionContext, Event* event)
{
    if (!event->hasInterface(eventNames().interfaceForErrorEvent))
        return JSEventListener::handleEvent(scriptExecutionContext, event);

    ASSERT(scriptExecutionContext);
    if (!scriptExecutionContext)
        return;

    ErrorEvent* errorEvent = static_cast<ErrorEvent*>(event);

    JSLock lock(SilenceAssertionsOnly);

    JSObject* jsFunction = this->jsFunction(scriptExecutionContext);
    if (!jsFunction)
        return;

    JSDOMGlobalObject* globalObject = toJSDOMGlobalObject(scriptExecutionContext, isolatedWorld());
    if (!globalObject)
        return;

    ExecState* exec = globalObject->globalExec();

    CallData callData;
    CallType callType = jsFunction->methodTable()->getCallData(jsFunction, callData);

    if (callType != CallTypeNone) {
        RefPtr<JSErrorHandler> protectedctor(this);

        Event* savedEvent = globalObject->currentEvent();
        globalObject->setCurrentEvent(event);

        MarkedArgumentBuffer args;
        args.append(jsString(exec, errorEvent->message()));
        args.append(jsString(exec, errorEvent->filename()));
        args.append(jsNumber(errorEvent->lineno()));

        JSGlobalData& globalData = globalObject->globalData();
        DynamicGlobalObjectScope globalObjectScope(globalData, globalData.dynamicGlobalObject ? globalData.dynamicGlobalObject : globalObject);

        JSValue thisValue = globalObject->methodTable()->toThisObject(globalObject, exec);

        globalData.timeoutChecker.start();
        JSValue returnValue = scriptExecutionContext->isDocument()
            ? JSMainThreadExecState::call(exec, jsFunction, callType, callData, thisValue, args)
            : JSC::call(exec, jsFunction, callType, callData, thisValue, args);
        globalData.timeoutChecker.stop();

        globalObject->setCurrentEvent(savedEvent);

        if (exec->hadException())
            reportCurrentException(exec);
        else {
            if (returnValue.isTrue())
                event->preventDefault();
        }
    }
}
void JSErrorHandler::handleEvent(ScriptExecutionContext* scriptExecutionContext, Event* event)
{

    if (!is<ErrorEvent>(*event))
        return JSEventListener::handleEvent(scriptExecutionContext, event);

    ASSERT(scriptExecutionContext);
    if (!scriptExecutionContext)
        return;

    ErrorEvent& errorEvent = downcast<ErrorEvent>(*event);

    JSLockHolder lock(scriptExecutionContext->vm());

    JSObject* jsFunction = this->jsFunction(scriptExecutionContext);
    if (!jsFunction)
        return;

    JSDOMGlobalObject* globalObject = toJSDOMGlobalObject(scriptExecutionContext, isolatedWorld());
    if (!globalObject)
        return;

    ExecState* exec = globalObject->globalExec();

    CallData callData;
    CallType callType = jsFunction->methodTable()->getCallData(jsFunction, callData);

    if (callType != CallTypeNone) {
        Ref<JSErrorHandler> protectedctor(*this);

        Event* savedEvent = globalObject->currentEvent();
        globalObject->setCurrentEvent(event);

        MarkedArgumentBuffer args;
        args.append(jsStringWithCache(exec, errorEvent.message()));
        args.append(jsStringWithCache(exec, errorEvent.filename()));
        args.append(jsNumber(errorEvent.lineno()));
        args.append(jsNumber(errorEvent.colno()));

        VM& vm = globalObject->vm();
        VMEntryScope entryScope(vm, vm.entryScope ? vm.entryScope->globalObject() : globalObject);

        NakedPtr<Exception> exception;
        JSValue returnValue = scriptExecutionContext->isDocument()
            ? JSMainThreadExecState::call(exec, jsFunction, callType, callData, globalObject, args, exception)
            : JSC::call(exec, jsFunction, callType, callData, globalObject, args, exception);

        globalObject->setCurrentEvent(savedEvent);

        if (exception)
            reportException(exec, exception);
        else {
            if (returnValue.isTrue())
                event->preventDefault();
        }
    }
}
JSObject* JSLazyEventListener::initializeJSFunction(ScriptExecutionContext* executionContext) const
{
    ASSERT(executionContext);
    ASSERT(executionContext->isDocument());
    if (!executionContext)
        return 0;

    Document* document = static_cast<Document*>(executionContext);

    if (!document->frame())
        return 0;

    if (!document->contentSecurityPolicy()->allowInlineEventHandlers())
        return 0;

    ScriptController* script = document->frame()->script();
    if (!script->canExecuteScripts(AboutToExecuteScript) || script->isPaused())
        return 0;

    JSDOMGlobalObject* globalObject = toJSDOMGlobalObject(executionContext, isolatedWorld());
    if (!globalObject)
        return 0;

    ExecState* exec = globalObject->globalExec();

    MarkedArgumentBuffer args;
    args.append(jsNontrivialString(exec, stringToUString(m_eventParameterName)));
    args.append(jsString(exec, m_code));

    JSObject* jsFunction = constructFunctionSkippingEvalEnabledCheck(exec, exec->lexicalGlobalObject(), args, Identifier(exec, stringToUString(m_functionName)), stringToUString(m_sourceURL), m_position); // FIXME: is globalExec ok?
    if (exec->hadException()) {
        reportCurrentException(exec);
        exec->clearException();
        return 0;
    }

    JSFunction* listenerAsFunction = jsCast<JSFunction*>(jsFunction);
    if (m_originalNode) {
        if (!wrapper()) {
            // Ensure that 'node' has a JavaScript wrapper to mark the event listener we're creating.
            JSLock lock(SilenceAssertionsOnly);
            // FIXME: Should pass the global object associated with the node
            setWrapper(exec->globalData(), asObject(toJS(exec, globalObject, m_originalNode)));
        }

        // Add the event's home element to the scope
        // (and the document, and the form - see JSHTMLElement::eventHandlerScope)
        listenerAsFunction->setScope(exec->globalData(), jsCast<JSNode*>(wrapper())->pushEventHandlerScope(exec, listenerAsFunction->scope()));
    }

    // 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();
    return jsFunction;
}
static inline bool checkReadableStream(JSDOMGlobalObject& globalObject, JSReadableStream* readableStream, JSC::JSValue function)
{
    auto& state = *globalObject.globalExec();

    ASSERT(function);
    JSC::MarkedArgumentBuffer arguments;
    arguments.append(readableStream);
    ASSERT(!arguments.hasOverflowed());
    return ReadableStreamInternal::callFunction(state, function, JSC::jsUndefined(), arguments).isTrue();
}
void HTMLPlugInImageElement::didAddUserAgentShadowRoot(ShadowRoot* root)
{
    HTMLPlugInElement::didAddUserAgentShadowRoot(root);
    if (displayState() >= PreparingPluginReplacement)
        return;

    Page* page = document().page();
    if (!page)
        return;

    // Reset any author styles that may apply as we only want explicit
    // styles defined in the injected user agents stylesheets to specify
    // the look-and-feel of the snapshotted plug-in overlay. 
    root->setResetStyleInheritance(true);
    
    String mimeType = loadedMimeType();

    DOMWrapperWorld& isolatedWorld = plugInImageElementIsolatedWorld();
    document().ensurePlugInsInjectedScript(isolatedWorld);

    ScriptController& scriptController = document().frame()->script();
    JSDOMGlobalObject* globalObject = JSC::jsCast<JSDOMGlobalObject*>(scriptController.globalObject(isolatedWorld));
    JSC::ExecState* exec = globalObject->globalExec();

    JSC::JSLockHolder lock(exec);

    JSC::MarkedArgumentBuffer argList;
    argList.append(toJS(exec, globalObject, root));
    argList.append(jsString(exec, titleText(page, mimeType)));
    argList.append(jsString(exec, subtitleText(page, mimeType)));
    
    // This parameter determines whether or not the snapshot overlay should always be visible over the plugin snapshot.
    // If no snapshot was found then we want the overlay to be visible.
    argList.append(JSC::jsBoolean(!m_snapshotImage));

    // It is expected the JS file provides a createOverlay(shadowRoot, title, subtitle) function.
    JSC::JSObject* overlay = globalObject->get(exec, JSC::Identifier::fromString(exec, "createOverlay")).toObject(exec);
    if (!overlay) {
        ASSERT(exec->hadException());
        exec->clearException();
        return;
    }
    JSC::CallData callData;
    JSC::CallType callType = overlay->methodTable()->getCallData(overlay, callData);
    if (callType == JSC::CallType::None)
        return;

    JSC::call(exec, overlay, callType, callData, globalObject, argList);
    exec->clearException();
}
Exemple #8
0
TransferSharedPtr<WebValue> WebFrame::getWrappedAttributeEventListener(const char* name)
{
    AtomicString type(name);
    Frame* coreFrame = core(this);
    if (!coreFrame && !coreFrame->document())
        return 0;
    EventListener* listener = coreFrame->document()->getWindowAttributeEventListener(type);
    if (listener && listener->type() == EventListener::JSEventListenerType) {
        JSEventListener* jsListener = static_cast<JSEventListener*>(listener);
        JSDOMGlobalObject* globalObject = toJSDOMGlobalObject(coreFrame->document(), mainThreadNormalWorld());
        JSC::ExecState* execState = globalObject->globalExec();
        return WebValue::createInstance(BALValue::create(coreFrame, execState, jsListener->jsFunction(coreFrame->document())).get());
    }
    return 0;
}
bool JSEventListener::reportError(const String& message, const String& url, int lineNumber)
{
    JSLock lock(SilenceAssertionsOnly);

    JSObject* jsFunction = this->jsFunction();
    if (!jsFunction)
        return false;

    JSDOMGlobalObject* globalObject = m_globalObject;
    if (!globalObject)
        return false;

    ExecState* exec = globalObject->globalExec();

    CallData callData;
    CallType callType = jsFunction->getCallData(callData);

    if (callType == CallTypeNone)
        return false;

    MarkedArgumentBuffer args;
    args.append(jsString(exec, message));
    args.append(jsString(exec, url));
    args.append(jsNumber(exec, lineNumber));

    // If this event handler is the first JavaScript to execute, then the
    // dynamic global object should be set to the global object of the
    // window in which the event occurred.
    JSGlobalData* globalData = globalObject->globalData();
    DynamicGlobalObjectScope globalObjectScope(exec, globalData->dynamicGlobalObject ? globalData->dynamicGlobalObject : globalObject);    

    JSValue thisValue = globalObject->toThisObject(exec);

    globalObject->globalData()->timeoutChecker.start();
    JSValue returnValue = call(exec, jsFunction, callType, callData, thisValue, args);
    globalObject->globalData()->timeoutChecker.stop();

    // If an error occurs while handling the script error, it should be bubbled up.
    if (exec->hadException()) {
        exec->clearException();
        return false;
    }
    
    bool bubbleEvent;
    return returnValue.getBoolean(bubbleEvent) && !bubbleEvent;
}
Exemple #10
0
void JSMutationCallback::call(const Vector<RefPtr<MutationRecord> >& mutations, MutationObserver* observer)
{
    if (!canInvokeCallback())
        return;

    RefPtr<JSMutationCallback> protect(this);

    JSLockHolder lock(m_isolatedWorld->globalData());

    if (!m_callback)
        return;

    JSValue callback = m_callback.get();
    CallData callData;
    CallType callType = getCallData(callback, callData);
    if (callType == CallTypeNone) {
        ASSERT_NOT_REACHED();
        return;
    }

    ScriptExecutionContext* context = scriptExecutionContext();
    if (!context)
        return;
    ASSERT(context->isDocument());

    JSDOMGlobalObject* globalObject = toJSDOMGlobalObject(context, m_isolatedWorld.get());
    ExecState* exec = globalObject->globalExec();

    JSValue jsObserver = toJS(exec, globalObject, observer);

    MarkedArgumentBuffer args;
    args.append(jsArray(exec, globalObject, mutations));
    args.append(jsObserver);

    globalObject->globalData().timeoutChecker.start();
    InspectorInstrumentationCookie cookie = JSMainThreadExecState::instrumentFunctionCall(context, callType, callData);

    JSMainThreadExecState::call(exec, callback, callType, callData, jsObserver, args);

    InspectorInstrumentation::didCallFunction(cookie);
    globalObject->globalData().timeoutChecker.stop();

    if (exec->hadException())
        reportCurrentException(exec);
}
void JSMutationCallback::call(const Vector<RefPtr<MutationRecord>>& mutations, MutationObserver* observer)
{
    if (!canInvokeCallback())
        return;

    Ref<JSMutationCallback> protect(*this);

    JSLockHolder lock(m_isolatedWorld->vm());

    if (!m_callback)
        return;

    JSValue callback = m_callback.get();
    CallData callData;
    CallType callType = getCallData(callback, callData);
    if (callType == CallType::None) {
        ASSERT_NOT_REACHED();
        return;
    }

    ScriptExecutionContext* context = scriptExecutionContext();
    if (!context)
        return;
    ASSERT(context->isDocument());

    JSDOMGlobalObject* globalObject = toJSDOMGlobalObject(context, *m_isolatedWorld);
    ExecState* exec = globalObject->globalExec();

    JSValue jsObserver = toJS(exec, globalObject, observer);

    MarkedArgumentBuffer args;
    args.append(jsArray(exec, globalObject, mutations));
    args.append(jsObserver);

    InspectorInstrumentationCookie cookie = JSMainThreadExecState::instrumentFunctionCall(context, callType, callData);

    NakedPtr<Exception> exception;
    JSMainThreadExecState::profiledCall(exec, JSC::ProfilingReason::Other, callback, callType, callData, jsObserver, args, exception);

    InspectorInstrumentation::didCallFunction(cookie, context);

    if (exception)
        reportException(exec, exception);
}
bool JSDatabaseCallback::handleEvent(ScriptExecutionContext* context, DatabaseSync* database)
{
    ASSERT(m_data);
    ASSERT(context);

    RefPtr<JSDatabaseCallback> protect(this);

    JSLock lock(SilenceAssertionsOnly);

    JSDOMGlobalObject* globalObject = toJSDOMGlobalObject(context, m_isolatedWorld.get());
    if (!globalObject)
        return true;

    ExecState* exec = globalObject->globalExec();
    MarkedArgumentBuffer args;
    args.append(toJS(exec, database));

    bool raisedException = false;
    m_data->invokeCallback(args, &raisedException);
    return !raisedException;
}
Exemple #13
0
bool JSEventListener::reportError(ScriptExecutionContext* context, const String& message, const String& url, int lineNumber)
{
    JSLock lock(SilenceAssertionsOnly);

    JSObject* jsFunction = this->jsFunction(context);
    if (!jsFunction)
        return false;

    JSDOMGlobalObject* globalObject = toJSDOMGlobalObject(context, m_isolatedWorld.get());
    ExecState* exec = globalObject->globalExec();

    CallData callData;
    CallType callType = jsFunction->getCallData(callData);

    if (callType == CallTypeNone)
        return false;

    MarkedArgumentBuffer args;
    args.append(jsString(exec, message));
    args.append(jsString(exec, url));
    args.append(jsNumber(exec, lineNumber));

    JSGlobalData* globalData = globalObject->globalData();
    DynamicGlobalObjectScope globalObjectScope(exec, globalData->dynamicGlobalObject ? globalData->dynamicGlobalObject : globalObject);    

    JSValue thisValue = globalObject->toThisObject(exec);

    globalData->timeoutChecker.start();
    JSValue returnValue = JSC::call(exec, jsFunction, callType, callData, thisValue, args);
    globalData->timeoutChecker.stop();

    // If an error occurs while handling the script error, it should be bubbled up.
    if (exec->hadException()) {
        exec->clearException();
        return false;
    }
    
    bool bubbleEvent;
    return returnValue.getBoolean(bubbleEvent) && !bubbleEvent;
}
void JSEventListener::handleEvent(ScriptExecutionContext* scriptExecutionContext, Event* event)
{
    ASSERT(scriptExecutionContext);
    if (!scriptExecutionContext || scriptExecutionContext->isJSExecutionForbidden())
        return;

    JSLockHolder lock(scriptExecutionContext->vm());

    JSObject* jsFunction = this->jsFunction(scriptExecutionContext);
    if (!jsFunction)
        return;

    JSDOMGlobalObject* globalObject = toJSDOMGlobalObject(scriptExecutionContext, *m_isolatedWorld);
    if (!globalObject)
        return;

    if (scriptExecutionContext->isDocument()) {
        JSDOMWindow* window = jsCast<JSDOMWindow*>(globalObject);
        if (!window->impl().isCurrentlyDisplayedInFrame())
            return;
        // FIXME: Is this check needed for other contexts?
        ScriptController& script = window->impl().frame()->script();
        if (!script.canExecuteScripts(AboutToExecuteScript) || script.isPaused())
            return;
    }

    ExecState* exec = globalObject->globalExec();
    JSValue handleEventFunction = jsFunction;

    CallData callData;
    CallType callType = getCallData(handleEventFunction, callData);
    // If jsFunction is not actually a function, see if it implements the EventListener interface and use that
    if (callType == CallTypeNone) {
        handleEventFunction = jsFunction->get(exec, Identifier::fromString(exec, "handleEvent"));
        callType = getCallData(handleEventFunction, callData);
    }

    if (callType != CallTypeNone) {
        Ref<JSEventListener> protect(*this);

        MarkedArgumentBuffer args;
        args.append(toJS(exec, globalObject, event));

        Event* savedEvent = globalObject->currentEvent();
        globalObject->setCurrentEvent(event);

        VM& vm = globalObject->vm();
        VMEntryScope entryScope(vm, vm.entryScope ? vm.entryScope->globalObject() : globalObject);

        InspectorInstrumentationCookie cookie = JSMainThreadExecState::instrumentFunctionCall(scriptExecutionContext, callType, callData);

        JSValue thisValue = handleEventFunction == jsFunction ? toJS(exec, globalObject, event->currentTarget()) : jsFunction;
        NakedPtr<Exception> exception;
        JSValue retval = scriptExecutionContext->isDocument()
            ? JSMainThreadExecState::call(exec, handleEventFunction, callType, callData, thisValue, args, exception)
            : JSC::call(exec, handleEventFunction, callType, callData, thisValue, args, exception);

        InspectorInstrumentation::didCallFunction(cookie, scriptExecutionContext);

        globalObject->setCurrentEvent(savedEvent);

        if (is<WorkerGlobalScope>(*scriptExecutionContext)) {
            bool terminatorCausedException = (exec->hadException() && isTerminatedExecutionException(exec->exception()));
            if (terminatorCausedException || (vm.watchdog && vm.watchdog->didFire()))
                downcast<WorkerGlobalScope>(*scriptExecutionContext).script()->forbidExecution();
        }

        if (exception) {
            event->target()->uncaughtExceptionInEventHandler();
            reportException(exec, exception);
        } else {
            if (!retval.isUndefinedOrNull() && is<BeforeUnloadEvent>(*event))
                downcast<BeforeUnloadEvent>(*event).setReturnValue(retval.toString(exec)->value(exec));
            if (m_isAttribute) {
                if (retval.isFalse())
                    event->preventDefault();
            }
        }
    }
}
JSObject* JSLazyEventListener::initializeJSFunction(ScriptExecutionContext* executionContext) const
{
    ASSERT(executionContext);
    ASSERT(executionContext->isDocument());
    if (!executionContext)
        return 0;

    Frame* frame = static_cast<Document*>(executionContext)->frame();
    if (!frame)
        return 0;

    ScriptController* scriptController = frame->script();
    if (!scriptController->canExecuteScripts(AboutToExecuteScript))
        return 0;

    JSDOMGlobalObject* globalObject = toJSDOMGlobalObject(executionContext, isolatedWorld());
    if (!globalObject)
        return 0;

    if (executionContext->isDocument()) {
        JSDOMWindow* window = static_cast<JSDOMWindow*>(globalObject);
        Frame* frame = window->impl()->frame();
        if (!frame)
            return 0;
        // FIXME: Is this check needed for non-Document contexts?
        ScriptController* script = frame->script();
        if (!script->canExecuteScripts(AboutToExecuteScript) || script->isPaused())
            return 0;
    }

    ExecState* exec = globalObject->globalExec();

    MarkedArgumentBuffer args;
    args.append(jsNontrivialString(exec, stringToUString(m_eventParameterName)));
    args.append(jsString(exec, m_code));

    JSObject* jsFunction = constructFunction(exec, args, Identifier(exec, stringToUString(m_functionName)), stringToUString(m_sourceURL), m_lineNumber); // FIXME: is globalExec ok?
    if (exec->hadException()) {
        exec->clearException();
        return 0;
    }

    JSFunction* listenerAsFunction = static_cast<JSFunction*>(jsFunction);
    if (m_originalNode) {
        if (!wrapper()) {
            // Ensure that 'node' has a JavaScript wrapper to mark the event listener we're creating.
            JSLock lock(SilenceAssertionsOnly);
            // FIXME: Should pass the global object associated with the node
            setWrapper(asObject(toJS(globalObject->globalExec(), globalObject, m_originalNode)));
        }

        // Add the event's home element to the scope
        // (and the document, and the form - see JSHTMLElement::eventHandlerScope)
        ScopeChain scope = listenerAsFunction->scope();
        static_cast<JSNode*>(wrapper())->pushEventHandlerScope(exec, scope);
        listenerAsFunction->setScope(scope);
    }

    // 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();
    return jsFunction;
}
Exemple #16
0
void JSEventListener::handleEvent(ScriptExecutionContext* scriptExecutionContext, Event* event)
{
    ASSERT(scriptExecutionContext);
    if (!scriptExecutionContext || scriptExecutionContext->isJSExecutionTerminated())
        return;

    JSLock lock(SilenceAssertionsOnly);

    JSObject* jsFunction = this->jsFunction(scriptExecutionContext);
    if (!jsFunction)
        return;

    JSDOMGlobalObject* globalObject = toJSDOMGlobalObject(scriptExecutionContext, m_isolatedWorld.get());
    if (!globalObject)
        return;

    if (scriptExecutionContext->isDocument()) {
        JSDOMWindow* window = static_cast<JSDOMWindow*>(globalObject);
        Frame* frame = window->impl()->frame();
        if (!frame)
            return;
        // The window must still be active in its frame. See <https://bugs.webkit.org/show_bug.cgi?id=21921>.
        // FIXME: A better fix for this may be to change DOMWindow::frame() to not return a frame the detached window used to be in.
        if (frame->domWindow() != window->impl())
            return;
        // FIXME: Is this check needed for other contexts?
        ScriptController* script = frame->script();
        if (!script->canExecuteScripts(AboutToExecuteScript) || script->isPaused())
            return;
    }

    ExecState* exec = globalObject->globalExec();
    JSValue handleEventFunction = jsFunction->get(exec, Identifier(exec, "handleEvent"));

    CallData callData;
    CallType callType = handleEventFunction.getCallData(callData);
    if (callType == CallTypeNone) {
        handleEventFunction = JSValue();
        callType = jsFunction->getCallData(callData);
    }

    if (callType != CallTypeNone) {
        ref();

        MarkedArgumentBuffer args;
        args.append(toJS(exec, globalObject, event));

        Event* savedEvent = globalObject->currentEvent();
        globalObject->setCurrentEvent(event);

        JSGlobalData* globalData = globalObject->globalData();
        DynamicGlobalObjectScope globalObjectScope(exec, globalData->dynamicGlobalObject ? globalData->dynamicGlobalObject : globalObject);

        globalData->timeoutChecker.start();
        JSValue retval = handleEventFunction
            ? JSC::call(exec, handleEventFunction, callType, callData, jsFunction, args)
            : JSC::call(exec, jsFunction, callType, callData, toJS(exec, globalObject, event->currentTarget()), args);
        globalData->timeoutChecker.stop();

        globalObject->setCurrentEvent(savedEvent);

        if (exec->hadException())
#if PLATFORM(APOLLO)
            reportApolloException(globalObject);
#else
            reportCurrentException(exec);
#endif
        else {
            if (!retval.isUndefinedOrNull() && event->storesResultAsString())
Exemple #17
0
void JSLazyEventListener::parseCode(ScriptExecutionContext* executionContext) const
{
    ASSERT(executionContext);
    ASSERT(executionContext->isDocument());
    if (!executionContext)
        return;

    if (m_parsed)
        return;

    Frame* frame = static_cast<Document*>(executionContext)->frame();
    if (!frame)
        return;

    ScriptController* scriptController = frame->script();
    if (!scriptController->isEnabled())
        return;

    JSDOMGlobalObject* globalObject = toJSDOMGlobalObject(executionContext);
    if (!globalObject)
        return;

    // Ensure that 'node' has a JavaScript wrapper to mark the event listener we're creating.
    if (m_originalNode) {
        JSLock lock(SilenceAssertionsOnly);
        // FIXME: Should pass the global object associated with the node
        toJS(globalObject->globalExec(), globalObject, m_originalNode);
    }

    if (executionContext->isDocument()) {
        JSDOMWindow* window = static_cast<JSDOMWindow*>(globalObject);
        Frame* frame = window->impl()->frame();
        if (!frame)
            return;
        // FIXME: Is this check needed for non-Document contexts?
        ScriptController* script = frame->script();
        if (!script->isEnabled() || script->isPaused())
            return;
    }

    m_parsed = true;

    ExecState* exec = globalObject->globalExec();

    MarkedArgumentBuffer args;
    args.append(jsNontrivialString(exec, m_eventParameterName));
    args.append(jsString(exec, m_code));

    m_jsFunction = constructFunction(exec, args, Identifier(exec, m_functionName), m_sourceURL, m_lineNumber); // FIXME: is globalExec ok?

    JSFunction* listenerAsFunction = static_cast<JSFunction*>(m_jsFunction);

    if (exec->hadException()) {
        exec->clearException();

        // failed to parse, so let's just make this listener a no-op
        m_jsFunction = 0;
    } else if (m_originalNode) {
        // Add the event's home element to the scope
        // (and the document, and the form - see JSHTMLElement::eventHandlerScope)
        ScopeChain scope = listenerAsFunction->scope();

        JSValue thisObj = toJS(exec, globalObject, m_originalNode);
        if (thisObj.isObject()) {
            static_cast<JSNode*>(asObject(thisObj))->pushEventHandlerScope(exec, scope);
            listenerAsFunction->setScope(scope);
        }
    }

    // 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();
}
void JSEventListener::handleEvent(Event* event, bool isWindowEvent)
{
    JSLock lock(SilenceAssertionsOnly);

    JSObject* jsFunction = this->jsFunction();
    if (!jsFunction)
        return;

    JSDOMGlobalObject* globalObject = m_globalObject;
    // Null check as clearGlobalObject() can clear this and we still get called back by
    // xmlhttprequest objects. See http://bugs.webkit.org/show_bug.cgi?id=13275
    // FIXME: Is this check still necessary? Requests are supposed to be stopped before clearGlobalObject() is called.
    ASSERT(globalObject);
    if (!globalObject)
        return;

    ScriptExecutionContext* scriptExecutionContext = globalObject->scriptExecutionContext();
    if (!scriptExecutionContext)
        return;

    if (scriptExecutionContext->isDocument()) {
        JSDOMWindow* window = static_cast<JSDOMWindow*>(globalObject);
        Frame* frame = window->impl()->frame();
        if (!frame)
            return;
        // The window must still be active in its frame. See <https://bugs.webkit.org/show_bug.cgi?id=21921>.
        // FIXME: A better fix for this may be to change DOMWindow::frame() to not return a frame the detached window used to be in.
        if (frame->domWindow() != window->impl())
            return;
        // FIXME: Is this check needed for other contexts?
        ScriptController* script = frame->script();
        if (!script->isEnabled() || script->isPaused())
            return;
    }

    ExecState* exec = globalObject->globalExec();

    JSValue handleEventFunction = jsFunction->get(exec, Identifier(exec, "handleEvent"));
    CallData callData;
    CallType callType = handleEventFunction.getCallData(callData);
    if (callType == CallTypeNone) {
        handleEventFunction = JSValue();
        callType = jsFunction->getCallData(callData);
    }

    if (callType != CallTypeNone) {
        ref();

        MarkedArgumentBuffer args;
        args.append(toJS(exec, globalObject, event));

        Event* savedEvent = globalObject->currentEvent();
        globalObject->setCurrentEvent(event);

        // If this event handler is the first JavaScript to execute, then the
        // dynamic global object should be set to the global object of the
        // window in which the event occurred.
        JSGlobalData* globalData = globalObject->globalData();
        DynamicGlobalObjectScope globalObjectScope(exec, globalData->dynamicGlobalObject ? globalData->dynamicGlobalObject : globalObject);

        JSValue retval;
        if (handleEventFunction) {
            globalObject->globalData()->timeoutChecker.start();
            retval = call(exec, handleEventFunction, callType, callData, jsFunction, args);
        } else {
            JSValue thisValue;
            if (isWindowEvent)
                thisValue = globalObject->toThisObject(exec);
            else
                thisValue = toJS(exec, globalObject, event->currentTarget());
            globalObject->globalData()->timeoutChecker.start();
            retval = call(exec, jsFunction, callType, callData, thisValue, args);
        }
        globalObject->globalData()->timeoutChecker.stop();

        globalObject->setCurrentEvent(savedEvent);

        if (exec->hadException())
            reportCurrentException(exec);
        else {
            if (!retval.isUndefinedOrNull() && event->storesResultAsString())
                event->storeResult(retval.toString(exec));
            if (m_isAttribute) {
                bool retvalbool;
                if (retval.getBoolean(retvalbool) && !retvalbool)
                    event->preventDefault();
            }
        }

        if (scriptExecutionContext->isDocument())
            Document::updateStyleForAllDocuments();
        deref();
    }
}
JSObject* JSLazyEventListener::initializeJSFunction(ScriptExecutionContext* executionContext) const
{
    ASSERT(is<Document>(executionContext));
    if (!executionContext)
        return nullptr;

    ASSERT(!m_code.isNull());
    ASSERT(!m_eventParameterName.isNull());
    if (m_code.isNull() || m_eventParameterName.isNull())
        return nullptr;

    Document& document = downcast<Document>(*executionContext);

    if (!document.frame())
        return nullptr;

    if (!document.contentSecurityPolicy()->allowInlineEventHandlers(m_sourceURL, m_sourcePosition.m_line))
        return nullptr;

    ScriptController& script = document.frame()->script();
    if (!script.canExecuteScripts(AboutToExecuteScript) || script.isPaused())
        return nullptr;

    JSDOMGlobalObject* globalObject = toJSDOMGlobalObject(executionContext, isolatedWorld());
    if (!globalObject)
        return nullptr;

    VM& vm = globalObject->vm();
    JSLockHolder lock(vm);
    auto scope = DECLARE_CATCH_SCOPE(vm);
    ExecState* exec = globalObject->globalExec();

    MarkedArgumentBuffer args;
    args.append(jsNontrivialString(exec, m_eventParameterName));
    args.append(jsStringWithCache(exec, m_code));

    // We want all errors to refer back to the line on which our attribute was
    // declared, regardless of any newlines in our JavaScript source text.
    int overrideLineNumber = m_sourcePosition.m_line.oneBasedInt();

    JSObject* jsFunction = constructFunctionSkippingEvalEnabledCheck(
        exec, exec->lexicalGlobalObject(), args, Identifier::fromString(exec, m_functionName),
        m_sourceURL, m_sourcePosition, overrideLineNumber);

    if (UNLIKELY(scope.exception())) {
        reportCurrentException(exec);
        scope.clearException();
        return nullptr;
    }

    JSFunction* listenerAsFunction = jsCast<JSFunction*>(jsFunction);

    if (m_originalNode) {
        if (!wrapper()) {
            // Ensure that 'node' has a JavaScript wrapper to mark the event listener we're creating.
            // FIXME: Should pass the global object associated with the node
            setWrapper(vm, asObject(toJS(exec, globalObject, *m_originalNode)));
        }

        // Add the event's home element to the scope
        // (and the document, and the form - see JSHTMLElement::eventHandlerScope)
        listenerAsFunction->setScope(vm, jsCast<JSNode*>(wrapper())->pushEventHandlerScope(exec, listenerAsFunction->scope()));
    }
    return jsFunction;
}
Exemple #20
0
void JSEventListener::handleEvent(ScriptExecutionContext* scriptExecutionContext, Event* event)
{
    ASSERT(scriptExecutionContext);
    if (!scriptExecutionContext || scriptExecutionContext->isJSExecutionForbidden())
        return;

    JSLock lock(SilenceAssertionsOnly);

    JSObject* jsFunction = this->jsFunction(scriptExecutionContext);
    if (!jsFunction)
        return;

    JSDOMGlobalObject* globalObject = toJSDOMGlobalObject(scriptExecutionContext, m_isolatedWorld.get());
    if (!globalObject)
        return;

    if (scriptExecutionContext->isDocument()) {
        JSDOMWindow* window = static_cast<JSDOMWindow*>(globalObject);
        Frame* frame = window->impl()->frame();
        if (!frame)
            return;
        // The window must still be active in its frame. See <https://bugs.webkit.org/show_bug.cgi?id=21921>.
        // FIXME: A better fix for this may be to change DOMWindow::frame() to not return a frame the detached window used to be in.
        if (frame->domWindow() != window->impl())
            return;
        // FIXME: Is this check needed for other contexts?
        ScriptController* script = frame->script();
        if (!script->canExecuteScripts(AboutToExecuteScript) || script->isPaused())
            return;
    }

    ExecState* exec = globalObject->globalExec();
    JSValue handleEventFunction = jsFunction;

    CallData callData;
    CallType callType = getCallData(handleEventFunction, callData);
    // If jsFunction is not actually a function, see if it implements the EventListener interface and use that
    if (callType == CallTypeNone) {
        handleEventFunction = jsFunction->get(exec, Identifier(exec, "handleEvent"));
        callType = getCallData(handleEventFunction, callData);
    }

    if (callType != CallTypeNone) {
        RefPtr<JSEventListener> protect(this);

        MarkedArgumentBuffer args;
        args.append(toJS(exec, globalObject, event));

        Event* savedEvent = globalObject->currentEvent();
        globalObject->setCurrentEvent(event);

        JSGlobalData& globalData = globalObject->globalData();
        DynamicGlobalObjectScope globalObjectScope(globalData, globalData.dynamicGlobalObject ? globalData.dynamicGlobalObject : globalObject);

        globalData.timeoutChecker.start();
        JSValue thisValue = handleEventFunction == jsFunction ? toJS(exec, globalObject, event->currentTarget()) : jsFunction;
        JSValue retval = scriptExecutionContext->isDocument()
                         ? JSMainThreadExecState::call(exec, handleEventFunction, callType, callData, thisValue, args)
                         : JSC::call(exec, handleEventFunction, callType, callData, thisValue, args);
        globalData.timeoutChecker.stop();

        globalObject->setCurrentEvent(savedEvent);

#if ENABLE(WORKERS)
        if (scriptExecutionContext->isWorkerContext()) {
            bool terminatorCausedException = (exec->hadException() && isTerminatedExecutionException(exec->exception()));
            if (terminatorCausedException || globalData.terminator.shouldTerminate())
                static_cast<WorkerContext*>(scriptExecutionContext)->script()->forbidExecution();
        }
#endif

        if (exec->hadException()) {
            event->target()->uncaughtExceptionInEventHandler();
            reportCurrentException(exec);
        } else {
            if (!retval.isUndefinedOrNull() && event->storesResultAsString())
                event->storeResult(ustringToString(retval.toString(exec)->value(exec)));
            if (m_isAttribute) {
                if (retval.isFalse())
                    event->preventDefault();
            }
        }
    }
}
Exemple #21
0
void JSEventListener::handleEvent(ScriptExecutionContext* scriptExecutionContext, Event* event)
{
    ASSERT(scriptExecutionContext);
    if (!scriptExecutionContext || scriptExecutionContext->isJSExecutionForbidden())
        return;

    VM& vm = scriptExecutionContext->vm();
    JSLockHolder lock(vm);
    auto scope = DECLARE_CATCH_SCOPE(vm);
    // See https://dom.spec.whatwg.org/#dispatching-events spec on calling handleEvent.
    // "If this throws an exception, report the exception." It should not propagate the
    // exception.

    JSObject* jsFunction = this->jsFunction(scriptExecutionContext);
    if (!jsFunction)
        return;

    JSDOMGlobalObject* globalObject = toJSDOMGlobalObject(scriptExecutionContext, *m_isolatedWorld);
    if (!globalObject)
        return;

    if (scriptExecutionContext->isDocument()) {
        JSDOMWindow* window = jsCast<JSDOMWindow*>(globalObject);
        if (!window->wrapped().isCurrentlyDisplayedInFrame())
            return;
        if (wasCreatedFromMarkup() && !scriptExecutionContext->contentSecurityPolicy()->allowInlineEventHandlers(sourceURL(), sourcePosition().m_line))
            return;
        // FIXME: Is this check needed for other contexts?
        ScriptController& script = window->wrapped().frame()->script();
        if (!script.canExecuteScripts(AboutToExecuteScript) || script.isPaused())
            return;
    }

    ExecState* exec = globalObject->globalExec();
    JSValue handleEventFunction = jsFunction;

    CallData callData;
    CallType callType = getCallData(handleEventFunction, callData);
    // If jsFunction is not actually a function, see if it implements the EventListener interface and use that
    if (callType == CallType::None) {
        handleEventFunction = jsFunction->get(exec, Identifier::fromString(exec, "handleEvent"));
        if (UNLIKELY(scope.exception())) {
            auto* exception = scope.exception();
            scope.clearException();

            event->target()->uncaughtExceptionInEventHandler();
            reportException(exec, exception);
            return;
        }
        callType = getCallData(handleEventFunction, callData);
    }

    if (callType != CallType::None) {
        Ref<JSEventListener> protectedThis(*this);

        MarkedArgumentBuffer args;
        args.append(toJS(exec, globalObject, event));

        Event* savedEvent = globalObject->currentEvent();
        globalObject->setCurrentEvent(event);

        VMEntryScope entryScope(vm, vm.entryScope ? vm.entryScope->globalObject() : globalObject);

        InspectorInstrumentationCookie cookie = JSMainThreadExecState::instrumentFunctionCall(scriptExecutionContext, callType, callData);

        JSValue thisValue = handleEventFunction == jsFunction ? toJS(exec, globalObject, event->currentTarget()) : jsFunction;
        NakedPtr<JSC::Exception> exception;
        JSValue retval = scriptExecutionContext->isDocument()
            ? JSMainThreadExecState::profiledCall(exec, JSC::ProfilingReason::Other, handleEventFunction, callType, callData, thisValue, args, exception)
            : JSC::profiledCall(exec, JSC::ProfilingReason::Other, handleEventFunction, callType, callData, thisValue, args, exception);

        InspectorInstrumentation::didCallFunction(cookie, scriptExecutionContext);

        globalObject->setCurrentEvent(savedEvent);

        if (is<WorkerGlobalScope>(*scriptExecutionContext)) {
            auto scriptController = downcast<WorkerGlobalScope>(*scriptExecutionContext).script();
            bool terminatorCausedException = (scope.exception() && isTerminatedExecutionException(scope.exception()));
            if (terminatorCausedException || scriptController->isTerminatingExecution())
                scriptController->forbidExecution();
        }

        if (exception) {
            event->target()->uncaughtExceptionInEventHandler();
            reportException(exec, exception);
        } else {
            if (!retval.isUndefinedOrNull() && is<BeforeUnloadEvent>(*event))
                downcast<BeforeUnloadEvent>(*event).setReturnValue(retval.toWTFString(exec));
            if (m_isAttribute) {
                if (retval.isFalse())
                    event->preventDefault();
            }
        }
    }
}