void AudioContext::constructCommon() { // According to spec AudioContext must die only after page navigate. // Lets mark it as ActiveDOMObject with pending activity and unmark it in clear method. setPendingActivity(this); #if USE(GSTREAMER) initializeGStreamer(); #endif FFTFrame::initialize(); m_listener = AudioListener::create(); #if PLATFORM(IOS) if (!document()->settings() || document()->settings()->mediaPlaybackRequiresUserGesture()) addBehaviorRestriction(RequireUserGestureForAudioStartRestriction); else m_restrictions = NoRestrictions; #endif #if PLATFORM(MAC) addBehaviorRestriction(RequirePageConsentForAudioStartRestriction); #endif }
EventSource::EventSource(const String& url, ScriptExecutionContext* context, ExceptionCode& ec) : ActiveDOMObject(context, this) , m_state(CONNECTING) , m_reconnectTimer(this, &EventSource::reconnectTimerFired) , m_discardTrailingNewline(false) , m_failSilently(false) , m_requestInFlight(false) , m_reconnectDelay(defaultReconnectDelay) { if (url.isEmpty() || !(m_url = context->completeURL(url)).isValid()) { ec = SYNTAX_ERR; return; } // FIXME: should support cross-origin requests if (!scriptExecutionContext()->securityOrigin()->canRequest(m_url)) { ec = SECURITY_ERR; return; } m_origin = scriptExecutionContext()->securityOrigin()->toString(); m_decoder = TextResourceDecoder::create("text/plain", "UTF-8"); setPendingActivity(this); connect(); }
bool XMLHttpRequest::initSend(ExceptionCode& ec) { if (!scriptExecutionContext()) return false; if (m_state != OPENED || m_sendFlag) { ec = INVALID_STATE_ERR; return false; } ASSERT(!m_loader); // FIXME: Convert this to check the isolated world's Content Security Policy once webkit.org/b/104520 is solved. if (!scriptExecutionContext()->contentSecurityPolicy()->allowConnectToSource(m_url, scriptExecutionContext()->shouldBypassMainWorldContentSecurityPolicy())) { if (m_async) { setPendingActivity(this); m_timeoutTimer.stop(); m_networkErrorTimer.startOneShot(0); } else ec = NETWORK_ERR; return false; } m_error = false; return true; }
Optional<ExceptionOr<void>> XMLHttpRequest::prepareToSend() { // A return value other than Nullopt means we should not try to send, and we should return that value to the caller. // Nullopt means we are ready to send and should continue with the send algorithm. if (!scriptExecutionContext()) return ExceptionOr<void> { }; auto& context = *scriptExecutionContext(); if (m_state != OPENED || m_sendFlag) return ExceptionOr<void> { Exception { INVALID_STATE_ERR } }; ASSERT(!m_loader); // FIXME: Convert this to check the isolated world's Content Security Policy once webkit.org/b/104520 is solved. if (!context.shouldBypassMainWorldContentSecurityPolicy() && !context.contentSecurityPolicy()->allowConnectToSource(m_url)) { if (!m_async) return ExceptionOr<void> { Exception { NETWORK_ERR } }; setPendingActivity(this); m_timeoutTimer.stop(); m_networkErrorTimer.startOneShot(0); return ExceptionOr<void> { }; } m_error = false; return Nullopt; }
ExceptionOr<Ref<Worker>> Worker::create(ScriptExecutionContext& context, const String& url, JSC::RuntimeFlags runtimeFlags) { ASSERT(isMainThread()); // We don't currently support nested workers, so workers can only be created from documents. ASSERT_WITH_SECURITY_IMPLICATION(context.isDocument()); auto worker = adoptRef(*new Worker(context, runtimeFlags)); worker->suspendIfNeeded(); bool shouldBypassMainWorldContentSecurityPolicy = context.shouldBypassMainWorldContentSecurityPolicy(); auto scriptURL = worker->resolveURL(url, shouldBypassMainWorldContentSecurityPolicy); if (scriptURL.hasException()) return scriptURL.releaseException(); worker->m_shouldBypassMainWorldContentSecurityPolicy = shouldBypassMainWorldContentSecurityPolicy; // The worker context does not exist while loading, so we must ensure that the worker object is not collected, nor are its event listeners. worker->setPendingActivity(worker.ptr()); worker->m_scriptLoader = WorkerScriptLoader::create(); auto contentSecurityPolicyEnforcement = shouldBypassMainWorldContentSecurityPolicy ? ContentSecurityPolicyEnforcement::DoNotEnforce : ContentSecurityPolicyEnforcement::EnforceChildSrcDirective; worker->m_scriptLoader->loadAsynchronously(&context, scriptURL.releaseReturnValue(), FetchOptions::Mode::SameOrigin, contentSecurityPolicyEnforcement, worker->m_identifier, worker.ptr()); return WTFMove(worker); }
RefPtr<EventSource> EventSource::create(ScriptExecutionContext& context, const String& url, const Init& eventSourceInit, ExceptionCode& ec) { if (url.isEmpty()) { ec = SYNTAX_ERR; return nullptr; } URL fullURL = context.completeURL(url); if (!fullURL.isValid()) { ec = SYNTAX_ERR; return nullptr; } // FIXME: Convert this to check the isolated world's Content Security Policy once webkit.org/b/104520 is solved. if (!context.contentSecurityPolicy()->allowConnectToSource(fullURL, context.shouldBypassMainWorldContentSecurityPolicy())) { // FIXME: Should this be throwing an exception? ec = SECURITY_ERR; return nullptr; } auto source = adoptRef(*new EventSource(context, fullURL, eventSourceInit)); source->setPendingActivity(source.ptr()); source->scheduleInitialConnect(); source->suspendIfNeeded(); return WTFMove(source); }
void Notification::show() { // prevent double-showing if (m_state == Idle && m_notificationCenter->client() && m_notificationCenter->client()->show(this)) { m_state = Showing; setPendingActivity(this); } }
void SharedWorkerScriptLoader::load(const KURL& url) { // Mark this object as active for the duration of the load. ASSERT(!hasPendingActivity()); m_scriptLoader = new WorkerScriptLoader(); m_scriptLoader->loadAsynchronously(scriptExecutionContext(), url, DenyCrossOriginRedirect, this); // Stay alive until the load finishes. setPendingActivity(this); }
void AudioContext::constructCommon() { ScriptWrappable::init(this); // According to spec AudioContext must die only after page navigate. // Lets mark it as ActiveDOMObject with pending activity and unmark it in clear method. setPendingActivity(this); FFTFrame::initialize(); m_listener = AudioListener::create(); }
void FetchResponse::startFetching(ScriptExecutionContext& context, const FetchRequest& request, FetchPromise&& promise) { auto response = adoptRef(*new FetchResponse(context, FetchBody::loadingBody(), FetchHeaders::create(FetchHeaders::Guard::Immutable), { })); // Setting pending activity until BodyLoader didFail or didSucceed callback is called. response->setPendingActivity(response.ptr()); response->m_bodyLoader = BodyLoader(response.get(), WTFMove(promise)); if (!response->m_bodyLoader->start(context, request)) response->m_bodyLoader = Nullopt; }
void Notification::startLoading() { if (m_state != Idle) return; setPendingActivity(this); m_state = Loading; ThreadableLoaderOptions options; options.sendLoadCallbacks = false; options.sniffContent = false; options.forcePreflight = false; options.allowCredentials = AllowStoredCredentials; options.crossOriginRequestPolicy = AllowCrossOriginRequests; m_loader = ThreadableLoader::create(scriptExecutionContext(), this, ResourceRequest(iconURL()), options); }
void AudioContext::constructCommon() { // According to spec AudioContext must die only after page navigate. // Lets mark it as ActiveDOMObject with pending activity and unmark it in clear method. setPendingActivity(this); #if USE(GSTREAMER) initializeGStreamer(); #endif FFTFrame::initialize(); m_listener = AudioListener::create(); }
void FileWriter::doOperation(Operation operation) { switch (operation) { case OperationWrite: ASSERT(m_operationInProgress == OperationNone); ASSERT(m_truncateLength == -1); ASSERT(m_blobBeingWritten.get()); ASSERT(m_readyState == WRITING); setPendingActivity(this); writer()->write(position(), m_blobBeingWritten.get()); break; case OperationTruncate: ASSERT(m_operationInProgress == OperationNone); ASSERT(m_truncateLength >= 0); ASSERT(m_readyState == WRITING); setPendingActivity(this); writer()->truncate(m_truncateLength); break; case OperationNone: ASSERT(m_operationInProgress == OperationNone); ASSERT(m_truncateLength == -1); ASSERT(!m_blobBeingWritten.get()); ASSERT(m_readyState == DONE); break; case OperationAbort: if (m_operationInProgress == OperationWrite || m_operationInProgress == OperationTruncate) writer()->abort(); else if (m_operationInProgress != OperationAbort) operation = OperationNone; m_queuedOperation = OperationNone; m_blobBeingWritten.clear(); m_truncateLength = -1; break; } ASSERT(m_queuedOperation == OperationNone); m_operationInProgress = operation; }
Worker::Worker(const String& url, ScriptExecutionContext* context, ExceptionCode& ec) : AbstractWorker(context) , m_contextProxy(WorkerContextProxy::create(this)) { KURL scriptURL = resolveURL(url, ec); if (ec) return; m_scriptLoader = new WorkerScriptLoader(ResourceRequestBase::TargetIsWorker); m_scriptLoader->loadAsynchronously(scriptExecutionContext(), scriptURL, DenyCrossOriginRequests, this); setPendingActivity(this); // The worker context does not exist while loading, so we must ensure that the worker object is not collected, as well as its event listeners. #if ENABLE(INSPECTOR) if (InspectorController* inspector = scriptExecutionContext()->inspectorController()) inspector->didCreateWorker(asID(), scriptURL.string(), false); #endif }
void Notification::show() { // prevent double-showing if (m_state == Idle) { if (!toDocument(scriptExecutionContext())->page()) return; if (NotificationController::from(toDocument(scriptExecutionContext())->page())->client()->checkPermission(scriptExecutionContext()) != NotificationClient::PermissionAllowed) { dispatchErrorEvent(); return; } if (m_notificationClient->show(this)) { m_state = Showing; setPendingActivity(this); } } }
void Notification::show() { // prevent double-showing if (m_state == Idle && m_notificationCenter->client()) { #if ENABLE(NOTIFICATIONS) if (!downcast<Document>(*scriptExecutionContext()).page()) return; if (NotificationController::from(downcast<Document>(*scriptExecutionContext()).page())->client()->checkPermission(scriptExecutionContext()) != NotificationClient::PermissionAllowed) { dispatchErrorEvent(); return; } #endif if (m_notificationCenter->client()->show(this)) { m_state = Showing; setPendingActivity(this); } } }
void FileReader::readInternal(Blob* blob, FileReaderLoader::ReadType type, ExceptionCode& ec) { // If multiple concurrent read methods are called on the same FileReader, INVALID_STATE_ERR should be thrown when the state is LOADING. if (m_state == LOADING) { ec = INVALID_STATE_ERR; return; } setPendingActivity(this); m_blob = blob; m_readType = type; m_state = LOADING; m_error = 0; m_loader = adoptPtr(new FileReaderLoader(m_readType, this)); m_loader->setEncoding(m_encoding); m_loader->setDataType(m_blob->type()); m_loader->start(scriptExecutionContext(), m_blob.get()); }
void XMLHttpRequest::loadRequestAsynchronously(ResourceRequest& request) { ASSERT(m_async); // SubresourceLoader::create can return null here, for example if we're no longer attached to a page. // This is true while running onunload handlers. // FIXME: 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? // We need to keep content sniffing enabled for local files due to CFNetwork not providing a MIME type // for local files otherwise, <rdar://problem/5671813>. LoadCallbacks callbacks = m_inPreflight ? DoNotSendLoadCallbacks : SendLoadCallbacks; ContentSniff contentSniff = request.url().isLocalFile() ? SniffContent : DoNotSniffContent; m_loader = ThreadableLoader::create(scriptExecutionContext(), this, request, callbacks, contentSniff); 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); } }
void XMLHttpRequest::loadRequestAsynchronously(ResourceRequest& request) { ASSERT(m_async); m_exceptionCode = 0; // SubresourceLoader::create can return null here, for example if we're no longer attached to a page. // This is true while running onunload handlers. // FIXME: 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? LoadCallbacks callbacks = m_inPreflight ? DoNotSendLoadCallbacks : SendLoadCallbacks; StoredCredentials storedCredentials = (m_sameOriginRequest || m_includeCredentials) ? AllowStoredCredentials : DoNotAllowStoredCredentials; if (m_upload) request.setReportUploadProgress(true); m_loader = ThreadableLoader::create(scriptExecutionContext(), this, request, callbacks, DoNotSniffContent, storedCredentials); 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); } }
Worker::Worker(const String& url, Document* doc, ExceptionCode& ec) : ActiveDOMObject(doc, this) , m_messagingProxy(new WorkerMessagingProxy(doc, this)) { m_scriptURL = doc->completeURL(url); if (url.isEmpty() || !m_scriptURL.isValid()) { ec = SYNTAX_ERR; return; } if (!doc->securityOrigin()->canAccess(SecurityOrigin::create(m_scriptURL).get())) { ec = SECURITY_ERR; return; } m_cachedScript = doc->docLoader()->requestScript(m_scriptURL, document()->charset()); if (!m_cachedScript) { dispatchErrorEvent(); return; } setPendingActivity(this); // The worker context does not exist while loading, so we much ensure that the worker object is not collected, as well as its event listeners. m_cachedScript->addClient(this); }
void DOMFileSystem::addPendingCallbacks() { setPendingActivity(this); }
void SharedWorker::setPreventGC() { setPendingActivity(this); }
void XMLHttpRequest::createRequest(ExceptionCode& ec) { // Only GET request is supported for blob URL. if (!m_async && m_url.protocolIsBlob() && m_method != "GET") { ec = NETWORK_ERR; return; } m_sendFlag = true; // 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.dispatchProgressEvent(eventNames().loadstartEvent); if (m_requestEntityBody && m_upload) { uploadEvents = m_upload->hasEventListeners(); m_upload->dispatchProgressEvent(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.setRequester(ResourceRequest::Requester::XHR); request.setHTTPMethod(m_method); if (m_requestEntityBody) { ASSERT(m_method != "GET"); ASSERT(m_method != "HEAD"); request.setHTTPBody(WTFMove(m_requestEntityBody)); } if (!m_requestHeaders.isEmpty()) request.setHTTPHeaderFields(m_requestHeaders); ThreadableLoaderOptions options; options.setSendLoadCallbacks(SendCallbacks); options.setSniffContent(DoNotSniffContent); options.preflightPolicy = uploadEvents ? ForcePreflight : ConsiderPreflight; options.setAllowCredentials((m_sameOriginRequest || m_includeCredentials) ? AllowStoredCredentials : DoNotAllowStoredCredentials); options.setCredentialRequest(m_includeCredentials ? ClientRequestedCredentials : ClientDidNotRequestCredentials); options.crossOriginRequestPolicy = UseAccessControl; options.securityOrigin = securityOrigin(); options.contentSecurityPolicyEnforcement = scriptExecutionContext()->shouldBypassMainWorldContentSecurityPolicy() ? ContentSecurityPolicyEnforcement::DoNotEnforce : ContentSecurityPolicyEnforcement::EnforceConnectSrcDirective; options.initiator = cachedResourceRequestInitiators().xmlhttprequest; if (m_timeoutMilliseconds) { if (!m_async) request.setTimeoutInterval(m_timeoutMilliseconds / 1000.0); else { m_sendingTime = std::chrono::steady_clock::now(); m_timeoutTimer.startOneShot(std::chrono::milliseconds { m_timeoutMilliseconds }); } } 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 or if a content blocker blocks the load. // 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>. m_loader = ThreadableLoader::create(scriptExecutionContext(), this, request, options); // 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); if (!m_loader) { m_sendFlag = false; m_timeoutTimer.stop(); m_networkErrorTimer.startOneShot(0); } } else { InspectorInstrumentation::willLoadXHRSynchronously(scriptExecutionContext()); ThreadableLoader::loadResourceSynchronously(scriptExecutionContext(), request, *this, options); InspectorInstrumentation::didLoadXHRSynchronously(scriptExecutionContext()); } if (!m_exceptionCode && m_error) m_exceptionCode = NETWORK_ERR; ec = m_exceptionCode; }
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 = scriptExecutionContext()->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 (m_requestEntityBody) { ASSERT(m_method != "GET"); ASSERT(m_method != "HEAD"); request.setHTTPBody(m_requestEntityBody.release()); } if (m_requestHeaders.size() > 0) request.addHTTPHeaderFields(m_requestHeaders); #if PLATFORM(BLACKBERRY) request.setIsXMLHTTPRequest(true); #endif ThreadableLoaderOptions options; options.sendLoadCallbacks = true; options.sniffContent = false; options.forcePreflight = uploadEvents; options.allowCredentials = m_sameOriginRequest || m_includeCredentials; options.crossOriginRequestPolicy = UseAccessControl; #if PLATFORM(BLACKBERRY) // We may stay in worker thread in which script execution context // is not document. So check it first. if (scriptExecutionContext()->isDocument() && document()->settings() && !document()->settings()->shouldUseCrossOriginProtocolCheck()) options.enforceCrossOriginProtocolCheck = false; #endif 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); // For now we should only balance the nonCached request count for main-thread XHRs and not // Worker XHRs, as the Cache is not thread-safe. // This will become irrelevant after https://bugs.webkit.org/show_bug.cgi?id=27165 is resolved. if (!scriptExecutionContext()->isWorkerContext()) { ASSERT(isMainThread()); ASSERT(!m_didTellLoaderAboutRequest); cache()->loader()->nonCacheRequestInFlight(m_url); m_didTellLoaderAboutRequest = true; } } } else ThreadableLoader::loadResourceSynchronously(scriptExecutionContext(), request, *this, options); if (!m_exceptionCode && m_error) m_exceptionCode = XMLHttpRequestException::NETWORK_ERR; ec = m_exceptionCode; }
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 MediaSource::addedToRegistry() { setPendingActivity(this); }
void XMLHttpRequest::createRequest(ExceptionState& exceptionState) { // Only GET request is supported for blob URL. if (m_url.protocolIs("blob") && m_method != "GET") { exceptionState.throwDOMException(NetworkError, "'GET' is the only method allowed for 'blob:' URLs."); return; } // 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(EventTypeNames::loadstart)); if (m_requestEntityBody && m_upload) { uploadEvents = m_upload->hasEventListeners(); m_upload->dispatchEvent(XMLHttpRequestProgressEvent::create(EventTypeNames::loadstart)); } } 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); request.setTargetType(ResourceRequest::TargetIsXHR); // When "blob" is specified for the responseType attribute, // we redirect the downloaded data to a file-handle directly // and get the file-path as the result. if (responseTypeCode() == ResponseTypeBlob) request.setDownloadToFile(true); InspectorInstrumentation::willLoadXHR(executionContext(), this, this, m_method, m_url, m_async, m_requestEntityBody ? m_requestEntityBody->deepCopy() : 0, m_requestHeaders, m_includeCredentials); 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.credentialsRequested = m_includeCredentials ? ClientRequestedCredentials : ClientDidNotRequestCredentials; options.crossOriginRequestPolicy = UseAccessControl; options.securityOrigin = securityOrigin(); options.initiator = FetchInitiatorTypeNames::xmlhttprequest; options.contentSecurityPolicyEnforcement = ContentSecurityPolicy::shouldBypassMainWorld(executionContext()) ? DoNotEnforceContentSecurityPolicy : EnforceConnectSrcDirective; // TODO(tsepez): Specify TreatAsActiveContent per http://crbug.com/305303. options.mixedContentBlockingTreatment = TreatAsPassiveContent; options.timeoutMilliseconds = m_timeoutMilliseconds; // Since we redirect the downloaded data to a file-handle directly // when "blob" is specified for the responseType attribute, // buffering is not needed. if (responseTypeCode() == ResponseTypeBlob) options.dataBufferingPolicy = DoNotBufferData; 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? ASSERT(!m_loader); m_loader = ThreadableLoader::create(executionContext(), 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 { ThreadableLoader::loadResourceSynchronously(executionContext(), request, *this, options); } if (!m_exceptionCode && m_error) m_exceptionCode = NetworkError; if (m_exceptionCode) exceptionState.throwUninformativeAndGenericDOMException(m_exceptionCode); }