Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 /* | 1 /* |
| 2 Copyright (C) 1998 Lars Knoll (knoll@mpi-hd.mpg.de) | 2 Copyright (C) 1998 Lars Knoll (knoll@mpi-hd.mpg.de) |
| 3 Copyright (C) 2001 Dirk Mueller (mueller@kde.org) | 3 Copyright (C) 2001 Dirk Mueller (mueller@kde.org) |
| 4 Copyright (C) 2002 Waldo Bastian (bastian@kde.org) | 4 Copyright (C) 2002 Waldo Bastian (bastian@kde.org) |
| 5 Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All | 5 Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All |
| 6 rights reserved. | 6 rights reserved. |
| 7 Copyright (C) 2009 Torch Mobile Inc. http://www.torchmobile.com/ | 7 Copyright (C) 2009 Torch Mobile Inc. http://www.torchmobile.com/ |
| 8 | 8 |
| 9 This library is free software; you can redistribute it and/or | 9 This library is free software; you can redistribute it and/or |
| 10 modify it under the terms of the GNU Library General Public | 10 modify it under the terms of the GNU Library General Public |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 21 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | 21 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
| 22 Boston, MA 02110-1301, USA. | 22 Boston, MA 02110-1301, USA. |
| 23 | 23 |
| 24 This class provides all functionality needed for loading images, style | 24 This class provides all functionality needed for loading images, style |
| 25 sheets and html pages from the web. It has a memory cache for these objects. | 25 sheets and html pages from the web. It has a memory cache for these objects. |
| 26 */ | 26 */ |
| 27 | 27 |
| 28 #include "core/fetch/ResourceFetcher.h" | 28 #include "core/fetch/ResourceFetcher.h" |
| 29 | 29 |
| 30 #include "bindings/core/v8/V8DOMActivityLogger.h" | 30 #include "bindings/core/v8/V8DOMActivityLogger.h" |
| 31 #include "core/fetch/CrossOriginAccessControl.h" | |
| 32 #include "core/fetch/FetchContext.h" | 31 #include "core/fetch/FetchContext.h" |
| 33 #include "core/fetch/FetchInitiatorTypeNames.h" | 32 #include "core/fetch/FetchInitiatorTypeNames.h" |
| 34 #include "core/fetch/ImageResource.h" | 33 #include "core/fetch/ImageResource.h" |
| 35 #include "core/fetch/MemoryCache.h" | 34 #include "core/fetch/MemoryCache.h" |
| 36 #include "core/fetch/ResourceLoader.h" | 35 #include "core/fetch/ResourceLoader.h" |
| 37 #include "core/fetch/ResourceLoadingLog.h" | 36 #include "core/fetch/ResourceLoadingLog.h" |
| 38 #include "core/fetch/UniqueIdentifier.h" | 37 #include "core/fetch/UniqueIdentifier.h" |
| 39 #include "platform/Histogram.h" | 38 #include "platform/Histogram.h" |
| 40 #include "platform/RuntimeEnabledFeatures.h" | 39 #include "platform/RuntimeEnabledFeatures.h" |
| 41 #include "platform/mhtml/ArchiveResource.h" | 40 #include "platform/mhtml/ArchiveResource.h" |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 90 DEFINE_SINGLE_RESOURCE_HISTOGRAM(prefix, MainResource) \ | 89 DEFINE_SINGLE_RESOURCE_HISTOGRAM(prefix, MainResource) \ |
| 91 DEFINE_SINGLE_RESOURCE_HISTOGRAM(prefix, Manifest) \ | 90 DEFINE_SINGLE_RESOURCE_HISTOGRAM(prefix, Manifest) \ |
| 92 DEFINE_SINGLE_RESOURCE_HISTOGRAM(prefix, Media) \ | 91 DEFINE_SINGLE_RESOURCE_HISTOGRAM(prefix, Media) \ |
| 93 DEFINE_SINGLE_RESOURCE_HISTOGRAM(prefix, Raw) \ | 92 DEFINE_SINGLE_RESOURCE_HISTOGRAM(prefix, Raw) \ |
| 94 DEFINE_SINGLE_RESOURCE_HISTOGRAM(prefix, Script) \ | 93 DEFINE_SINGLE_RESOURCE_HISTOGRAM(prefix, Script) \ |
| 95 DEFINE_SINGLE_RESOURCE_HISTOGRAM(prefix, SVGDocument) \ | 94 DEFINE_SINGLE_RESOURCE_HISTOGRAM(prefix, SVGDocument) \ |
| 96 DEFINE_SINGLE_RESOURCE_HISTOGRAM(prefix, TextTrack) \ | 95 DEFINE_SINGLE_RESOURCE_HISTOGRAM(prefix, TextTrack) \ |
| 97 DEFINE_SINGLE_RESOURCE_HISTOGRAM(prefix, XSLStyleSheet) \ | 96 DEFINE_SINGLE_RESOURCE_HISTOGRAM(prefix, XSLStyleSheet) \ |
| 98 } | 97 } |
| 99 | 98 |
| 100 bool IsCrossOrigin(const KURL& a, const KURL& b) { | |
| 101 RefPtr<SecurityOrigin> originA = SecurityOrigin::create(a); | |
| 102 RefPtr<SecurityOrigin> originB = SecurityOrigin::create(b); | |
| 103 return !originB->isSameSchemeHostPort(originA.get()); | |
| 104 } | |
| 105 | |
| 106 } // namespace | 99 } // namespace |
| 107 | 100 |
| 108 static void RecordSriResourceIntegrityMismatchEvent( | 101 static void RecordSriResourceIntegrityMismatchEvent( |
| 109 SriResourceIntegrityMismatchEvent event) { | 102 SriResourceIntegrityMismatchEvent event) { |
| 110 DEFINE_THREAD_SAFE_STATIC_LOCAL( | 103 DEFINE_THREAD_SAFE_STATIC_LOCAL( |
| 111 EnumerationHistogram, integrityHistogram, | 104 EnumerationHistogram, integrityHistogram, |
| 112 new EnumerationHistogram("sri.resource_integrity_mismatch_event", | 105 new EnumerationHistogram("sri.resource_integrity_mismatch_event", |
| 113 SriResourceIntegrityMismatchEventCount)); | 106 SriResourceIntegrityMismatchEventCount)); |
| 114 integrityHistogram.count(event); | 107 integrityHistogram.count(event); |
| 115 } | 108 } |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 191 | 184 |
| 192 static void populateResourceTiming(ResourceTimingInfo* info, | 185 static void populateResourceTiming(ResourceTimingInfo* info, |
| 193 Resource* resource) { | 186 Resource* resource) { |
| 194 KURL initialURL = resource->response().redirectResponses().isEmpty() | 187 KURL initialURL = resource->response().redirectResponses().isEmpty() |
| 195 ? resource->resourceRequest().url() | 188 ? resource->resourceRequest().url() |
| 196 : resource->response().redirectResponses()[0].url(); | 189 : resource->response().redirectResponses()[0].url(); |
| 197 info->setInitialURL(initialURL); | 190 info->setInitialURL(initialURL); |
| 198 info->setFinalResponse(resource->response()); | 191 info->setFinalResponse(resource->response()); |
| 199 } | 192 } |
| 200 | 193 |
| 194 static void populateRedirectResourceTimingOnFinish(ResourceTimingInfo* info, | |
|
yhirano
2016/12/12 06:32:04
[optional] I prefer placing this function to the u
tyoshino (SeeGerritForStatus)
2016/12/12 11:10:55
Done.
| |
| 195 Resource* resource) { | |
| 196 // Store redirect responses that were packed inside the final response. | |
| 197 const Vector<ResourceResponse>& redirectResponses = | |
| 198 resource->response().redirectResponses(); | |
| 199 for (size_t i = 0; i < redirectResponses.size(); ++i) { | |
| 200 const KURL& newURL = i + 1 < redirectResponses.size() | |
| 201 ? KURL(redirectResponses[i + 1].url()) | |
| 202 : resource->resourceRequest().url(); | |
| 203 bool crossOrigin = | |
| 204 !SecurityOrigin::areSameOrigin(redirectResponses[i].url(), newURL); | |
| 205 info->addRedirect(redirectResponses[i], crossOrigin); | |
| 206 } | |
| 207 } | |
| 208 | |
| 201 static WebURLRequest::RequestContext requestContextFromType( | 209 static WebURLRequest::RequestContext requestContextFromType( |
| 202 bool isMainFrame, | 210 bool isMainFrame, |
| 203 Resource::Type type) { | 211 Resource::Type type) { |
| 204 switch (type) { | 212 switch (type) { |
| 205 case Resource::MainResource: | 213 case Resource::MainResource: |
| 206 if (!isMainFrame) | 214 if (!isMainFrame) |
| 207 return WebURLRequest::RequestContextIframe; | 215 return WebURLRequest::RequestContextIframe; |
| 208 // FIXME: Change this to a context frame type (once we introduce them): | 216 // FIXME: Change this to a context frame type (once we introduce them): |
| 209 // http://fetch.spec.whatwg.org/#concept-request-context-frame-type | 217 // http://fetch.spec.whatwg.org/#concept-request-context-frame-type |
| 210 return WebURLRequest::RequestContextHyperlink; | 218 return WebURLRequest::RequestContextHyperlink; |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 251 } | 259 } |
| 252 | 260 |
| 253 ResourceFetcher::~ResourceFetcher() {} | 261 ResourceFetcher::~ResourceFetcher() {} |
| 254 | 262 |
| 255 Resource* ResourceFetcher::cachedResource(const KURL& resourceURL) const { | 263 Resource* ResourceFetcher::cachedResource(const KURL& resourceURL) const { |
| 256 KURL url = MemoryCache::removeFragmentIdentifierIfNeeded(resourceURL); | 264 KURL url = MemoryCache::removeFragmentIdentifierIfNeeded(resourceURL); |
| 257 const WeakMember<Resource>& resource = m_documentResources.get(url); | 265 const WeakMember<Resource>& resource = m_documentResources.get(url); |
| 258 return resource.get(); | 266 return resource.get(); |
| 259 } | 267 } |
| 260 | 268 |
| 261 bool ResourceFetcher::canAccessResponse( | |
| 262 Resource* resource, | |
| 263 const ResourceResponse& response) const { | |
| 264 // Redirects can change the response URL different from one of request. | |
| 265 bool forPreload = resource->isUnusedPreload(); | |
| 266 if (!context().canRequest(resource->getType(), resource->resourceRequest(), | |
| 267 response.url(), resource->options(), forPreload, | |
| 268 FetchRequest::UseDefaultOriginRestrictionForType)) | |
| 269 return false; | |
| 270 | |
| 271 SecurityOrigin* sourceOrigin = resource->options().securityOrigin.get(); | |
| 272 if (!sourceOrigin) | |
| 273 sourceOrigin = context().getSecurityOrigin(); | |
| 274 | |
| 275 if (sourceOrigin->canRequestNoSuborigin(response.url())) | |
| 276 return true; | |
| 277 | |
| 278 // Use the original response instead of the 304 response for a successful | |
| 279 // revaldiation. | |
| 280 const ResourceResponse& responseForAccessControl = | |
| 281 (resource->isCacheValidator() && response.httpStatusCode() == 304) | |
| 282 ? resource->response() | |
| 283 : response; | |
| 284 String errorDescription; | |
| 285 if (!passesAccessControlCheck( | |
| 286 responseForAccessControl, resource->options().allowCredentials, | |
| 287 sourceOrigin, errorDescription, | |
| 288 resource->lastResourceRequest().requestContext())) { | |
| 289 resource->setCORSFailed(); | |
| 290 if (!forPreload) { | |
| 291 String resourceType = Resource::resourceTypeToString( | |
| 292 resource->getType(), resource->options().initiatorInfo); | |
| 293 context().addConsoleMessage( | |
| 294 "Access to " + resourceType + " at '" + response.url().getString() + | |
| 295 "' from origin '" + sourceOrigin->toString() + | |
| 296 "' has been blocked by CORS policy: " + errorDescription); | |
| 297 } | |
| 298 return false; | |
| 299 } | |
| 300 return true; | |
| 301 } | |
| 302 | |
| 303 bool ResourceFetcher::isControlledByServiceWorker() const { | 269 bool ResourceFetcher::isControlledByServiceWorker() const { |
| 304 return context().isControlledByServiceWorker(); | 270 return context().isControlledByServiceWorker(); |
| 305 } | 271 } |
| 306 | 272 |
| 307 bool ResourceFetcher::resourceNeedsLoad(Resource* resource, | 273 bool ResourceFetcher::resourceNeedsLoad(Resource* resource, |
| 308 const FetchRequest& request, | 274 const FetchRequest& request, |
| 309 RevalidationPolicy policy) { | 275 RevalidationPolicy policy) { |
| 310 // Defer a font load until it is actually needed unless this is a preload. | 276 // Defer a font load until it is actually needed unless this is a preload. |
| 311 if (resource->getType() == Resource::Font && !request.forPreload()) | 277 if (resource->getType() == Resource::Font && !request.forPreload()) |
| 312 return false; | 278 return false; |
| (...skipping 461 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 774 resource->response().httpHeaderField(HTTPNames::Timing_Allow_Origin); | 740 resource->response().httpHeaderField(HTTPNames::Timing_Allow_Origin); |
| 775 if (!timingAllowOrigin.isEmpty()) | 741 if (!timingAllowOrigin.isEmpty()) |
| 776 info->setOriginalTimingAllowOrigin(timingAllowOrigin); | 742 info->setOriginalTimingAllowOrigin(timingAllowOrigin); |
| 777 } | 743 } |
| 778 | 744 |
| 779 if (!isMainResource || | 745 if (!isMainResource || |
| 780 context().updateTimingInfoForIFrameNavigation(info.get())) | 746 context().updateTimingInfoForIFrameNavigation(info.get())) |
| 781 m_resourceTimingInfoMap.add(resource, std::move(info)); | 747 m_resourceTimingInfoMap.add(resource, std::move(info)); |
| 782 } | 748 } |
| 783 | 749 |
| 750 void ResourceFetcher::recordResourceTimingOnRedirect( | |
| 751 Resource* resource, | |
| 752 const ResourceResponse& redirectResponse, | |
| 753 bool crossOrigin) { | |
| 754 ResourceTimingInfoMap::iterator it = m_resourceTimingInfoMap.find(resource); | |
| 755 if (it != m_resourceTimingInfoMap.end()) { | |
| 756 it->value->addRedirect(redirectResponse, crossOrigin); | |
| 757 } | |
| 758 } | |
| 759 | |
| 784 ResourceFetcher::RevalidationPolicy | 760 ResourceFetcher::RevalidationPolicy |
| 785 ResourceFetcher::determineRevalidationPolicy(Resource::Type type, | 761 ResourceFetcher::determineRevalidationPolicy(Resource::Type type, |
| 786 const FetchRequest& fetchRequest, | 762 const FetchRequest& fetchRequest, |
| 787 Resource* existingResource, | 763 Resource* existingResource, |
| 788 bool isStaticData) const { | 764 bool isStaticData) const { |
| 789 const ResourceRequest& request = fetchRequest.resourceRequest(); | 765 const ResourceRequest& request = fetchRequest.resourceRequest(); |
| 790 | 766 |
| 791 if (!existingResource) | 767 if (!existingResource) |
| 792 return Load; | 768 return Load; |
| 793 | 769 |
| (...skipping 319 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1113 } | 1089 } |
| 1114 | 1090 |
| 1115 ArchiveResource* ResourceFetcher::createArchive(Resource* resource) { | 1091 ArchiveResource* ResourceFetcher::createArchive(Resource* resource) { |
| 1116 // Only the top-frame can load MHTML. | 1092 // Only the top-frame can load MHTML. |
| 1117 if (!context().isMainFrame()) | 1093 if (!context().isMainFrame()) |
| 1118 return nullptr; | 1094 return nullptr; |
| 1119 m_archive = MHTMLArchive::create(resource->url(), resource->resourceBuffer()); | 1095 m_archive = MHTMLArchive::create(resource->url(), resource->resourceBuffer()); |
| 1120 return m_archive ? m_archive->mainResource() : nullptr; | 1096 return m_archive ? m_archive->mainResource() : nullptr; |
| 1121 } | 1097 } |
| 1122 | 1098 |
| 1123 void ResourceFetcher::didFinishLoading(Resource* resource, | 1099 void ResourceFetcher::handleLoadCompletion(Resource* resource) { |
| 1124 double finishTime, | 1100 context().didLoadResource(resource); |
| 1125 DidFinishLoadingReason finishReason) { | 1101 |
| 1126 network_instrumentation::endResourceLoad( | 1102 if (resource->isImage() && |
| 1127 resource->identifier(), network_instrumentation::RequestOutcome::Success); | 1103 toImageResource(resource)->shouldReloadBrokenPlaceholder()) { |
| 1104 toImageResource(resource)->reloadIfLoFiOrPlaceholder(this); | |
| 1105 } | |
| 1106 } | |
| 1107 | |
| 1108 void ResourceFetcher::handleLoaderFinish(Resource* resource, | |
| 1109 double finishTime, | |
| 1110 LoaderFinishType type) { | |
| 1128 DCHECK(resource); | 1111 DCHECK(resource); |
| 1112 | |
| 1113 ResourceLoader* loader = resource->loader(); | |
| 1114 if (type == DidFinishFirstPartInMultipart) { | |
| 1115 // When loading a multipart resource, make the loader non-block when | |
| 1116 // finishing loading the first part. | |
| 1117 moveResourceLoaderToNonBlocking(loader); | |
| 1118 } else { | |
| 1119 removeResourceLoader(loader); | |
| 1120 DCHECK(!m_nonBlockingLoaders.contains(loader)); | |
| 1121 } | |
| 1122 DCHECK(!m_loaders.contains(loader)); | |
| 1123 | |
| 1129 const int64_t encodedDataLength = resource->response().encodedDataLength(); | 1124 const int64_t encodedDataLength = resource->response().encodedDataLength(); |
| 1130 | 1125 |
| 1131 // When loading a multipart resource, make the loader non-block when finishing | |
| 1132 // loading the first part. | |
| 1133 if (finishReason == DidFinishFirstPartInMultipart) | |
| 1134 moveResourceLoaderToNonBlocking(resource->loader()); | |
| 1135 else | |
| 1136 removeResourceLoader(resource->loader()); | |
| 1137 DCHECK(!m_loaders.contains(resource->loader())); | |
| 1138 DCHECK(finishReason == DidFinishFirstPartInMultipart || | |
| 1139 !m_nonBlockingLoaders.contains(resource->loader())); | |
| 1140 | |
| 1141 if (std::unique_ptr<ResourceTimingInfo> info = | 1126 if (std::unique_ptr<ResourceTimingInfo> info = |
| 1142 m_resourceTimingInfoMap.take(resource)) { | 1127 m_resourceTimingInfoMap.take(resource)) { |
| 1143 // Store redirect responses that were packed inside the final response. | 1128 populateRedirectResourceTimingOnFinish(info.get(), resource); |
| 1144 const Vector<ResourceResponse>& responses = | |
| 1145 resource->response().redirectResponses(); | |
| 1146 for (size_t i = 0; i < responses.size(); ++i) { | |
| 1147 const KURL& newURL = i + 1 < responses.size() | |
| 1148 ? KURL(responses[i + 1].url()) | |
| 1149 : resource->resourceRequest().url(); | |
| 1150 bool crossOrigin = IsCrossOrigin(responses[i].url(), newURL); | |
| 1151 info->addRedirect(responses[i], crossOrigin); | |
| 1152 } | |
| 1153 | 1129 |
| 1154 if (resource->response().isHTTP() && | 1130 if (resource->response().isHTTP() && |
| 1155 resource->response().httpStatusCode() < 400) { | 1131 resource->response().httpStatusCode() < 400) { |
| 1156 populateResourceTiming(info.get(), resource); | 1132 populateResourceTiming(info.get(), resource); |
| 1157 info->setLoadFinishTime(finishTime); | 1133 info->setLoadFinishTime(finishTime); |
| 1158 // encodedDataLength == -1 means "not available". | 1134 // encodedDataLength == -1 means "not available". |
| 1159 // TODO(ricea): Find cases where it is not available but the | 1135 // TODO(ricea): Find cases where it is not available but the |
| 1160 // PerformanceResourceTiming spec requires it to be available and fix | 1136 // PerformanceResourceTiming spec requires it to be available and fix |
| 1161 // them. | 1137 // them. |
| 1162 info->addFinalTransferSize(encodedDataLength == -1 ? 0 | 1138 info->addFinalTransferSize(encodedDataLength == -1 ? 0 |
| 1163 : encodedDataLength); | 1139 : encodedDataLength); |
| 1140 | |
| 1164 if (resource->options().requestInitiatorContext == DocumentContext) | 1141 if (resource->options().requestInitiatorContext == DocumentContext) |
| 1165 context().addResourceTiming(*info); | 1142 context().addResourceTiming(*info); |
| 1166 resource->reportResourceTimingToClients(*info); | 1143 resource->reportResourceTimingToClients(*info); |
| 1167 } | 1144 } |
| 1168 } | 1145 } |
| 1146 | |
| 1169 context().dispatchDidFinishLoading(resource->identifier(), finishTime, | 1147 context().dispatchDidFinishLoading(resource->identifier(), finishTime, |
| 1170 encodedDataLength); | 1148 encodedDataLength); |
| 1171 if (finishReason == DidFinishLoading) | 1149 |
| 1150 if (type == DidFinishLoading) | |
| 1172 resource->finish(finishTime); | 1151 resource->finish(finishTime); |
| 1173 context().didLoadResource(resource); | |
| 1174 | 1152 |
| 1175 if (resource->isImage() && | 1153 handleLoadCompletion(resource); |
| 1176 toImageResource(resource)->shouldReloadBrokenPlaceholder()) { | |
| 1177 toImageResource(resource)->reloadIfLoFiOrPlaceholder(this); | |
| 1178 } | |
| 1179 } | 1154 } |
| 1180 | 1155 |
| 1181 void ResourceFetcher::didFailLoading(Resource* resource, | 1156 void ResourceFetcher::handleLoaderError(Resource* resource, |
| 1182 const ResourceError& error) { | 1157 const ResourceError& error) { |
| 1183 network_instrumentation::endResourceLoad( | 1158 DCHECK(resource); |
| 1184 resource->identifier(), network_instrumentation::RequestOutcome::Fail); | 1159 |
| 1185 removeResourceLoader(resource->loader()); | 1160 removeResourceLoader(resource->loader()); |
| 1186 m_resourceTimingInfoMap.take(const_cast<Resource*>(resource)); | 1161 |
| 1162 m_resourceTimingInfoMap.take(resource); | |
| 1163 | |
| 1187 bool isInternalRequest = resource->options().initiatorInfo.name == | 1164 bool isInternalRequest = resource->options().initiatorInfo.name == |
| 1188 FetchInitiatorTypeNames::internal; | 1165 FetchInitiatorTypeNames::internal; |
| 1189 context().dispatchDidFail(resource->identifier(), error, isInternalRequest); | 1166 context().dispatchDidFail(resource->identifier(), error, isInternalRequest); |
| 1167 | |
| 1190 resource->error(error); | 1168 resource->error(error); |
| 1191 context().didLoadResource(resource); | |
| 1192 | 1169 |
| 1193 if (resource->isImage() && | 1170 handleLoadCompletion(resource); |
| 1194 toImageResource(resource)->shouldReloadBrokenPlaceholder()) { | |
| 1195 toImageResource(resource)->reloadIfLoFiOrPlaceholder(this); | |
| 1196 } | |
| 1197 } | |
| 1198 | |
| 1199 void ResourceFetcher::didReceiveResponse( | |
| 1200 Resource* resource, | |
| 1201 const ResourceResponse& response, | |
| 1202 std::unique_ptr<WebDataConsumerHandle> handle) { | |
| 1203 if (response.wasFetchedViaServiceWorker()) { | |
| 1204 if (resource->options().corsEnabled == IsCORSEnabled && | |
| 1205 response.wasFallbackRequiredByServiceWorker()) { | |
| 1206 ResourceRequest request = resource->lastResourceRequest(); | |
| 1207 DCHECK_EQ(request.skipServiceWorker(), | |
| 1208 WebURLRequest::SkipServiceWorker::None); | |
| 1209 // This code handles the case when a regular controlling service worker | |
| 1210 // doesn't handle a cross origin request. When this happens we still want | |
| 1211 // to give foreign fetch a chance to handle the request, so only skip the | |
| 1212 // controlling service worker for the fallback request. This is currently | |
| 1213 // safe because of http://crbug.com/604084 the | |
| 1214 // wasFallbackRequiredByServiceWorker flag is never set when foreign fetch | |
| 1215 // handled a request. | |
| 1216 if (!context().shouldLoadNewResource(resource->getType())) { | |
| 1217 // Cancel the request if we should not trigger a reload now. | |
| 1218 resource->loader()->didFail( | |
| 1219 ResourceError::cancelledError(response.url())); | |
| 1220 return; | |
| 1221 } | |
| 1222 request.setSkipServiceWorker( | |
| 1223 WebURLRequest::SkipServiceWorker::Controlling); | |
| 1224 resource->loader()->restart(request, context().loadingTaskRunner(), | |
| 1225 context().defersLoading()); | |
| 1226 return; | |
| 1227 } | |
| 1228 | |
| 1229 // If the response is fetched via ServiceWorker, the original URL of the | |
| 1230 // response could be different from the URL of the request. We check the URL | |
| 1231 // not to load the resources which are forbidden by the page CSP. | |
| 1232 // https://w3c.github.io/webappsec-csp/#should-block-response | |
| 1233 const KURL& originalURL = response.originalURLViaServiceWorker(); | |
| 1234 if (!originalURL.isEmpty() && | |
| 1235 !context().allowResponse(resource->getType(), | |
| 1236 resource->resourceRequest(), originalURL, | |
| 1237 resource->options())) { | |
| 1238 resource->loader()->didFail( | |
| 1239 ResourceError::cancelledDueToAccessCheckError(originalURL)); | |
| 1240 return; | |
| 1241 } | |
| 1242 } else if (resource->options().corsEnabled == IsCORSEnabled && | |
| 1243 !canAccessResponse(resource, response)) { | |
| 1244 resource->loader()->didFail( | |
| 1245 ResourceError::cancelledDueToAccessCheckError(response.url())); | |
| 1246 return; | |
| 1247 } | |
| 1248 | |
| 1249 context().dispatchDidReceiveResponse( | |
| 1250 resource->identifier(), response, resource->resourceRequest().frameType(), | |
| 1251 resource->resourceRequest().requestContext(), resource); | |
| 1252 resource->responseReceived(response, std::move(handle)); | |
| 1253 if (resource->loader() && response.httpStatusCode() >= 400 && | |
| 1254 !resource->shouldIgnoreHTTPStatusCodeErrors()) { | |
| 1255 resource->loader()->didFail(ResourceError::cancelledError(response.url())); | |
| 1256 } | |
| 1257 } | |
| 1258 | |
| 1259 void ResourceFetcher::didReceiveData(const Resource* resource, | |
| 1260 const char* data, | |
| 1261 int dataLength, | |
| 1262 int encodedDataLength) { | |
| 1263 context().dispatchDidReceiveData(resource->identifier(), data, dataLength, | |
| 1264 encodedDataLength); | |
| 1265 } | |
| 1266 | |
| 1267 void ResourceFetcher::didDownloadData(const Resource* resource, | |
| 1268 int dataLength, | |
| 1269 int encodedDataLength) { | |
| 1270 context().dispatchDidDownloadData(resource->identifier(), dataLength, | |
| 1271 encodedDataLength); | |
| 1272 } | |
| 1273 | |
| 1274 void ResourceFetcher::acceptDataFromThreadedReceiver(unsigned long identifier, | |
| 1275 const char* data, | |
| 1276 int dataLength, | |
| 1277 int encodedDataLength) { | |
| 1278 context().dispatchDidReceiveData(identifier, data, dataLength, | |
| 1279 encodedDataLength); | |
| 1280 } | 1171 } |
| 1281 | 1172 |
| 1282 void ResourceFetcher::moveResourceLoaderToNonBlocking(ResourceLoader* loader) { | 1173 void ResourceFetcher::moveResourceLoaderToNonBlocking(ResourceLoader* loader) { |
| 1283 m_nonBlockingLoaders.add(loader); | 1174 m_nonBlockingLoaders.add(loader); |
| 1284 m_loaders.remove(loader); | 1175 m_loaders.remove(loader); |
| 1285 } | 1176 } |
| 1286 | 1177 |
| 1287 bool ResourceFetcher::startLoad(Resource* resource) { | 1178 bool ResourceFetcher::startLoad(Resource* resource) { |
| 1288 DCHECK(resource); | 1179 DCHECK(resource); |
| 1289 DCHECK(resource->stillNeedsLoad()); | 1180 DCHECK(resource->stillNeedsLoad()); |
| 1290 if (!context().shouldLoadNewResource(resource->getType())) { | 1181 if (!context().shouldLoadNewResource(resource->getType())) { |
| 1291 memoryCache()->remove(resource); | 1182 memoryCache()->remove(resource); |
| 1292 return false; | 1183 return false; |
| 1293 } | 1184 } |
| 1294 | 1185 |
| 1295 ResourceRequest request(resource->resourceRequest()); | 1186 ResourceRequest request(resource->resourceRequest()); |
| 1296 willSendRequest(resource->identifier(), request, ResourceResponse(), | 1187 context().dispatchWillSendRequest(resource->identifier(), request, |
| 1297 resource->options()); | 1188 ResourceResponse(), |
| 1189 resource->options().initiatorInfo); | |
| 1298 | 1190 |
| 1299 // TODO(shaochuan): Saving modified ResourceRequest back to |resource|, remove | 1191 // TODO(shaochuan): Saving modified ResourceRequest back to |resource|, remove |
| 1300 // once willSendRequest() takes const ResourceRequest. crbug.com/632580 | 1192 // once dispatchWillSendRequest() takes const ResourceRequest. |
| 1193 // crbug.com/632580 | |
| 1301 resource->setResourceRequest(request); | 1194 resource->setResourceRequest(request); |
| 1302 | 1195 |
| 1303 // Resource requests from suborigins should not be intercepted by the service | 1196 // Resource requests from suborigins should not be intercepted by the service |
| 1304 // worker of the physical origin. This has the effect that, for now, | 1197 // worker of the physical origin. This has the effect that, for now, |
| 1305 // suborigins do not work with service workers. See | 1198 // suborigins do not work with service workers. See |
| 1306 // https://w3c.github.io/webappsec-suborigins/. | 1199 // https://w3c.github.io/webappsec-suborigins/. |
| 1307 SecurityOrigin* sourceOrigin = context().getSecurityOrigin(); | 1200 SecurityOrigin* sourceOrigin = context().getSecurityOrigin(); |
| 1308 if (sourceOrigin && sourceOrigin->hasSuborigin()) | 1201 if (sourceOrigin && sourceOrigin->hasSuborigin()) |
| 1309 request.setSkipServiceWorker(WebURLRequest::SkipServiceWorker::All); | 1202 request.setSkipServiceWorker(WebURLRequest::SkipServiceWorker::All); |
| 1310 | 1203 |
| 1311 ResourceLoader* loader = ResourceLoader::create(this, resource); | 1204 ResourceLoader* loader = ResourceLoader::create(this, resource); |
| 1312 if (resource->shouldBlockLoadEvent()) | 1205 if (resource->shouldBlockLoadEvent()) |
| 1313 m_loaders.add(loader); | 1206 m_loaders.add(loader); |
| 1314 else | 1207 else |
| 1315 m_nonBlockingLoaders.add(loader); | 1208 m_nonBlockingLoaders.add(loader); |
| 1316 | 1209 |
| 1317 storeResourceTimingInitiatorInformation(resource); | 1210 storeResourceTimingInitiatorInformation(resource); |
| 1318 resource->setFetcherSecurityOrigin(sourceOrigin); | 1211 resource->setFetcherSecurityOrigin(sourceOrigin); |
| 1319 | 1212 |
| 1320 loader->activateCacheAwareLoadingIfNeeded(request); | 1213 loader->activateCacheAwareLoadingIfNeeded(request); |
| 1321 loader->start(request, context().loadingTaskRunner(), | 1214 loader->start(request); |
| 1322 context().defersLoading()); | |
| 1323 return true; | 1215 return true; |
| 1324 } | 1216 } |
| 1325 | 1217 |
| 1326 void ResourceFetcher::removeResourceLoader(ResourceLoader* loader) { | 1218 void ResourceFetcher::removeResourceLoader(ResourceLoader* loader) { |
| 1327 if (m_loaders.contains(loader)) | 1219 if (m_loaders.contains(loader)) |
| 1328 m_loaders.remove(loader); | 1220 m_loaders.remove(loader); |
| 1329 else if (m_nonBlockingLoaders.contains(loader)) | 1221 else if (m_nonBlockingLoaders.contains(loader)) |
| 1330 m_nonBlockingLoaders.remove(loader); | 1222 m_nonBlockingLoaders.remove(loader); |
| 1331 else | 1223 else |
| 1332 NOTREACHED(); | 1224 NOTREACHED(); |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 1349 return !m_loaders.isEmpty(); | 1241 return !m_loaders.isEmpty(); |
| 1350 } | 1242 } |
| 1351 | 1243 |
| 1352 void ResourceFetcher::setDefersLoading(bool defers) { | 1244 void ResourceFetcher::setDefersLoading(bool defers) { |
| 1353 for (const auto& loader : m_nonBlockingLoaders) | 1245 for (const auto& loader : m_nonBlockingLoaders) |
| 1354 loader->setDefersLoading(defers); | 1246 loader->setDefersLoading(defers); |
| 1355 for (const auto& loader : m_loaders) | 1247 for (const auto& loader : m_loaders) |
| 1356 loader->setDefersLoading(defers); | 1248 loader->setDefersLoading(defers); |
| 1357 } | 1249 } |
| 1358 | 1250 |
| 1359 bool ResourceFetcher::defersLoading() const { | |
| 1360 return context().defersLoading(); | |
| 1361 } | |
| 1362 | |
| 1363 static bool isManualRedirectFetchRequest(const ResourceRequest& request) { | |
| 1364 return request.fetchRedirectMode() == | |
| 1365 WebURLRequest::FetchRedirectModeManual && | |
| 1366 request.requestContext() == WebURLRequest::RequestContextFetch; | |
| 1367 } | |
| 1368 | |
| 1369 bool ResourceFetcher::willFollowRedirect( | |
| 1370 Resource* resource, | |
| 1371 ResourceRequest& newRequest, | |
| 1372 const ResourceResponse& redirectResponse) { | |
| 1373 if (!isManualRedirectFetchRequest(resource->resourceRequest())) { | |
| 1374 if (!context().canRequest(resource->getType(), newRequest, newRequest.url(), | |
| 1375 resource->options(), resource->isUnusedPreload(), | |
| 1376 FetchRequest::UseDefaultOriginRestrictionForType)) | |
| 1377 return false; | |
| 1378 if (resource->options().corsEnabled == IsCORSEnabled) { | |
| 1379 RefPtr<SecurityOrigin> sourceOrigin = resource->options().securityOrigin; | |
| 1380 if (!sourceOrigin.get()) | |
| 1381 sourceOrigin = context().getSecurityOrigin(); | |
| 1382 | |
| 1383 String errorMessage; | |
| 1384 StoredCredentials withCredentials = | |
| 1385 resource->lastResourceRequest().allowStoredCredentials() | |
| 1386 ? AllowStoredCredentials | |
| 1387 : DoNotAllowStoredCredentials; | |
| 1388 if (!CrossOriginAccessControl::handleRedirect( | |
| 1389 sourceOrigin, newRequest, redirectResponse, withCredentials, | |
| 1390 resource->mutableOptions(), errorMessage)) { | |
| 1391 resource->setCORSFailed(); | |
| 1392 context().addConsoleMessage(errorMessage); | |
| 1393 return false; | |
| 1394 } | |
| 1395 } | |
| 1396 if (resource->getType() == Resource::Image && | |
| 1397 shouldDeferImageLoad(newRequest.url())) | |
| 1398 return false; | |
| 1399 } | |
| 1400 | |
| 1401 ResourceTimingInfoMap::iterator it = m_resourceTimingInfoMap.find(resource); | |
| 1402 if (it != m_resourceTimingInfoMap.end()) { | |
| 1403 bool crossOrigin = IsCrossOrigin(redirectResponse.url(), newRequest.url()); | |
| 1404 it->value->addRedirect(redirectResponse, crossOrigin); | |
| 1405 } | |
| 1406 newRequest.setAllowStoredCredentials(resource->options().allowCredentials == | |
| 1407 AllowStoredCredentials); | |
| 1408 willSendRequest(resource->identifier(), newRequest, redirectResponse, | |
| 1409 resource->options()); | |
| 1410 return true; | |
| 1411 } | |
| 1412 | |
| 1413 void ResourceFetcher::willSendRequest(unsigned long identifier, | |
| 1414 ResourceRequest& newRequest, | |
| 1415 const ResourceResponse& redirectResponse, | |
| 1416 const ResourceLoaderOptions& options) { | |
| 1417 context().dispatchWillSendRequest(identifier, newRequest, redirectResponse, | |
| 1418 options.initiatorInfo); | |
| 1419 } | |
| 1420 | |
| 1421 void ResourceFetcher::updateAllImageResourcePriorities() { | 1251 void ResourceFetcher::updateAllImageResourcePriorities() { |
| 1422 TRACE_EVENT0( | 1252 TRACE_EVENT0( |
| 1423 "blink", | 1253 "blink", |
| 1424 "ResourceLoadPriorityOptimizer::updateAllImageResourcePriorities"); | 1254 "ResourceLoadPriorityOptimizer::updateAllImageResourcePriorities"); |
| 1425 for (const auto& documentResource : m_documentResources) { | 1255 for (const auto& documentResource : m_documentResources) { |
| 1426 Resource* resource = documentResource.value.get(); | 1256 Resource* resource = documentResource.value.get(); |
| 1427 if (!resource || !resource->isImage() || !resource->isLoading()) | 1257 if (!resource || !resource->isImage() || !resource->isLoading()) |
| 1428 continue; | 1258 continue; |
| 1429 | 1259 |
| 1430 ResourcePriority resourcePriority = resource->priorityFromObservers(); | 1260 ResourcePriority resourcePriority = resource->priorityFromObservers(); |
| (...skipping 210 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1641 visitor->trace(m_context); | 1471 visitor->trace(m_context); |
| 1642 visitor->trace(m_archive); | 1472 visitor->trace(m_archive); |
| 1643 visitor->trace(m_loaders); | 1473 visitor->trace(m_loaders); |
| 1644 visitor->trace(m_nonBlockingLoaders); | 1474 visitor->trace(m_nonBlockingLoaders); |
| 1645 visitor->trace(m_documentResources); | 1475 visitor->trace(m_documentResources); |
| 1646 visitor->trace(m_preloads); | 1476 visitor->trace(m_preloads); |
| 1647 visitor->trace(m_resourceTimingInfoMap); | 1477 visitor->trace(m_resourceTimingInfoMap); |
| 1648 } | 1478 } |
| 1649 | 1479 |
| 1650 } // namespace blink | 1480 } // namespace blink |
| OLD | NEW |