void EventSource::connect() { ASSERT(m_state == CONNECTING); ASSERT(!m_requestInFlight); ResourceRequest request(m_url); request.setHTTPMethod("GET"); request.setHTTPHeaderField(HTTPHeaderName::Accept, "text/event-stream"); request.setHTTPHeaderField(HTTPHeaderName::CacheControl, "no-cache"); if (!m_lastEventId.isEmpty()) request.setHTTPHeaderField(HTTPHeaderName::LastEventID, m_lastEventId); SecurityOrigin* origin = scriptExecutionContext()->securityOrigin(); ThreadableLoaderOptions options; options.setSendLoadCallbacks(SendCallbacks); options.setSniffContent(DoNotSniffContent); options.setAllowCredentials((origin->canRequest(m_url) || m_withCredentials) ? AllowStoredCredentials : DoNotAllowStoredCredentials); options.preflightPolicy = PreventPreflight; options.crossOriginRequestPolicy = UseAccessControl; options.setDataBufferingPolicy(DoNotBufferData); options.securityOrigin = origin; m_loader = ThreadableLoader::create(scriptExecutionContext(), this, request, options); if (m_loader) m_requestInFlight = true; }
void FileReaderLoader::start(ScriptExecutionContext* scriptExecutionContext, Blob* blob) { // The blob is read by routing through the request handling layer given a temporary public url. m_urlForReading = BlobURL::createPublicURL(scriptExecutionContext->securityOrigin()); if (m_urlForReading.isEmpty()) { failed(FileError::SECURITY_ERR); return; } ThreadableBlobRegistry::registerBlobURL(scriptExecutionContext->securityOrigin(), m_urlForReading, blob->url()); // Construct and load the request. ResourceRequest request(m_urlForReading); request.setHTTPMethod("GET"); if (m_hasRange) request.setHTTPHeaderField(HTTPHeaderName::Range, String::format("bytes=%d-%d", m_rangeStart, m_rangeEnd)); ThreadableLoaderOptions options; options.setSendLoadCallbacks(SendCallbacks); options.setSniffContent(DoNotSniffContent); options.preflightPolicy = ConsiderPreflight; options.setAllowCredentials(AllowStoredCredentials); options.crossOriginRequestPolicy = DenyCrossOriginRequests; if (m_client) m_loader = ThreadableLoader::create(scriptExecutionContext, this, request, options); else ThreadableLoader::loadResourceSynchronously(scriptExecutionContext, request, *this, options); }
void EventSource::connect() { ASSERT(m_state == CONNECTING); ASSERT(!m_requestInFlight); ResourceRequest request { m_url }; request.setHTTPMethod("GET"); request.setHTTPHeaderField(HTTPHeaderName::Accept, "text/event-stream"); request.setHTTPHeaderField(HTTPHeaderName::CacheControl, "no-cache"); if (!m_lastEventId.isEmpty()) request.setHTTPHeaderField(HTTPHeaderName::LastEventID, m_lastEventId); ThreadableLoaderOptions options; options.setSendLoadCallbacks(SendCallbacks); options.setSniffContent(DoNotSniffContent); options.credentials = m_withCredentials ? FetchOptions::Credentials::Include : FetchOptions::Credentials::SameOrigin; options.preflightPolicy = PreventPreflight; options.mode = FetchOptions::Mode::Cors; options.setDataBufferingPolicy(DoNotBufferData); options.contentSecurityPolicyEnforcement = scriptExecutionContext()->shouldBypassMainWorldContentSecurityPolicy() ? ContentSecurityPolicyEnforcement::DoNotEnforce : ContentSecurityPolicyEnforcement::EnforceConnectSrcDirective; m_loader = ThreadableLoader::create(scriptExecutionContext(), this, request, options); // FIXME: Can we just use m_loader for this, null it out when it's no longer in flight, and eliminate the m_requestInFlight member? if (m_loader) m_requestInFlight = true; }
void FetchLoader::start(ScriptExecutionContext& context, const FetchRequest& request) { // FIXME: Compute loading options according fetch options. ThreadableLoaderOptions options; options.setSendLoadCallbacks(SendCallbacks); options.setSniffContent(DoNotSniffContent); options.setDataBufferingPolicy(DoNotBufferData); options.preflightPolicy = ConsiderPreflight; options.setAllowCredentials(AllowStoredCredentials); options.crossOriginRequestPolicy = DenyCrossOriginRequests; options.contentSecurityPolicyEnforcement = ContentSecurityPolicyEnforcement::DoNotEnforce; m_loader = ThreadableLoader::create(&context, this, request.internalRequest(), options); }
void WorkerScriptLoader::loadSynchronously(ScriptExecutionContext* scriptExecutionContext, const URL& url, CrossOriginRequestPolicy crossOriginRequestPolicy) { m_url = url; std::unique_ptr<ResourceRequest> request(createResourceRequest()); if (!request) return; ASSERT_WITH_SECURITY_IMPLICATION(scriptExecutionContext->isWorkerGlobalScope()); ThreadableLoaderOptions options; options.setAllowCredentials(AllowStoredCredentials); options.crossOriginRequestPolicy = crossOriginRequestPolicy; options.setSendLoadCallbacks(SendCallbacks); WorkerThreadableLoader::loadResourceSynchronously(toWorkerGlobalScope(scriptExecutionContext), *request, *this, options); }
void WorkerScriptLoader::loadAsynchronously(ScriptExecutionContext* scriptExecutionContext, const URL& url, CrossOriginRequestPolicy crossOriginRequestPolicy, WorkerScriptLoaderClient* client) { ASSERT(client); m_client = client; m_url = url; std::unique_ptr<ResourceRequest> request(createResourceRequest()); if (!request) return; ThreadableLoaderOptions options; options.setAllowCredentials(AllowStoredCredentials); options.crossOriginRequestPolicy = crossOriginRequestPolicy; options.setSendLoadCallbacks(SendCallbacks); // During create, callbacks may happen which remove the last reference to this object. Ref<WorkerScriptLoader> protect(*this); m_threadableLoader = ThreadableLoader::create(scriptExecutionContext, this, *request, options); }
void InspectorResourceAgent::loadResource(ErrorString* errorString, const String& frameId, const String& urlString, PassRefPtr<LoadResourceCallback> prpCallback) { Frame* frame = m_pageAgent->assertFrame(errorString, frameId); if (!frame) return; Document* document = frame->document(); if (!document) { *errorString = ASCIILiteral("No Document instance for the specified frame"); return; } RefPtr<LoadResourceCallback> callback = prpCallback; URL url = document->completeURL(urlString); ResourceRequest request(url); request.setHTTPMethod(ASCIILiteral("GET")); request.setHiddenFromInspector(true); ThreadableLoaderOptions options; options.setSendLoadCallbacks(SendCallbacks); // So we remove this from m_hiddenRequestIdentifiers on completion. options.setAllowCredentials(AllowStoredCredentials); options.crossOriginRequestPolicy = AllowCrossOriginRequests; // InspectorThreadableLoaderClient deletes itself when the load completes. InspectorThreadableLoaderClient* inspectorThreadableLoaderClient = new InspectorThreadableLoaderClient(callback); RefPtr<DocumentThreadableLoader> loader = DocumentThreadableLoader::create(*document, *inspectorThreadableLoaderClient, request, options); if (!loader) { inspectorThreadableLoaderClient->didFailLoaderCreation(); return; } loader->setDefersLoading(false); // If the load already completed, inspectorThreadableLoaderClient will have been deleted and we will have already called the callback. if (!callback->isActive()) return; inspectorThreadableLoaderClient->setLoader(loader.release()); }
void FetchLoader::start(ScriptExecutionContext& context, Blob& blob) { auto urlForReading = BlobURL::createPublicURL(context.securityOrigin()); if (urlForReading.isEmpty()) { m_client.didFail(); return; } ThreadableBlobRegistry::registerBlobURL(context.securityOrigin(), urlForReading, blob.url()); ResourceRequest request(urlForReading); request.setHTTPMethod("GET"); ThreadableLoaderOptions options; options.setSendLoadCallbacks(SendCallbacks); options.setSniffContent(DoNotSniffContent); options.setDataBufferingPolicy(DoNotBufferData); options.preflightPolicy = ConsiderPreflight; options.setAllowCredentials(AllowStoredCredentials); options.crossOriginRequestPolicy = DenyCrossOriginRequests; options.contentSecurityPolicyEnforcement = ContentSecurityPolicyEnforcement::DoNotEnforce; m_loader = ThreadableLoader::create(&context, this, request, options); }
void XMLHttpRequest::createRequest(ExceptionCode& ec) { // Only GET request is supported for blob URL. if (m_url.protocolIs("blob") && m_method != "GET") { ec = XMLHttpRequestException::NETWORK_ERR; 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.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.setHTTPMethod(m_method); if (m_requestEntityBody) { ASSERT(m_method != "GET"); ASSERT(m_method != "HEAD"); request.setHTTPBody(m_requestEntityBody.release()); } 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.crossOriginRequestPolicy = UseAccessControl; options.securityOrigin = securityOrigin(); #if ENABLE(RESOURCE_TIMING) options.initiator = cachedResourceRequestInitiators().xmlhttprequest; #endif #if ENABLE(XHR_TIMEOUT) if (m_timeoutMilliseconds) request.setTimeoutInterval(m_timeoutMilliseconds / 1000.0); #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); } } 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 DocumentThreadableLoader::loadRequest(const ResourceRequest& request, SecurityCheckPolicy securityCheck) { // Any credential should have been removed from the cross-site requests. const URL& requestURL = request.url(); m_options.setSecurityCheck(securityCheck); ASSERT(m_sameOriginRequest || requestURL.user().isEmpty()); ASSERT(m_sameOriginRequest || requestURL.pass().isEmpty()); if (m_async) { ThreadableLoaderOptions options = m_options; options.setClientCredentialPolicy(DoNotAskClientForCrossOriginCredentials); if (m_actualRequest) { // Don't sniff content or send load callbacks for the preflight request. options.setSendLoadCallbacks(DoNotSendCallbacks); options.setSniffContent(DoNotSniffContent); // Keep buffering the data for the preflight request. options.setDataBufferingPolicy(BufferData); } CachedResourceRequest newRequest(request, options); if (RuntimeEnabledFeatures::sharedFeatures().resourceTimingEnabled()) newRequest.setInitiator(m_options.initiator); ASSERT(!m_resource); m_resource = m_document.cachedResourceLoader().requestRawResource(newRequest); if (m_resource) m_resource->addClient(this); return; } // FIXME: ThreadableLoaderOptions.sniffContent is not supported for synchronous requests. RefPtr<SharedBuffer> data; ResourceError error; ResourceResponse response; unsigned long identifier = std::numeric_limits<unsigned long>::max(); if (m_document.frame()) identifier = m_document.frame()->loader().loadResourceSynchronously(request, m_options.allowCredentials(), m_options.clientCredentialPolicy(), error, response, data); if (!error.isNull() && response.httpStatusCode() <= 0) { if (requestURL.isLocalFile()) { // We don't want XMLHttpRequest to raise an exception for file:// resources, see <rdar://problem/4962298>. // FIXME: XMLHttpRequest quirks should be in XMLHttpRequest code, not in DocumentThreadableLoader.cpp. didReceiveResponse(identifier, response); didFinishLoading(identifier, 0.0); return; } m_client->didFail(error); return; } // FIXME: FrameLoader::loadSynchronously() does not tell us whether a redirect happened or not, so we guess by comparing the // request and response URLs. This isn't a perfect test though, since a server can serve a redirect to the same URL that was // requested. Also comparing the request and response URLs as strings will fail if the requestURL still has its credentials. bool didRedirect = requestURL != response.url(); if (didRedirect && (!isAllowedByContentSecurityPolicy(response.url(), didRedirect) || !isAllowedRedirect(response.url()))) { m_client->didFailRedirectCheck(); return; } didReceiveResponse(identifier, response); if (data) didReceiveData(identifier, data->data(), data->size()); didFinishLoading(identifier, 0.0); }
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; }