Index: third_party/WebKit/Source/core/fetch/ResourceLoader.cpp |
diff --git a/third_party/WebKit/Source/core/fetch/ResourceLoader.cpp b/third_party/WebKit/Source/core/fetch/ResourceLoader.cpp |
deleted file mode 100644 |
index 7f11fb7e3efb0206727a53ebf1397a4cc64f2195..0000000000000000000000000000000000000000 |
--- a/third_party/WebKit/Source/core/fetch/ResourceLoader.cpp |
+++ /dev/null |
@@ -1,521 +0,0 @@ |
-/* |
- * Copyright (C) 2006, 2007, 2010, 2011 Apple Inc. All rights reserved. |
- * (C) 2007 Graham Dennis (graham.dennis@gmail.com) |
- * |
- * Redistribution and use in source and binary forms, with or without |
- * modification, are permitted provided that the following conditions |
- * are met: |
- * |
- * 1. Redistributions of source code must retain the above copyright |
- * notice, this list of conditions and the following disclaimer. |
- * 2. Redistributions in binary form must reproduce the above copyright |
- * notice, this list of conditions and the following disclaimer in the |
- * documentation and/or other materials provided with the distribution. |
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of |
- * its contributors may be used to endorse or promote products derived |
- * from this software without specific prior written permission. |
- * |
- * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY |
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
- * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY |
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
- */ |
- |
-#include "core/fetch/ResourceLoader.h" |
- |
-#include "core/fetch/CrossOriginAccessControl.h" |
-#include "core/fetch/FetchContext.h" |
-#include "core/fetch/Resource.h" |
-#include "core/fetch/ResourceFetcher.h" |
-#include "platform/SharedBuffer.h" |
-#include "platform/exported/WrappedResourceRequest.h" |
-#include "platform/exported/WrappedResourceResponse.h" |
-#include "platform/network/NetworkInstrumentation.h" |
-#include "platform/network/ResourceError.h" |
-#include "public/platform/Platform.h" |
-#include "public/platform/WebCachePolicy.h" |
-#include "public/platform/WebData.h" |
-#include "public/platform/WebURLError.h" |
-#include "public/platform/WebURLRequest.h" |
-#include "public/platform/WebURLResponse.h" |
-#include "wtf/Assertions.h" |
-#include "wtf/CurrentTime.h" |
-#include "wtf/PtrUtil.h" |
-#include "wtf/text/StringBuilder.h" |
-#include <memory> |
- |
-namespace blink { |
- |
-ResourceLoader* ResourceLoader::create(ResourceFetcher* fetcher, |
- Resource* resource) { |
- return new ResourceLoader(fetcher, resource); |
-} |
- |
-ResourceLoader::ResourceLoader(ResourceFetcher* fetcher, Resource* resource) |
- : m_fetcher(fetcher), |
- m_resource(resource), |
- m_isCacheAwareLoadingActivated(false) { |
- DCHECK(m_resource); |
- DCHECK(m_fetcher); |
- |
- m_resource->setLoader(this); |
-} |
- |
-ResourceLoader::~ResourceLoader() {} |
- |
-DEFINE_TRACE(ResourceLoader) { |
- visitor->trace(m_fetcher); |
- visitor->trace(m_resource); |
-} |
- |
-void ResourceLoader::start(const ResourceRequest& request) { |
- DCHECK(!m_loader); |
- |
- if (m_resource->options().synchronousPolicy == RequestSynchronously && |
- context().defersLoading()) { |
- cancel(); |
- return; |
- } |
- |
- m_loader = WTF::wrapUnique(Platform::current()->createURLLoader()); |
- DCHECK(m_loader); |
- m_loader->setDefersLoading(context().defersLoading()); |
- m_loader->setLoadingTaskRunner(context().loadingTaskRunner().get()); |
- |
- if (m_isCacheAwareLoadingActivated) { |
- // Override cache policy for cache-aware loading. If this request fails, a |
- // reload with original request will be triggered in didFail(). |
- ResourceRequest cacheAwareRequest(request); |
- cacheAwareRequest.setCachePolicy(WebCachePolicy::ReturnCacheDataIfValid); |
- m_loader->loadAsynchronously(WrappedResourceRequest(cacheAwareRequest), |
- this); |
- return; |
- } |
- |
- if (m_resource->options().synchronousPolicy == RequestSynchronously) |
- requestSynchronously(request); |
- else |
- m_loader->loadAsynchronously(WrappedResourceRequest(request), this); |
-} |
- |
-void ResourceLoader::restart(const ResourceRequest& request) { |
- CHECK_EQ(m_resource->options().synchronousPolicy, RequestAsynchronously); |
- |
- m_loader.reset(); |
- start(request); |
-} |
- |
-void ResourceLoader::setDefersLoading(bool defers) { |
- DCHECK(m_loader); |
- |
- m_loader->setDefersLoading(defers); |
-} |
- |
-void ResourceLoader::didChangePriority(ResourceLoadPriority loadPriority, |
- int intraPriorityValue) { |
- if (m_loader) { |
- m_loader->didChangePriority( |
- static_cast<WebURLRequest::Priority>(loadPriority), intraPriorityValue); |
- } |
-} |
- |
-void ResourceLoader::cancel() { |
- handleError( |
- ResourceError::cancelledError(m_resource->lastResourceRequest().url())); |
-} |
- |
-void ResourceLoader::cancelForRedirectAccessCheckError( |
- const KURL& newURL, |
- ResourceRequestBlockedReason blockedReason) { |
- m_resource->willNotFollowRedirect(); |
- |
- if (m_loader) |
- handleError( |
- ResourceError::cancelledDueToAccessCheckError(newURL, blockedReason)); |
-} |
- |
-static bool isManualRedirectFetchRequest(const ResourceRequest& request) { |
- return request.fetchRedirectMode() == |
- WebURLRequest::FetchRedirectModeManual && |
- request.requestContext() == WebURLRequest::RequestContextFetch; |
-} |
- |
-bool ResourceLoader::willFollowRedirect( |
- WebURLRequest& passedNewRequest, |
- const WebURLResponse& passedRedirectResponse) { |
- DCHECK(!passedNewRequest.isNull()); |
- DCHECK(!passedRedirectResponse.isNull()); |
- |
- if (m_isCacheAwareLoadingActivated) { |
- // Fail as cache miss if cached response is a redirect. |
- handleError( |
- ResourceError::cacheMissError(m_resource->lastResourceRequest().url())); |
- return false; |
- } |
- |
- ResourceRequest& newRequest(passedNewRequest.toMutableResourceRequest()); |
- const ResourceResponse& redirectResponse( |
- passedRedirectResponse.toResourceResponse()); |
- |
- newRequest.setRedirectStatus( |
- ResourceRequest::RedirectStatus::FollowedRedirect); |
- |
- const KURL originalURL = newRequest.url(); |
- |
- if (!isManualRedirectFetchRequest(m_resource->resourceRequest())) { |
- ResourceRequestBlockedReason blockedReason = context().canRequest( |
- m_resource->getType(), newRequest, newRequest.url(), |
- m_resource->options(), m_resource->isUnusedPreload(), |
- FetchRequest::UseDefaultOriginRestrictionForType); |
- if (blockedReason != ResourceRequestBlockedReason::None) { |
- cancelForRedirectAccessCheckError(newRequest.url(), blockedReason); |
- return false; |
- } |
- |
- if (m_resource->options().corsEnabled == IsCORSEnabled) { |
- RefPtr<SecurityOrigin> sourceOrigin = |
- m_resource->options().securityOrigin; |
- if (!sourceOrigin.get()) |
- sourceOrigin = context().getSecurityOrigin(); |
- |
- String errorMessage; |
- StoredCredentials withCredentials = |
- m_resource->lastResourceRequest().allowStoredCredentials() |
- ? AllowStoredCredentials |
- : DoNotAllowStoredCredentials; |
- if (!CrossOriginAccessControl::handleRedirect( |
- sourceOrigin, newRequest, redirectResponse, withCredentials, |
- m_resource->mutableOptions(), errorMessage)) { |
- m_resource->setCORSFailed(); |
- context().addConsoleMessage(errorMessage); |
- cancelForRedirectAccessCheckError(newRequest.url(), |
- ResourceRequestBlockedReason::Other); |
- return false; |
- } |
- } |
- if (m_resource->getType() == Resource::Image && |
- m_fetcher->shouldDeferImageLoad(newRequest.url())) { |
- cancelForRedirectAccessCheckError(newRequest.url(), |
- ResourceRequestBlockedReason::Other); |
- return false; |
- } |
- } |
- |
- bool crossOrigin = !SecurityOrigin::areSameSchemeHostPort( |
- redirectResponse.url(), newRequest.url()); |
- m_fetcher->recordResourceTimingOnRedirect(m_resource.get(), redirectResponse, |
- crossOrigin); |
- |
- newRequest.setAllowStoredCredentials(m_resource->options().allowCredentials == |
- AllowStoredCredentials); |
- |
- context().dispatchWillSendRequest(m_resource->identifier(), newRequest, |
- redirectResponse, |
- m_resource->options().initiatorInfo); |
- |
- // ResourceFetcher::willFollowRedirect() may rewrite the URL to |
- // something else not for rejecting redirect but for other reasons. |
- // E.g. WebFrameTestClient::willSendRequest() and |
- // RenderFrameImpl::willSendRequest(). We should reflect the |
- // rewriting but currently we cannot. So, return false to make the |
- // redirect fail. |
- if (newRequest.url() != originalURL) { |
- cancelForRedirectAccessCheckError(newRequest.url(), |
- ResourceRequestBlockedReason::Other); |
- return false; |
- } |
- |
- if (!m_resource->willFollowRedirect(newRequest, redirectResponse)) { |
- cancelForRedirectAccessCheckError(newRequest.url(), |
- ResourceRequestBlockedReason::Other); |
- return false; |
- } |
- |
- return true; |
-} |
- |
-void ResourceLoader::didReceiveCachedMetadata(const char* data, int length) { |
- m_resource->setSerializedCachedMetadata(data, length); |
-} |
- |
-void ResourceLoader::didSendData(unsigned long long bytesSent, |
- unsigned long long totalBytesToBeSent) { |
- m_resource->didSendData(bytesSent, totalBytesToBeSent); |
-} |
- |
-FetchContext& ResourceLoader::context() const { |
- return m_fetcher->context(); |
-} |
- |
-ResourceRequestBlockedReason ResourceLoader::canAccessResponse( |
- Resource* resource, |
- const ResourceResponse& response) const { |
- // Redirects can change the response URL different from one of request. |
- bool forPreload = resource->isUnusedPreload(); |
- ResourceRequestBlockedReason blockedReason = |
- context().canRequest(resource->getType(), resource->resourceRequest(), |
- response.url(), resource->options(), forPreload, |
- FetchRequest::UseDefaultOriginRestrictionForType); |
- if (blockedReason != ResourceRequestBlockedReason::None) |
- return blockedReason; |
- |
- SecurityOrigin* sourceOrigin = resource->options().securityOrigin.get(); |
- if (!sourceOrigin) |
- sourceOrigin = context().getSecurityOrigin(); |
- |
- if (sourceOrigin->canRequestNoSuborigin(response.url())) |
- return ResourceRequestBlockedReason::None; |
- |
- // Use the original response instead of the 304 response for a successful |
- // revaldiation. |
- const ResourceResponse& responseForAccessControl = |
- (resource->isCacheValidator() && response.httpStatusCode() == 304) |
- ? resource->response() |
- : response; |
- |
- CrossOriginAccessControl::AccessStatus corsStatus = |
- CrossOriginAccessControl::checkAccess( |
- responseForAccessControl, resource->options().allowCredentials, |
- sourceOrigin); |
- if (corsStatus != CrossOriginAccessControl::kAccessAllowed) { |
- resource->setCORSFailed(); |
- if (!forPreload) { |
- String resourceType = Resource::resourceTypeToString( |
- resource->getType(), resource->options().initiatorInfo.name); |
- StringBuilder builder; |
- builder.append("Access to "); |
- builder.append(resourceType); |
- builder.append(" at '"); |
- builder.append(response.url().getString()); |
- builder.append("' from origin '"); |
- builder.append(sourceOrigin->toString()); |
- builder.append("' has been blocked by CORS policy: "); |
- CrossOriginAccessControl::accessControlErrorString( |
- builder, corsStatus, responseForAccessControl, sourceOrigin, |
- resource->lastResourceRequest().requestContext()); |
- context().addConsoleMessage(builder.toString()); |
- } |
- return ResourceRequestBlockedReason::Other; |
- } |
- return ResourceRequestBlockedReason::None; |
-} |
- |
-void ResourceLoader::didReceiveResponse( |
- const WebURLResponse& webURLResponse, |
- std::unique_ptr<WebDataConsumerHandle> handle) { |
- DCHECK(!webURLResponse.isNull()); |
- |
- const ResourceResponse& response = webURLResponse.toResourceResponse(); |
- |
- if (response.wasFetchedViaServiceWorker()) { |
- if (m_resource->options().corsEnabled == IsCORSEnabled && |
- response.wasFallbackRequiredByServiceWorker()) { |
- ResourceRequest request = m_resource->lastResourceRequest(); |
- DCHECK_EQ(request.skipServiceWorker(), |
- WebURLRequest::SkipServiceWorker::None); |
- // This code handles the case 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. |
- if (!context().shouldLoadNewResource(m_resource->getType())) { |
- // Cancel the request if we should not trigger a reload now. |
- handleError(ResourceError::cancelledError(response.url())); |
- return; |
- } |
- request.setSkipServiceWorker( |
- WebURLRequest::SkipServiceWorker::Controlling); |
- restart(request); |
- return; |
- } |
- |
- // If the response is fetched via ServiceWorker, the original URL of the |
- // response could be different from the URL of the request. We check the URL |
- // not to load the resources which are forbidden by the page CSP. |
- // https://w3c.github.io/webappsec-csp/#should-block-response |
- const KURL& originalURL = response.originalURLViaServiceWorker(); |
- if (!originalURL.isEmpty()) { |
- ResourceRequestBlockedReason blockedReason = context().allowResponse( |
- m_resource->getType(), m_resource->resourceRequest(), originalURL, |
- m_resource->options()); |
- if (blockedReason != ResourceRequestBlockedReason::None) { |
- handleError(ResourceError::cancelledDueToAccessCheckError( |
- originalURL, blockedReason)); |
- return; |
- } |
- } |
- } else if (m_resource->options().corsEnabled == IsCORSEnabled) { |
- ResourceRequestBlockedReason blockedReason = |
- canAccessResponse(m_resource, response); |
- if (blockedReason != ResourceRequestBlockedReason::None) { |
- handleError(ResourceError::cancelledDueToAccessCheckError(response.url(), |
- blockedReason)); |
- return; |
- } |
- } |
- |
- context().dispatchDidReceiveResponse( |
- m_resource->identifier(), response, |
- m_resource->resourceRequest().frameType(), |
- m_resource->resourceRequest().requestContext(), m_resource); |
- |
- m_resource->responseReceived(response, std::move(handle)); |
- if (!m_resource->loader()) |
- return; |
- |
- if (response.httpStatusCode() >= 400 && |
- !m_resource->shouldIgnoreHTTPStatusCodeErrors()) |
- handleError(ResourceError::cancelledError(response.url())); |
-} |
- |
-void ResourceLoader::didReceiveResponse(const WebURLResponse& response) { |
- didReceiveResponse(response, nullptr); |
-} |
- |
-void ResourceLoader::didDownloadData(int length, int encodedDataLength) { |
- context().dispatchDidDownloadData(m_resource->identifier(), length, |
- encodedDataLength); |
- m_resource->didDownloadData(length); |
-} |
- |
-void ResourceLoader::didReceiveData(const char* data, int length) { |
- CHECK_GE(length, 0); |
- |
- context().dispatchDidReceiveData(m_resource->identifier(), data, length); |
- m_resource->addToDecodedBodyLength(length); |
- m_resource->appendData(data, length); |
-} |
- |
-void ResourceLoader::didReceiveTransferSizeUpdate(int transferSizeDiff) { |
- DCHECK_GT(transferSizeDiff, 0); |
- context().dispatchDidReceiveEncodedData(m_resource->identifier(), |
- transferSizeDiff); |
-} |
- |
-void ResourceLoader::didFinishLoadingFirstPartInMultipart() { |
- network_instrumentation::endResourceLoad( |
- m_resource->identifier(), |
- network_instrumentation::RequestOutcome::Success); |
- |
- m_fetcher->handleLoaderFinish(m_resource.get(), 0, |
- ResourceFetcher::DidFinishFirstPartInMultipart); |
-} |
- |
-void ResourceLoader::didFinishLoading(double finishTime, |
- int64_t encodedDataLength, |
- int64_t encodedBodyLength) { |
- m_resource->setEncodedDataLength(encodedDataLength); |
- m_resource->addToEncodedBodyLength(encodedBodyLength); |
- |
- m_loader.reset(); |
- |
- network_instrumentation::endResourceLoad( |
- m_resource->identifier(), |
- network_instrumentation::RequestOutcome::Success); |
- |
- m_fetcher->handleLoaderFinish(m_resource.get(), finishTime, |
- ResourceFetcher::DidFinishLoading); |
-} |
- |
-void ResourceLoader::didFail(const WebURLError& error, |
- int64_t encodedDataLength, |
- int64_t encodedBodyLength) { |
- m_resource->setEncodedDataLength(encodedDataLength); |
- m_resource->addToEncodedBodyLength(encodedBodyLength); |
- handleError(error); |
-} |
- |
-void ResourceLoader::handleError(const ResourceError& error) { |
- if (m_isCacheAwareLoadingActivated && error.isCacheMiss() && |
- context().shouldLoadNewResource(m_resource->getType())) { |
- m_resource->willReloadAfterDiskCacheMiss(); |
- m_isCacheAwareLoadingActivated = false; |
- restart(m_resource->resourceRequest()); |
- return; |
- } |
- |
- m_loader.reset(); |
- |
- network_instrumentation::endResourceLoad( |
- m_resource->identifier(), network_instrumentation::RequestOutcome::Fail); |
- |
- m_fetcher->handleLoaderError(m_resource.get(), error); |
-} |
- |
-void ResourceLoader::requestSynchronously(const ResourceRequest& request) { |
- // downloadToFile is not supported for synchronous requests. |
- DCHECK(!request.downloadToFile()); |
- DCHECK(m_loader); |
- DCHECK_EQ(request.priority(), ResourceLoadPriorityHighest); |
- |
- WrappedResourceRequest requestIn(request); |
- WebURLResponse responseOut; |
- WebURLError errorOut; |
- WebData dataOut; |
- int64_t encodedDataLength = WebURLLoaderClient::kUnknownEncodedDataLength; |
- int64_t encodedBodyLength = 0; |
- m_loader->loadSynchronously(requestIn, responseOut, errorOut, dataOut, |
- encodedDataLength, encodedBodyLength); |
- |
- // A message dispatched while synchronously fetching the resource |
- // can bring about the cancellation of this load. |
- if (!m_loader) |
- return; |
- if (errorOut.reason) { |
- didFail(errorOut, encodedDataLength, encodedBodyLength); |
- return; |
- } |
- didReceiveResponse(responseOut); |
- if (!m_loader) |
- return; |
- DCHECK_GE(responseOut.toResourceResponse().encodedBodyLength(), 0); |
- |
- // Follow the async case convention of not calling didReceiveData or |
- // appending data to m_resource if the response body is empty. Copying the |
- // empty buffer is a noop in most cases, but is destructive in the case of |
- // a 304, where it will overwrite the cached data we should be reusing. |
- if (dataOut.size()) { |
- context().dispatchDidReceiveData(m_resource->identifier(), dataOut.data(), |
- dataOut.size()); |
- m_resource->setResourceBuffer(dataOut); |
- } |
- didFinishLoading(monotonicallyIncreasingTime(), encodedDataLength, |
- encodedBodyLength); |
-} |
- |
-void ResourceLoader::dispose() { |
- m_loader = nullptr; |
-} |
- |
-void ResourceLoader::activateCacheAwareLoadingIfNeeded( |
- const ResourceRequest& request) { |
- DCHECK(!m_isCacheAwareLoadingActivated); |
- |
- if (m_resource->options().cacheAwareLoadingEnabled != |
- IsCacheAwareLoadingEnabled) |
- return; |
- |
- // Synchronous requests are not supported. |
- if (m_resource->options().synchronousPolicy == RequestSynchronously) |
- return; |
- |
- // Don't activate on Resource revalidation. |
- if (m_resource->isCacheValidator()) |
- return; |
- |
- // Don't activate if cache policy is explicitly set. |
- if (request.getCachePolicy() != WebCachePolicy::UseProtocolCachePolicy) |
- return; |
- |
- m_isCacheAwareLoadingActivated = true; |
-} |
- |
-} // namespace blink |