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 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 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 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_url.protocolIs("blob") && m_method != "GET") { ec = XMLHttpRequestException::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(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(); options.initiator = cachedResourceRequestInitiators().xmlhttprequest; if (m_responseTypeCode == ResponseTypeArrayBuffer) options.setDataBufferingPolicy(DoNotBufferData); 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 = XMLHttpRequestException::NETWORK_ERR; ec = m_exceptionCode; }