void DocumentThreadableLoader::loadFallbackRequestForServiceWorker() { clearResource(); ResourceRequest fallbackRequest(m_fallbackRequestForServiceWorker); m_fallbackRequestForServiceWorker = ResourceRequest(); dispatchInitialRequest(fallbackRequest); // |this| may be dead here in async mode. }
void DocumentThreadableLoader::loadFallbackRequestForServiceWorker() { clearResource(); ResourceRequest fallbackRequest(m_fallbackRequestForServiceWorker); m_fallbackRequestForServiceWorker = ResourceRequest(); dispatchInitialRequest(fallbackRequest); }
void DocumentThreadableLoader::start(const ResourceRequest& request) { // Setting an outgoing referer is only supported in the async code path. DCHECK(m_async || request.httpReferrer().isEmpty()); m_sameOriginRequest = getSecurityOrigin()->canRequestNoSuborigin(request.url()); m_requestContext = request.requestContext(); m_redirectMode = request.fetchRedirectMode(); if (!m_sameOriginRequest && m_options.crossOriginRequestPolicy == DenyCrossOriginRequests) { InspectorInstrumentation:: documentThreadableLoaderFailedToStartLoadingForClient(m_document, m_client); ThreadableLoaderClient* client = m_client; clear(); client->didFail(ResourceError(errorDomainBlinkInternal, 0, request.url().getString(), "Cross origin requests are not supported.")); return; } m_requestStartedSeconds = monotonicallyIncreasingTime(); // Save any headers on the request here. If this request redirects // cross-origin, we cancel the old request create a new one, and copy these // headers. m_requestHeaders = request.httpHeaderFields(); // DocumentThreadableLoader is used by all javascript initiated fetch, so we // use this chance to record non-GET fetch script requests. However, this is // based on the following assumptions, so please be careful when adding // similar logic: // - ThreadableLoader is used as backend for all javascript initiated network // fetches. // - Note that ThreadableLoader is also used for non-network fetch such as // FileReaderLoader. However it emulates GET method so signal is not // recorded here. // - ThreadableLoader w/ non-GET request is only created from javascript // initiated fetch. // - Some non-script initiated fetches such as WorkerScriptLoader also use // ThreadableLoader, but they are guaranteed to use GET method. if (request.httpMethod() != HTTPNames::GET) { if (Page* page = m_document->page()) page->chromeClient().didObserveNonGetFetchFromScript(); } ResourceRequest newRequest(request); if (m_requestContext != WebURLRequest::RequestContextFetch) { // When the request context is not "fetch", |crossOriginRequestPolicy| // represents the fetch request mode, and |credentialsRequested| represents // the fetch credentials mode. So we set those flags here so that we can see // the correct request mode and credentials mode in the service worker's // fetch event handler. switch (m_options.crossOriginRequestPolicy) { case DenyCrossOriginRequests: newRequest.setFetchRequestMode( WebURLRequest::FetchRequestModeSameOrigin); break; case UseAccessControl: if (m_options.preflightPolicy == ForcePreflight) { newRequest.setFetchRequestMode( WebURLRequest::FetchRequestModeCORSWithForcedPreflight); } else { newRequest.setFetchRequestMode(WebURLRequest::FetchRequestModeCORS); } break; case AllowCrossOriginRequests: SECURITY_CHECK(IsNoCORSAllowedContext(m_requestContext, request.skipServiceWorker())); newRequest.setFetchRequestMode(WebURLRequest::FetchRequestModeNoCORS); break; } if (m_resourceLoaderOptions.allowCredentials == AllowStoredCredentials) { newRequest.setFetchCredentialsMode( WebURLRequest::FetchCredentialsModeInclude); } else { newRequest.setFetchCredentialsMode( WebURLRequest::FetchCredentialsModeSameOrigin); } } // We assume that ServiceWorker is skipped for sync requests and unsupported // protocol requests by content/ code. if (m_async && request.skipServiceWorker() == WebURLRequest::SkipServiceWorker::None && SchemeRegistry::shouldTreatURLSchemeAsAllowingServiceWorkers( request.url().protocol()) && m_document->fetcher()->isControlledByServiceWorker()) { if (newRequest.fetchRequestMode() == WebURLRequest::FetchRequestModeCORS || newRequest.fetchRequestMode() == WebURLRequest::FetchRequestModeCORSWithForcedPreflight) { m_fallbackRequestForServiceWorker = ResourceRequest(request); // m_fallbackRequestForServiceWorker is used when a regular controlling // service worker doesn't handle a cross origin request. When this happens // we still want to give foreign fetch a chance to handle the request, so // only skip the controlling service worker for the fallback request. This // is currently safe because of http://crbug.com/604084 the // wasFallbackRequiredByServiceWorker flag is never set when foreign fetch // handled a request. m_fallbackRequestForServiceWorker.setSkipServiceWorker( WebURLRequest::SkipServiceWorker::Controlling); } loadRequest(newRequest, m_resourceLoaderOptions); return; } dispatchInitialRequest(newRequest); }
DocumentThreadableLoader::DocumentThreadableLoader(Document& document, ThreadableLoaderClient* client, BlockingBehavior blockingBehavior, const ResourceRequest& request, const ThreadableLoaderOptions& options, const ResourceLoaderOptions& resourceLoaderOptions) : m_client(client) , m_document(&document) , m_options(options) , m_resourceLoaderOptions(resourceLoaderOptions) , m_forceDoNotAllowStoredCredentials(false) , m_securityOrigin(m_resourceLoaderOptions.securityOrigin) , m_sameOriginRequest(securityOrigin()->canRequestNoSuborigin(request.url())) , m_crossOriginNonSimpleRequest(false) , m_isUsingDataConsumerHandle(false) , m_async(blockingBehavior == LoadAsynchronously) , m_requestContext(request.requestContext()) , m_timeoutTimer(this, &DocumentThreadableLoader::didTimeout) , m_requestStartedSeconds(0.0) , m_corsRedirectLimit(kMaxCORSRedirects) , m_redirectMode(request.fetchRedirectMode()) { ASSERT(client); // Setting an outgoing referer is only supported in the async code path. ASSERT(m_async || request.httpReferrer().isEmpty()); if (!m_sameOriginRequest && m_options.crossOriginRequestPolicy == DenyCrossOriginRequests) { ThreadableLoaderClient* client = m_client; clear(); client->didFail(ResourceError(errorDomainBlinkInternal, 0, request.url().string(), "Cross origin requests are not supported.")); // |this| may be dead here. return; } m_requestStartedSeconds = monotonicallyIncreasingTime(); // Save any CORS simple headers on the request here. If this request redirects cross-origin, we cancel the old request // create a new one, and copy these headers. const HTTPHeaderMap& headerMap = request.httpHeaderFields(); for (const auto& header : headerMap) { if (FetchUtils::isSimpleHeader(header.key, header.value)) { m_simpleRequestHeaders.add(header.key, header.value); } else if (equalIgnoringCase(header.key, HTTPNames::Range) && m_options.crossOriginRequestPolicy == UseAccessControl && m_options.preflightPolicy == PreventPreflight) { // Allow an exception for the "range" header for when CORS callers request no preflight, this ensures cross-origin // redirects work correctly for crossOrigin enabled WebURLRequest::RequestContextVideo type requests. m_simpleRequestHeaders.add(header.key, header.value); } } // DocumentThreadableLoader is used by all javascript initiated fetch, so // we use this chance to record non-GET fetch script requests. // However, this is based on the following assumptions, so please be careful // when adding similar logic: // - ThreadableLoader is used as backend for all javascript initiated network // fetches. // - Note that ThreadableLoader is also used for non-network fetch such as // FileReaderLoader. However it emulates GET method so signal is not // recorded here. // - ThreadableLoader w/ non-GET request is only created from javascript // initiated fetch. // - Some non-script initiated fetches such as WorkerScriptLoader also use // ThreadableLoader, but they are guaranteed to use GET method. if (request.httpMethod() != HTTPNames::GET) { if (Page* page = document.page()) page->chromeClient().didObserveNonGetFetchFromScript(); } // If the fetch request will be handled by the ServiceWorker, the // FetchRequestMode of the request must be FetchRequestModeCORS or // FetchRequestModeCORSWithForcedPreflight. Otherwise the ServiceWorker can // return a opaque response which is from the other origin site and the // script in the page can read the content. // // We assume that ServiceWorker is skipped for sync requests and unsupported // protocol requests by content/ code. if (m_async && !request.skipServiceWorker() && SchemeRegistry::shouldTreatURLSchemeAsAllowingServiceWorkers(request.url().protocol()) && document.fetcher()->isControlledByServiceWorker()) { ResourceRequest newRequest(request); // FetchRequestMode should be set by the caller. But the expected value // of FetchRequestMode is not speced yet except for XHR. So we set here. // FIXME: When we support fetch API in document, this value should not // be overridden here. if (options.preflightPolicy == ForcePreflight) newRequest.setFetchRequestMode(WebURLRequest::FetchRequestModeCORSWithForcedPreflight); else newRequest.setFetchRequestMode(WebURLRequest::FetchRequestModeCORS); m_fallbackRequestForServiceWorker = ResourceRequest(request); m_fallbackRequestForServiceWorker.setSkipServiceWorker(true); loadRequest(newRequest, m_resourceLoaderOptions); return; } dispatchInitialRequest(request); // |this| may be dead here in async mode. }