void FetchManager::Loader::performBasicFetch() { // "To perform a basic fetch using |request|, switch on |request|'s url's // scheme, and run the associated steps:" if (m_request->url().protocolIsInHTTPFamily()) { // "Return the result of performing an HTTP fetch using |request|." performHTTPFetch(false, false); } else { // FIXME: implement other protocols. performNetworkError("Fetch API cannot load " + m_request->url().string() + ". URL scheme \"" + m_request->url().protocol() + "\" is not supported."); } }
void FetchManager::Loader::performBasicFetch() { // "To perform a basic fetch using |request|, switch on |request|'s url's // scheme, and run the associated steps:" if (m_request->url().protocolIsInHTTPFamily()) { // "Return the result of performing an HTTP fetch using |request|." m_corsFlag = false; m_corsPreflightFlag = false; performHTTPFetch(); } else { // FIXME: implement other protocols. performNetworkError(); } }
void FetchManager::Loader::performHTTPFetch(bool corsFlag, bool corsPreflightFlag) { ASSERT(m_request->url().protocolIsInHTTPFamily()); // CORS preflight fetch procedure is implemented inside DocumentThreadableLoader. // "1. Let |HTTPRequest| be a copy of |request|, except that |HTTPRequest|'s // body is a tee of |request|'s body." // We use ResourceRequest class for HTTPRequest. // FIXME: Support body. ResourceRequest request(m_request->url()); request.setRequestContext(m_request->context()); request.setHTTPMethod(m_request->method()); const Vector<OwnPtr<FetchHeaderList::Header>>& list = m_request->headerList()->list(); for (size_t i = 0; i < list.size(); ++i) { request.addHTTPHeaderField(AtomicString(list[i]->first), AtomicString(list[i]->second)); } if (m_request->method() != "GET" && m_request->method() != "HEAD") { if (BodyStreamBuffer* buffer = m_request->buffer()) { RefPtr<BlobDataHandle> blobDataHandle = buffer->handle()->obtainReader(nullptr)->drainAsBlobDataHandle(FetchDataConsumerHandle::Reader::AllowBlobWithInvalidSize); RefPtr<FormData> httpBody(FormData::create()); if (blobDataHandle) httpBody->appendBlob(blobDataHandle->uuid(), blobDataHandle); request.setHTTPBody(httpBody); } } request.setUseStreamOnResponse(true); // "2. Append `Referer`/empty byte sequence, if |HTTPRequest|'s |referrer| // is none, and `Referer`/|HTTPRequest|'s referrer, serialized and utf-8 // encoded, otherwise, to HTTPRequest's header list. // We set the referrer using workerGlobalScope's URL in // WorkerThreadableLoader. // "3. Append `Host`, ..." // FIXME: Implement this when the spec is fixed. // "4.If |HTTPRequest|'s force Origin header flag is set, append `Origin`/ // |HTTPRequest|'s origin, serialized and utf-8 encoded, to |HTTPRequest|'s // header list." // We set Origin header in updateRequestForAccessControl() called from // DocumentThreadableLoader::makeCrossOriginAccessRequest // "5. Let |credentials flag| be set if either |HTTPRequest|'s credentials // mode is |include|, or |HTTPRequest|'s credentials mode is |same-origin| // and the |CORS flag| is unset, and unset otherwise. ResourceLoaderOptions resourceLoaderOptions; resourceLoaderOptions.dataBufferingPolicy = DoNotBufferData; if (m_request->credentials() == WebURLRequest::FetchCredentialsModeInclude || (m_request->credentials() == WebURLRequest::FetchCredentialsModeSameOrigin && !corsFlag)) { resourceLoaderOptions.allowCredentials = AllowStoredCredentials; } if (m_request->credentials() == WebURLRequest::FetchCredentialsModeInclude) resourceLoaderOptions.credentialsRequested = ClientRequestedCredentials; resourceLoaderOptions.securityOrigin = m_request->origin().get(); ThreadableLoaderOptions threadableLoaderOptions; threadableLoaderOptions.contentSecurityPolicyEnforcement = ContentSecurityPolicy::shouldBypassMainWorld(executionContext()) ? DoNotEnforceContentSecurityPolicy : EnforceConnectSrcDirective; if (corsPreflightFlag) threadableLoaderOptions.preflightPolicy = ForcePreflight; switch (m_request->mode()) { case WebURLRequest::FetchRequestModeSameOrigin: threadableLoaderOptions.crossOriginRequestPolicy = DenyCrossOriginRequests; break; case WebURLRequest::FetchRequestModeNoCORS: threadableLoaderOptions.crossOriginRequestPolicy = AllowCrossOriginRequests; break; case WebURLRequest::FetchRequestModeCORS: case WebURLRequest::FetchRequestModeCORSWithForcedPreflight: threadableLoaderOptions.crossOriginRequestPolicy = UseAccessControl; break; } m_loader = ThreadableLoader::create(*executionContext(), this, request, threadableLoaderOptions, resourceLoaderOptions); if (!m_loader) performNetworkError("Can't create ThreadableLoader"); }
void FetchManager::Loader::start() { // "1. If |request|'s url contains a Known HSTS Host, modify it per the // requirements of the 'URI [sic] Loading and Port Mapping' chapter of HTTP // Strict Transport Security." // FIXME: Implement this. // "2. If |request|'s referrer is not none, set |request|'s referrer to the // result of invoking determine |request|'s referrer." // We set the referrer using workerGlobalScope's URL in // WorkerThreadableLoader. // "3. If |request|'s synchronous flag is unset and fetch is not invoked // recursively, run the remaining steps asynchronously." // We don't support synchronous flag. // "4. Let response be the value corresponding to the first matching // statement:" // "- should fetching |request| be blocked as mixed content returns blocked" // We do mixed content checking in ResourceFetcher. // "- should fetching |request| be blocked as content security returns // blocked" if (!ContentSecurityPolicy::shouldBypassMainWorld(executionContext()) && !executionContext()->contentSecurityPolicy()->allowConnectToSource(m_request->url())) { // "A network error." performNetworkError("Refused to connect to '" + m_request->url().elidedString() + "' because it violates the document's Content Security Policy."); return; } // "- |request|'s url's origin is |request|'s origin and the |CORS flag| is // unset" // "- |request|'s url's scheme is 'data' and |request|'s same-origin data // URL flag is set" // "- |request|'s url's scheme is 'about'" // Note we don't support to call this method with |CORS flag|. if ((SecurityOrigin::create(m_request->url())->isSameSchemeHostPort(m_request->origin().get())) || (m_request->url().protocolIsData() && m_request->sameOriginDataURLFlag()) || (m_request->url().protocolIsAbout())) { // "The result of performing a basic fetch using request." performBasicFetch(); return; } // "- |request|'s mode is |same-origin|" if (m_request->mode() == WebURLRequest::FetchRequestModeSameOrigin) { // "A network error." performNetworkError("Fetch API cannot load " + m_request->url().string() + ". Request mode is \"same-origin\" but the URL\'s origin is not same as the request origin " + m_request->origin()->toString() + "."); return; } // "- |request|'s mode is |no CORS|" if (m_request->mode() == WebURLRequest::FetchRequestModeNoCORS) { // "Set |request|'s response tainting to |opaque|." m_request->setResponseTainting(FetchRequestData::OpaqueTainting); // "The result of performing a basic fetch using |request|." performBasicFetch(); return; } // "- |request|'s url's scheme is not one of 'http' and 'https'" if (!m_request->url().protocolIsInHTTPFamily()) { // "A network error." performNetworkError("Fetch API cannot load " + m_request->url().string() + ". URL scheme must be \"http\" or \"https\" for CORS request."); return; } // "- |request|'s mode is |CORS-with-forced-preflight|. // "- |request|'s unsafe request flag is set and either |request|'s method // is not a simple method or a header in |request|'s header list is not a // simple header" if (m_request->mode() == WebURLRequest::FetchRequestModeCORSWithForcedPreflight || (m_request->unsafeRequestFlag() && (!FetchUtils::isSimpleMethod(m_request->method()) || m_request->headerList()->containsNonSimpleHeader()))) { // "Set |request|'s response tainting to |CORS|." m_request->setResponseTainting(FetchRequestData::CORSTainting); // "The result of performing an HTTP fetch using |request| with the // |CORS flag| and |CORS preflight flag| set." performHTTPFetch(true, true); return; } // "- Otherwise // Set |request|'s response tainting to |CORS|." m_request->setResponseTainting(FetchRequestData::CORSTainting); // "The result of performing an HTTP fetch using |request| with the // |CORS flag| set." performHTTPFetch(true, false); }
void FetchManager::Loader::start() { // "1. If |request|'s url contains a Known HSTS Host, modify it per the // requirements of the 'URI [sic] Loading and Port Mapping' chapter of HTTP // Strict Transport Security." // FIXME: Implement this. // "2. If |request|'s referrer is not none, set |request|'s referrer to the // result of invoking determine |request|'s referrer." // We set the referrer using workerGlobalScope's URL in // WorkerThreadableLoader. // "3. If |request|'s synchronous flag is unset and fetch is not invoked // recursively, run the remaining steps asynchronously." // We don't support synchronous flag. // "4. Let response be the value corresponding to the first matching // statement:" // "- should fetching |request| be blocked as mixed content returns blocked // - should fetching |request| be blocked as content security returns // blocked // A network error." // We do mixed content checking and CSP checking in ResourceFetcher. // "- |request|'s url's origin is |request|'s origin and the |CORS flag| is // unset" // "- |request|'s url's scheme is 'data' and |request|'s same-origin data // URL flag is set" // "- |request|'s url's scheme is 'about'" if ((SecurityOrigin::create(m_request->url())->isSameSchemeHostPort(m_request->origin().get()) && !m_corsFlag) || (m_request->url().protocolIsData() && m_request->sameOriginDataURLFlag()) || (m_request->url().protocolIsAbout())) { // "The result of performing a basic fetch using request." performBasicFetch(); return; } // "- |request|'s mode is |same-origin|" if (m_request->mode() == FetchRequestData::SameOriginMode) { // "A network error." performNetworkError(); return; } // "- |request|'s mode is |no CORS|" if (m_request->mode() == FetchRequestData::NoCORSMode) { // "Set |request|'s response tainting to |opaque|." m_request->setResponseTainting(FetchRequestData::OpaqueTainting); // "The result of performing a basic fetch using |request|." performBasicFetch(); return; } // "- |request|'s url's scheme is not one of 'http' and 'https'" if (!m_request->url().protocolIsInHTTPFamily()) { // "A network error." performNetworkError(); return; } // "- |request|'s mode is |CORS-with-forced-preflight|. // "- |request|'s unsafe request flag is set and either |request|'s method // is not a simple method or a header in |request|'s header list is not a // simple header" if (m_request->mode() == FetchRequestData::CORSWithForcedPreflight || (m_request->unsafeRequestFlag() && (!FetchUtils::isSimpleMethod(m_request->method()) || m_request->headerList()->containsNonSimpleHeader()))) { // "Set |request|'s response tainting to |CORS|." m_request->setResponseTainting(FetchRequestData::CORSTainting); // "The result of performing an HTTP fetch using |request| with the // |CORS flag| and |CORS preflight flag| set." m_corsFlag = true; m_corsPreflightFlag = true; performHTTPFetch(); return; } // "- Otherwise // Set |request|'s response tainting to |CORS|." m_request->setResponseTainting(FetchRequestData::CORSTainting); // "The result of performing an HTTP fetch using |request| with the // |CORS flag| set." m_corsFlag = true; m_corsPreflightFlag = false; performHTTPFetch(); }