void NetworkResourceLoader::retrieveCacheEntry(const ResourceRequest& request) { ASSERT(canUseCache(request)); RefPtr<NetworkResourceLoader> loader(this); NetworkCache::singleton().retrieve(request, { m_parameters.webPageID, m_parameters.webFrameID }, [loader, request](auto entry) { if (loader->hasOneRef()) { // The loader has been aborted and is only held alive by this lambda. return; } if (!entry) { loader->startNetworkLoad(request); return; } if (entry->redirectRequest()) { loader->dispatchWillSendRequestForCacheEntry(WTFMove(entry)); return; } if (loader->m_parameters.needsCertificateInfo && !entry->response().certificateInfo()) { loader->startNetworkLoad(request); return; } if (entry->needsValidation() || request.cachePolicy() == WebCore::RefreshAnyCacheData) { loader->validateCacheEntry(WTFMove(entry)); return; } loader->didRetrieveCacheEntry(WTFMove(entry)); }); }
void MainResourceLoader::willSendRequest(ResourceRequest& newRequest, const ResourceResponse& redirectResponse) { // Note that there are no asserts here as there are for the other callbacks. This is due to the // fact that this "callback" is sent when starting every load, and the state of callback // deferrals plays less of a part in this function in preventing the bad behavior deferring // callbacks is meant to prevent. ASSERT(!newRequest.isNull()); // The additional processing can do anything including possibly removing the last // reference to this object; one example of this is 3266216. RefPtr<MainResourceLoader> protect(this); // Update cookie policy base URL as URL changes, except for subframes, which use the // URL of the main frame which doesn't change when we redirect. if (frameLoader()->isLoadingMainFrame()) newRequest.setMainDocumentURL(newRequest.url()); // If we're fielding a redirect in response to a POST, force a load from origin, since // this is a common site technique to return to a page viewing some data that the POST // just modified. // Also, POST requests always load from origin, but this does not affect subresources. if (newRequest.cachePolicy() == UseProtocolCachePolicy && isPostOrRedirectAfterPost(newRequest, redirectResponse)) newRequest.setCachePolicy(ReloadIgnoringCacheData); if (!newRequest.isNull()) { ResourceLoader::willSendRequest(newRequest, redirectResponse); setRequest(newRequest); } // Don't set this on the first request. It is set when the main load was started. frameLoader()->setRequest(newRequest); ref(); // balanced by deref in continueAfterNavigationPolicy frameLoader()->checkNavigationPolicy(newRequest, callContinueAfterNavigationPolicy, this); }
void ResourceRequestBase::setAsIsolatedCopy(const ResourceRequest& other) { setURL(other.url().isolatedCopy()); setCachePolicy(other.cachePolicy()); setTimeoutInterval(other.timeoutInterval()); setFirstPartyForCookies(other.firstPartyForCookies().isolatedCopy()); setHTTPMethod(other.httpMethod().isolatedCopy()); setPriority(other.priority()); setRequester(other.requester()); updateResourceRequest(); m_httpHeaderFields = other.httpHeaderFields().isolatedCopy(); size_t encodingCount = other.m_responseContentDispositionEncodingFallbackArray.size(); if (encodingCount > 0) { String encoding1 = other.m_responseContentDispositionEncodingFallbackArray[0].isolatedCopy(); String encoding2; String encoding3; if (encodingCount > 1) { encoding2 = other.m_responseContentDispositionEncodingFallbackArray[1].isolatedCopy(); if (encodingCount > 2) encoding3 = other.m_responseContentDispositionEncodingFallbackArray[2].isolatedCopy(); } ASSERT(encodingCount <= 3); setResponseContentDispositionEncodingFallbackArray(encoding1, encoding2, encoding3); } if (other.m_httpBody) setHTTPBody(other.m_httpBody->isolatedCopy()); setAllowCookies(other.m_allowCookies); const_cast<ResourceRequest&>(asResourceRequest()).doPlatformSetAsIsolatedCopy(other); }
void DocumentLoader::willSendRequest(ResourceRequest& newRequest, const ResourceResponse& redirectResponse) { // Note that there are no asserts here as there are for the other callbacks. This is due to the // fact that this "callback" is sent when starting every load, and the state of callback // deferrals plays less of a part in this function in preventing the bad behavior deferring // callbacks is meant to prevent. ASSERT(!newRequest.isNull()); if (!frameLoader()->checkIfFormActionAllowedByCSP(newRequest.url())) { cancelMainResourceLoad(frameLoader()->cancelledError(newRequest)); return; } ASSERT(timing()->fetchStart()); if (!redirectResponse.isNull()) { // If the redirecting url is not allowed to display content from the target origin, // then block the redirect. RefPtr<SecurityOrigin> redirectingOrigin = SecurityOrigin::create(redirectResponse.url()); if (!redirectingOrigin->canDisplay(newRequest.url())) { FrameLoader::reportLocalLoadFailed(m_frame, newRequest.url().string()); cancelMainResourceLoad(frameLoader()->cancelledError(newRequest)); return; } timing()->addRedirect(redirectResponse.url(), newRequest.url()); } // Update cookie policy base URL as URL changes, except for subframes, which use the // URL of the main frame which doesn't change when we redirect. if (frameLoader()->isLoadingMainFrame()) newRequest.setFirstPartyForCookies(newRequest.url()); // If we're fielding a redirect in response to a POST, force a load from origin, since // this is a common site technique to return to a page viewing some data that the POST // just modified. // Also, POST requests always load from origin, but this does not affect subresources. if (newRequest.cachePolicy() == UseProtocolCachePolicy && isPostOrRedirectAfterPost(newRequest, redirectResponse)) newRequest.setCachePolicy(ReloadIgnoringCacheData); Frame* top = m_frame->tree()->top(); if (top) { if (!top->loader()->mixedContentChecker()->canDisplayInsecureContent(top->document()->securityOrigin(), newRequest.url())) { cancelMainResourceLoad(frameLoader()->cancelledError(newRequest)); return; } } setRequest(newRequest); if (redirectResponse.isNull()) return; frameLoader()->client()->dispatchDidReceiveServerRedirectForProvisionalLoad(); if (!shouldContinueForNavigationPolicy(newRequest)) stopLoadingForPolicyChange(); }
bool equalIgnoringHeaderFields(const ResourceRequest& a, const ResourceRequest& b) { if (a.url() != b.url()) return false; if (a.cachePolicy() != b.cachePolicy()) return false; if (a.timeoutInterval() != b.timeoutInterval()) return false; if (a.firstPartyForCookies() != b.firstPartyForCookies()) return false; if (a.httpMethod() != b.httpMethod()) return false; if (a.allowStoredCredentials() != b.allowStoredCredentials()) return false; if (a.priority() != b.priority()) return false; if (a.referrerPolicy() != b.referrerPolicy()) return false; FormData* formDataA = a.httpBody(); FormData* formDataB = b.httpBody(); if (!formDataA) return !formDataB; if (!formDataB) return !formDataA; if (*formDataA != *formDataB) return false; return true; }
void DocumentLoader::willSendRequest(ResourceRequest& newRequest, const ResourceResponse& redirectResponse) { // Note that there are no asserts here as there are for the other callbacks. This is due to the // fact that this "callback" is sent when starting every load, and the state of callback // deferrals plays less of a part in this function in preventing the bad behavior deferring // callbacks is meant to prevent. ASSERT(!newRequest.isNull()); if (isFormSubmission(m_triggeringAction.type()) && !m_frame->document()->contentSecurityPolicy()->allowFormAction(newRequest.url())) { cancelMainResourceLoad(ResourceError::cancelledError(newRequest.url())); return; } ASSERT(timing()->fetchStart()); if (!redirectResponse.isNull()) { // If the redirecting url is not allowed to display content from the target origin, // then block the redirect. RefPtr<SecurityOrigin> redirectingOrigin = SecurityOrigin::create(redirectResponse.url()); if (!redirectingOrigin->canDisplay(newRequest.url())) { FrameLoader::reportLocalLoadFailed(m_frame, newRequest.url().string()); cancelMainResourceLoad(ResourceError::cancelledError(newRequest.url())); return; } timing()->addRedirect(redirectResponse.url(), newRequest.url()); } // If we're fielding a redirect in response to a POST, force a load from origin, since // this is a common site technique to return to a page viewing some data that the POST // just modified. if (newRequest.cachePolicy() == UseProtocolCachePolicy && isRedirectAfterPost(newRequest, redirectResponse)) newRequest.setCachePolicy(ReloadBypassingCache); // If this is a sub-frame, check for mixed content blocking against the top frame. if (m_frame->tree().parent()) { // FIXME: This does not yet work with out-of-process iframes. Frame* top = m_frame->tree().top(); if (top->isLocalFrame() && !toLocalFrame(top)->loader().mixedContentChecker()->canRunInsecureContent(toLocalFrame(top)->document()->securityOrigin(), newRequest.url())) { cancelMainResourceLoad(ResourceError::cancelledError(newRequest.url())); return; } } m_request = newRequest; if (redirectResponse.isNull()) return; appendRedirect(newRequest.url()); frameLoader()->client()->dispatchDidReceiveServerRedirectForProvisionalLoad(); if (!shouldContinueForNavigationPolicy(newRequest)) cancelMainResourceLoad(ResourceError::cancelledError(m_request.url())); }
void ResourceFetcher::addAdditionalRequestHeaders(ResourceRequest& request, Resource::Type type) { if (!frame()) return; if (request.cachePolicy() == UseProtocolCachePolicy) request.setCachePolicy(resourceRequestCachePolicy(request, type)); if (request.requestContext() == WebURLRequest::RequestContextUnspecified) determineRequestContext(request, type); if (type == Resource::LinkPrefetch || type == Resource::LinkSubresource) request.setHTTPHeaderField("Purpose", "prefetch"); context().addAdditionalRequestHeaders(document(), request, (type == Resource::MainResource) ? FetchMainResource : FetchSubresource); }
static inline NetworkRequest::CachePolicy platformCachePolicyForRequest(const ResourceRequest& request) { switch (request.cachePolicy()) { case WebCore::UseProtocolCachePolicy: return NetworkRequest::UseProtocolCachePolicy; case WebCore::ReloadIgnoringCacheData: return NetworkRequest::ReloadIgnoringCacheData; case WebCore::ReturnCacheDataElseLoad: return NetworkRequest::ReturnCacheDataElseLoad; case WebCore::ReturnCacheDataDontLoad: return NetworkRequest::ReturnCacheDataDontLoad; default: return NetworkRequest::UseProtocolCachePolicy; } }
void MainResourceLoader::willSendRequest(ResourceRequest& newRequest, const ResourceResponse& redirectResponse) { // Note that there are no asserts here as there are for the other callbacks. This is due to the // fact that this "callback" is sent when starting every load, and the state of callback // deferrals plays less of a part in this function in preventing the bad behavior deferring // callbacks is meant to prevent. ASSERT(!newRequest.isNull()); // The additional processing can do anything including possibly removing the last // reference to this object; one example of this is 3266216. RefPtr<MainResourceLoader> protect(this); // Update cookie policy base URL as URL changes, except for subframes, which use the // URL of the main frame which doesn't change when we redirect. if (frameLoader()->isLoadingMainFrame()) newRequest.setFirstPartyForCookies(newRequest.url()); // If we're fielding a redirect in response to a POST, force a load from origin, since // this is a common site technique to return to a page viewing some data that the POST // just modified. // Also, POST requests always load from origin, but this does not affect subresources. if (newRequest.cachePolicy() == UseProtocolCachePolicy && isPostOrRedirectAfterPost(newRequest, redirectResponse)) newRequest.setCachePolicy(ReloadIgnoringCacheData); ResourceLoader::willSendRequest(newRequest, redirectResponse); // Don't set this on the first request. It is set when the main load was started. m_documentLoader->setRequest(newRequest); Frame* top = m_frame->tree()->top(); if (top != m_frame) frameLoader()->checkIfDisplayInsecureContent(top->document()->securityOrigin(), newRequest.url()); // FIXME: Ideally we'd stop the I/O until we hear back from the navigation policy delegate // listener. But there's no way to do that in practice. So instead we cancel later if the // listener tells us to. In practice that means the navigation policy needs to be decided // synchronously for these redirect cases. if (!redirectResponse.isNull()) { ref(); // balanced by deref in continueAfterNavigationPolicy frameLoader()->policyChecker()->checkNavigationPolicy(newRequest, callContinueAfterNavigationPolicy, this); } }
void ArgumentCoder<ResourceRequest>::encodePlatformData(ArgumentEncoder& encoder, const ResourceRequest& resourceRequest) { encoder << resourceRequest.url().string(); encoder << resourceRequest.httpMethod(); encoder << resourceRequest.httpHeaderFields(); encoder << resourceRequest.timeoutInterval(); // FIXME: Do not encode HTTP message body. // 1. It can be large and thus costly to send across. // 2. It is misleading to provide a body with some requests, while others use body streams, which cannot be serialized at all. FormData* httpBody = resourceRequest.httpBody(); encoder << static_cast<bool>(httpBody); if (httpBody) encoder << httpBody->flattenToString(); encoder << resourceRequest.firstPartyForCookies().string(); encoder << resourceRequest.allowCookies(); encoder.encodeEnum(resourceRequest.priority()); encoder.encodeEnum(resourceRequest.cachePolicy()); encoder.encodeEnum(resourceRequest.requester()); encoder << static_cast<uint32_t>(resourceRequest.soupMessageFlags()); encoder << resourceRequest.initiatingPageID(); }
CFURLRequestRef cfURLRequest(const ResourceRequest& request) { CFURLRef url = request.url().createCFURL(); CFURLRef mainDocumentURL = request.mainDocumentURL().createCFURL(); CFMutableURLRequestRef cfRequest = CFURLRequestCreateMutable(0, url, (CFURLRequestCachePolicy)request.cachePolicy(), request.timeoutInterval(), mainDocumentURL); CFRelease(url); CFRelease(mainDocumentURL); CFStringRef requestMethod = request.httpMethod().createCFString(); CFURLRequestSetHTTPRequestMethod(cfRequest, requestMethod); CFRelease(requestMethod); addHeadersFromHashMap(cfRequest, request.httpHeaderFields()); setHTTPBody(cfRequest, request.httpBody()); CFURLRequestSetShouldHandleHTTPCookies(cfRequest, request.allowHTTPCookies()); return cfRequest; }
void MainResourceLoader::willSendRequest(ResourceRequest& newRequest, const ResourceResponse& redirectResponse) { // Note that there are no asserts here as there are for the other callbacks. This is due to the // fact that this "callback" is sent when starting every load, and the state of callback // deferrals plays less of a part in this function in preventing the bad behavior deferring // callbacks is meant to prevent. ASSERT(!newRequest.isNull()); // The additional processing can do anything including possibly removing the last // reference to this object; one example of this is 3266216. RefPtr<MainResourceLoader> protect(this); ASSERT(documentLoader()->timing()->fetchStart); if (!redirectResponse.isNull()) { DocumentLoadTiming* documentLoadTiming = documentLoader()->timing(); // Check if the redirected url is allowed to access the redirecting url's timing information. RefPtr<SecurityOrigin> securityOrigin = SecurityOrigin::create(newRequest.url()); if (!securityOrigin->canRequest(redirectResponse.url())) documentLoadTiming->hasCrossOriginRedirect = true; documentLoadTiming->redirectCount++; if (!documentLoadTiming->redirectStart) documentLoadTiming->redirectStart = documentLoadTiming->fetchStart; documentLoadTiming->redirectEnd = currentTime(); documentLoadTiming->fetchStart = documentLoadTiming->redirectEnd; } // Update cookie policy base URL as URL changes, except for subframes, which use the // URL of the main frame which doesn't change when we redirect. if (frameLoader()->isLoadingMainFrame()) newRequest.setFirstPartyForCookies(newRequest.url()); // If we're fielding a redirect in response to a POST, force a load from origin, since // this is a common site technique to return to a page viewing some data that the POST // just modified. // Also, POST requests always load from origin, but this does not affect subresources. if (newRequest.cachePolicy() == UseProtocolCachePolicy && isPostOrRedirectAfterPost(newRequest, redirectResponse)) newRequest.setCachePolicy(ReloadIgnoringCacheData); Frame* top = m_frame->tree()->top(); if (top != m_frame) { if (!frameLoader()->checkIfDisplayInsecureContent(top->document()->securityOrigin(), newRequest.url())) { cancel(); return; } } ResourceLoader::willSendRequest(newRequest, redirectResponse); // Don't set this on the first request. It is set when the main load was started. m_documentLoader->setRequest(newRequest); #if ENABLE(OFFLINE_WEB_APPLICATIONS) if (!redirectResponse.isNull()) { // We checked application cache for initial URL, now we need to check it for redirected one. ASSERT(!m_substituteData.isValid()); documentLoader()->applicationCacheHost()->maybeLoadMainResourceForRedirect(newRequest, m_substituteData); } #endif // FIXME: Ideally we'd stop the I/O until we hear back from the navigation policy delegate // listener. But there's no way to do that in practice. So instead we cancel later if the // listener tells us to. In practice that means the navigation policy needs to be decided // synchronously for these redirect cases. if (!redirectResponse.isNull()) { ref(); // balanced by deref in continueAfterNavigationPolicy frameLoader()->policyChecker()->checkNavigationPolicy(newRequest, callContinueAfterNavigationPolicy, this); } }
TEST(ResourceRequestTest, CrossThreadResourceRequestData) { ResourceRequest original; original.setURL(KURL(ParsedURLString, "http://www.example.com/test.htm")); original.setCachePolicy(UseProtocolCachePolicy); original.setTimeoutInterval(10); original.setFirstPartyForCookies(KURL(ParsedURLString, "http://www.example.com/first_party.htm")); original.setHTTPMethod(AtomicString("GET", AtomicString::ConstructFromLiteral)); original.setHTTPHeaderField(AtomicString("Foo"), AtomicString("Bar")); original.setHTTPHeaderField(AtomicString("Piyo"), AtomicString("Fuga")); original.setPriority(ResourceLoadPriorityLow, 20); RefPtr<FormData> originalBody(FormData::create("Test Body")); original.setHTTPBody(originalBody); original.setAllowStoredCredentials(false); original.setReportUploadProgress(false); original.setHasUserGesture(false); original.setDownloadToFile(false); original.setSkipServiceWorker(false); original.setFetchRequestMode(WebURLRequest::FetchRequestModeCORS); original.setFetchCredentialsMode(WebURLRequest::FetchCredentialsModeSameOrigin); original.setRequestorID(30); original.setRequestorProcessID(40); original.setAppCacheHostID(50); original.setRequestContext(WebURLRequest::RequestContextAudio); original.setFrameType(WebURLRequest::FrameTypeNested); original.setHTTPReferrer(Referrer("http://www.example.com/referrer.htm", ReferrerPolicyDefault)); EXPECT_STREQ("http://www.example.com/test.htm", original.url().string().utf8().data()); EXPECT_EQ(UseProtocolCachePolicy, original.cachePolicy()); EXPECT_EQ(10, original.timeoutInterval()); EXPECT_STREQ("http://www.example.com/first_party.htm", original.firstPartyForCookies().string().utf8().data()); EXPECT_STREQ("GET", original.httpMethod().utf8().data()); EXPECT_STREQ("Bar", original.httpHeaderFields().get("Foo").utf8().data()); EXPECT_STREQ("Fuga", original.httpHeaderFields().get("Piyo").utf8().data()); EXPECT_EQ(ResourceLoadPriorityLow, original.priority()); EXPECT_STREQ("Test Body", original.httpBody()->flattenToString().utf8().data()); EXPECT_FALSE(original.allowStoredCredentials()); EXPECT_FALSE(original.reportUploadProgress()); EXPECT_FALSE(original.hasUserGesture()); EXPECT_FALSE(original.downloadToFile()); EXPECT_FALSE(original.skipServiceWorker()); EXPECT_EQ(WebURLRequest::FetchRequestModeCORS, original.fetchRequestMode()); EXPECT_EQ(WebURLRequest::FetchCredentialsModeSameOrigin, original.fetchCredentialsMode()); EXPECT_EQ(30, original.requestorID()); EXPECT_EQ(40, original.requestorProcessID()); EXPECT_EQ(50, original.appCacheHostID()); EXPECT_EQ(WebURLRequest::RequestContextAudio, original.requestContext()); EXPECT_EQ(WebURLRequest::FrameTypeNested, original.frameType()); EXPECT_STREQ("http://www.example.com/referrer.htm", original.httpReferrer().utf8().data()); EXPECT_EQ(ReferrerPolicyDefault, original.referrerPolicy()); OwnPtr<CrossThreadResourceRequestData> data1(original.copyData()); OwnPtr<ResourceRequest> copy1(ResourceRequest::adopt(data1.release())); EXPECT_STREQ("http://www.example.com/test.htm", copy1->url().string().utf8().data()); EXPECT_EQ(UseProtocolCachePolicy, copy1->cachePolicy()); EXPECT_EQ(10, copy1->timeoutInterval()); EXPECT_STREQ("http://www.example.com/first_party.htm", copy1->firstPartyForCookies().string().utf8().data()); EXPECT_STREQ("GET", copy1->httpMethod().utf8().data()); EXPECT_STREQ("Bar", copy1->httpHeaderFields().get("Foo").utf8().data()); EXPECT_EQ(ResourceLoadPriorityLow, copy1->priority()); EXPECT_STREQ("Test Body", copy1->httpBody()->flattenToString().utf8().data()); EXPECT_FALSE(copy1->allowStoredCredentials()); EXPECT_FALSE(copy1->reportUploadProgress()); EXPECT_FALSE(copy1->hasUserGesture()); EXPECT_FALSE(copy1->downloadToFile()); EXPECT_FALSE(copy1->skipServiceWorker()); EXPECT_EQ(WebURLRequest::FetchRequestModeCORS, copy1->fetchRequestMode()); EXPECT_EQ(WebURLRequest::FetchCredentialsModeSameOrigin, copy1->fetchCredentialsMode()); EXPECT_EQ(30, copy1->requestorID()); EXPECT_EQ(40, copy1->requestorProcessID()); EXPECT_EQ(50, copy1->appCacheHostID()); EXPECT_EQ(WebURLRequest::RequestContextAudio, copy1->requestContext()); EXPECT_EQ(WebURLRequest::FrameTypeNested, copy1->frameType()); EXPECT_STREQ("http://www.example.com/referrer.htm", copy1->httpReferrer().utf8().data()); EXPECT_EQ(ReferrerPolicyDefault, copy1->referrerPolicy()); copy1->setAllowStoredCredentials(true); copy1->setReportUploadProgress(true); copy1->setHasUserGesture(true); copy1->setDownloadToFile(true); copy1->setSkipServiceWorker(true); copy1->setFetchRequestMode(WebURLRequest::FetchRequestModeNoCORS); copy1->setFetchCredentialsMode(WebURLRequest::FetchCredentialsModeInclude); OwnPtr<CrossThreadResourceRequestData> data2(copy1->copyData()); OwnPtr<ResourceRequest> copy2(ResourceRequest::adopt(data2.release())); EXPECT_TRUE(copy2->allowStoredCredentials()); EXPECT_TRUE(copy2->reportUploadProgress()); EXPECT_TRUE(copy2->hasUserGesture()); EXPECT_TRUE(copy2->downloadToFile()); EXPECT_TRUE(copy2->skipServiceWorker()); EXPECT_EQ(WebURLRequest::FetchRequestModeNoCORS, copy1->fetchRequestMode()); EXPECT_EQ(WebURLRequest::FetchCredentialsModeInclude, copy1->fetchCredentialsMode()); }