[Quick Look] Rename PreviewLoader{,Client} to LegacyPreviewLoader{,Client}
[WebKit-https.git] / Source / WebCore / loader / SubresourceLoader.cpp
1 /*
2  * Copyright (C) 2006-2019 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * 1.  Redistributions of source code must retain the above copyright
9  *     notice, this list of conditions and the following disclaimer.
10  * 2.  Redistributions in binary form must reproduce the above copyright
11  *     notice, this list of conditions and the following disclaimer in the
12  *     documentation and/or other materials provided with the distribution.
13  * 3.  Neither the name of Apple Inc. ("Apple") nor the names of
14  *     its contributors may be used to endorse or promote products derived
15  *     from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 #include "config.h"
30 #include "SubresourceLoader.h"
31
32 #include "CachedRawResource.h"
33 #include "CachedResourceLoader.h"
34 #include "CrossOriginAccessControl.h"
35 #include "CustomHeaderFields.h"
36 #include "DiagnosticLoggingClient.h"
37 #include "DiagnosticLoggingKeys.h"
38 #include "Document.h"
39 #include "DocumentLoader.h"
40 #include "Frame.h"
41 #include "FrameLoader.h"
42 #include "HTTPParsers.h"
43 #include "LinkLoader.h"
44 #include "Logging.h"
45 #include "MemoryCache.h"
46 #include "Page.h"
47 #include "ResourceLoadObserver.h"
48 #include "ResourceTiming.h"
49 #include "RuntimeEnabledFeatures.h"
50 #include "Settings.h"
51 #include <wtf/CompletionHandler.h>
52 #include <wtf/Ref.h>
53 #include <wtf/RefCountedLeakCounter.h>
54 #include <wtf/StdLibExtras.h>
55 #include <wtf/SystemTracing.h>
56 #include <wtf/text/CString.h>
57
58 #if PLATFORM(IOS_FAMILY)
59 #include <RuntimeApplicationChecks.h>
60 #endif
61
62 #if ENABLE(CONTENT_EXTENSIONS)
63 #include "ResourceLoadInfo.h"
64 #endif
65
66 #if USE(QUICK_LOOK)
67 #include "LegacyPreviewLoader.h"
68 #include "PreviewConverter.h"
69 #endif
70
71 #undef RELEASE_LOG_IF_ALLOWED
72 #undef RELEASE_LOG_ERROR_IF_ALLOWED
73 #define RELEASE_LOG_IF_ALLOWED(fmt, ...) RELEASE_LOG_IF(isAlwaysOnLoggingAllowed(), ResourceLoading, "%p - SubresourceLoader::" fmt, this, ##__VA_ARGS__)
74 #define RELEASE_LOG_ERROR_IF_ALLOWED(fmt, ...) RELEASE_LOG_ERROR_IF(isAlwaysOnLoggingAllowed(), ResourceLoading, "%p - SubresourceLoader::" fmt, this, ##__VA_ARGS__)
75
76 namespace WebCore {
77
78 DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, subresourceLoaderCounter, ("SubresourceLoader"));
79
80 SubresourceLoader::RequestCountTracker::RequestCountTracker(CachedResourceLoader& cachedResourceLoader, const CachedResource& resource)
81     : m_cachedResourceLoader(cachedResourceLoader)
82     , m_resource(resource)
83 {
84     m_cachedResourceLoader.incrementRequestCount(m_resource);
85 }
86
87 SubresourceLoader::RequestCountTracker::~RequestCountTracker()
88 {
89     m_cachedResourceLoader.decrementRequestCount(m_resource);
90 }
91
92 SubresourceLoader::SubresourceLoader(Frame& frame, CachedResource& resource, const ResourceLoaderOptions& options)
93     : ResourceLoader(frame, options)
94     , m_resource(&resource)
95     , m_state(Uninitialized)
96     , m_requestCountTracker(std::in_place, frame.document()->cachedResourceLoader(), resource)
97 {
98 #ifndef NDEBUG
99     subresourceLoaderCounter.increment();
100 #endif
101 #if ENABLE(CONTENT_EXTENSIONS)
102     m_resourceType = ContentExtensions::toResourceType(resource.type());
103 #endif
104     m_canCrossOriginRequestsAskUserForCredentials = resource.type() == CachedResource::Type::MainResource || frame.settings().allowCrossOriginSubresourcesToAskForCredentials();
105 }
106
107 SubresourceLoader::~SubresourceLoader()
108 {
109     ASSERT(m_state != Initialized);
110     ASSERT(reachedTerminalState());
111 #ifndef NDEBUG
112     subresourceLoaderCounter.decrement();
113 #endif
114 }
115
116 void SubresourceLoader::create(Frame& frame, CachedResource& resource, ResourceRequest&& request, const ResourceLoaderOptions& options, CompletionHandler<void(RefPtr<SubresourceLoader>&&)>&& completionHandler)
117 {
118     auto subloader(adoptRef(*new SubresourceLoader(frame, resource, options)));
119 #if PLATFORM(IOS_FAMILY)
120     if (!IOSApplication::isWebProcess()) {
121         // On iOS, do not invoke synchronous resource load delegates while resource load scheduling
122         // is disabled to avoid re-entering style selection from a different thread (see <rdar://problem/9121719>).
123         // FIXME: This should be fixed for all ports in <https://bugs.webkit.org/show_bug.cgi?id=56647>.
124         subloader->m_iOSOriginalRequest = request;
125         return completionHandler(WTFMove(subloader));
126     }
127 #endif
128     subloader->init(WTFMove(request), [subloader = subloader.copyRef(), completionHandler = WTFMove(completionHandler)] (bool initialized) mutable {
129         if (!initialized)
130             return completionHandler(nullptr);
131         completionHandler(WTFMove(subloader));
132     });
133 }
134     
135 #if PLATFORM(IOS_FAMILY)
136 void SubresourceLoader::startLoading()
137 {
138     // FIXME: this should probably be removed.
139     ASSERT(!IOSApplication::isWebProcess());
140     init(ResourceRequest(m_iOSOriginalRequest), [this, protectedThis = makeRef(*this)] (bool success) {
141         if (!success)
142             return;
143         m_iOSOriginalRequest = ResourceRequest();
144         start();
145     });
146 }
147 #endif
148
149 CachedResource* SubresourceLoader::cachedResource()
150 {
151     return m_resource;
152 }
153
154 void SubresourceLoader::cancelIfNotFinishing()
155 {
156     if (m_state != Initialized)
157         return;
158
159     ResourceLoader::cancel();
160 }
161
162 void SubresourceLoader::init(ResourceRequest&& request, CompletionHandler<void(bool)>&& completionHandler)
163 {
164     ResourceLoader::init(WTFMove(request), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)] (bool initialized) mutable {
165         if (!initialized)
166             return completionHandler(false);
167         if (!m_documentLoader) {
168             ASSERT_NOT_REACHED();
169             RELEASE_LOG_ERROR(ResourceLoading, "SubresourceLoader::init: resource load canceled because document loader is null (frame = %p, frameLoader = %p, resourceID = %lu)", frame(), frameLoader(), identifier());
170             return completionHandler(false);
171         }
172         ASSERT(!reachedTerminalState());
173         m_state = Initialized;
174         m_documentLoader->addSubresourceLoader(this);
175         m_origin = m_resource->origin();
176         completionHandler(true);
177     });
178 }
179
180 bool SubresourceLoader::isSubresourceLoader() const
181 {
182     return true;
183 }
184
185 void SubresourceLoader::willSendRequestInternal(ResourceRequest&& newRequest, const ResourceResponse& redirectResponse, CompletionHandler<void(ResourceRequest&&)>&& completionHandler)
186 {
187     // Store the previous URL because the call to ResourceLoader::willSendRequest will modify it.
188     URL previousURL = request().url();
189     Ref<SubresourceLoader> protectedThis(*this);
190
191     if (!newRequest.url().isValid()) {
192         cancel(cannotShowURLError());
193         return completionHandler(WTFMove(newRequest));
194     }
195
196     if (newRequest.requester() != ResourceRequestBase::Requester::Main) {
197         tracePoint(SubresourceLoadWillStart);
198         ResourceLoadObserver::shared().logSubresourceLoading(m_frame.get(), newRequest, redirectResponse);
199     }
200
201     auto continueWillSendRequest = [this, protectedThis = makeRef(*this), redirectResponse] (CompletionHandler<void(ResourceRequest&&)>&& completionHandler, ResourceRequest&& newRequest) mutable {
202         if (newRequest.isNull() || reachedTerminalState())
203             return completionHandler(WTFMove(newRequest));
204
205         ResourceLoader::willSendRequestInternal(WTFMove(newRequest), redirectResponse, [this, protectedThis = WTFMove(protectedThis), completionHandler = WTFMove(completionHandler), redirectResponse] (ResourceRequest&& request) mutable {
206             if (reachedTerminalState())
207                 return completionHandler(WTFMove(request));
208
209             if (request.isNull()) {
210                 cancel();
211                 return completionHandler(WTFMove(request));
212             }
213
214             if (m_resource->type() == CachedResource::Type::MainResource && !redirectResponse.isNull())
215                 m_documentLoader->willContinueMainResourceLoadAfterRedirect(request);
216             completionHandler(WTFMove(request));
217         });
218     };
219
220     ASSERT(!newRequest.isNull());
221     if (!redirectResponse.isNull()) {
222         if (options().redirect != FetchOptions::Redirect::Follow) {
223             if (options().redirect == FetchOptions::Redirect::Error) {
224                 ResourceError error { errorDomainWebKitInternal, 0, request().url(), makeString("Not allowed to follow a redirection while loading ", request().url().string()), ResourceError::Type::AccessControl };
225
226                 if (m_frame && m_frame->document())
227                     m_frame->document()->addConsoleMessage(MessageSource::Security, MessageLevel::Error, error.localizedDescription());
228
229                 RELEASE_LOG_IF_ALLOWED("willSendRequestinternal: resource load canceled because not allowed to follow a redirect (frame = %p, frameLoader = %p, resourceID = %lu)", frame(), frameLoader(), identifier());
230
231                 cancel(error);
232                 return completionHandler(WTFMove(newRequest));
233             }
234
235             ResourceResponse opaqueRedirectedResponse = redirectResponse;
236             opaqueRedirectedResponse.setType(ResourceResponse::Type::Opaqueredirect);
237             opaqueRedirectedResponse.setTainting(ResourceResponse::Tainting::Opaqueredirect);
238             m_resource->responseReceived(opaqueRedirectedResponse);
239             if (reachedTerminalState()) {
240                 RELEASE_LOG_IF_ALLOWED("willSendRequestinternal: reached terminal state (frame = %p, frameLoader = %p, resourceID = %lu)", frame(), frameLoader(), identifier());
241                 return;
242             }
243
244             RELEASE_LOG_IF_ALLOWED("willSendRequestinternal: resource load completed (frame = %p, frameLoader = %p, resourceID = %lu)", frame(), frameLoader(), identifier());
245
246             NetworkLoadMetrics emptyMetrics;
247             didFinishLoading(emptyMetrics);
248             return completionHandler(WTFMove(newRequest));
249         } else if (m_redirectCount++ >= options().maxRedirectCount) {
250             RELEASE_LOG_IF_ALLOWED("willSendRequestinternal: resource load canceled because too many redirects (frame = %p, frameLoader = %p, resourceID = %lu)", frame(), frameLoader(), identifier());
251             cancel(ResourceError(String(), 0, request().url(), "Too many redirections"_s, ResourceError::Type::General));
252             return completionHandler(WTFMove(newRequest));
253         }
254
255         // CachedResources are keyed off their original request URL.
256         // Requesting the same original URL a second time can redirect to a unique second resource.
257         // Therefore, if a redirect to a different destination URL occurs, we should no longer consider this a revalidation of the first resource.
258         // Doing so would have us reusing the resource from the first request if the second request's revalidation succeeds.
259         if (newRequest.isConditional() && m_resource->resourceToRevalidate() && newRequest.url() != m_resource->resourceToRevalidate()->response().url()) {
260             newRequest.makeUnconditional();
261             MemoryCache::singleton().revalidationFailed(*m_resource);
262             if (m_frame && m_frame->page())
263                 m_frame->page()->diagnosticLoggingClient().logDiagnosticMessageWithResult(DiagnosticLoggingKeys::cachedResourceRevalidationKey(), emptyString(), DiagnosticLoggingResultFail, ShouldSample::Yes);
264         }
265
266         if (!m_documentLoader->cachedResourceLoader().updateRequestAfterRedirection(m_resource->type(), newRequest, options())) {
267             RELEASE_LOG_IF_ALLOWED("willSendRequestinternal: resource load canceled because something about updateRequestAfterRedirection (frame = %p, frameLoader = %p, resourceID = %lu)", frame(), frameLoader(), identifier());
268             cancel();
269             return completionHandler(WTFMove(newRequest));
270         }
271
272         String errorDescription;
273         if (!checkRedirectionCrossOriginAccessControl(request(), redirectResponse, newRequest, errorDescription)) {
274             String errorMessage = "Cross-origin redirection to " + newRequest.url().string() + " denied by Cross-Origin Resource Sharing policy: " + errorDescription;
275             if (m_frame && m_frame->document())
276                 m_frame->document()->addConsoleMessage(MessageSource::Security, MessageLevel::Error, errorMessage);
277             RELEASE_LOG_IF_ALLOWED("willSendRequestinternal: resource load canceled because crosss-origin redirection denied by CORS policy (frame = %p, frameLoader = %p, resourceID = %lu)", frame(), frameLoader(), identifier());
278             cancel(ResourceError(String(), 0, request().url(), errorMessage, ResourceError::Type::AccessControl));
279             return completionHandler(WTFMove(newRequest));
280         }
281
282         if (m_resource->isImage() && m_documentLoader->cachedResourceLoader().shouldDeferImageLoad(newRequest.url())) {
283             RELEASE_LOG_IF_ALLOWED("willSendRequestinternal: resource load canceled because it's an image that should be defered (frame = %p, frameLoader = %p, resourceID = %lu)", frame(), frameLoader(), identifier());
284             cancel();
285             return completionHandler(WTFMove(newRequest));
286         }
287         m_loadTiming.addRedirect(redirectResponse.url(), newRequest.url());
288         m_resource->redirectReceived(WTFMove(newRequest), redirectResponse, [completionHandler = WTFMove(completionHandler), continueWillSendRequest = WTFMove(continueWillSendRequest)] (ResourceRequest&& request) mutable {
289             continueWillSendRequest(WTFMove(completionHandler), WTFMove(request));
290         });
291         return;
292     }
293
294     continueWillSendRequest(WTFMove(completionHandler), WTFMove(newRequest));
295 }
296
297 void SubresourceLoader::didSendData(unsigned long long bytesSent, unsigned long long totalBytesToBeSent)
298 {
299     ASSERT(m_state == Initialized);
300     Ref<SubresourceLoader> protectedThis(*this);
301     m_resource->didSendData(bytesSent, totalBytesToBeSent);
302 }
303
304 #if USE(QUICK_LOOK)
305
306 bool SubresourceLoader::shouldCreatePreviewLoaderForResponse(const ResourceResponse& response) const
307 {
308     if (m_resource->type() != CachedResource::Type::MainResource)
309         return false;
310
311     if (m_previewLoader)
312         return false;
313
314     return PreviewConverter::supportsMIMEType(response.mimeType());
315 }
316
317 void SubresourceLoader::didReceivePreviewResponse(const ResourceResponse& response)
318 {
319     ASSERT(m_state == Initialized);
320     ASSERT(!response.isNull());
321     ASSERT(m_resource);
322     m_resource->previewResponseReceived(response);
323     ResourceLoader::didReceivePreviewResponse(response);
324 }
325
326 #endif
327
328 void SubresourceLoader::didReceiveResponse(const ResourceResponse& response, CompletionHandler<void()>&& policyCompletionHandler)
329 {
330     ASSERT(!response.isNull());
331     ASSERT(m_state == Initialized);
332
333     CompletionHandlerCallingScope completionHandlerCaller(WTFMove(policyCompletionHandler));
334
335 #if USE(QUICK_LOOK)
336     if (shouldCreatePreviewLoaderForResponse(response)) {
337         m_previewLoader = LegacyPreviewLoader::create(*this, response);
338         if (m_previewLoader->didReceiveResponse(response))
339             return;
340     }
341 #endif
342 #if ENABLE(SERVICE_WORKER)
343     // Implementing step 10 of https://fetch.spec.whatwg.org/#main-fetch for service worker responses.
344     if (response.source() == ResourceResponse::Source::ServiceWorker && response.url() != request().url()) {
345         auto& loader = m_documentLoader->cachedResourceLoader();
346         if (!loader.allowedByContentSecurityPolicy(m_resource->type(), response.url(), options(), ContentSecurityPolicy::RedirectResponseReceived::Yes)) {
347             RELEASE_LOG_IF_ALLOWED("didReceiveResponse: canceling load because not allowed by content policy (frame = %p, frameLoader = %p, resourceID = %lu)", frame(), frameLoader(), identifier());
348             cancel(ResourceError({ }, 0, response.url(), { }, ResourceError::Type::General));
349             return;
350         }
351     }
352 #endif
353
354     // We want redirect responses to be processed through willSendRequestInternal. Exceptions are
355     // redirection with no Location headers and fetch in manual redirect mode. Or in rare circumstances,
356     // cases of too many redirects from CFNetwork (<rdar://problem/30610988>).
357 #if !PLATFORM(COCOA)
358     ASSERT(response.httpStatusCode() < 300 || response.httpStatusCode() >= 400 || response.httpStatusCode() == 304 || !response.httpHeaderField(HTTPHeaderName::Location) || response.type() == ResourceResponse::Type::Opaqueredirect);
359 #endif
360
361     // Reference the object in this method since the additional processing can do
362     // anything including removing the last reference to this object; one example of this is 3266216.
363     Ref<SubresourceLoader> protectedThis(*this);
364
365     if (shouldIncludeCertificateInfo())
366         response.includeCertificateInfo();
367
368     if (m_resource->resourceToRevalidate()) {
369         if (response.httpStatusCode() == 304) {
370             // 304 Not modified / Use local copy
371             // Existing resource is ok, just use it updating the expiration time.
372             ResourceResponse revalidationResponse = response;
373             revalidationResponse.setSource(ResourceResponse::Source::MemoryCacheAfterValidation);
374             m_resource->setResponse(revalidationResponse);
375             MemoryCache::singleton().revalidationSucceeded(*m_resource, revalidationResponse);
376             if (m_frame && m_frame->page())
377                 m_frame->page()->diagnosticLoggingClient().logDiagnosticMessageWithResult(DiagnosticLoggingKeys::cachedResourceRevalidationKey(), emptyString(), DiagnosticLoggingResultPass, ShouldSample::Yes);
378             if (!reachedTerminalState())
379                 ResourceLoader::didReceiveResponse(revalidationResponse, [completionHandlerCaller = WTFMove(completionHandlerCaller)] { });
380             return;
381         }
382         // Did not get 304 response, continue as a regular resource load.
383         MemoryCache::singleton().revalidationFailed(*m_resource);
384         if (m_frame && m_frame->page())
385             m_frame->page()->diagnosticLoggingClient().logDiagnosticMessageWithResult(DiagnosticLoggingKeys::cachedResourceRevalidationKey(), emptyString(), DiagnosticLoggingResultFail, ShouldSample::Yes);
386     }
387
388     String errorDescription;
389     if (!checkResponseCrossOriginAccessControl(response, errorDescription)) {
390         if (m_frame && m_frame->document())
391             m_frame->document()->addConsoleMessage(MessageSource::Security, MessageLevel::Error, errorDescription);
392         RELEASE_LOG_IF_ALLOWED("didReceiveResponse: canceling load because of cross origin access control (frame = %p, frameLoader = %p, resourceID = %lu)", frame(), frameLoader(), identifier());
393         cancel(ResourceError(String(), 0, request().url(), errorDescription, ResourceError::Type::AccessControl));
394         return;
395     }
396
397     if (options().redirect == FetchOptions::Redirect::Manual && response.isRedirection()) {
398         ResourceResponse opaqueRedirectedResponse = response;
399         opaqueRedirectedResponse.setType(ResourceResponse::Type::Opaqueredirect);
400         opaqueRedirectedResponse.setTainting(ResourceResponse::Tainting::Opaqueredirect);
401         m_resource->responseReceived(opaqueRedirectedResponse);
402         if (!reachedTerminalState())
403             ResourceLoader::didReceiveResponse(opaqueRedirectedResponse, [completionHandlerCaller = WTFMove(completionHandlerCaller)] { });
404         return;
405     }
406     m_resource->responseReceived(response);
407     if (reachedTerminalState())
408         return;
409
410     bool isResponseMultipart = response.isMultipart();
411     if (options().mode != FetchOptions::Mode::Navigate)
412         LinkLoader::loadLinksFromHeader(response.httpHeaderField(HTTPHeaderName::Link), m_documentLoader->url(), *m_frame->document(), LinkLoader::MediaAttributeCheck::SkipMediaAttributeCheck);
413     ResourceLoader::didReceiveResponse(response, [this, protectedThis = WTFMove(protectedThis), isResponseMultipart, completionHandlerCaller = WTFMove(completionHandlerCaller)]() mutable {
414         if (reachedTerminalState())
415             return;
416
417         // FIXME: Main resources have a different set of rules for multipart than images do.
418         // Hopefully we can merge those 2 paths.
419         if (isResponseMultipart && m_resource->type() != CachedResource::Type::MainResource) {
420             m_loadingMultipartContent = true;
421
422             // We don't count multiParts in a CachedResourceLoader's request count
423             m_requestCountTracker = WTF::nullopt;
424             if (!m_resource->isImage()) {
425                 RELEASE_LOG_IF_ALLOWED("didReceiveResponse: canceling load because something about a multi-part non-image (frame = %p, frameLoader = %p, resourceID = %lu)", frame(), frameLoader(), identifier());
426                 cancel();
427                 return;
428             }
429         }
430
431         auto* buffer = resourceData();
432         if (m_loadingMultipartContent && buffer && buffer->size()) {
433             // The resource data will change as the next part is loaded, so we need to make a copy.
434             m_resource->finishLoading(buffer->copy().ptr());
435             clearResourceData();
436             // Since a subresource loader does not load multipart sections progressively, data was delivered to the loader all at once.
437             // After the first multipart section is complete, signal to delegates that this load is "finished"
438             NetworkLoadMetrics emptyMetrics;
439             m_documentLoader->subresourceLoaderFinishedLoadingOnePart(this);
440             didFinishLoadingOnePart(emptyMetrics);
441         }
442
443         checkForHTTPStatusCodeError();
444
445         if (m_inAsyncResponsePolicyCheck)
446             m_policyForResponseCompletionHandler = completionHandlerCaller.release();
447     });
448 }
449
450 void SubresourceLoader::didReceiveResponsePolicy()
451 {
452     ASSERT(m_inAsyncResponsePolicyCheck);
453     m_inAsyncResponsePolicyCheck = false;
454     if (auto completionHandler = WTFMove(m_policyForResponseCompletionHandler))
455         completionHandler();
456 }
457
458 void SubresourceLoader::didReceiveData(const char* data, unsigned length, long long encodedDataLength, DataPayloadType dataPayloadType)
459 {
460 #if USE(QUICK_LOOK)
461     if (auto previewLoader = m_previewLoader.get()) {
462         if (previewLoader->didReceiveData(data, length))
463             return;
464     }
465 #endif
466
467     didReceiveDataOrBuffer(data, length, nullptr, encodedDataLength, dataPayloadType);
468 }
469
470 void SubresourceLoader::didReceiveBuffer(Ref<SharedBuffer>&& buffer, long long encodedDataLength, DataPayloadType dataPayloadType)
471 {
472 #if USE(QUICK_LOOK)
473     if (auto previewLoader = m_previewLoader.get()) {
474         if (previewLoader->didReceiveBuffer(buffer.get()))
475             return;
476     }
477 #endif
478
479     didReceiveDataOrBuffer(nullptr, 0, WTFMove(buffer), encodedDataLength, dataPayloadType);
480 }
481
482 void SubresourceLoader::didReceiveDataOrBuffer(const char* data, int length, RefPtr<SharedBuffer>&& buffer, long long encodedDataLength, DataPayloadType dataPayloadType)
483 {
484     ASSERT(m_resource);
485
486     if (m_resource->response().httpStatusCode() >= 400 && !m_resource->shouldIgnoreHTTPStatusCodeErrors())
487         return;
488     ASSERT(!m_resource->resourceToRevalidate());
489     ASSERT(!m_resource->errorOccurred());
490     ASSERT(m_state == Initialized);
491     // Reference the object in this method since the additional processing can do
492     // anything including removing the last reference to this object; one example of this is 3266216.
493     Ref<SubresourceLoader> protectedThis(*this);
494
495     ResourceLoader::didReceiveDataOrBuffer(data, length, buffer.copyRef(), encodedDataLength, dataPayloadType);
496
497     if (!m_loadingMultipartContent) {
498         if (auto* resourceData = this->resourceData())
499             m_resource->updateBuffer(*resourceData);
500         else
501             m_resource->updateData(buffer ? buffer->data() : data, buffer ? buffer->size() : length);
502     }
503 }
504
505 bool SubresourceLoader::checkForHTTPStatusCodeError()
506 {
507     if (m_resource->response().httpStatusCode() < 400 || m_resource->shouldIgnoreHTTPStatusCodeErrors())
508         return false;
509
510     m_state = Finishing;
511     m_resource->error(CachedResource::LoadError);
512     cancel();
513     return true;
514 }
515
516 static void logResourceLoaded(Frame* frame, CachedResource::Type type)
517 {
518     if (!frame || !frame->page())
519         return;
520
521     String resourceType;
522     switch (type) {
523     case CachedResource::Type::MainResource:
524         resourceType = DiagnosticLoggingKeys::mainResourceKey();
525         break;
526     case CachedResource::Type::ImageResource:
527         resourceType = DiagnosticLoggingKeys::imageKey();
528         break;
529 #if ENABLE(XSLT)
530     case CachedResource::Type::XSLStyleSheet:
531 #endif
532     case CachedResource::Type::CSSStyleSheet:
533         resourceType = DiagnosticLoggingKeys::styleSheetKey();
534         break;
535     case CachedResource::Type::Script:
536         resourceType = DiagnosticLoggingKeys::scriptKey();
537         break;
538     case CachedResource::Type::FontResource:
539 #if ENABLE(SVG_FONTS)
540     case CachedResource::Type::SVGFontResource:
541 #endif
542         resourceType = DiagnosticLoggingKeys::fontKey();
543         break;
544     case CachedResource::Type::Beacon:
545     case CachedResource::Type::Ping:
546     case CachedResource::Type::MediaResource:
547     case CachedResource::Type::Icon:
548     case CachedResource::Type::RawResource:
549         resourceType = DiagnosticLoggingKeys::rawKey();
550         break;
551     case CachedResource::Type::SVGDocumentResource:
552         resourceType = DiagnosticLoggingKeys::svgDocumentKey();
553         break;
554 #if ENABLE(APPLICATION_MANIFEST)
555     case CachedResource::Type::ApplicationManifest:
556         resourceType = DiagnosticLoggingKeys::applicationManifestKey();
557         break;
558 #endif
559     case CachedResource::Type::LinkPrefetch:
560 #if ENABLE(VIDEO_TRACK)
561     case CachedResource::Type::TextTrackResource:
562 #endif
563         resourceType = DiagnosticLoggingKeys::otherKey();
564         break;
565     }
566     
567     frame->page()->diagnosticLoggingClient().logDiagnosticMessage(DiagnosticLoggingKeys::resourceLoadedKey(), resourceType, ShouldSample::Yes);
568 }
569
570 bool SubresourceLoader::checkResponseCrossOriginAccessControl(const ResourceResponse& response, String& errorDescription)
571 {
572     if (!m_resource->isCrossOrigin() || options().mode != FetchOptions::Mode::Cors)
573         return true;
574
575 #if ENABLE(SERVICE_WORKER)
576     if (response.source() == ResourceResponse::Source::ServiceWorker)
577         return response.tainting() != ResourceResponse::Tainting::Opaque;
578 #endif
579
580     ASSERT(m_origin);
581
582     return passesAccessControlCheck(response, options().credentials == FetchOptions::Credentials::Include ? StoredCredentialsPolicy::Use : StoredCredentialsPolicy::DoNotUse, *m_origin, errorDescription);
583 }
584
585 bool SubresourceLoader::checkRedirectionCrossOriginAccessControl(const ResourceRequest& previousRequest, const ResourceResponse& redirectResponse, ResourceRequest& newRequest, String& errorMessage)
586 {
587     bool crossOriginFlag = m_resource->isCrossOrigin();
588     bool isNextRequestCrossOrigin = m_origin && !m_origin->canRequest(newRequest.url());
589
590     if (isNextRequestCrossOrigin)
591         m_resource->setCrossOrigin();
592
593     ASSERT(options().mode != FetchOptions::Mode::SameOrigin || !m_resource->isCrossOrigin());
594
595     // Implementing https://fetch.spec.whatwg.org/#concept-http-redirect-fetch step 7 & 8.
596     if (options().mode == FetchOptions::Mode::Cors) {
597         if (m_resource->isCrossOrigin() && !isValidCrossOriginRedirectionURL(newRequest.url())) {
598             errorMessage = "URL is either a non-HTTP URL or contains credentials."_s;
599             return false;
600         }
601
602         ASSERT(m_origin);
603         if (crossOriginFlag && !passesAccessControlCheck(redirectResponse, options().storedCredentialsPolicy, *m_origin, errorMessage))
604             return false;
605     }
606
607     bool redirectingToNewOrigin = false;
608     if (m_resource->isCrossOrigin()) {
609         if (!crossOriginFlag && isNextRequestCrossOrigin)
610             redirectingToNewOrigin = true;
611         else
612             redirectingToNewOrigin = !protocolHostAndPortAreEqual(previousRequest.url(), newRequest.url());
613     }
614
615     // Implementing https://fetch.spec.whatwg.org/#concept-http-redirect-fetch step 10.
616     if (crossOriginFlag && redirectingToNewOrigin)
617         m_origin = SecurityOrigin::createUnique();
618
619     // Implementing https://fetch.spec.whatwg.org/#concept-http-redirect-fetch step 14.
620     updateReferrerPolicy(redirectResponse.httpHeaderField(HTTPHeaderName::ReferrerPolicy));
621     
622     if (options().mode == FetchOptions::Mode::Cors && redirectingToNewOrigin) {
623         cleanHTTPRequestHeadersForAccessControl(newRequest, options().httpHeadersToKeep);
624         updateRequestForAccessControl(newRequest, *m_origin, options().storedCredentialsPolicy);
625     }
626     
627     updateRequestReferrer(newRequest, referrerPolicy(), previousRequest.httpReferrer());
628
629     return true;
630 }
631
632 void SubresourceLoader::updateReferrerPolicy(const String& referrerPolicyValue)
633 {
634     if (auto referrerPolicy = parseReferrerPolicy(referrerPolicyValue, ReferrerPolicySource::HTTPHeader)) {
635         ASSERT(*referrerPolicy != ReferrerPolicy::EmptyString);
636         setReferrerPolicy(*referrerPolicy);
637     }
638 }
639
640 void SubresourceLoader::didFinishLoading(const NetworkLoadMetrics& networkLoadMetrics)
641 {
642     RELEASE_LOG_IF_ALLOWED("didFinishLoading: (frame = %p, frameLoader = %p, resourceID = %lu)", frame(), frameLoader(), identifier());
643
644 #if USE(QUICK_LOOK)
645     if (auto previewLoader = m_previewLoader.get()) {
646         if (previewLoader->didFinishLoading())
647             return;
648     }
649 #endif
650
651     if (m_state != Initialized)
652         return;
653     ASSERT(!reachedTerminalState());
654     ASSERT(!m_resource->resourceToRevalidate());
655     // FIXME (129394): We should cancel the load when a decode error occurs instead of continuing the load to completion.
656     ASSERT(!m_resource->errorOccurred() || m_resource->status() == CachedResource::DecodeError || !m_resource->isLoading());
657     LOG(ResourceLoading, "Received '%s'.", m_resource->url().string().latin1().data());
658     logResourceLoaded(m_frame.get(), m_resource->type());
659
660     Ref<SubresourceLoader> protectedThis(*this);
661     CachedResourceHandle<CachedResource> protectResource(m_resource);
662
663     // FIXME: Remove this with deprecatedNetworkLoadMetrics.
664     m_loadTiming.setResponseEnd(MonotonicTime::now());
665
666     if (networkLoadMetrics.isComplete())
667         reportResourceTiming(networkLoadMetrics);
668     else {
669         // This is the legacy path for platforms (and ResourceHandle paths) that do not provide
670         // complete load metrics in didFinishLoad. In those cases, fall back to the possibility
671         // that they populated partial load timing information on the ResourceResponse.
672         reportResourceTiming(m_resource->response().deprecatedNetworkLoadMetrics());
673     }
674
675     if (m_resource->type() != CachedResource::Type::MainResource)
676         tracePoint(SubresourceLoadDidEnd);
677
678     m_state = Finishing;
679     m_resource->finishLoading(resourceData());
680
681     if (wasCancelled()) {
682         RELEASE_LOG_IF_ALLOWED("didFinishLoading: was canceled (frame = %p, frameLoader = %p, resourceID = %lu)", frame(), frameLoader(), identifier());
683         return;
684     }
685
686     m_resource->finish();
687     ASSERT(!reachedTerminalState());
688     didFinishLoadingOnePart(networkLoadMetrics);
689     notifyDone(LoadCompletionType::Finish);
690
691     if (reachedTerminalState()) {
692         RELEASE_LOG_IF_ALLOWED("didFinishLoading: reached terminal state (frame = %p, frameLoader = %p, resourceID = %lu)", frame(), frameLoader(), identifier());
693         return;
694     }
695     releaseResources();
696 }
697
698 void SubresourceLoader::didFail(const ResourceError& error)
699 {
700     RELEASE_LOG_IF_ALLOWED("didFail: (frame = %p, frameLoader = %p, resourceID = %lu, type = %d, code = %d)", frame(), frameLoader(), identifier(), static_cast<int>(error.type()), error.errorCode());
701
702 #if USE(QUICK_LOOK)
703     if (auto previewLoader = m_previewLoader.get())
704         previewLoader->didFail();
705 #endif
706
707     if (m_state != Initialized)
708         return;
709
710     ASSERT(!reachedTerminalState());
711     LOG(ResourceLoading, "Failed to load '%s'.\n", m_resource->url().string().latin1().data());
712
713     if (m_frame->document() && error.isAccessControl() && m_resource->type() != CachedResource::Type::Ping)
714         m_frame->document()->addConsoleMessage(MessageSource::Security, MessageLevel::Error, error.localizedDescription());
715
716     Ref<SubresourceLoader> protectedThis(*this);
717     CachedResourceHandle<CachedResource> protectResource(m_resource);
718     m_state = Finishing;
719
720     if (m_resource->type() != CachedResource::Type::MainResource)
721         tracePoint(SubresourceLoadDidEnd);
722
723     if (m_resource->resourceToRevalidate())
724         MemoryCache::singleton().revalidationFailed(*m_resource);
725     m_resource->setResourceError(error);
726     if (!m_resource->isPreloaded())
727         MemoryCache::singleton().remove(*m_resource);
728     m_resource->error(CachedResource::LoadError);
729     cleanupForError(error);
730     notifyDone(LoadCompletionType::Cancel);
731     if (reachedTerminalState())
732         return;
733     releaseResources();
734 }
735
736 void SubresourceLoader::willCancel(const ResourceError& error)
737 {
738     RELEASE_LOG_IF_ALLOWED("willCancel: (frame = %p, frameLoader = %p, resourceID = %lu, type = %d, code = %d)", frame(), frameLoader(), identifier(), static_cast<int>(error.type()), error.errorCode());
739
740 #if PLATFORM(IOS_FAMILY)
741     // Since we defer initialization to scheduling time on iOS but
742     // CachedResourceLoader stores resources in the memory cache immediately,
743     // m_resource might be cached despite its loader not being initialized.
744     if (m_state != Initialized && m_state != Uninitialized)
745 #else
746     if (m_state != Initialized)
747 #endif
748         return;
749
750     ASSERT(!reachedTerminalState());
751     LOG(ResourceLoading, "Cancelled load of '%s'.\n", m_resource->url().string().latin1().data());
752
753     Ref<SubresourceLoader> protectedThis(*this);
754 #if PLATFORM(IOS_FAMILY)
755     m_state = m_state == Uninitialized ? CancelledWhileInitializing : Finishing;
756 #else
757     m_state = Finishing;
758 #endif
759     auto& memoryCache = MemoryCache::singleton();
760     if (m_resource->resourceToRevalidate())
761         memoryCache.revalidationFailed(*m_resource);
762     m_resource->setResourceError(error);
763     memoryCache.remove(*m_resource);
764 }
765
766 void SubresourceLoader::didCancel(const ResourceError&)
767 {
768     if (m_state == Uninitialized)
769         return;
770
771     if (m_resource->type() != CachedResource::Type::MainResource)
772         tracePoint(SubresourceLoadDidEnd);
773
774     m_resource->cancelLoad();
775     notifyDone(LoadCompletionType::Cancel);
776 }
777
778 void SubresourceLoader::notifyDone(LoadCompletionType type)
779 {
780     if (reachedTerminalState())
781         return;
782
783     m_requestCountTracker = WTF::nullopt;
784     bool shouldPerformPostLoadActions = true;
785 #if PLATFORM(IOS_FAMILY)
786     if (m_state == CancelledWhileInitializing)
787         shouldPerformPostLoadActions = false;
788 #endif
789     m_documentLoader->cachedResourceLoader().loadDone(type, shouldPerformPostLoadActions);
790     if (reachedTerminalState())
791         return;
792     m_documentLoader->removeSubresourceLoader(type, this);
793 }
794
795 void SubresourceLoader::releaseResources()
796 {
797     ASSERT(!reachedTerminalState());
798 #if PLATFORM(IOS_FAMILY)
799     if (m_state != Uninitialized && m_state != CancelledWhileInitializing)
800 #else
801     if (m_state != Uninitialized)
802 #endif
803         m_resource->clearLoader();
804     m_resource = nullptr;
805     ResourceLoader::releaseResources();
806 }
807
808 void SubresourceLoader::reportResourceTiming(const NetworkLoadMetrics& networkLoadMetrics)
809 {
810     if (!RuntimeEnabledFeatures::sharedFeatures().resourceTimingEnabled())
811         return;
812
813     if (!ResourceTimingInformation::shouldAddResourceTiming(*m_resource))
814         return;
815
816     Document* document = m_documentLoader->cachedResourceLoader().document();
817     if (!document)
818         return;
819
820     SecurityOrigin& origin = m_origin ? *m_origin : document->securityOrigin();
821     auto resourceTiming = ResourceTiming::fromLoad(*m_resource, m_resource->initiatorName(), m_loadTiming, networkLoadMetrics, origin);
822
823     // Worker resources loaded here are all CachedRawResources loaded through WorkerThreadableLoader.
824     // Pass the ResourceTiming information on so that WorkerThreadableLoader may add them to the
825     // Worker's Performance object.
826     if (options().initiatorContext == InitiatorContext::Worker) {
827         ASSERT(m_origin);
828         ASSERT(is<CachedRawResource>(m_resource));
829         downcast<CachedRawResource>(*m_resource).finishedTimingForWorkerLoad(WTFMove(resourceTiming));
830         return;
831     }
832
833     ASSERT(options().initiatorContext == InitiatorContext::Document);
834     m_documentLoader->cachedResourceLoader().resourceTimingInformation().addResourceTiming(*m_resource, *document, WTFMove(resourceTiming));
835 }
836
837 const HTTPHeaderMap* SubresourceLoader::originalHeaders() const
838 {
839     return (m_resource  && m_resource->originalRequest()) ? &m_resource->originalRequest()->httpHeaderFields() : nullptr;
840 }
841
842 }
843
844 #undef RELEASE_LOG_IF_ALLOWED
845 #undef RELEASE_LOG_ERROR_IF_ALLOWED