int WorkerGlobalScope::setInterval(PassOwnPtr<ScheduledAction> action, int timeout) { return DOMTimer::install(scriptExecutionContext(), action, timeout, false); }
Document* XMLHttpRequest::document() const { ASSERT(scriptExecutionContext()); return downcast<Document>(scriptExecutionContext()); }
void Notification::taskTimerFired(Timer<Notification>* timer) { ASSERT(scriptExecutionContext()->isDocument()); ASSERT_UNUSED(timer, timer == m_taskTimer.get()); show(); }
void RTCPeerConnection::getStats(PassRefPtr<RTCStatsCallback> successCallback, PassRefPtr<MediaStreamTrack> selector) { RefPtr<RTCStatsRequestImpl> statsRequest = RTCStatsRequestImpl::create(scriptExecutionContext(), successCallback, selector); // FIXME: Add passing selector as part of the statsRequest. m_peerHandler->getStats(statsRequest.release()); }
Document* XMLHttpRequest::document() const { ASSERT(scriptExecutionContext()->isDocument()); return static_cast<Document*>(scriptExecutionContext()); }
void XMLHttpRequest::createRequest(ExceptionCode& ec) { #if ENABLE(BLOB) // Only GET request is supported for blob URL. if (m_url.protocolIs("blob") && m_method != "GET") { ec = XMLHttpRequestException::NETWORK_ERR; return; } #endif // The presence of upload event listeners forces us to use preflighting because POSTing to an URL that does not // permit cross origin requests should look exactly like POSTing to an URL that does not respond at all. // Also, only async requests support upload progress events. bool uploadEvents = false; if (m_async) { m_progressEventThrottle.dispatchEvent(XMLHttpRequestProgressEvent::create(eventNames().loadstartEvent)); if (m_requestEntityBody && m_upload) { uploadEvents = m_upload->hasEventListeners(); m_upload->dispatchEvent(XMLHttpRequestProgressEvent::create(eventNames().loadstartEvent)); } } m_sameOriginRequest = securityOrigin()->canRequest(m_url); // We also remember whether upload events should be allowed for this request in case the upload listeners are // added after the request is started. m_uploadEventsAllowed = m_sameOriginRequest || uploadEvents || !isSimpleCrossOriginAccessRequest(m_method, m_requestHeaders); ResourceRequest request(m_url); request.setHTTPMethod(m_method); #if PLATFORM(CHROMIUM) request.setTargetType(ResourceRequest::TargetIsXHR); #endif if (m_requestEntityBody) { ASSERT(m_method != "GET"); ASSERT(m_method != "HEAD"); request.setHTTPBody(m_requestEntityBody.release()); } if (m_requestHeaders.size() > 0) request.addHTTPHeaderFields(m_requestHeaders); ThreadableLoaderOptions options; options.sendLoadCallbacks = SendCallbacks; options.sniffContent = DoNotSniffContent; options.preflightPolicy = uploadEvents ? ForcePreflight : ConsiderPreflight; options.allowCredentials = (m_sameOriginRequest || m_includeCredentials) ? AllowStoredCredentials : DoNotAllowStoredCredentials; options.crossOriginRequestPolicy = UseAccessControl; options.securityOrigin = securityOrigin(); m_exceptionCode = 0; m_error = false; if (m_async) { if (m_upload) request.setReportUploadProgress(true); // ThreadableLoader::create can return null here, for example if we're no longer attached to a page. // This is true while running onunload handlers. // FIXME: Maybe we need to be able to send XMLHttpRequests from onunload, <http://bugs.webkit.org/show_bug.cgi?id=10904>. // FIXME: Maybe create() can return null for other reasons too? m_loader = ThreadableLoader::create(scriptExecutionContext(), this, request, options); if (m_loader) { // Neither this object nor the JavaScript wrapper should be deleted while // a request is in progress because we need to keep the listeners alive, // and they are referenced by the JavaScript wrapper. setPendingActivity(this); } } else { InspectorInstrumentation::willLoadXHRSynchronously(scriptExecutionContext()); ThreadableLoader::loadResourceSynchronously(scriptExecutionContext(), request, *this, options); InspectorInstrumentation::didLoadXHRSynchronously(scriptExecutionContext()); } if (!m_exceptionCode && m_error) m_exceptionCode = XMLHttpRequestException::NETWORK_ERR; ec = m_exceptionCode; }
void Worker::didReceiveResponse(unsigned long identifier, const ResourceResponse&) { InspectorInstrumentation::didReceiveScriptResponse(scriptExecutionContext(), identifier); }
void WebSocket::connect(const String& url, const Vector<String>& protocols, ExceptionCode& ec) { LOG(Network, "WebSocket %p connect() url='%s'", this, url.utf8().data()); m_url = URL(URL(), url); if (!m_url.isValid()) { scriptExecutionContext()->addConsoleMessage(MessageSource::JS, MessageLevel::Error, "Invalid url for WebSocket " + m_url.stringCenterEllipsizedToLength()); m_state = CLOSED; ec = SYNTAX_ERR; return; } if (!m_url.protocolIs("ws") && !m_url.protocolIs("wss")) { scriptExecutionContext()->addConsoleMessage(MessageSource::JS, MessageLevel::Error, "Wrong url scheme for WebSocket " + m_url.stringCenterEllipsizedToLength()); m_state = CLOSED; ec = SYNTAX_ERR; return; } if (m_url.hasFragmentIdentifier()) { scriptExecutionContext()->addConsoleMessage(MessageSource::JS, MessageLevel::Error, "URL has fragment component " + m_url.stringCenterEllipsizedToLength()); m_state = CLOSED; ec = SYNTAX_ERR; return; } if (!portAllowed(m_url)) { scriptExecutionContext()->addConsoleMessage(MessageSource::JS, MessageLevel::Error, "WebSocket port " + String::number(m_url.port()) + " blocked"); m_state = CLOSED; ec = SECURITY_ERR; return; } // FIXME: Convert this to check the isolated world's Content Security Policy once webkit.org/b/104520 is solved. bool shouldBypassMainWorldContentSecurityPolicy = false; if (scriptExecutionContext()->isDocument()) { Document* document = toDocument(scriptExecutionContext()); shouldBypassMainWorldContentSecurityPolicy = document->frame()->script().shouldBypassMainWorldContentSecurityPolicy(); } if (!shouldBypassMainWorldContentSecurityPolicy && !scriptExecutionContext()->contentSecurityPolicy()->allowConnectToSource(m_url)) { m_state = CLOSED; // FIXME: Should this be throwing an exception? ec = SECURITY_ERR; return; } m_channel = ThreadableWebSocketChannel::create(scriptExecutionContext(), this); // FIXME: There is a disagreement about restriction of subprotocols between WebSocket API and hybi-10 protocol // draft. The former simply says "only characters in the range U+0021 to U+007E are allowed," while the latter // imposes a stricter rule: "the elements MUST be non-empty strings with characters as defined in [RFC2616], // and MUST all be unique strings." // // Here, we throw SYNTAX_ERR if the given protocols do not meet the latter criteria. This behavior does not // comply with WebSocket API specification, but it seems to be the only reasonable way to handle this conflict. for (size_t i = 0; i < protocols.size(); ++i) { if (!isValidProtocolString(protocols[i])) { scriptExecutionContext()->addConsoleMessage(MessageSource::JS, MessageLevel::Error, "Wrong protocol for WebSocket '" + encodeProtocolString(protocols[i]) + "'"); m_state = CLOSED; ec = SYNTAX_ERR; return; } } HashSet<String> visited; for (size_t i = 0; i < protocols.size(); ++i) { if (!visited.add(protocols[i]).isNewEntry) { scriptExecutionContext()->addConsoleMessage(MessageSource::JS, MessageLevel::Error, "WebSocket protocols contain duplicates: '" + encodeProtocolString(protocols[i]) + "'"); m_state = CLOSED; ec = SYNTAX_ERR; return; } } String protocolString; if (!protocols.isEmpty()) protocolString = joinStrings(protocols, subProtocolSeperator()); m_channel->connect(m_url, protocolString); ActiveDOMObject::setPendingActivity(this); }
bool IDBRequest::dispatchEvent(PassRefPtr<Event> event) { IDB_TRACE("IDBRequest::dispatchEvent"); ASSERT(m_readyState == PENDING); ASSERT(!m_contextStopped); ASSERT(m_hasPendingActivity); ASSERT(m_enqueuedEvents.size()); ASSERT(scriptExecutionContext()); ASSERT(event->target() == this); ASSERT_WITH_MESSAGE(m_readyState < DONE, "When dispatching event %s, m_readyState < DONE(%d), was %d", event->type().string().utf8().data(), DONE, m_readyState); if (event->type() != eventNames().blockedEvent) m_readyState = DONE; for (size_t i = 0; i < m_enqueuedEvents.size(); ++i) { if (m_enqueuedEvents[i].get() == event.get()) m_enqueuedEvents.remove(i); } Vector<RefPtr<EventTarget> > targets; targets.append(this); if (m_transaction && !m_preventPropagation) { targets.append(m_transaction); // If there ever are events that are associated with a database but // that do not have a transaction, then this will not work and we need // this object to actually hold a reference to the database (to ensure // it stays alive). targets.append(m_transaction->db()); } // Cursor properties should not updated until the success event is being dispatched. RefPtr<IDBCursor> cursorToNotify; if (event->type() == eventNames().successEvent) { cursorToNotify = getResultCursor(); if (cursorToNotify) cursorToNotify->setValueReady(m_cursorKey.release(), m_cursorPrimaryKey.release(), m_cursorValue); } if (event->type() == eventNames().upgradeneededEvent) { ASSERT(!m_didFireUpgradeNeededEvent); m_didFireUpgradeNeededEvent = true; } // FIXME: When we allow custom event dispatching, this will probably need to change. ASSERT_WITH_MESSAGE(event->type() == eventNames().successEvent || event->type() == eventNames().errorEvent || event->type() == eventNames().blockedEvent || event->type() == eventNames().upgradeneededEvent, "event type was %s", event->type().string().utf8().data()); const bool setTransactionActive = m_transaction && (event->type() == eventNames().successEvent || event->type() == eventNames().upgradeneededEvent || (event->type() == eventNames().errorEvent && m_errorCode != IDBDatabaseException::IDB_ABORT_ERR)); if (setTransactionActive) m_transaction->setActive(true); bool dontPreventDefault = IDBEventDispatcher::dispatch(event.get(), targets); if (setTransactionActive) m_transaction->setActive(false); if (cursorToNotify) cursorToNotify->postSuccessHandlerCallback(); if (m_readyState == DONE && (!cursorToNotify || m_cursorFinished) && event->type() != eventNames().upgradeneededEvent) m_hasPendingActivity = false; if (m_transaction) { if (event->type() == eventNames().errorEvent && dontPreventDefault && !m_requestAborted) { m_transaction->setError(m_error); ExceptionCode unused; m_transaction->abort(unused); } if (event->type() != eventNames().blockedEvent) m_transaction->backend()->didCompleteTaskEvents(); if (m_readyState == DONE) m_transaction->unregisterRequest(this); } return dontPreventDefault; }
Document* Geolocation::document() const { return downcast<Document>(scriptExecutionContext()); }
void DOMTimer::fired() { // Retain this - if the timer is cancelled while this function is on the stack (implicitly and always // for one-shot timers, or if removeById is called on itself from within an interval timer fire) then // wait unit the end of this function to delete DOMTimer. RefPtr<DOMTimer> reference = this; ScriptExecutionContext* context = scriptExecutionContext(); ASSERT(context); DOMTimerFireState fireState(context); #if PLATFORM(IOS) Document* document = nullptr; if (context->isDocument()) { document = toDocument(context); ASSERT(!document->frame()->timersPaused()); } #endif context->setTimerNestingLevel(std::min(m_nestingLevel + 1, maxTimerNestingLevel)); ASSERT(!isSuspended()); ASSERT(!context->activeDOMObjectsAreSuspended()); UserGestureIndicator gestureIndicator(m_shouldForwardUserGesture ? DefinitelyProcessingUserGesture : PossiblyProcessingUserGesture); // Only the first execution of a multi-shot timer should get an affirmative user gesture indicator. m_shouldForwardUserGesture = false; InspectorInstrumentationCookie cookie = InspectorInstrumentation::willFireTimer(context, m_timeoutId); // Simple case for non-one-shot timers. if (isActive()) { if (m_nestingLevel < maxTimerNestingLevel) { m_nestingLevel++; updateTimerIntervalIfNecessary(); } m_action->execute(context); InspectorInstrumentation::didFireTimer(cookie); if (fireState.scriptDidInteractWithUserObservablePlugin && m_throttleState != ShouldNotThrottle) { m_throttleState = ShouldNotThrottle; updateTimerIntervalIfNecessary(); } else if (fireState.scriptDidInteractWithNonUserObservablePlugin && m_throttleState == Undetermined) { m_throttleState = ShouldThrottle; updateTimerIntervalIfNecessary(); } return; } context->removeTimeout(m_timeoutId); #if PLATFORM(IOS) bool shouldReportLackOfChanges; bool shouldBeginObservingChanges; if (document) { shouldReportLackOfChanges = WebThreadCountOfObservedContentModifiers() == 1; shouldBeginObservingChanges = WebThreadContainsObservedContentModifier(this); } else { shouldReportLackOfChanges = false; shouldBeginObservingChanges = false; } if (shouldBeginObservingChanges) { WKBeginObservingContentChanges(false); WebThreadRemoveObservedContentModifier(this); } #endif m_action->execute(context); #if PLATFORM(IOS) if (shouldBeginObservingChanges) { WKStopObservingContentChanges(); if (WKObservedContentChange() == WKContentVisibilityChange || shouldReportLackOfChanges) if (document && document->page()) document->page()->chrome().client().observedContentChange(document->frame()); } #endif InspectorInstrumentation::didFireTimer(cookie); context->setTimerNestingLevel(0); }
void IDBRequest::setResult(uint64_t number) { ASSERT(scriptExecutionContext()); m_result = IDBAny::create(Deprecated::ScriptValue(scriptExecutionContext()->vm(), JSC::JSValue(number))); }
int WorkerContext::installTimeout(ScheduledAction* action, int timeout, bool singleShot) { return DOMTimer::install(scriptExecutionContext(), action, timeout, singleShot); }
void XMLHttpRequest::open(const String& method, const URL& url, bool async, ExceptionCode& ec) { if (!internalAbort()) return; State previousState = m_state; m_state = UNSENT; m_error = false; m_uploadComplete = false; // clear stuff from possible previous load clearResponse(); clearRequest(); ASSERT(m_state == UNSENT); if (!isValidHTTPToken(method)) { ec = SYNTAX_ERR; return; } if (!isAllowedHTTPMethod(method)) { ec = SECURITY_ERR; return; } // FIXME: Convert this to check the isolated world's Content Security Policy once webkit.org/b/104520 is solved. bool shouldBypassMainWorldContentSecurityPolicy = false; if (scriptExecutionContext()->isDocument()) { Document* document = toDocument(scriptExecutionContext()); if (document->frame()) shouldBypassMainWorldContentSecurityPolicy = document->frame()->script().shouldBypassMainWorldContentSecurityPolicy(); } if (!shouldBypassMainWorldContentSecurityPolicy && !scriptExecutionContext()->contentSecurityPolicy()->allowConnectToSource(url)) { // FIXME: Should this be throwing an exception? ec = SECURITY_ERR; return; } if (!async && scriptExecutionContext()->isDocument()) { if (document()->settings() && !document()->settings()->syncXHRInDocumentsEnabled()) { logConsoleError(scriptExecutionContext(), "Synchronous XMLHttpRequests are disabled for this page."); ec = INVALID_ACCESS_ERR; return; } // Newer functionality is not available to synchronous requests in window contexts, as a spec-mandated // attempt to discourage synchronous XHR use. responseType is one such piece of functionality. // We'll only disable this functionality for HTTP(S) requests since sync requests for local protocols // such as file: and data: still make sense to allow. if (url.protocolIsInHTTPFamily() && m_responseTypeCode != ResponseTypeDefault) { logConsoleError(scriptExecutionContext(), "Synchronous HTTP(S) requests made from the window context cannot have XMLHttpRequest.responseType set."); ec = INVALID_ACCESS_ERR; return; } #if ENABLE(XHR_TIMEOUT) // Similarly, timeouts are disabled for synchronous requests as well. if (m_timeoutMilliseconds > 0) { logConsoleError(scriptExecutionContext(), "Synchronous XMLHttpRequests must not have a timeout value set."); ec = INVALID_ACCESS_ERR; return; } #endif } m_method = uppercaseKnownHTTPMethod(method); m_url = url; m_async = async; ASSERT(!m_loader); // Check previous state to avoid dispatching readyState event // when calling open several times in a row. if (previousState != OPENED) changeState(OPENED); else m_state = OPENED; }
Worker::~Worker() { ASSERT(isMainThread()); ASSERT(scriptExecutionContext()); // The context is protected by worker context proxy, so it cannot be destroyed while a Worker exists. m_contextProxy->workerObjectDestroyed(); }
DOMTimer::~DOMTimer() { if (scriptExecutionContext()) scriptExecutionContext()->removeTimeout(m_timeoutId); }
int WorkerContext::setTimeout(PassOwnPtr<ScheduledAction> action, int timeout) { return DOMTimer::install(scriptExecutionContext(), action, timeout, true); }
void WebSocket::didReceiveMessageError() { LOG(Network, "WebSocket %p didReceiveErrorMessage()", this); ASSERT(scriptExecutionContext()); dispatchEvent(Event::create(eventNames().errorEvent, false, false)); }
void WorkerContext::clearTimeout(int timeoutId) { DOMTimer::removeById(scriptExecutionContext(), timeoutId); }
SecurityOrigin* XMLHttpRequest::securityOrigin() const { return m_securityOrigin ? m_securityOrigin.get() : scriptExecutionContext()->securityOrigin(); }
NotificationCenter* WorkerContext::webkitNotifications() const { if (!m_notifications) m_notifications = NotificationCenter::create(scriptExecutionContext(), m_thread->getNotificationPresenter()); return m_notifications.get(); }
Document* Geolocation::document() const { ASSERT(!scriptExecutionContext() || scriptExecutionContext()->isDocument()); return static_cast<Document*>(scriptExecutionContext()); }
bool IDBRequest::dispatchEvent(PassRefPtr<Event> event) { IDB_TRACE("IDBRequest::dispatchEvent"); ASSERT(m_readyState == PENDING); ASSERT(!m_contextStopped); ASSERT(m_hasPendingActivity); ASSERT(m_enqueuedEvents.size()); ASSERT(scriptExecutionContext()); ASSERT(event->target() == this); ASSERT_WITH_MESSAGE(m_readyState < DONE, "When dispatching event %s, m_readyState < DONE(%d), was %d", event->type().string().utf8().data(), DONE, m_readyState); // FIXME: This method should not be called if stop() was previously called, // but there are crash reports (no local repro) indicating a null pointer // deference in the following DOMRequestState::Scope constructor. If this // resolves the crashes, track down the root cause, otherwise back this out. if (m_contextStopped) return false; DOMRequestState::Scope scope(m_requestState); if (event->type() != eventNames().blockedEvent) m_readyState = DONE; for (size_t i = 0; i < m_enqueuedEvents.size(); ++i) { if (m_enqueuedEvents[i].get() == event.get()) m_enqueuedEvents.remove(i); } Vector<RefPtr<EventTarget> > targets; targets.append(this); if (m_transaction && !m_preventPropagation) { targets.append(m_transaction); // If there ever are events that are associated with a database but // that do not have a transaction, then this will not work and we need // this object to actually hold a reference to the database (to ensure // it stays alive). targets.append(m_transaction->db()); } // Cursor properties should not updated until the success event is being dispatched. RefPtr<IDBCursor> cursorToNotify; if (event->type() == eventNames().successEvent) { cursorToNotify = getResultCursor(); if (cursorToNotify) { cursorToNotify->setValueReady(requestState(), m_cursorKey.release(), m_cursorPrimaryKey.release(), m_cursorValue); m_cursorValue.clear(); } } if (event->type() == eventNames().upgradeneededEvent) { ASSERT(!m_didFireUpgradeNeededEvent); m_didFireUpgradeNeededEvent = true; } // FIXME: When we allow custom event dispatching, this will probably need to change. ASSERT_WITH_MESSAGE(event->type() == eventNames().successEvent || event->type() == eventNames().errorEvent || event->type() == eventNames().blockedEvent || event->type() == eventNames().upgradeneededEvent, "event type was %s", event->type().string().utf8().data()); const bool setTransactionActive = m_transaction && (event->type() == eventNames().successEvent || event->type() == eventNames().upgradeneededEvent || (event->type() == eventNames().errorEvent && m_errorCode != IDBDatabaseException::AbortError)); if (setTransactionActive) m_transaction->setActive(true); bool dontPreventDefault = IDBEventDispatcher::dispatch(event.get(), targets); if (m_transaction) { if (m_readyState == DONE) m_transaction->unregisterRequest(this); // Possibly abort the transaction. This must occur after unregistering (so this request // doesn't receive a second error) and before deactivating (which might trigger commit). if (event->type() == eventNames().errorEvent && dontPreventDefault && !m_requestAborted) { m_transaction->setError(m_error, m_errorMessage); ExceptionCode unused; m_transaction->abort(unused); } // If this was the last request in the transaction's list, it may commit here. if (setTransactionActive) m_transaction->setActive(false); } if (cursorToNotify) cursorToNotify->postSuccessHandlerCallback(); if (m_readyState == DONE && (!cursorToNotify || m_cursorFinished) && event->type() != eventNames().upgradeneededEvent) m_hasPendingActivity = false; return dontPreventDefault; }
void RTCPeerConnection::createAnswer(PassRefPtr<RTCSessionDescriptionCallback> successCallback, PassRefPtr<RTCErrorCallback> errorCallback, const Dictionary& mediaConstraints, ExceptionCode& ec) { if (m_readyState == ReadyStateClosed) { ec = INVALID_STATE_ERR; return; } if (!successCallback) { ec = TYPE_MISMATCH_ERR; return; } RefPtr<MediaConstraints> constraints = MediaConstraintsImpl::create(mediaConstraints, ec); if (ec) return; RefPtr<RTCSessionDescriptionRequestImpl> request = RTCSessionDescriptionRequestImpl::create(scriptExecutionContext(), successCallback, errorCallback); m_peerHandler->createAnswer(request.release(), constraints.release()); }
IDBRequest::~IDBRequest() { ASSERT(m_readyState == DONE || m_readyState == EarlyDeath || !scriptExecutionContext()); }
void RTCPeerConnection::didChangeIceState(IceState newState) { ASSERT(scriptExecutionContext()->isContextThread()); changeIceState(newState); }
Document* XMLHttpRequest::document() const { ASSERT(scriptExecutionContext()); return toDocument(scriptExecutionContext()); }
void WorkerGlobalScope::clearInterval(int timeoutId) { DOMTimer::removeById(scriptExecutionContext(), timeoutId); }
bool ActiveDOMCallback::canInvokeCallback() const { ScriptExecutionContext* context = scriptExecutionContext(); return context && !context->activeDOMObjectsAreSuspended() && !context->activeDOMObjectsAreStopped(); }