RefPtr<JSLazyEventListener> JSLazyEventListener::create(DOMWindow& window, const QualifiedName& attributeName, const AtomicString& attributeValue) { ASSERT(window.document()); auto& document = *window.document(); ASSERT(document.frame()); return create({ attributeName, attributeValue, document, nullptr, toJSDOMWindow(document.frame(), mainThreadNormalWorld()), document.isSVGDocument() }); }
static void messageHandlerInMainThread(v8::Handle<v8::Message> message, v8::Handle<v8::Value> data) { DOMWindow* firstWindow = firstDOMWindow(); if (!firstWindow->isCurrentlyDisplayedInFrame()) return; String errorMessage = toWebCoreString(message->Get()); v8::Handle<v8::StackTrace> stackTrace = message->GetStackTrace(); RefPtr<ScriptCallStack> callStack; // Currently stack trace is only collected when inspector is open. if (!stackTrace.IsEmpty() && stackTrace->GetFrameCount() > 0) callStack = createScriptCallStack(stackTrace, ScriptCallStack::maxCallStackSizeToCapture); v8::Handle<v8::Value> resourceName = message->GetScriptResourceName(); bool shouldUseDocumentURL = resourceName.IsEmpty() || !resourceName->IsString(); String resource = shouldUseDocumentURL ? firstWindow->document()->url() : toWebCoreString(resourceName); RefPtr<ErrorEvent> event = ErrorEvent::create(errorMessage, resource, message->GetLineNumber(), message->GetStartColumn()); // messageHandlerInMainThread can be called while we're creating a new context. // Since we cannot create a wrapper in the intermediate timing, we need to skip // creating a wrapper for |event|. DOMWrapperWorld* world = DOMWrapperWorld::current(); Frame* frame = firstWindow->document()->frame(); if (world && frame && frame->script()->existingWindowShell(world)) { v8::Local<v8::Value> wrappedEvent = toV8(event.get(), v8::Handle<v8::Object>(), v8::Isolate::GetCurrent()); if (!wrappedEvent.IsEmpty()) { ASSERT(wrappedEvent->IsObject()); v8::Local<v8::Object>::Cast(wrappedEvent)->SetHiddenValue(V8HiddenPropertyName::error(), data); } } AccessControlStatus corsStatus = message->IsSharedCrossOrigin() ? SharableCrossOrigin : NotSharableCrossOrigin; firstWindow->document()->reportException(event.release(), callStack, corsStatus); }
EncodedJSValue JSC_HOST_CALL JSSharedWorkerConstructor::constructJSSharedWorker(ExecState* exec) { JSSharedWorkerConstructor* jsConstructor = jsCast<JSSharedWorkerConstructor*>(exec->callee()); if (exec->argumentCount() < 1) return throwVMError(exec, createNotEnoughArgumentsError(exec)); UString scriptURL = exec->argument(0).toString(exec)->value(exec); UString name; if (exec->argumentCount() > 1) name = exec->argument(1).toString(exec)->value(exec); if (exec->hadException()) return JSValue::encode(JSValue()); // FIXME: We need to use both the dynamic scope and the lexical scope (dynamic scope for resolving the worker URL) DOMWindow* window = asJSDOMWindow(exec->lexicalGlobalObject())->impl(); ExceptionCode ec = 0; RefPtr<SharedWorker> worker = SharedWorker::create(window->document(), ustringToString(scriptURL), ustringToString(name), ec); if (ec) { setDOMException(exec, ec); return JSValue::encode(JSValue()); } return JSValue::encode(asObject(toJS(exec, jsConstructor->globalObject(), worker.release()))); }
void Location::reload(DOMWindow& activeWindow) { if (!m_frame) return; // FIXME: It's not clear this cross-origin security check is valuable. // We allow one page to change the location of another. Why block attempts to reload? // Other location operations simply block use of JavaScript URLs cross origin. DOMWindow* targetWindow = m_frame->document()->domWindow(); if (!activeWindow.document()->securityOrigin()->canAccess(m_frame->document()->securityOrigin())) { targetWindow->printErrorMessage(targetWindow->crossDomainAccessErrorMessage(activeWindow)); return; } if (protocolIsJavaScript(m_frame->document()->url())) return; m_frame->navigationScheduler().scheduleRefresh(activeWindow.document()); }
v8::Handle<v8::Value> V8DOMWindow::removeEventListenerCallback(const v8::Arguments& args) { INC_STATS("DOM.DOMWindow.removeEventListener()"); String eventType = toWebCoreString(args[0]); bool useCapture = args[2]->BooleanValue(); DOMWindow* imp = V8DOMWindow::toNative(args.Holder()); if (!V8BindingSecurity::canAccessFrame(V8BindingState::Only(), imp->frame(), true)) return v8::Undefined(); Document* doc = imp->document(); if (!doc) return v8::Undefined(); V8Proxy* proxy = V8Proxy::retrieve(imp->frame()); if (!proxy) return v8::Undefined(); RefPtr<EventListener> listener = V8DOMWrapper::getEventListener(args[1], false, ListenerFindOnly); if (listener) { imp->removeEventListener(eventType, listener.get(), useCapture); removeHiddenDependency(args.Holder(), args[1], eventListenerCacheIndex); } return v8::Undefined(); }
RefPtr<Database> DOMWindowWebDatabase::openDatabase(DOMWindow& window, const String& name, const String& version, const String& displayName, unsigned long estimatedSize, PassRefPtr<DatabaseCallback> creationCallback, ExceptionCode& ec) { if (!window.isCurrentlyDisplayedInFrame()) return nullptr; RefPtr<Database> database = nullptr; DatabaseManager& dbManager = DatabaseManager::singleton(); DatabaseError error = DatabaseError::None; if (dbManager.isAvailable() && window.document()->securityOrigin()->canAccessDatabase(window.document()->topOrigin())) { database = dbManager.openDatabase(window.document(), name, version, displayName, estimatedSize, creationCallback, error); ASSERT(database || error != DatabaseError::None); ec = DatabaseManager::exceptionCodeForDatabaseError(error); } else ec = SECURITY_ERR; return database; }
void Location::setLocation(DOMWindow& activeWindow, DOMWindow& firstWindow, const String& url) { ASSERT(m_frame); Frame* frame = m_frame->loader().findFrameForNavigation(String(), activeWindow.document()); if (!frame) return; frame->document()->domWindow()->setLocation(activeWindow, firstWindow, url); }
static void reportUncaughtException(v8::Handle<v8::Message> message, v8::Handle<v8::Value> data) { DOMWindow* firstWindow = firstDOMWindow(BindingState::instance()); if (!firstWindow->isCurrentlyDisplayedInFrame()) return; String errorMessage = toWebCoreString(message->Get()); v8::Handle<v8::StackTrace> stackTrace = message->GetStackTrace(); RefPtr<ScriptCallStack> callStack; // Currently stack trace is only collected when inspector is open. if (!stackTrace.IsEmpty() && stackTrace->GetFrameCount() > 0) callStack = createScriptCallStack(stackTrace, ScriptCallStack::maxCallStackSizeToCapture); v8::Handle<v8::Value> resourceName = message->GetScriptResourceName(); bool shouldUseDocumentURL = resourceName.IsEmpty() || !resourceName->IsString(); String resource = shouldUseDocumentURL ? firstWindow->document()->url() : toWebCoreString(resourceName); firstWindow->document()->reportException(errorMessage, message->GetLineNumber(), resource, callStack); }
PassRefPtr<Database> DOMWindowWebDatabase::openDatabase(DOMWindow& window, const String& name, const String& version, const String& displayName, unsigned long estimatedSize, PassOwnPtr<DatabaseCallback> creationCallback, ExceptionState& exceptionState) { if (!window.isCurrentlyDisplayedInFrame()) return nullptr; RefPtr<Database> database = nullptr; DatabaseManager& dbManager = DatabaseManager::manager(); DatabaseError error = DatabaseError::None; if (RuntimeEnabledFeatures::databaseEnabled() && window.document()->securityOrigin()->canAccessDatabase()) { String errorMessage; database = dbManager.openDatabase(window.document(), name, version, displayName, estimatedSize, creationCallback, error, errorMessage); ASSERT(database || error != DatabaseError::None); if (error != DatabaseError::None) DatabaseManager::throwExceptionForDatabaseError(error, errorMessage, exceptionState); } else { exceptionState.throwSecurityError("Access to the WebDatabase API is denied in this context."); } return database; }
void WebDOMMessageEvent::initMessageEvent(const WebString& type, bool canBubble, bool cancelable, const WebSerializedScriptValue& messageData, const WebString& origin, const WebFrame* sourceFrame, const WebString& lastEventId, const WebMessagePortChannelArray& webChannels) { ASSERT(m_private.get()); ASSERT(isMessageEvent()); DOMWindow* window = 0; if (sourceFrame) window = toWebFrameImpl(sourceFrame)->frame()->domWindow(); OwnPtr<MessagePortArray> ports; if (sourceFrame) ports = MessagePort::toMessagePortArray(window->document(), webChannels); unwrap<MessageEvent>()->initMessageEvent(type, canBubble, cancelable, messageData, origin, lastEventId, window, ports.release()); }
ExceptionOr<RefPtr<Database>> DOMWindowWebDatabase::openDatabase(DOMWindow& window, const String& name, const String& version, const String& displayName, unsigned estimatedSize, RefPtr<DatabaseCallback>&& creationCallback) { if (!window.isCurrentlyDisplayedInFrame()) return RefPtr<Database> { nullptr }; auto& manager = DatabaseManager::singleton(); if (!manager.isAvailable()) return Exception { SecurityError }; auto* document = window.document(); if (!document) return Exception { SecurityError }; document->addConsoleMessage(MessageSource::Storage, MessageLevel::Warning, "Web SQL is deprecated. Please use IndexedDB instead."); auto& securityOrigin = document->securityOrigin(); if (!securityOrigin.canAccessDatabase(document->topOrigin())) return Exception { SecurityError }; auto result = manager.openDatabase(*window.document(), name, version, displayName, estimatedSize, WTFMove(creationCallback)); if (result.hasException()) { // FIXME: To preserve our past behavior, this discards the error string in the exception. // At a later time we may decide that we want to use the error strings, and if so we can just return the exception as is. return Exception { result.releaseException().code() }; } return RefPtr<Database> { result.releaseReturnValue() }; }
static bool canAccessDocument(BindingState* state, Document* targetDocument, SecurityReportingOption reportingOption = ReportSecurityError) { if (!targetDocument) return false; DOMWindow* active = activeDOMWindow(state); if (!active) return false; if (active->document()->securityOrigin()->canAccess(targetDocument->securityOrigin())) return true; if (reportingOption == ReportSecurityError) printErrorMessageForFrame(targetDocument->frame(), targetDocument->domWindow()->crossDomainAccessErrorMessage(active)); return false; }
EncodedJSValue JSC_HOST_CALL JSWorkerConstructor::constructJSWorker(ExecState* exec) { JSWorkerConstructor* jsConstructor = static_cast<JSWorkerConstructor*>(exec->callee()); if (!exec->argumentCount()) return throwVMError(exec, createTypeError(exec, "Not enough arguments")); UString scriptURL = exec->argument(0).toString(exec); if (exec->hadException()) return JSValue::encode(JSValue()); // See section 4.8.2 step 14 of WebWorkers for why this is the lexicalGlobalObject. DOMWindow* window = asJSDOMWindow(exec->lexicalGlobalObject())->impl(); ExceptionCode ec = 0; RefPtr<Worker> worker = Worker::create(ustringToString(scriptURL), window->document(), ec); if (ec) { setDOMException(exec, ec); return JSValue::encode(JSValue()); } return JSValue::encode(asObject(toJS(exec, jsConstructor->globalObject(), worker.release()))); }
static JSObject* constructSharedWorker(ExecState* exec, JSObject* constructor, const ArgList& args) { JSSharedWorkerConstructor* jsConstructor = static_cast<JSSharedWorkerConstructor*>(constructor); if (args.size() < 1) return throwError(exec, SyntaxError, "Not enough arguments"); UString scriptURL = args.at(0).toString(exec); UString name; if (args.size() > 1) name = args.at(1).toString(exec); if (exec->hadException()) return 0; // FIXME: We need to use both the dynamic scope and the lexical scope (dynamic scope for resolving the worker URL) DOMWindow* window = asJSDOMWindow(exec->lexicalGlobalObject())->impl(); ExceptionCode ec = 0; RefPtr<SharedWorker> worker = SharedWorker::create(scriptURL, name, window->document(), ec); setDOMException(exec, ec); return asObject(toJS(exec, jsConstructor->globalObject(), worker.release())); }
static JSObject* constructWorker(ExecState* exec, JSObject* constructor, const ArgList& args) { JSWorkerConstructor* jsConstructor = static_cast<JSWorkerConstructor*>(constructor); if (args.size() == 0) return throwError(exec, SyntaxError, "Not enough arguments"); UString scriptURL = args.at(0).toString(exec); if (exec->hadException()) return 0; // See section 4.8.2 step 14 of WebWorkers for why this is the lexicalGlobalObject. DOMWindow* window = asJSDOMWindow(exec->lexicalGlobalObject())->impl(); ExceptionCode ec = 0; RefPtr<Worker> worker = Worker::create(scriptURL, window->document(), ec); if (ec) { setDOMException(exec, ec); return 0; } return asObject(toJS(exec, jsConstructor->globalObject(), worker.release())); }
bool BindingSecurity::shouldAllowAccessToDOMWindow(JSC::ExecState* state, DOMWindow& target, SecurityReportingOption reportingOption) { return canAccessDocument(state, target.document(), reportingOption); }
// FIXME: There is a lot of duplication with SetTimeoutOrInterval() in V8WorkerGlobalScopeCustom.cpp. // We should refactor this. void WindowSetTimeoutImpl(const v8::FunctionCallbackInfo<v8::Value>& args, bool singleShot) { int argumentCount = args.Length(); if (argumentCount < 1) return; DOMWindow* imp = V8Window::toNative(args.Holder()); ScriptExecutionContext* scriptContext = static_cast<ScriptExecutionContext*>(imp->document()); if (!scriptContext) { setDOMException(InvalidAccessError, args.GetIsolate()); return; } v8::Handle<v8::Value> function = args[0]; String functionString; if (!function->IsFunction()) { if (function->IsString()) { functionString = toWebCoreString(function); } else { v8::Handle<v8::Value> v8String = function->ToString(); // Bail out if string conversion failed. if (v8String.IsEmpty()) return; functionString = toWebCoreString(v8String); } // Don't allow setting timeouts to run empty functions! // (Bug 1009597) if (!functionString.length()) return; } if (!BindingSecurity::shouldAllowAccessToFrame(imp->frame())) return; OwnPtr<ScheduledAction> action; if (function->IsFunction()) { int paramCount = argumentCount >= 2 ? argumentCount - 2 : 0; OwnArrayPtr<v8::Local<v8::Value> > params; if (paramCount > 0) { params = adoptArrayPtr(new v8::Local<v8::Value>[paramCount]); for (int i = 0; i < paramCount; i++) { // parameters must be globalized params[i] = args[i+2]; } } // params is passed to action, and released in action's destructor ASSERT(imp->frame()); action = adoptPtr(new ScheduledAction(imp->frame()->script()->currentWorldContext(), v8::Handle<v8::Function>::Cast(function), paramCount, params.get(), args.GetIsolate())); } else { if (imp->document() && !imp->document()->contentSecurityPolicy()->allowEval()) { v8SetReturnValue(args, 0); return; } ASSERT(imp->frame()); action = adoptPtr(new ScheduledAction(imp->frame()->script()->currentWorldContext(), functionString, KURL(), args.GetIsolate())); } int32_t timeout = argumentCount >= 2 ? args[1]->Int32Value() : 0; int timerId; if (singleShot) timerId = DOMWindowTimers::setTimeout(imp, action.release(), timeout); else timerId = DOMWindowTimers::setInterval(imp, action.release(), timeout); // Try to do the idle notification before the timeout expires to get better // use of any idle time. Aim for the middle of the interval for simplicity. if (timeout >= 0) { double maximumFireInterval = static_cast<double>(timeout) / 1000 / 2; V8GCForContextDispose::instance().notifyIdleSooner(maximumFireInterval); } v8SetReturnValue(args, timerId); }
v8::Handle<v8::Value> WindowSetTimeoutImpl(const v8::Arguments& args, bool singleShot) { int argumentCount = args.Length(); if (argumentCount < 1) return v8::Undefined(); DOMWindow* imp = V8DOMWindow::toNative(args.Holder()); ScriptExecutionContext* scriptContext = static_cast<ScriptExecutionContext*>(imp->document()); if (!scriptContext) { V8Proxy::setDOMException(INVALID_ACCESS_ERR); return v8::Undefined(); } v8::Handle<v8::Value> function = args[0]; WTF::String functionString; if (!function->IsFunction()) { if (function->IsString()) functionString = toWebCoreString(function); else { v8::Handle<v8::Value> v8String = function->ToString(); // Bail out if string conversion failed. if (v8String.IsEmpty()) return v8::Undefined(); functionString = toWebCoreString(v8String); } // Don't allow setting timeouts to run empty functions! // (Bug 1009597) if (functionString.length() == 0) return v8::Undefined(); } int32_t timeout = 0; if (argumentCount >= 2) timeout = args[1]->Int32Value(); if (!V8BindingSecurity::canAccessFrame(V8BindingState::Only(), imp->frame(), true)) return v8::Undefined(); int id; if (function->IsFunction()) { int paramCount = argumentCount >= 2 ? argumentCount - 2 : 0; v8::Local<v8::Value>* params = 0; if (paramCount > 0) { params = new v8::Local<v8::Value>[paramCount]; for (int i = 0; i < paramCount; i++) // parameters must be globalized params[i] = args[i+2]; } // params is passed to action, and released in action's destructor OwnPtr<ScheduledAction> action = adoptPtr(new ScheduledAction(V8Proxy::context(imp->frame()), v8::Handle<v8::Function>::Cast(function), paramCount, params)); // FIXME: We should use OwnArrayPtr for params. delete[] params; id = DOMTimer::install(scriptContext, action.release(), timeout, singleShot); } else { if (imp->document() && !imp->document()->contentSecurityPolicy()->allowEval()) return v8::Integer::New(0); id = DOMTimer::install(scriptContext, adoptPtr(new ScheduledAction(V8Proxy::context(imp->frame()), functionString)), timeout, singleShot); } // Try to do the idle notification before the timeout expires to get better // use of any idle time. Aim for the middle of the interval for simplicity. if (timeout > 0) { double maximumFireInterval = static_cast<double>(timeout) / 1000 / 2; V8GCForContextDispose::instance().notifyIdleSooner(maximumFireInterval); } return v8::Integer::New(id); }