| 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 void addRedirectsToTimingInfo(Resource* resource, ResourceTimingInfo* info) { | 99 void addRedirectsToTimingInfo(Resource* resource, ResourceTimingInfo* info) { |
| 107 // Store redirect responses that were packed inside the final response. | 100 // Store redirect responses that were packed inside the final response. |
| 108 const auto& responses = resource->response().redirectResponses(); | 101 const auto& responses = resource->response().redirectResponses(); |
| 109 for (size_t i = 0; i < responses.size(); ++i) { | 102 for (size_t i = 0; i < responses.size(); ++i) { |
| 110 const KURL& newURL = i + 1 < responses.size() | 103 const KURL& newURL = i + 1 < responses.size() |
| 111 ? KURL(responses[i + 1].url()) | 104 ? KURL(responses[i + 1].url()) |
| 112 : resource->resourceRequest().url(); | 105 : resource->resourceRequest().url(); |
| 113 bool crossOrigin = IsCrossOrigin(responses[i].url(), newURL); | 106 bool crossOrigin = |
| 107 !SecurityOrigin::areSameSchemeHostPort(responses[i].url(), newURL); |
| 114 info->addRedirect(responses[i], crossOrigin); | 108 info->addRedirect(responses[i], crossOrigin); |
| 115 } | 109 } |
| 116 } | 110 } |
| 117 | 111 |
| 118 } // namespace | 112 void RecordSriResourceIntegrityMismatchEvent( |
| 119 | |
| 120 static void RecordSriResourceIntegrityMismatchEvent( | |
| 121 SriResourceIntegrityMismatchEvent event) { | 113 SriResourceIntegrityMismatchEvent event) { |
| 122 DEFINE_THREAD_SAFE_STATIC_LOCAL( | 114 DEFINE_THREAD_SAFE_STATIC_LOCAL( |
| 123 EnumerationHistogram, integrityHistogram, | 115 EnumerationHistogram, integrityHistogram, |
| 124 new EnumerationHistogram("sri.resource_integrity_mismatch_event", | 116 new EnumerationHistogram("sri.resource_integrity_mismatch_event", |
| 125 SriResourceIntegrityMismatchEventCount)); | 117 SriResourceIntegrityMismatchEventCount)); |
| 126 integrityHistogram.count(event); | 118 integrityHistogram.count(event); |
| 127 } | 119 } |
| 128 | 120 |
| 129 static ResourceLoadPriority typeToPriority(Resource::Type type) { | 121 ResourceLoadPriority typeToPriority(Resource::Type type) { |
| 130 switch (type) { | 122 switch (type) { |
| 131 case Resource::MainResource: | 123 case Resource::MainResource: |
| 132 case Resource::CSSStyleSheet: | 124 case Resource::CSSStyleSheet: |
| 133 case Resource::Font: | 125 case Resource::Font: |
| 134 // Also parser-blocking scripts (set explicitly in loadPriority) | 126 // Also parser-blocking scripts (set explicitly in loadPriority) |
| 135 return ResourceLoadPriorityVeryHigh; | 127 return ResourceLoadPriorityVeryHigh; |
| 136 case Resource::XSLStyleSheet: | 128 case Resource::XSLStyleSheet: |
| 137 DCHECK(RuntimeEnabledFeatures::xsltEnabled()); | 129 DCHECK(RuntimeEnabledFeatures::xsltEnabled()); |
| 138 case Resource::Raw: | 130 case Resource::Raw: |
| 139 case Resource::ImportResource: | 131 case Resource::ImportResource: |
| (...skipping 11 matching lines...) Expand all Loading... |
| 151 // Also async scripts (set explicitly in loadPriority) | 143 // Also async scripts (set explicitly in loadPriority) |
| 152 return ResourceLoadPriorityLow; | 144 return ResourceLoadPriorityLow; |
| 153 case Resource::LinkPrefetch: | 145 case Resource::LinkPrefetch: |
| 154 return ResourceLoadPriorityVeryLow; | 146 return ResourceLoadPriorityVeryLow; |
| 155 } | 147 } |
| 156 | 148 |
| 157 NOTREACHED(); | 149 NOTREACHED(); |
| 158 return ResourceLoadPriorityUnresolved; | 150 return ResourceLoadPriorityUnresolved; |
| 159 } | 151 } |
| 160 | 152 |
| 153 } // namespace |
| 154 |
| 161 ResourceLoadPriority ResourceFetcher::computeLoadPriority( | 155 ResourceLoadPriority ResourceFetcher::computeLoadPriority( |
| 162 Resource::Type type, | 156 Resource::Type type, |
| 163 const FetchRequest& request, | 157 const FetchRequest& request, |
| 164 ResourcePriority::VisibilityStatus visibility) { | 158 ResourcePriority::VisibilityStatus visibility) { |
| 165 ResourceLoadPriority priority = typeToPriority(type); | 159 ResourceLoadPriority priority = typeToPriority(type); |
| 166 | 160 |
| 167 // Visible resources (images in practice) get a boost to High priority. | 161 // Visible resources (images in practice) get a boost to High priority. |
| 168 if (visibility == ResourcePriority::Visible) | 162 if (visibility == ResourcePriority::Visible) |
| 169 priority = ResourceLoadPriorityHigh; | 163 priority = ResourceLoadPriorityHigh; |
| 170 | 164 |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 263 } | 257 } |
| 264 | 258 |
| 265 ResourceFetcher::~ResourceFetcher() {} | 259 ResourceFetcher::~ResourceFetcher() {} |
| 266 | 260 |
| 267 Resource* ResourceFetcher::cachedResource(const KURL& resourceURL) const { | 261 Resource* ResourceFetcher::cachedResource(const KURL& resourceURL) const { |
| 268 KURL url = MemoryCache::removeFragmentIdentifierIfNeeded(resourceURL); | 262 KURL url = MemoryCache::removeFragmentIdentifierIfNeeded(resourceURL); |
| 269 const WeakMember<Resource>& resource = m_documentResources.get(url); | 263 const WeakMember<Resource>& resource = m_documentResources.get(url); |
| 270 return resource.get(); | 264 return resource.get(); |
| 271 } | 265 } |
| 272 | 266 |
| 273 ResourceRequestBlockedReason ResourceFetcher::canAccessResponse( | |
| 274 Resource* resource, | |
| 275 const ResourceResponse& response) const { | |
| 276 // Redirects can change the response URL different from one of request. | |
| 277 bool forPreload = resource->isUnusedPreload(); | |
| 278 ResourceRequestBlockedReason blockedReason = | |
| 279 context().canRequest(resource->getType(), resource->resourceRequest(), | |
| 280 response.url(), resource->options(), forPreload, | |
| 281 FetchRequest::UseDefaultOriginRestrictionForType); | |
| 282 if (blockedReason != ResourceRequestBlockedReason::None) | |
| 283 return blockedReason; | |
| 284 | |
| 285 SecurityOrigin* sourceOrigin = resource->options().securityOrigin.get(); | |
| 286 if (!sourceOrigin) | |
| 287 sourceOrigin = context().getSecurityOrigin(); | |
| 288 | |
| 289 if (sourceOrigin->canRequestNoSuborigin(response.url())) | |
| 290 return ResourceRequestBlockedReason::None; | |
| 291 | |
| 292 // Use the original response instead of the 304 response for a successful | |
| 293 // revaldiation. | |
| 294 const ResourceResponse& responseForAccessControl = | |
| 295 (resource->isCacheValidator() && response.httpStatusCode() == 304) | |
| 296 ? resource->response() | |
| 297 : response; | |
| 298 String errorDescription; | |
| 299 if (!passesAccessControlCheck( | |
| 300 responseForAccessControl, resource->options().allowCredentials, | |
| 301 sourceOrigin, errorDescription, | |
| 302 resource->lastResourceRequest().requestContext())) { | |
| 303 resource->setCORSFailed(); | |
| 304 if (!forPreload) { | |
| 305 String resourceType = Resource::resourceTypeToString( | |
| 306 resource->getType(), resource->options().initiatorInfo); | |
| 307 context().addConsoleMessage( | |
| 308 "Access to " + resourceType + " at '" + response.url().getString() + | |
| 309 "' from origin '" + sourceOrigin->toString() + | |
| 310 "' has been blocked by CORS policy: " + errorDescription); | |
| 311 } | |
| 312 return ResourceRequestBlockedReason::Other; | |
| 313 } | |
| 314 return ResourceRequestBlockedReason::None; | |
| 315 } | |
| 316 | |
| 317 bool ResourceFetcher::isControlledByServiceWorker() const { | 267 bool ResourceFetcher::isControlledByServiceWorker() const { |
| 318 return context().isControlledByServiceWorker(); | 268 return context().isControlledByServiceWorker(); |
| 319 } | 269 } |
| 320 | 270 |
| 321 bool ResourceFetcher::resourceNeedsLoad(Resource* resource, | 271 bool ResourceFetcher::resourceNeedsLoad(Resource* resource, |
| 322 const FetchRequest& request, | 272 const FetchRequest& request, |
| 323 RevalidationPolicy policy) { | 273 RevalidationPolicy policy) { |
| 324 // Defer a font load until it is actually needed unless this is a preload. | 274 // Defer a font load until it is actually needed unless this is a preload. |
| 325 if (resource->getType() == Resource::Font && !request.forPreload()) | 275 if (resource->getType() == Resource::Font && !request.forPreload()) |
| 326 return false; | 276 return false; |
| (...skipping 471 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 798 if (!timingAllowOrigin.isEmpty()) | 748 if (!timingAllowOrigin.isEmpty()) |
| 799 info->setOriginalTimingAllowOrigin(timingAllowOrigin); | 749 info->setOriginalTimingAllowOrigin(timingAllowOrigin); |
| 800 } | 750 } |
| 801 | 751 |
| 802 if (!isMainResource || | 752 if (!isMainResource || |
| 803 context().updateTimingInfoForIFrameNavigation(info.get())) { | 753 context().updateTimingInfoForIFrameNavigation(info.get())) { |
| 804 m_resourceTimingInfoMap.add(resource, std::move(info)); | 754 m_resourceTimingInfoMap.add(resource, std::move(info)); |
| 805 } | 755 } |
| 806 } | 756 } |
| 807 | 757 |
| 758 void ResourceFetcher::recordResourceTimingOnRedirect( |
| 759 Resource* resource, |
| 760 const ResourceResponse& redirectResponse, |
| 761 bool crossOrigin) { |
| 762 ResourceTimingInfoMap::iterator it = m_resourceTimingInfoMap.find(resource); |
| 763 if (it != m_resourceTimingInfoMap.end()) { |
| 764 it->value->addRedirect(redirectResponse, crossOrigin); |
| 765 } |
| 766 |
| 767 if (resource->getType() == Resource::MainResource) { |
| 768 DCHECK(m_navigationTimingInfo); |
| 769 m_navigationTimingInfo->addRedirect(redirectResponse, crossOrigin); |
| 770 } |
| 771 } |
| 772 |
| 808 ResourceFetcher::RevalidationPolicy | 773 ResourceFetcher::RevalidationPolicy |
| 809 ResourceFetcher::determineRevalidationPolicy(Resource::Type type, | 774 ResourceFetcher::determineRevalidationPolicy(Resource::Type type, |
| 810 const FetchRequest& fetchRequest, | 775 const FetchRequest& fetchRequest, |
| 811 Resource* existingResource, | 776 Resource* existingResource, |
| 812 bool isStaticData) const { | 777 bool isStaticData) const { |
| 813 const ResourceRequest& request = fetchRequest.resourceRequest(); | 778 const ResourceRequest& request = fetchRequest.resourceRequest(); |
| 814 | 779 |
| 815 if (!existingResource) | 780 if (!existingResource) |
| 816 return Load; | 781 return Load; |
| 817 | 782 |
| (...skipping 323 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1141 if (!context().isMainFrame()) | 1106 if (!context().isMainFrame()) |
| 1142 return nullptr; | 1107 return nullptr; |
| 1143 m_archive = MHTMLArchive::create(resource->url(), resource->resourceBuffer()); | 1108 m_archive = MHTMLArchive::create(resource->url(), resource->resourceBuffer()); |
| 1144 return m_archive ? m_archive->mainResource() : nullptr; | 1109 return m_archive ? m_archive->mainResource() : nullptr; |
| 1145 } | 1110 } |
| 1146 | 1111 |
| 1147 ResourceTimingInfo* ResourceFetcher::getNavigationTimingInfo() { | 1112 ResourceTimingInfo* ResourceFetcher::getNavigationTimingInfo() { |
| 1148 return m_navigationTimingInfo.get(); | 1113 return m_navigationTimingInfo.get(); |
| 1149 } | 1114 } |
| 1150 | 1115 |
| 1151 void ResourceFetcher::didFinishLoading(Resource* resource, | 1116 void ResourceFetcher::handleLoadCompletion(Resource* resource) { |
| 1152 double finishTime, | 1117 context().didLoadResource(resource); |
| 1153 DidFinishLoadingReason finishReason) { | 1118 |
| 1154 network_instrumentation::endResourceLoad( | 1119 if (resource->isImage() && |
| 1155 resource->identifier(), network_instrumentation::RequestOutcome::Success); | 1120 toImageResource(resource)->shouldReloadBrokenPlaceholder()) { |
| 1121 toImageResource(resource)->reloadIfLoFiOrPlaceholder(this); |
| 1122 } |
| 1123 } |
| 1124 |
| 1125 void ResourceFetcher::handleLoaderFinish(Resource* resource, |
| 1126 double finishTime, |
| 1127 LoaderFinishType type) { |
| 1156 DCHECK(resource); | 1128 DCHECK(resource); |
| 1129 |
| 1130 ResourceLoader* loader = resource->loader(); |
| 1131 if (type == DidFinishFirstPartInMultipart) { |
| 1132 // When loading a multipart resource, make the loader non-block when |
| 1133 // finishing loading the first part. |
| 1134 moveResourceLoaderToNonBlocking(loader); |
| 1135 } else { |
| 1136 removeResourceLoader(loader); |
| 1137 DCHECK(!m_nonBlockingLoaders.contains(loader)); |
| 1138 } |
| 1139 DCHECK(!m_loaders.contains(loader)); |
| 1140 |
| 1157 const int64_t encodedDataLength = resource->response().encodedDataLength(); | 1141 const int64_t encodedDataLength = resource->response().encodedDataLength(); |
| 1158 | 1142 |
| 1159 // When loading a multipart resource, make the loader non-block when finishing | |
| 1160 // loading the first part. | |
| 1161 if (finishReason == DidFinishFirstPartInMultipart) | |
| 1162 moveResourceLoaderToNonBlocking(resource->loader()); | |
| 1163 else | |
| 1164 removeResourceLoader(resource->loader()); | |
| 1165 DCHECK(!m_loaders.contains(resource->loader())); | |
| 1166 DCHECK(finishReason == DidFinishFirstPartInMultipart || | |
| 1167 !m_nonBlockingLoaders.contains(resource->loader())); | |
| 1168 | |
| 1169 if (resource->getType() == Resource::MainResource) { | 1143 if (resource->getType() == Resource::MainResource) { |
| 1170 DCHECK(m_navigationTimingInfo); | 1144 DCHECK(m_navigationTimingInfo); |
| 1171 // Store redirect responses that were packed inside the final response. | 1145 // Store redirect responses that were packed inside the final response. |
| 1172 addRedirectsToTimingInfo(resource, m_navigationTimingInfo.get()); | 1146 addRedirectsToTimingInfo(resource, m_navigationTimingInfo.get()); |
| 1173 if (resource->response().isHTTP()) { | 1147 if (resource->response().isHTTP()) { |
| 1174 m_navigationTimingInfo->addFinalTransferSize( | 1148 m_navigationTimingInfo->addFinalTransferSize( |
| 1175 encodedDataLength == -1 ? 0 : encodedDataLength); | 1149 encodedDataLength == -1 ? 0 : encodedDataLength); |
| 1176 } | 1150 } |
| 1177 } | 1151 } |
| 1178 if (std::unique_ptr<ResourceTimingInfo> info = | 1152 if (std::unique_ptr<ResourceTimingInfo> info = |
| 1179 m_resourceTimingInfoMap.take(resource)) { | 1153 m_resourceTimingInfoMap.take(resource)) { |
| 1180 // Store redirect responses that were packed inside the final response. | 1154 // Store redirect responses that were packed inside the final response. |
| 1181 addRedirectsToTimingInfo(resource, info.get()); | 1155 addRedirectsToTimingInfo(resource, info.get()); |
| 1182 | 1156 |
| 1183 if (resource->response().isHTTP() && | 1157 if (resource->response().isHTTP() && |
| 1184 resource->response().httpStatusCode() < 400) { | 1158 resource->response().httpStatusCode() < 400) { |
| 1185 populateResourceTiming(info.get(), resource); | 1159 populateResourceTiming(info.get(), resource); |
| 1186 info->setLoadFinishTime(finishTime); | 1160 info->setLoadFinishTime(finishTime); |
| 1187 // encodedDataLength == -1 means "not available". | 1161 // encodedDataLength == -1 means "not available". |
| 1188 // TODO(ricea): Find cases where it is not available but the | 1162 // TODO(ricea): Find cases where it is not available but the |
| 1189 // PerformanceResourceTiming spec requires it to be available and fix | 1163 // PerformanceResourceTiming spec requires it to be available and fix |
| 1190 // them. | 1164 // them. |
| 1191 info->addFinalTransferSize(encodedDataLength == -1 ? 0 | 1165 info->addFinalTransferSize(encodedDataLength == -1 ? 0 |
| 1192 : encodedDataLength); | 1166 : encodedDataLength); |
| 1167 |
| 1193 if (resource->options().requestInitiatorContext == DocumentContext) | 1168 if (resource->options().requestInitiatorContext == DocumentContext) |
| 1194 context().addResourceTiming(*info); | 1169 context().addResourceTiming(*info); |
| 1195 resource->reportResourceTimingToClients(*info); | 1170 resource->reportResourceTimingToClients(*info); |
| 1196 } | 1171 } |
| 1197 } | 1172 } |
| 1173 |
| 1198 context().dispatchDidFinishLoading(resource->identifier(), finishTime, | 1174 context().dispatchDidFinishLoading(resource->identifier(), finishTime, |
| 1199 encodedDataLength); | 1175 encodedDataLength); |
| 1200 if (finishReason == DidFinishLoading) | 1176 |
| 1177 if (type == DidFinishLoading) |
| 1201 resource->finish(finishTime); | 1178 resource->finish(finishTime); |
| 1202 context().didLoadResource(resource); | |
| 1203 | 1179 |
| 1204 if (resource->isImage() && | 1180 handleLoadCompletion(resource); |
| 1205 toImageResource(resource)->shouldReloadBrokenPlaceholder()) { | |
| 1206 toImageResource(resource)->reloadIfLoFiOrPlaceholder(this); | |
| 1207 } | |
| 1208 } | 1181 } |
| 1209 | 1182 |
| 1210 void ResourceFetcher::didFailLoading(Resource* resource, | 1183 void ResourceFetcher::handleLoaderError(Resource* resource, |
| 1211 const ResourceError& error) { | 1184 const ResourceError& error) { |
| 1212 network_instrumentation::endResourceLoad( | 1185 DCHECK(resource); |
| 1213 resource->identifier(), network_instrumentation::RequestOutcome::Fail); | 1186 |
| 1214 removeResourceLoader(resource->loader()); | 1187 removeResourceLoader(resource->loader()); |
| 1215 m_resourceTimingInfoMap.take(const_cast<Resource*>(resource)); | 1188 |
| 1189 m_resourceTimingInfoMap.take(resource); |
| 1190 |
| 1216 bool isInternalRequest = resource->options().initiatorInfo.name == | 1191 bool isInternalRequest = resource->options().initiatorInfo.name == |
| 1217 FetchInitiatorTypeNames::internal; | 1192 FetchInitiatorTypeNames::internal; |
| 1193 |
| 1218 context().dispatchDidFail(resource->identifier(), error, | 1194 context().dispatchDidFail(resource->identifier(), error, |
| 1219 resource->response().encodedDataLength(), | 1195 resource->response().encodedDataLength(), |
| 1220 isInternalRequest); | 1196 isInternalRequest); |
| 1197 |
| 1221 resource->error(error); | 1198 resource->error(error); |
| 1222 context().didLoadResource(resource); | |
| 1223 | 1199 |
| 1224 if (resource->isImage() && | 1200 handleLoadCompletion(resource); |
| 1225 toImageResource(resource)->shouldReloadBrokenPlaceholder()) { | |
| 1226 toImageResource(resource)->reloadIfLoFiOrPlaceholder(this); | |
| 1227 } | |
| 1228 } | |
| 1229 | |
| 1230 void ResourceFetcher::didReceiveResponse( | |
| 1231 Resource* resource, | |
| 1232 const ResourceResponse& response, | |
| 1233 std::unique_ptr<WebDataConsumerHandle> handle) { | |
| 1234 if (response.wasFetchedViaServiceWorker()) { | |
| 1235 if (resource->options().corsEnabled == IsCORSEnabled && | |
| 1236 response.wasFallbackRequiredByServiceWorker()) { | |
| 1237 ResourceRequest request = resource->lastResourceRequest(); | |
| 1238 DCHECK_EQ(request.skipServiceWorker(), | |
| 1239 WebURLRequest::SkipServiceWorker::None); | |
| 1240 // This code handles the case when a regular controlling service worker | |
| 1241 // doesn't handle a cross origin request. When this happens we still want | |
| 1242 // to give foreign fetch a chance to handle the request, so only skip the | |
| 1243 // controlling service worker for the fallback request. This is currently | |
| 1244 // safe because of http://crbug.com/604084 the | |
| 1245 // wasFallbackRequiredByServiceWorker flag is never set when foreign fetch | |
| 1246 // handled a request. | |
| 1247 if (!context().shouldLoadNewResource(resource->getType())) { | |
| 1248 // Cancel the request if we should not trigger a reload now. | |
| 1249 resource->loader()->didFail( | |
| 1250 ResourceError::cancelledError(response.url())); | |
| 1251 return; | |
| 1252 } | |
| 1253 request.setSkipServiceWorker( | |
| 1254 WebURLRequest::SkipServiceWorker::Controlling); | |
| 1255 resource->loader()->restart(request, context().loadingTaskRunner(), | |
| 1256 context().defersLoading()); | |
| 1257 return; | |
| 1258 } | |
| 1259 | |
| 1260 // If the response is fetched via ServiceWorker, the original URL of the | |
| 1261 // response could be different from the URL of the request. We check the URL | |
| 1262 // not to load the resources which are forbidden by the page CSP. | |
| 1263 // https://w3c.github.io/webappsec-csp/#should-block-response | |
| 1264 const KURL& originalURL = response.originalURLViaServiceWorker(); | |
| 1265 if (!originalURL.isEmpty()) { | |
| 1266 ResourceRequestBlockedReason blockedReason = context().allowResponse( | |
| 1267 resource->getType(), resource->resourceRequest(), originalURL, | |
| 1268 resource->options()); | |
| 1269 if (blockedReason != ResourceRequestBlockedReason::None) { | |
| 1270 resource->loader()->didFail( | |
| 1271 ResourceError::cancelledDueToAccessCheckError(originalURL, | |
| 1272 blockedReason)); | |
| 1273 return; | |
| 1274 } | |
| 1275 } | |
| 1276 } else if (resource->options().corsEnabled == IsCORSEnabled) { | |
| 1277 ResourceRequestBlockedReason blockedReason = | |
| 1278 canAccessResponse(resource, response); | |
| 1279 if (blockedReason != ResourceRequestBlockedReason::None) { | |
| 1280 resource->loader()->didFail(ResourceError::cancelledDueToAccessCheckError( | |
| 1281 response.url(), blockedReason)); | |
| 1282 return; | |
| 1283 } | |
| 1284 } | |
| 1285 | |
| 1286 context().dispatchDidReceiveResponse( | |
| 1287 resource->identifier(), response, resource->resourceRequest().frameType(), | |
| 1288 resource->resourceRequest().requestContext(), resource); | |
| 1289 resource->responseReceived(response, std::move(handle)); | |
| 1290 if (resource->loader() && response.httpStatusCode() >= 400 && | |
| 1291 !resource->shouldIgnoreHTTPStatusCodeErrors()) { | |
| 1292 resource->loader()->didFail(ResourceError::cancelledError(response.url())); | |
| 1293 } | |
| 1294 } | |
| 1295 | |
| 1296 void ResourceFetcher::didReceiveData(const Resource* resource, | |
| 1297 const char* data, | |
| 1298 int dataLength) { | |
| 1299 context().dispatchDidReceiveData(resource->identifier(), data, dataLength); | |
| 1300 } | |
| 1301 | |
| 1302 void ResourceFetcher::didReceiveTransferSizeUpdate(const Resource* resource, | |
| 1303 int transferSizeDiff) { | |
| 1304 context().dispatchDidReceiveEncodedData(resource->identifier(), | |
| 1305 transferSizeDiff); | |
| 1306 } | |
| 1307 | |
| 1308 void ResourceFetcher::didDownloadData(const Resource* resource, | |
| 1309 int dataLength, | |
| 1310 int encodedDataLength) { | |
| 1311 context().dispatchDidDownloadData(resource->identifier(), dataLength, | |
| 1312 encodedDataLength); | |
| 1313 } | 1201 } |
| 1314 | 1202 |
| 1315 void ResourceFetcher::moveResourceLoaderToNonBlocking(ResourceLoader* loader) { | 1203 void ResourceFetcher::moveResourceLoaderToNonBlocking(ResourceLoader* loader) { |
| 1316 DCHECK(loader); | 1204 DCHECK(loader); |
| 1317 // TODO(yoav): Convert CHECK to DCHECK if no crash reports come in. | 1205 // TODO(yoav): Convert CHECK to DCHECK if no crash reports come in. |
| 1318 CHECK(m_loaders.contains(loader)); | 1206 CHECK(m_loaders.contains(loader)); |
| 1319 m_nonBlockingLoaders.add(loader); | 1207 m_nonBlockingLoaders.add(loader); |
| 1320 m_loaders.remove(loader); | 1208 m_loaders.remove(loader); |
| 1321 } | 1209 } |
| 1322 | 1210 |
| 1323 bool ResourceFetcher::startLoad(Resource* resource) { | 1211 bool ResourceFetcher::startLoad(Resource* resource) { |
| 1324 DCHECK(resource); | 1212 DCHECK(resource); |
| 1325 DCHECK(resource->stillNeedsLoad()); | 1213 DCHECK(resource->stillNeedsLoad()); |
| 1326 if (!context().shouldLoadNewResource(resource->getType())) { | 1214 if (!context().shouldLoadNewResource(resource->getType())) { |
| 1327 memoryCache()->remove(resource); | 1215 memoryCache()->remove(resource); |
| 1328 return false; | 1216 return false; |
| 1329 } | 1217 } |
| 1330 | 1218 |
| 1331 ResourceRequest request(resource->resourceRequest()); | 1219 ResourceRequest request(resource->resourceRequest()); |
| 1332 willSendRequest(resource->identifier(), request, ResourceResponse(), | 1220 context().dispatchWillSendRequest(resource->identifier(), request, |
| 1333 resource->options()); | 1221 ResourceResponse(), |
| 1222 resource->options().initiatorInfo); |
| 1334 | 1223 |
| 1335 // TODO(shaochuan): Saving modified ResourceRequest back to |resource|, remove | 1224 // TODO(shaochuan): Saving modified ResourceRequest back to |resource|, remove |
| 1336 // once willSendRequest() takes const ResourceRequest. crbug.com/632580 | 1225 // once dispatchWillSendRequest() takes const ResourceRequest. |
| 1226 // crbug.com/632580 |
| 1337 resource->setResourceRequest(request); | 1227 resource->setResourceRequest(request); |
| 1338 | 1228 |
| 1339 // Resource requests from suborigins should not be intercepted by the service | 1229 // Resource requests from suborigins should not be intercepted by the service |
| 1340 // worker of the physical origin. This has the effect that, for now, | 1230 // worker of the physical origin. This has the effect that, for now, |
| 1341 // suborigins do not work with service workers. See | 1231 // suborigins do not work with service workers. See |
| 1342 // https://w3c.github.io/webappsec-suborigins/. | 1232 // https://w3c.github.io/webappsec-suborigins/. |
| 1343 SecurityOrigin* sourceOrigin = context().getSecurityOrigin(); | 1233 SecurityOrigin* sourceOrigin = context().getSecurityOrigin(); |
| 1344 if (sourceOrigin && sourceOrigin->hasSuborigin()) | 1234 if (sourceOrigin && sourceOrigin->hasSuborigin()) |
| 1345 request.setSkipServiceWorker(WebURLRequest::SkipServiceWorker::All); | 1235 request.setSkipServiceWorker(WebURLRequest::SkipServiceWorker::All); |
| 1346 | 1236 |
| 1347 ResourceLoader* loader = ResourceLoader::create(this, resource); | 1237 ResourceLoader* loader = ResourceLoader::create(this, resource); |
| 1348 if (resource->shouldBlockLoadEvent()) | 1238 if (resource->shouldBlockLoadEvent()) |
| 1349 m_loaders.add(loader); | 1239 m_loaders.add(loader); |
| 1350 else | 1240 else |
| 1351 m_nonBlockingLoaders.add(loader); | 1241 m_nonBlockingLoaders.add(loader); |
| 1352 | 1242 |
| 1353 storePerformanceTimingInitiatorInformation(resource); | 1243 storePerformanceTimingInitiatorInformation(resource); |
| 1354 resource->setFetcherSecurityOrigin(sourceOrigin); | 1244 resource->setFetcherSecurityOrigin(sourceOrigin); |
| 1355 | 1245 |
| 1356 loader->activateCacheAwareLoadingIfNeeded(request); | 1246 loader->activateCacheAwareLoadingIfNeeded(request); |
| 1357 loader->start(request, context().loadingTaskRunner(), | 1247 loader->start(request); |
| 1358 context().defersLoading()); | |
| 1359 return true; | 1248 return true; |
| 1360 } | 1249 } |
| 1361 | 1250 |
| 1362 void ResourceFetcher::removeResourceLoader(ResourceLoader* loader) { | 1251 void ResourceFetcher::removeResourceLoader(ResourceLoader* loader) { |
| 1363 DCHECK(loader); | 1252 DCHECK(loader); |
| 1364 if (m_loaders.contains(loader)) | 1253 if (m_loaders.contains(loader)) |
| 1365 m_loaders.remove(loader); | 1254 m_loaders.remove(loader); |
| 1366 else if (m_nonBlockingLoaders.contains(loader)) | 1255 else if (m_nonBlockingLoaders.contains(loader)) |
| 1367 m_nonBlockingLoaders.remove(loader); | 1256 m_nonBlockingLoaders.remove(loader); |
| 1368 else | 1257 else |
| (...skipping 17 matching lines...) Expand all Loading... |
| 1386 return !m_loaders.isEmpty(); | 1275 return !m_loaders.isEmpty(); |
| 1387 } | 1276 } |
| 1388 | 1277 |
| 1389 void ResourceFetcher::setDefersLoading(bool defers) { | 1278 void ResourceFetcher::setDefersLoading(bool defers) { |
| 1390 for (const auto& loader : m_nonBlockingLoaders) | 1279 for (const auto& loader : m_nonBlockingLoaders) |
| 1391 loader->setDefersLoading(defers); | 1280 loader->setDefersLoading(defers); |
| 1392 for (const auto& loader : m_loaders) | 1281 for (const auto& loader : m_loaders) |
| 1393 loader->setDefersLoading(defers); | 1282 loader->setDefersLoading(defers); |
| 1394 } | 1283 } |
| 1395 | 1284 |
| 1396 bool ResourceFetcher::defersLoading() const { | |
| 1397 return context().defersLoading(); | |
| 1398 } | |
| 1399 | |
| 1400 static bool isManualRedirectFetchRequest(const ResourceRequest& request) { | |
| 1401 return request.fetchRedirectMode() == | |
| 1402 WebURLRequest::FetchRedirectModeManual && | |
| 1403 request.requestContext() == WebURLRequest::RequestContextFetch; | |
| 1404 } | |
| 1405 | |
| 1406 ResourceRequestBlockedReason ResourceFetcher::willFollowRedirect( | |
| 1407 Resource* resource, | |
| 1408 ResourceRequest& newRequest, | |
| 1409 const ResourceResponse& redirectResponse) { | |
| 1410 if (!isManualRedirectFetchRequest(resource->resourceRequest())) { | |
| 1411 ResourceRequestBlockedReason blockedReason = | |
| 1412 context().canRequest(resource->getType(), newRequest, newRequest.url(), | |
| 1413 resource->options(), resource->isUnusedPreload(), | |
| 1414 FetchRequest::UseDefaultOriginRestrictionForType); | |
| 1415 if (blockedReason != ResourceRequestBlockedReason::None) | |
| 1416 return blockedReason; | |
| 1417 if (resource->options().corsEnabled == IsCORSEnabled) { | |
| 1418 RefPtr<SecurityOrigin> sourceOrigin = resource->options().securityOrigin; | |
| 1419 if (!sourceOrigin.get()) | |
| 1420 sourceOrigin = context().getSecurityOrigin(); | |
| 1421 | |
| 1422 String errorMessage; | |
| 1423 StoredCredentials withCredentials = | |
| 1424 resource->lastResourceRequest().allowStoredCredentials() | |
| 1425 ? AllowStoredCredentials | |
| 1426 : DoNotAllowStoredCredentials; | |
| 1427 if (!CrossOriginAccessControl::handleRedirect( | |
| 1428 sourceOrigin, newRequest, redirectResponse, withCredentials, | |
| 1429 resource->mutableOptions(), errorMessage)) { | |
| 1430 resource->setCORSFailed(); | |
| 1431 context().addConsoleMessage(errorMessage); | |
| 1432 return ResourceRequestBlockedReason::Other; | |
| 1433 } | |
| 1434 } | |
| 1435 if (resource->getType() == Resource::Image && | |
| 1436 shouldDeferImageLoad(newRequest.url())) { | |
| 1437 return ResourceRequestBlockedReason::Other; | |
| 1438 } | |
| 1439 } | |
| 1440 | |
| 1441 ResourceTimingInfoMap::iterator it = m_resourceTimingInfoMap.find(resource); | |
| 1442 if (it != m_resourceTimingInfoMap.end()) { | |
| 1443 bool crossOrigin = IsCrossOrigin(redirectResponse.url(), newRequest.url()); | |
| 1444 it->value->addRedirect(redirectResponse, crossOrigin); | |
| 1445 } | |
| 1446 | |
| 1447 if (resource->getType() == Resource::MainResource) { | |
| 1448 DCHECK(m_navigationTimingInfo); | |
| 1449 bool crossOrigin = IsCrossOrigin(redirectResponse.url(), newRequest.url()); | |
| 1450 m_navigationTimingInfo->addRedirect(redirectResponse, crossOrigin); | |
| 1451 } | |
| 1452 | |
| 1453 newRequest.setAllowStoredCredentials(resource->options().allowCredentials == | |
| 1454 AllowStoredCredentials); | |
| 1455 willSendRequest(resource->identifier(), newRequest, redirectResponse, | |
| 1456 resource->options()); | |
| 1457 return ResourceRequestBlockedReason::None; | |
| 1458 } | |
| 1459 | |
| 1460 void ResourceFetcher::willSendRequest(unsigned long identifier, | |
| 1461 ResourceRequest& newRequest, | |
| 1462 const ResourceResponse& redirectResponse, | |
| 1463 const ResourceLoaderOptions& options) { | |
| 1464 context().dispatchWillSendRequest(identifier, newRequest, redirectResponse, | |
| 1465 options.initiatorInfo); | |
| 1466 } | |
| 1467 | |
| 1468 void ResourceFetcher::updateAllImageResourcePriorities() { | 1285 void ResourceFetcher::updateAllImageResourcePriorities() { |
| 1469 TRACE_EVENT0( | 1286 TRACE_EVENT0( |
| 1470 "blink", | 1287 "blink", |
| 1471 "ResourceLoadPriorityOptimizer::updateAllImageResourcePriorities"); | 1288 "ResourceLoadPriorityOptimizer::updateAllImageResourcePriorities"); |
| 1472 for (const auto& documentResource : m_documentResources) { | 1289 for (const auto& documentResource : m_documentResources) { |
| 1473 Resource* resource = documentResource.value.get(); | 1290 Resource* resource = documentResource.value.get(); |
| 1474 if (!resource || !resource->isImage() || !resource->isLoading()) | 1291 if (!resource || !resource->isImage() || !resource->isLoading()) |
| 1475 continue; | 1292 continue; |
| 1476 | 1293 |
| 1477 ResourcePriority resourcePriority = resource->priorityFromObservers(); | 1294 ResourcePriority resourcePriority = resource->priorityFromObservers(); |
| (...skipping 227 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1705 visitor->trace(m_context); | 1522 visitor->trace(m_context); |
| 1706 visitor->trace(m_archive); | 1523 visitor->trace(m_archive); |
| 1707 visitor->trace(m_loaders); | 1524 visitor->trace(m_loaders); |
| 1708 visitor->trace(m_nonBlockingLoaders); | 1525 visitor->trace(m_nonBlockingLoaders); |
| 1709 visitor->trace(m_documentResources); | 1526 visitor->trace(m_documentResources); |
| 1710 visitor->trace(m_preloads); | 1527 visitor->trace(m_preloads); |
| 1711 visitor->trace(m_resourceTimingInfoMap); | 1528 visitor->trace(m_resourceTimingInfoMap); |
| 1712 } | 1529 } |
| 1713 | 1530 |
| 1714 } // namespace blink | 1531 } // namespace blink |
| OLD | NEW |