2 * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
3 * Copyright (C) 2011 Google Inc. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of Apple Inc. ("Apple") nor the names of
15 * its contributors may be used to endorse or promote products derived
16 * from this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
19 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 #include "DocumentLoader.h"
33 #include "ApplicationCacheHost.h"
34 #include "ArchiveResourceCollection.h"
35 #include "CachedPage.h"
36 #include "CachedRawResource.h"
37 #include "CachedResourceLoader.h"
38 #include "DOMWindow.h"
40 #include "DocumentParser.h"
41 #include "DocumentWriter.h"
43 #include "FormState.h"
44 #include "FrameLoader.h"
45 #include "FrameLoaderClient.h"
46 #include "FrameTree.h"
47 #include "HTMLFormElement.h"
48 #include "HTMLFrameOwnerElement.h"
49 #include "HTTPHeaderNames.h"
50 #include "HistoryItem.h"
51 #include "IconController.h"
52 #include "InspectorInstrumentation.h"
54 #include "MainFrame.h"
55 #include "MemoryCache.h"
57 #include "PolicyChecker.h"
58 #include "ProgressTracker.h"
59 #include "ResourceHandle.h"
60 #include "SchemeRegistry.h"
61 #include "ScriptController.h"
62 #include "SecurityPolicy.h"
64 #include "SubresourceLoader.h"
65 #include "TextResourceDecoder.h"
66 #include <wtf/Assertions.h>
67 #include <wtf/NeverDestroyed.h>
69 #include <wtf/text/CString.h>
70 #include <wtf/text/WTFString.h>
72 #if ENABLE(WEB_ARCHIVE) || ENABLE(MHTML)
73 #include "ArchiveFactory.h"
76 #if ENABLE(CONTENT_FILTERING)
77 #include "ContentFilter.h"
82 static void cancelAll(const ResourceLoaderMap& loaders)
84 Vector<RefPtr<ResourceLoader>> loadersCopy;
85 copyValuesToVector(loaders, loadersCopy);
86 for (auto& loader : loadersCopy)
90 static void setAllDefersLoading(const ResourceLoaderMap& loaders, bool defers)
92 Vector<RefPtr<ResourceLoader>> loadersCopy;
93 copyValuesToVector(loaders, loadersCopy);
94 for (auto& loader : loadersCopy)
95 loader->setDefersLoading(defers);
98 static bool areAllLoadersPageCacheAcceptable(const ResourceLoaderMap& loaders)
100 Vector<RefPtr<ResourceLoader>> loadersCopy;
101 copyValuesToVector(loaders, loadersCopy);
102 for (auto& loader : loadersCopy) {
103 if (!loader->frameLoader() || !loader->frameLoader()->frame().page())
106 CachedResource* cachedResource = MemoryCache::singleton().resourceForRequest(loader->request(), loader->frameLoader()->frame().page()->sessionID());
110 // Only image and XHR loads do prevent the page from entering the PageCache.
111 // All non-image loads will prevent the page from entering the PageCache.
112 if (!cachedResource->isImage() && !cachedResource->areAllClientsXMLHttpRequests())
118 DocumentLoader::DocumentLoader(const ResourceRequest& req, const SubstituteData& substituteData)
119 : m_deferMainResourceDataLoad(true)
121 , m_cachedResourceLoader(CachedResourceLoader::create(this))
123 , m_originalRequest(req)
124 , m_substituteData(substituteData)
125 , m_originalRequestCopy(req)
127 , m_originalSubstituteDataWasValid(substituteData.isValid())
129 , m_isStopping(false)
130 , m_gotFirstByte(false)
131 , m_isClientRedirect(false)
132 , m_isLoadingMultipartContent(false)
133 , m_wasOnloadHandled(false)
134 , m_stopRecordingResponses(false)
135 , m_substituteResourceDeliveryTimer(*this, &DocumentLoader::substituteResourceDeliveryTimerFired)
136 , m_didCreateGlobalHistoryEntry(false)
137 , m_loadingMainResource(false)
138 , m_timeOfLastDataReceived(0.0)
139 , m_identifierForLoadWithoutResourceLoader(0)
140 , m_dataLoadTimer(*this, &DocumentLoader::handleSubstituteDataLoadNow)
141 , m_waitingForContentPolicy(false)
142 , m_subresourceLoadersArePageCacheAcceptable(false)
143 , m_applicationCacheHost(std::make_unique<ApplicationCacheHost>(*this))
144 #if ENABLE(CONTENT_FILTERING)
145 , m_contentFilter(!substituteData.isValid() ? ContentFilter::createIfEnabled(*this) : nullptr)
150 FrameLoader* DocumentLoader::frameLoader() const
154 return &m_frame->loader();
157 SubresourceLoader* DocumentLoader::mainResourceLoader() const
159 return m_mainResource ? m_mainResource->loader() : 0;
162 DocumentLoader::~DocumentLoader()
164 ASSERT(!m_frame || frameLoader()->activeDocumentLoader() != this || !isLoading());
165 ASSERT_WITH_MESSAGE(!m_waitingForContentPolicy, "The content policy callback should never outlive its DocumentLoader.");
166 if (m_iconLoadDecisionCallback)
167 m_iconLoadDecisionCallback->invalidate();
168 if (m_iconDataCallback)
169 m_iconDataCallback->invalidate();
170 m_cachedResourceLoader->clearDocumentLoader();
175 PassRefPtr<SharedBuffer> DocumentLoader::mainResourceData() const
177 if (m_substituteData.isValid())
178 return m_substituteData.content()->copy();
180 return m_mainResource->resourceBuffer();
184 Document* DocumentLoader::document() const
186 if (m_frame && m_frame->loader().documentLoader() == this)
187 return m_frame->document();
191 const ResourceRequest& DocumentLoader::originalRequest() const
193 return m_originalRequest;
196 const ResourceRequest& DocumentLoader::originalRequestCopy() const
198 return m_originalRequestCopy;
201 const ResourceRequest& DocumentLoader::request() const
206 ResourceRequest& DocumentLoader::request()
211 const URL& DocumentLoader::url() const
213 return request().url();
216 void DocumentLoader::replaceRequestURLForSameDocumentNavigation(const URL& url)
218 m_originalRequestCopy.setURL(url);
219 m_request.setURL(url);
222 void DocumentLoader::setRequest(const ResourceRequest& req)
224 // Replacing an unreachable URL with alternate content looks like a server-side
225 // redirect at this point, but we can replace a committed dataSource.
226 bool handlingUnreachableURL = false;
228 handlingUnreachableURL = m_substituteData.isValid() && !m_substituteData.failingURL().isEmpty();
230 if (handlingUnreachableURL)
233 // We should never be getting a redirect callback after the data
234 // source is committed, except in the unreachable URL case. It
235 // would be a WebFoundation bug if it sent a redirect callback after commit.
236 ASSERT(!m_committed);
241 void DocumentLoader::setMainDocumentError(const ResourceError& error)
243 m_mainDocumentError = error;
244 frameLoader()->client().setMainDocumentError(this, error);
247 void DocumentLoader::mainReceivedError(const ResourceError& error)
249 ASSERT(!error.isNull());
251 if (m_identifierForLoadWithoutResourceLoader) {
252 ASSERT(!mainResourceLoader());
253 frameLoader()->client().dispatchDidFailLoading(this, m_identifierForLoadWithoutResourceLoader, error);
256 // There is a bug in CFNetwork where callbacks can be dispatched even when loads are deferred.
257 // See <rdar://problem/6304600> for more details.
259 ASSERT(!mainResourceLoader() || !mainResourceLoader()->defersLoading());
262 m_applicationCacheHost->failedLoadingMainResource();
266 setMainDocumentError(error);
267 clearMainResourceLoader();
268 frameLoader()->receivedMainResourceError(error);
271 // Cancels the data source's pending loads. Conceptually, a data source only loads
272 // one document at a time, but one document may have many related resources.
273 // stopLoading will stop all loads initiated by the data source,
274 // but not loads initiated by child frames' data sources -- that's the WebFrame's job.
275 void DocumentLoader::stopLoading()
277 RefPtr<Frame> protectFrame(m_frame);
278 Ref<DocumentLoader> protectLoader(*this);
280 // In some rare cases, calling FrameLoader::stopLoading could cause isLoading() to return false.
281 // (This can happen when there's a single XMLHttpRequest currently loading and stopLoading causes it
282 // to stop loading. Because of this, we need to save it so we don't return early.
283 bool loading = isLoading();
285 // We may want to audit the existing subresource loaders when we are on a page which has completed
286 // loading but there are subresource loads during cancellation. This must be done before the
287 // frame->stopLoading() call, which may evict the CachedResources, which we rely on to check
288 // the type of the resource loads.
289 if (loading && m_committed && !mainResourceLoader() && !m_subresourceLoaders.isEmpty())
290 m_subresourceLoadersArePageCacheAcceptable = areAllLoadersPageCacheAcceptable(m_subresourceLoaders);
293 // Attempt to stop the frame if the document loader is loading, or if it is done loading but
294 // still parsing. Failure to do so can cause a world leak.
295 Document* doc = m_frame->document();
297 if (loading || doc->parsing())
298 m_frame->loader().stopLoading(UnloadEventPolicyNone);
301 // Always cancel multipart loaders
302 cancelAll(m_multipartSubresourceLoaders);
304 // Appcache uses ResourceHandle directly, DocumentLoader doesn't count these loads.
305 m_applicationCacheHost->stopLoadingInFrame(m_frame);
307 #if ENABLE(WEB_ARCHIVE) || ENABLE(MHTML)
308 clearArchiveResources();
312 // If something above restarted loading we might run into mysterious crashes like
313 // https://bugs.webkit.org/show_bug.cgi?id=62764 and <rdar://problem/9328684>
314 ASSERT(!isLoading());
318 // We might run in to infinite recursion if we're stopping loading as the result of
319 // detaching from the frame, so break out of that recursion here.
320 // See <rdar://problem/9673866> for more details.
326 FrameLoader* frameLoader = DocumentLoader::frameLoader();
328 if (isLoadingMainResource()) {
329 // Stop the main resource loader and let it send the cancelled message.
330 cancelMainResourceLoad(frameLoader->cancelledError(m_request));
331 } else if (!m_subresourceLoaders.isEmpty() || !m_plugInStreamLoaders.isEmpty()) {
332 // The main resource loader already finished loading. Set the cancelled error on the
333 // document and let the subresourceLoaders and pluginLoaders send individual cancelled messages below.
334 setMainDocumentError(frameLoader->cancelledError(m_request));
336 // If there are no resource loaders, we need to manufacture a cancelled message.
337 // (A back/forward navigation has no resource loaders because its resources are cached.)
338 mainReceivedError(frameLoader->cancelledError(m_request));
341 // We always need to explicitly cancel the Document's parser when stopping the load.
342 // Otherwise cancelling the parser while starting the next page load might result
343 // in unexpected side effects such as erroneous event dispatch. ( http://webkit.org/b/117112 )
344 if (Document* document = this->document())
345 document->cancelParsing();
347 stopLoadingSubresources();
348 stopLoadingPlugIns();
350 m_isStopping = false;
353 void DocumentLoader::commitIfReady()
357 frameLoader()->commitProvisionalLoad();
361 bool DocumentLoader::isLoading() const
363 // if (document() && document()->hasActiveParser())
365 // FIXME: The above code should be enabled, but it seems to cause
366 // http/tests/security/feed-urls-from-remote.html to timeout on Mac WK1
367 // see http://webkit.org/b/110554 and http://webkit.org/b/110401
369 return isLoadingMainResource() || !m_subresourceLoaders.isEmpty() || !m_plugInStreamLoaders.isEmpty();
372 void DocumentLoader::notifyFinished(CachedResource* resource)
374 ASSERT_UNUSED(resource, m_mainResource == resource);
375 ASSERT(m_mainResource);
376 if (!m_mainResource->errorOccurred() && !m_mainResource->wasCanceled()) {
377 finishedLoading(m_mainResource->loadFinishTime());
381 if (m_request.cachePolicy() == ReturnCacheDataDontLoad && !m_mainResource->wasCanceled()) {
382 frameLoader()->retryAfterFailedCacheOnlyMainResourceLoad();
386 mainReceivedError(m_mainResource->resourceError());
389 void DocumentLoader::finishedLoading(double finishTime)
391 // There is a bug in CFNetwork where callbacks can be dispatched even when loads are deferred.
392 // See <rdar://problem/6304600> for more details.
394 ASSERT(!m_frame->page()->defersLoading() || InspectorInstrumentation::isDebuggerPaused(m_frame));
397 Ref<DocumentLoader> protect(*this);
399 if (m_identifierForLoadWithoutResourceLoader) {
400 // A didFinishLoading delegate might try to cancel the load (despite it
401 // being finished). Clear m_identifierForLoadWithoutResourceLoader
402 // before calling dispatchDidFinishLoading so that we don't later try to
403 // cancel the already-finished substitute load.
404 unsigned long identifier = m_identifierForLoadWithoutResourceLoader;
405 m_identifierForLoadWithoutResourceLoader = 0;
406 frameLoader()->notifier().dispatchDidFinishLoading(this, identifier, finishTime);
409 maybeFinishLoadingMultipartContent();
411 double responseEndTime = finishTime;
412 if (!responseEndTime)
413 responseEndTime = m_timeOfLastDataReceived;
414 if (!responseEndTime)
415 responseEndTime = monotonicallyIncreasingTime();
416 timing().setResponseEnd(responseEndTime);
422 if (!maybeCreateArchive()) {
423 // If this is an empty document, it will not have actually been created yet. Commit dummy data so that
424 // DocumentWriter::begin() gets called and creates the Document.
427 frameLoader()->client().finishedLoading(this);
431 if (!m_mainDocumentError.isNull())
433 clearMainResourceLoader();
434 if (!frameLoader()->stateMachine().creatingInitialEmptyDocument())
435 frameLoader()->checkLoadComplete();
437 // If the document specified an application cache manifest, it violates the author's intent if we store it in the memory cache
438 // and deny the appcache the chance to intercept it in the future, so remove from the memory cache.
440 if (m_mainResource && m_frame->document()->hasManifest())
441 MemoryCache::singleton().remove(*m_mainResource);
443 m_applicationCacheHost->finishedLoadingMainResource();
446 bool DocumentLoader::isPostOrRedirectAfterPost(const ResourceRequest& newRequest, const ResourceResponse& redirectResponse)
448 if (newRequest.httpMethod() == "POST")
451 int status = redirectResponse.httpStatusCode();
452 if (((status >= 301 && status <= 303) || status == 307)
453 && m_originalRequest.httpMethod() == "POST")
459 void DocumentLoader::handleSubstituteDataLoadNow()
461 ResourceResponse response = m_substituteData.response();
462 if (response.url().isEmpty())
463 response = ResourceResponse(m_request.url(), m_substituteData.mimeType(), m_substituteData.content()->size(), m_substituteData.textEncoding());
465 responseReceived(0, response);
468 void DocumentLoader::startDataLoadTimer()
470 m_dataLoadTimer.startOneShot(0);
472 #if HAVE(RUNLOOP_TIMER)
473 if (SchedulePairHashSet* scheduledPairs = m_frame->page()->scheduledRunLoopPairs())
474 m_dataLoadTimer.schedule(*scheduledPairs);
478 void DocumentLoader::handleSubstituteDataLoadSoon()
480 if (!m_deferMainResourceDataLoad || frameLoader()->loadsSynchronously())
481 handleSubstituteDataLoadNow();
483 startDataLoadTimer();
486 void DocumentLoader::redirectReceived(CachedResource* resource, ResourceRequest& request, const ResourceResponse& redirectResponse)
488 ASSERT_UNUSED(resource, resource == m_mainResource);
489 willSendRequest(request, redirectResponse);
492 void DocumentLoader::willSendRequest(ResourceRequest& newRequest, const ResourceResponse& redirectResponse)
494 // Note that there are no asserts here as there are for the other callbacks. This is due to the
495 // fact that this "callback" is sent when starting every load, and the state of callback
496 // deferrals plays less of a part in this function in preventing the bad behavior deferring
497 // callbacks is meant to prevent.
498 ASSERT(!newRequest.isNull());
500 if (!frameLoader()->checkIfFormActionAllowedByCSP(newRequest.url())) {
501 cancelMainResourceLoad(frameLoader()->cancelledError(newRequest));
505 ASSERT(timing().fetchStart());
506 if (!redirectResponse.isNull()) {
507 // If the redirecting url is not allowed to display content from the target origin,
508 // then block the redirect.
509 Ref<SecurityOrigin> redirectingOrigin(SecurityOrigin::create(redirectResponse.url()));
510 if (!redirectingOrigin.get().canDisplay(newRequest.url())) {
511 FrameLoader::reportLocalLoadFailed(m_frame, newRequest.url().string());
512 cancelMainResourceLoad(frameLoader()->cancelledError(newRequest));
515 timing().addRedirect(redirectResponse.url(), newRequest.url());
518 // Update cookie policy base URL as URL changes, except for subframes, which use the
519 // URL of the main frame which doesn't change when we redirect.
520 if (frameLoader()->frame().isMainFrame())
521 newRequest.setFirstPartyForCookies(newRequest.url());
523 // If we're fielding a redirect in response to a POST, force a load from origin, since
524 // this is a common site technique to return to a page viewing some data that the POST
526 // Also, POST requests always load from origin, but this does not affect subresources.
527 if (newRequest.cachePolicy() == UseProtocolCachePolicy && isPostOrRedirectAfterPost(newRequest, redirectResponse))
528 newRequest.setCachePolicy(ReloadIgnoringCacheData);
530 Frame& topFrame = m_frame->tree().top();
531 if (&topFrame != m_frame) {
532 if (!frameLoader()->mixedContentChecker().canDisplayInsecureContent(topFrame.document()->securityOrigin(), MixedContentChecker::ContentType::Active, newRequest.url())) {
533 cancelMainResourceLoad(frameLoader()->cancelledError(newRequest));
538 #if ENABLE(CONTENT_FILTERING)
539 if (m_contentFilter && redirectResponse.isNull()) {
540 m_contentFilter->willSendRequest(newRequest, redirectResponse);
541 if (newRequest.isNull())
546 setRequest(newRequest);
548 if (!redirectResponse.isNull()) {
549 // We checked application cache for initial URL, now we need to check it for redirected one.
550 ASSERT(!m_substituteData.isValid());
551 m_applicationCacheHost->maybeLoadMainResourceForRedirect(newRequest, m_substituteData);
552 if (m_substituteData.isValid()) {
553 RELEASE_ASSERT(m_mainResource);
554 ResourceLoader* loader = m_mainResource->loader();
555 m_identifierForLoadWithoutResourceLoader = loader ? loader->identifier() : m_mainResource->identifierForLoadWithoutResourceLoader();
559 // FIXME: Ideally we'd stop the I/O until we hear back from the navigation policy delegate
560 // listener. But there's no way to do that in practice. So instead we cancel later if the
561 // listener tells us to. In practice that means the navigation policy needs to be decided
562 // synchronously for these redirect cases.
563 if (redirectResponse.isNull())
566 frameLoader()->policyChecker().checkNavigationPolicy(newRequest, [this](const ResourceRequest& request, PassRefPtr<FormState>, bool shouldContinue) {
567 continueAfterNavigationPolicy(request, shouldContinue);
571 void DocumentLoader::continueAfterNavigationPolicy(const ResourceRequest&, bool shouldContinue)
574 stopLoadingForPolicyChange();
575 else if (m_substituteData.isValid()) {
576 // A redirect resulted in loading substitute data.
577 ASSERT(timing().redirectCount());
579 // We need to remove our reference to the CachedResource in favor of a SubstituteData load.
580 // This will probably trigger the cancellation of the CachedResource's underlying ResourceLoader, though there is a
581 // small chance that the resource is being loaded by a different Frame, preventing the ResourceLoader from being cancelled.
582 // If the ResourceLoader is indeed cancelled, it would normally send resource load callbacks.
583 // However, from an API perspective, this isn't a cancellation. Therefore, sever our relationship with the network load,
584 // but prevent the ResourceLoader from sending ResourceLoadNotifier callbacks.
585 RefPtr<ResourceLoader> resourceLoader = mainResourceLoader();
586 if (resourceLoader) {
587 ASSERT(resourceLoader->shouldSendResourceLoadCallbacks());
588 resourceLoader->setSendCallbackPolicy(DoNotSendCallbacks);
594 resourceLoader->setSendCallbackPolicy(SendCallbacks);
595 handleSubstituteDataLoadSoon();
599 void DocumentLoader::responseReceived(CachedResource* resource, const ResourceResponse& response)
601 ASSERT_UNUSED(resource, m_mainResource == resource);
602 Ref<DocumentLoader> protect(*this);
603 bool willLoadFallback = m_applicationCacheHost->maybeLoadFallbackForMainResponse(request(), response);
605 // The memory cache doesn't understand the application cache or its caching rules. So if a main resource is served
606 // from the application cache, ensure we don't save the result for future use.
607 if (willLoadFallback)
608 MemoryCache::singleton().remove(*m_mainResource);
610 if (willLoadFallback)
613 const auto& commonHeaders = response.httpHeaderFields().commonHeaders();
614 auto it = commonHeaders.find(HTTPHeaderName::XFrameOptions);
615 if (it != commonHeaders.end()) {
616 String content = it->value;
617 ASSERT(m_identifierForLoadWithoutResourceLoader || m_mainResource);
618 unsigned long identifier = m_identifierForLoadWithoutResourceLoader ? m_identifierForLoadWithoutResourceLoader : m_mainResource->identifier();
620 if (frameLoader()->shouldInterruptLoadForXFrameOptions(content, response.url(), identifier)) {
621 InspectorInstrumentation::continueAfterXFrameOptionsDenied(m_frame, *this, identifier, response);
622 String message = "Refused to display '" + response.url().stringCenterEllipsizedToLength() + "' in a frame because it set 'X-Frame-Options' to '" + content + "'.";
623 frame()->document()->addConsoleMessage(MessageSource::Security, MessageLevel::Error, message, identifier);
624 frame()->document()->enforceSandboxFlags(SandboxOrigin);
625 if (HTMLFrameOwnerElement* ownerElement = frame()->ownerElement())
626 ownerElement->dispatchEvent(Event::create(eventNames().loadEvent, false, false));
628 // The load event might have detached this frame. In that case, the load will already have been cancelled during detach.
630 cancelMainResourceLoad(frameLoader()->cancelledError(m_request));
635 // There is a bug in CFNetwork where callbacks can be dispatched even when loads are deferred.
636 // See <rdar://problem/6304600> for more details.
638 ASSERT(!mainResourceLoader() || !mainResourceLoader()->defersLoading());
641 if (m_isLoadingMultipartContent) {
643 m_mainResource->clear();
644 } else if (response.isMultipart())
645 m_isLoadingMultipartContent = true;
647 m_response = response;
649 if (m_identifierForLoadWithoutResourceLoader) {
650 addResponse(m_response);
651 frameLoader()->notifier().dispatchDidReceiveResponse(this, m_identifierForLoadWithoutResourceLoader, m_response, 0);
654 ASSERT(!m_waitingForContentPolicy);
655 ASSERT(frameLoader());
656 m_waitingForContentPolicy = true;
658 // Always show content with valid substitute data.
659 if (m_substituteData.isValid()) {
660 continueAfterContentPolicy(PolicyUse);
665 // Respect the hidden FTP Directory Listing pref so it can be tested even if the policy delegate might otherwise disallow it
666 if (m_frame->settings().forceFTPDirectoryListings() && m_response.mimeType() == "application/x-ftp-directory") {
667 continueAfterContentPolicy(PolicyUse);
672 frameLoader()->policyChecker().checkContentPolicy(m_response, [this](PolicyAction policy) {
673 continueAfterContentPolicy(policy);
677 void DocumentLoader::continueAfterContentPolicy(PolicyAction policy)
679 ASSERT(m_waitingForContentPolicy);
680 m_waitingForContentPolicy = false;
684 URL url = m_request.url();
685 const String& mimeType = m_response.mimeType();
689 // Prevent remote web archives from loading because they can claim to be from any domain and thus avoid cross-domain security checks (4120255).
690 bool isRemoteWebArchive = (equalIgnoringCase("application/x-webarchive", mimeType)
691 || equalIgnoringCase("application/x-mimearchive", mimeType)
693 || equalIgnoringCase("message/rfc822", mimeType)
695 || equalIgnoringCase("multipart/related", mimeType))
696 && !m_substituteData.isValid() && !SchemeRegistry::shouldTreatURLSchemeAsLocal(url.protocol());
697 if (!frameLoader()->client().canShowMIMEType(mimeType) || isRemoteWebArchive) {
698 frameLoader()->policyChecker().cannotShowMIMEType(m_response);
699 // Check reachedTerminalState since the load may have already been canceled inside of _handleUnimplementablePolicyWithErrorCode::.
700 stopLoadingForPolicyChange();
706 case PolicyDownload: {
707 // m_mainResource can be null, e.g. when loading a substitute resource from application cache.
708 if (!m_mainResource) {
709 mainReceivedError(frameLoader()->client().cannotShowURLError(m_request));
713 if (ResourceLoader* mainResourceLoader = this->mainResourceLoader())
714 InspectorInstrumentation::continueWithPolicyDownload(m_frame, *this, mainResourceLoader->identifier(), m_response);
716 // When starting the request, we didn't know that it would result in download and not navigation. Now we know that main document URL didn't change.
717 // Download may use this knowledge for purposes unrelated to cookies, notably for setting file quarantine data.
718 frameLoader()->setOriginalURLForDownloadRequest(m_request);
719 frameLoader()->client().convertMainResourceLoadToDownload(this, m_request, m_response);
721 // It might have gone missing
722 if (mainResourceLoader())
723 static_cast<ResourceLoader*>(mainResourceLoader())->didFail(interruptedForPolicyChangeError());
727 if (ResourceLoader* mainResourceLoader = this->mainResourceLoader())
728 InspectorInstrumentation::continueWithPolicyIgnore(m_frame, *this, mainResourceLoader->identifier(), m_response);
729 stopLoadingForPolicyChange();
733 ASSERT_NOT_REACHED();
736 if (m_response.isHTTP()) {
737 int status = m_response.httpStatusCode(); // Status may be zero when loading substitute data, in particular from a WebArchive.
738 if (status && (status < 200 || status >= 300)) {
739 bool hostedByObject = frameLoader()->isHostedByObjectElement();
741 frameLoader()->handleFallbackContent();
742 // object elements are no longer rendered after we fallback, so don't
743 // keep trying to process data from their load
746 cancelMainResourceLoad(frameLoader()->cancelledError(m_request));
750 if (!isStopping() && m_substituteData.isValid() && isLoadingMainResource()) {
751 if (m_substituteData.content()->size())
752 dataReceived(0, m_substituteData.content()->data(), m_substituteData.content()->size());
753 if (isLoadingMainResource())
758 void DocumentLoader::commitLoad(const char* data, int length)
760 // Both unloading the old page and parsing the new page may execute JavaScript which destroys the datasource
761 // by starting a new load, so retain temporarily.
762 RefPtr<Frame> protectFrame(m_frame);
763 Ref<DocumentLoader> protectLoader(*this);
766 FrameLoader* frameLoader = DocumentLoader::frameLoader();
769 #if ENABLE(WEB_ARCHIVE) || ENABLE(MHTML)
770 if (ArchiveFactory::isArchiveMimeType(response().mimeType()))
773 frameLoader->client().committedLoad(this, data, length);
775 if (isMultipartReplacingLoad())
776 frameLoader->client().didReplaceMultipartContent();
779 ResourceError DocumentLoader::interruptedForPolicyChangeError() const
781 return frameLoader()->client().interruptedForPolicyChangeError(request());
784 void DocumentLoader::stopLoadingForPolicyChange()
786 ResourceError error = interruptedForPolicyChangeError();
787 error.setIsCancellation(true);
788 cancelMainResourceLoad(error);
791 void DocumentLoader::commitData(const char* bytes, size_t length)
793 if (!m_gotFirstByte) {
794 m_gotFirstByte = true;
795 m_writer.begin(documentURL(), false);
796 m_writer.setDocumentWasLoadedAsPartOfNavigation();
798 if (SecurityPolicy::allowSubstituteDataAccessToLocal() && m_originalSubstituteDataWasValid) {
799 // If this document was loaded with substituteData, then the document can
800 // load local resources. See https://bugs.webkit.org/show_bug.cgi?id=16756
801 // and https://bugs.webkit.org/show_bug.cgi?id=19760 for further
803 m_frame->document()->securityOrigin()->grantLoadLocalResources();
806 if (frameLoader()->stateMachine().creatingInitialEmptyDocument())
810 // The origin is the MHTML file, we need to set the base URL to the document encoded in the MHTML so
811 // relative URLs are resolved properly.
812 if (m_archive && m_archive->type() == Archive::MHTML)
813 m_frame->document()->setBaseURLOverride(m_archive->mainResource()->url());
816 // Call receivedFirstData() exactly once per load. We should only reach this point multiple times
817 // for multipart loads, and FrameLoader::isReplacing() will be true after the first time.
818 if (!isMultipartReplacingLoad())
819 frameLoader()->receivedFirstData();
821 // The load could be canceled under receivedFirstData(), which makes delegate calls and even sometimes dispatches DOM events.
827 if (overrideEncoding().isNull()) {
829 encoding = response().textEncodingName();
830 #if ENABLE(WEB_ARCHIVE)
831 if (m_archive && m_archive->type() == Archive::WebArchive)
832 encoding = m_archive->mainResource()->textEncoding();
836 encoding = overrideEncoding();
839 m_writer.setEncoding(encoding, userChosen);
842 #if ENABLE(CONTENT_EXTENSIONS)
843 DocumentStyleSheetCollection& styleSheetCollection = m_frame->document()->styleSheetCollection();
845 for (auto& pendingStyleSheet : m_pendingNamedContentExtensionStyleSheets)
846 styleSheetCollection.maybeAddContentExtensionSheet(pendingStyleSheet.key, *pendingStyleSheet.value);
847 for (auto& pendingSelectorEntry : m_pendingContentExtensionDisplayNoneSelectors) {
848 for (const auto& pendingSelector : pendingSelectorEntry.value)
849 styleSheetCollection.addDisplayNoneSelector(pendingSelectorEntry.key, pendingSelector.first, pendingSelector.second);
852 m_pendingNamedContentExtensionStyleSheets.clear();
853 m_pendingContentExtensionDisplayNoneSelectors.clear();
856 ASSERT(m_frame->document()->parsing());
857 m_writer.addData(bytes, length);
860 void DocumentLoader::dataReceived(CachedResource* resource, const char* data, int length)
864 ASSERT_UNUSED(resource, resource == m_mainResource);
865 ASSERT(!m_response.isNull());
867 // There is a bug in CFNetwork where callbacks can be dispatched even when loads are deferred.
868 // See <rdar://problem/6304600> for more details.
870 ASSERT(!mainResourceLoader() || !mainResourceLoader()->defersLoading());
873 if (m_identifierForLoadWithoutResourceLoader)
874 frameLoader()->notifier().dispatchDidReceiveData(this, m_identifierForLoadWithoutResourceLoader, data, length, -1);
876 m_applicationCacheHost->mainResourceDataReceived(data, length, -1, false);
877 m_timeOfLastDataReceived = monotonicallyIncreasingTime();
879 if (!isMultipartReplacingLoad())
880 commitLoad(data, length);
883 void DocumentLoader::setupForReplace()
885 if (!mainResourceData())
888 frameLoader()->client().willReplaceMultipartContent();
890 maybeFinishLoadingMultipartContent();
891 maybeCreateArchive();
893 frameLoader()->setReplacing();
894 m_gotFirstByte = false;
896 stopLoadingSubresources();
897 stopLoadingPlugIns();
898 #if ENABLE(WEB_ARCHIVE) || ENABLE(MHTML)
899 clearArchiveResources();
903 void DocumentLoader::checkLoadComplete()
905 if (!m_frame || isLoading())
908 ASSERT(this == frameLoader()->activeDocumentLoader());
909 m_frame->document()->domWindow()->finishedLoading();
912 void DocumentLoader::attachToFrame(Frame& frame)
914 if (m_frame == &frame)
919 m_writer.setFrame(&frame);
923 m_hasEverBeenAttached = true;
927 void DocumentLoader::attachToFrame()
932 void DocumentLoader::detachFromFrame()
935 if (m_hasEverBeenAttached)
936 ASSERT_WITH_MESSAGE(m_frame, "detachFromFrame() is being called on a DocumentLoader twice without an attachToFrame() inbetween");
938 ASSERT_WITH_MESSAGE(m_frame, "detachFromFrame() is being called on a DocumentLoader that has never attached to any Frame");
940 RefPtr<Frame> protectFrame(m_frame);
941 Ref<DocumentLoader> protectLoader(*this);
943 // It never makes sense to have a document loader that is detached from its
944 // frame have any loads active, so kill all the loads.
946 if (m_mainResource && m_mainResource->hasClient(this))
947 m_mainResource->removeClient(this);
948 #if ENABLE(CONTENT_FILTERING)
949 m_contentFilter = nullptr;
952 m_applicationCacheHost->setDOMApplicationCache(nullptr);
954 cancelPolicyCheckIfNeeded();
956 // Even though we ASSERT at the top of this method that we have an m_frame, we're seeing crashes where m_frame is null.
957 // This means either that a DocumentLoader is detaching twice, or is detaching before ever having attached.
958 // Until we figure out how that is happening, null check m_frame before dereferencing it here.
959 // <rdar://problem/21293082> and https://bugs.webkit.org/show_bug.cgi?id=146786
961 InspectorInstrumentation::loaderDetachedFromFrame(*m_frame, *this);
966 void DocumentLoader::clearMainResourceLoader()
968 m_loadingMainResource = false;
970 if (this == frameLoader()->activeDocumentLoader())
974 bool DocumentLoader::isLoadingInAPISense() const
976 // Once a frame has loaded, we no longer need to consider subresources,
977 // but we still need to consider subframes.
978 if (frameLoader()->state() != FrameStateComplete) {
979 if (m_frame->settings().needsIsLoadingInAPISenseQuirk() && !m_subresourceLoaders.isEmpty())
982 Document* doc = m_frame->document();
983 if ((isLoadingMainResource() || !m_frame->document()->loadEventFinished()) && isLoading())
985 if (m_cachedResourceLoader->requestCount())
987 if (doc->processingLoadEvent())
989 if (doc->hasActiveParser())
992 return frameLoader()->subframeIsLoading();
995 bool DocumentLoader::maybeCreateArchive()
997 #if !ENABLE(WEB_ARCHIVE) && !ENABLE(MHTML)
1001 // Give the archive machinery a crack at this document. If the MIME type is not an archive type, it will return 0.
1002 m_archive = ArchiveFactory::create(m_response.url(), mainResourceData().get(), m_response.mimeType());
1006 addAllArchiveResources(m_archive.get());
1007 ArchiveResource* mainResource = m_archive->mainResource();
1008 m_parsedArchiveData = mainResource->data();
1009 m_writer.setMIMEType(mainResource->mimeType());
1011 ASSERT(m_frame->document());
1012 commitData(mainResource->data()->data(), mainResource->data()->size());
1014 #endif // !ENABLE(WEB_ARCHIVE) && !ENABLE(MHTML)
1017 #if ENABLE(WEB_ARCHIVE) || ENABLE(MHTML)
1019 void DocumentLoader::setArchive(PassRefPtr<Archive> archive)
1021 m_archive = archive;
1022 addAllArchiveResources(m_archive.get());
1025 void DocumentLoader::addAllArchiveResources(Archive* archive)
1027 if (!m_archiveResourceCollection)
1028 m_archiveResourceCollection = std::make_unique<ArchiveResourceCollection>();
1034 m_archiveResourceCollection->addAllResources(archive);
1037 // FIXME: Adding a resource directly to a DocumentLoader/ArchiveResourceCollection seems like bad design, but is API some apps rely on.
1038 // Can we change the design in a manner that will let us deprecate that API without reducing functionality of those apps?
1039 void DocumentLoader::addArchiveResource(PassRefPtr<ArchiveResource> resource)
1041 if (!m_archiveResourceCollection)
1042 m_archiveResourceCollection = std::make_unique<ArchiveResourceCollection>();
1048 m_archiveResourceCollection->addResource(resource);
1051 PassRefPtr<Archive> DocumentLoader::popArchiveForSubframe(const String& frameName, const URL& url)
1053 return m_archiveResourceCollection ? m_archiveResourceCollection->popSubframeArchive(frameName, url) : PassRefPtr<Archive>(0);
1056 void DocumentLoader::clearArchiveResources()
1058 m_archiveResourceCollection = nullptr;
1059 m_substituteResourceDeliveryTimer.stop();
1062 SharedBuffer* DocumentLoader::parsedArchiveData() const
1064 return m_parsedArchiveData.get();
1067 #endif // ENABLE(WEB_ARCHIVE) || ENABLE(MHTML)
1069 ArchiveResource* DocumentLoader::archiveResourceForURL(const URL& url) const
1071 if (!m_archiveResourceCollection)
1073 ArchiveResource* resource = m_archiveResourceCollection->archiveResourceForURL(url);
1074 if (!resource || resource->shouldIgnoreWhenUnarchiving())
1079 PassRefPtr<ArchiveResource> DocumentLoader::mainResource() const
1081 RefPtr<SharedBuffer> data = mainResourceData();
1083 data = SharedBuffer::create();
1085 auto& response = this->response();
1086 return ArchiveResource::create(data, response.url(), response.mimeType(), response.textEncodingName(), frame()->tree().uniqueName());
1089 PassRefPtr<ArchiveResource> DocumentLoader::subresource(const URL& url) const
1094 CachedResource* resource = m_cachedResourceLoader->cachedResource(url);
1095 if (!resource || !resource->isLoaded())
1096 return archiveResourceForURL(url);
1098 if (resource->type() == CachedResource::MainResource)
1101 auto* data = resource->resourceBuffer();
1105 return ArchiveResource::create(data, url, resource->response());
1108 Vector<RefPtr<ArchiveResource>> DocumentLoader::subresources() const
1113 Vector<RefPtr<ArchiveResource>> subresources;
1115 for (auto& cachedResourceHandle : m_cachedResourceLoader->allCachedResources().values()) {
1116 if (RefPtr<ArchiveResource> subresource = this->subresource(URL(ParsedURLString, cachedResourceHandle->url())))
1117 subresources.append(WTF::move(subresource));
1120 return subresources;
1123 void DocumentLoader::deliverSubstituteResourcesAfterDelay()
1125 if (m_pendingSubstituteResources.isEmpty())
1127 ASSERT(m_frame && m_frame->page());
1128 if (m_frame->page()->defersLoading())
1130 if (!m_substituteResourceDeliveryTimer.isActive())
1131 m_substituteResourceDeliveryTimer.startOneShot(0);
1134 void DocumentLoader::substituteResourceDeliveryTimerFired()
1136 if (m_pendingSubstituteResources.isEmpty())
1138 ASSERT(m_frame && m_frame->page());
1139 if (m_frame->page()->defersLoading())
1142 SubstituteResourceMap copy;
1143 copy.swap(m_pendingSubstituteResources);
1145 SubstituteResourceMap::const_iterator end = copy.end();
1146 for (SubstituteResourceMap::const_iterator it = copy.begin(); it != end; ++it) {
1147 RefPtr<ResourceLoader> loader = it->key;
1148 SubstituteResource* resource = it->value.get();
1151 resource->deliver(*loader);
1153 // A null resource means that we should fail the load.
1154 // FIXME: Maybe we should use another error here - something like "not in cache".
1155 loader->didFail(loader->cannotShowURLError());
1161 bool DocumentLoader::isSubstituteLoadPending(ResourceLoader* loader) const
1163 return m_pendingSubstituteResources.contains(loader);
1167 void DocumentLoader::cancelPendingSubstituteLoad(ResourceLoader* loader)
1169 if (m_pendingSubstituteResources.isEmpty())
1171 m_pendingSubstituteResources.remove(loader);
1172 if (m_pendingSubstituteResources.isEmpty())
1173 m_substituteResourceDeliveryTimer.stop();
1176 #if ENABLE(WEB_ARCHIVE) || ENABLE(MHTML)
1177 bool DocumentLoader::scheduleArchiveLoad(ResourceLoader* loader, const ResourceRequest& request)
1179 if (ArchiveResource* resource = archiveResourceForURL(request.url())) {
1180 scheduleSubstituteResourceLoad(*loader, *resource);
1187 switch (m_archive->type()) {
1188 #if ENABLE(WEB_ARCHIVE)
1189 case Archive::WebArchive:
1190 // WebArchiveDebugMode means we fail loads instead of trying to fetch them from the network if they're not in the archive.
1191 return m_frame->settings().webArchiveDebugModeEnabled() && ArchiveFactory::isArchiveMimeType(responseMIMEType());
1194 case Archive::MHTML:
1195 return true; // Always fail the load for resources not included in the MHTML.
1201 #endif // ENABLE(WEB_ARCHIVE)
1203 void DocumentLoader::scheduleSubstituteResourceLoad(ResourceLoader& loader, SubstituteResource& resource)
1205 m_pendingSubstituteResources.set(&loader, &resource);
1206 deliverSubstituteResourcesAfterDelay();
1209 void DocumentLoader::addResponse(const ResourceResponse& r)
1211 if (!m_stopRecordingResponses)
1212 m_responses.append(r);
1215 void DocumentLoader::stopRecordingResponses()
1217 m_stopRecordingResponses = true;
1218 m_responses.shrinkToFit();
1221 void DocumentLoader::setTitle(const StringWithDirection& title)
1223 if (m_pageTitle == title)
1226 frameLoader()->willChangeTitle(this);
1227 m_pageTitle = title;
1228 frameLoader()->didChangeTitle(this);
1231 URL DocumentLoader::urlForHistory() const
1233 // Return the URL to be used for history and B/F list.
1234 // Returns nil for WebDataProtocol URLs that aren't alternates
1235 // for unreachable URLs, because these can't be stored in history.
1236 if (m_substituteData.isValid() && !m_substituteData.shouldRevealToSessionHistory())
1237 return unreachableURL();
1239 return m_originalRequestCopy.url();
1242 bool DocumentLoader::urlForHistoryReflectsFailure() const
1244 return m_substituteData.isValid() || m_response.httpStatusCode() >= 400;
1247 const URL& DocumentLoader::originalURL() const
1249 return m_originalRequestCopy.url();
1252 const URL& DocumentLoader::responseURL() const
1254 return m_response.url();
1257 URL DocumentLoader::documentURL() const
1259 URL url = substituteData().response().url();
1260 #if ENABLE(WEB_ARCHIVE)
1261 if (url.isEmpty() && m_archive && m_archive->type() == Archive::WebArchive)
1262 url = m_archive->mainResource()->url();
1265 url = m_request.url();
1267 url = m_response.url();
1271 const String& DocumentLoader::responseMIMEType() const
1273 return m_response.mimeType();
1276 const String& DocumentLoader::currentContentType() const
1278 return m_writer.mimeType();
1282 // FIXME: This method seems to violate the encapsulation of this class.
1283 void DocumentLoader::setResponseMIMEType(const String& responseMimeType)
1285 m_response.setMimeType(responseMimeType);
1289 const URL& DocumentLoader::unreachableURL() const
1291 return m_substituteData.failingURL();
1294 void DocumentLoader::setDefersLoading(bool defers)
1296 // Multiple frames may be loading the same main resource simultaneously. If deferral state changes,
1297 // each frame's DocumentLoader will try to send a setDefersLoading() to the same underlying ResourceLoader. Ensure only
1298 // the "owning" DocumentLoader does so, as setDefersLoading() is not resilient to setting the same value repeatedly.
1299 if (mainResourceLoader() && mainResourceLoader()->documentLoader() == this)
1300 mainResourceLoader()->setDefersLoading(defers);
1302 setAllDefersLoading(m_subresourceLoaders, defers);
1303 setAllDefersLoading(m_plugInStreamLoaders, defers);
1305 deliverSubstituteResourcesAfterDelay();
1308 void DocumentLoader::setMainResourceDataBufferingPolicy(DataBufferingPolicy dataBufferingPolicy)
1311 m_mainResource->setDataBufferingPolicy(dataBufferingPolicy);
1314 void DocumentLoader::stopLoadingPlugIns()
1316 cancelAll(m_plugInStreamLoaders);
1319 void DocumentLoader::stopLoadingSubresources()
1321 cancelAll(m_subresourceLoaders);
1322 ASSERT(m_subresourceLoaders.isEmpty());
1325 void DocumentLoader::addSubresourceLoader(ResourceLoader* loader)
1327 // The main resource's underlying ResourceLoader will ask to be added here.
1328 // It is much simpler to handle special casing of main resource loads if we don't
1329 // let it be added. In the main resource load case, mainResourceLoader()
1330 // will still be null at this point, but m_gotFirstByte should be false here if and only
1331 // if we are just starting the main resource load.
1332 if (!m_gotFirstByte)
1334 ASSERT(loader->identifier());
1335 ASSERT(!m_subresourceLoaders.contains(loader->identifier()));
1336 ASSERT(!mainResourceLoader() || mainResourceLoader() != loader);
1338 // A page in the PageCache should not be able to start loads.
1339 ASSERT_WITH_SECURITY_IMPLICATION(!document() || !document()->inPageCache());
1341 m_subresourceLoaders.add(loader->identifier(), loader);
1344 void DocumentLoader::removeSubresourceLoader(ResourceLoader* loader)
1346 ASSERT(loader->identifier());
1348 if (!m_subresourceLoaders.remove(loader->identifier()))
1350 checkLoadComplete();
1351 if (Frame* frame = m_frame)
1352 frame->loader().checkLoadComplete();
1355 void DocumentLoader::addPlugInStreamLoader(ResourceLoader& loader)
1357 ASSERT(loader.identifier());
1358 ASSERT(!m_plugInStreamLoaders.contains(loader.identifier()));
1360 m_plugInStreamLoaders.add(loader.identifier(), &loader);
1363 void DocumentLoader::removePlugInStreamLoader(ResourceLoader& loader)
1365 ASSERT(loader.identifier());
1366 ASSERT(&loader == m_plugInStreamLoaders.get(loader.identifier()));
1368 m_plugInStreamLoaders.remove(loader.identifier());
1369 checkLoadComplete();
1372 bool DocumentLoader::isMultipartReplacingLoad() const
1374 return isLoadingMultipartContent() && frameLoader()->isReplacing();
1377 bool DocumentLoader::maybeLoadEmpty()
1379 bool shouldLoadEmpty = !m_substituteData.isValid() && (m_request.url().isEmpty() || SchemeRegistry::shouldLoadURLSchemeAsEmptyDocument(m_request.url().protocol()));
1380 if (!shouldLoadEmpty && !frameLoader()->client().representationExistsForURLScheme(m_request.url().protocol()))
1383 if (m_request.url().isEmpty() && !frameLoader()->stateMachine().creatingInitialEmptyDocument()) {
1384 m_request.setURL(blankURL());
1385 if (isLoadingMainResource())
1386 frameLoader()->client().dispatchDidChangeProvisionalURL();
1389 String mimeType = shouldLoadEmpty ? "text/html" : frameLoader()->client().generatedMIMETypeForURLScheme(m_request.url().protocol());
1390 m_response = ResourceResponse(m_request.url(), mimeType, 0, String());
1391 finishedLoading(monotonicallyIncreasingTime());
1395 void DocumentLoader::startLoadingMainResource()
1397 m_mainDocumentError = ResourceError();
1398 timing().markNavigationStart();
1399 ASSERT(!m_mainResource);
1400 ASSERT(!m_loadingMainResource);
1401 m_loadingMainResource = true;
1403 if (maybeLoadEmpty())
1406 // FIXME: Is there any way the extra fields could have not been added by now?
1407 // If not, it would be great to remove this line of code.
1408 // Note that currently, some requests may have incorrect extra fields even if this function has been called,
1409 // because we pass a wrong loadType (see FIXME in addExtraFieldsToMainResourceRequest()).
1410 frameLoader()->addExtraFieldsToMainResourceRequest(m_request);
1412 ASSERT(timing().navigationStart());
1413 ASSERT(!timing().fetchStart());
1414 timing().markFetchStart();
1415 willSendRequest(m_request, ResourceResponse());
1417 // willSendRequest() may lead to our Frame being detached or cancelling the load via nulling the ResourceRequest.
1418 if (!m_frame || m_request.isNull())
1421 m_applicationCacheHost->maybeLoadMainResource(m_request, m_substituteData);
1423 if (m_substituteData.isValid()) {
1424 m_identifierForLoadWithoutResourceLoader = m_frame->page()->progress().createUniqueIdentifier();
1425 frameLoader()->notifier().assignIdentifierToInitialRequest(m_identifierForLoadWithoutResourceLoader, this, m_request);
1426 frameLoader()->notifier().dispatchWillSendRequest(this, m_identifierForLoadWithoutResourceLoader, m_request, ResourceResponse());
1427 handleSubstituteDataLoadSoon();
1431 ResourceRequest request(m_request);
1432 request.setRequester(ResourceRequest::Requester::Main);
1433 // If this is a reload the cache layer might have made the previous request conditional. DocumentLoader can't handle 304 responses itself.
1434 request.makeUnconditional();
1436 static NeverDestroyed<ResourceLoaderOptions> mainResourceLoadOptions(SendCallbacks, SniffContent, BufferData, AllowStoredCredentials, AskClientForAllCredentials, SkipSecurityCheck, UseDefaultOriginRestrictionsForType, IncludeCertificateInfo, ContentSecurityPolicyImposition::DoPolicyCheck);
1437 CachedResourceRequest cachedResourceRequest(request, mainResourceLoadOptions);
1438 cachedResourceRequest.setInitiator(*this);
1439 m_mainResource = m_cachedResourceLoader->requestMainResource(cachedResourceRequest);
1440 if (!m_mainResource) {
1441 setRequest(ResourceRequest());
1442 // If the load was aborted by clearing m_request, it's possible the ApplicationCacheHost
1443 // is now in a state where starting an empty load will be inconsistent. Replace it with
1444 // a new ApplicationCacheHost.
1445 m_applicationCacheHost = std::make_unique<ApplicationCacheHost>(*this);
1450 if (!mainResourceLoader()) {
1451 m_identifierForLoadWithoutResourceLoader = m_frame->page()->progress().createUniqueIdentifier();
1452 frameLoader()->notifier().assignIdentifierToInitialRequest(m_identifierForLoadWithoutResourceLoader, this, request);
1453 frameLoader()->notifier().dispatchWillSendRequest(this, m_identifierForLoadWithoutResourceLoader, request, ResourceResponse());
1456 becomeMainResourceClient();
1458 // A bunch of headers are set when the underlying ResourceLoader is created, and m_request needs to include those.
1459 if (mainResourceLoader())
1460 request = mainResourceLoader()->originalRequest();
1461 // If there was a fragment identifier on m_request, the cache will have stripped it. m_request should include
1462 // the fragment identifier, so add that back in.
1463 if (equalIgnoringFragmentIdentifier(m_request.url(), request.url()))
1464 request.setURL(m_request.url());
1465 setRequest(request);
1468 void DocumentLoader::cancelPolicyCheckIfNeeded()
1470 RELEASE_ASSERT(frameLoader());
1472 if (m_waitingForContentPolicy) {
1473 frameLoader()->policyChecker().cancelCheck();
1474 m_waitingForContentPolicy = false;
1478 void DocumentLoader::cancelMainResourceLoad(const ResourceError& resourceError)
1480 Ref<DocumentLoader> protect(*this);
1481 ResourceError error = resourceError.isNull() ? frameLoader()->cancelledError(m_request) : resourceError;
1483 m_dataLoadTimer.stop();
1485 cancelPolicyCheckIfNeeded();
1487 if (mainResourceLoader())
1488 mainResourceLoader()->cancel(error);
1490 clearMainResource();
1492 mainReceivedError(error);
1495 void DocumentLoader::clearMainResource()
1497 if (m_mainResource && m_mainResource->hasClient(this))
1498 m_mainResource->removeClient(this);
1499 #if ENABLE(CONTENT_FILTERING)
1500 m_contentFilter = nullptr;
1506 void DocumentLoader::subresourceLoaderFinishedLoadingOnePart(ResourceLoader* loader)
1508 unsigned long identifier = loader->identifier();
1511 if (!m_multipartSubresourceLoaders.add(identifier, loader).isNewEntry) {
1512 ASSERT(m_multipartSubresourceLoaders.get(identifier) == loader);
1513 ASSERT(!m_subresourceLoaders.contains(identifier));
1515 ASSERT(m_subresourceLoaders.contains(identifier));
1516 m_subresourceLoaders.remove(identifier);
1519 checkLoadComplete();
1520 if (Frame* frame = m_frame)
1521 frame->loader().checkLoadComplete();
1524 void DocumentLoader::maybeFinishLoadingMultipartContent()
1526 if (!isMultipartReplacingLoad())
1529 frameLoader()->setupForReplace();
1530 m_committed = false;
1531 RefPtr<SharedBuffer> resourceData = mainResourceData();
1532 commitLoad(resourceData->data(), resourceData->size());
1535 void DocumentLoader::iconLoadDecisionAvailable()
1538 m_frame->loader().icon().loadDecisionReceived(iconDatabase().synchronousLoadDecisionForIconURL(frameLoader()->icon().url(), this));
1541 static void iconLoadDecisionCallback(IconLoadDecision decision, void* context)
1543 static_cast<DocumentLoader*>(context)->continueIconLoadWithDecision(decision);
1546 void DocumentLoader::getIconLoadDecisionForIconURL(const String& urlString)
1548 if (m_iconLoadDecisionCallback)
1549 m_iconLoadDecisionCallback->invalidate();
1550 m_iconLoadDecisionCallback = IconLoadDecisionCallback::create(this, iconLoadDecisionCallback);
1551 iconDatabase().loadDecisionForIconURL(urlString, m_iconLoadDecisionCallback);
1554 void DocumentLoader::continueIconLoadWithDecision(IconLoadDecision decision)
1556 ASSERT(m_iconLoadDecisionCallback);
1557 m_iconLoadDecisionCallback = nullptr;
1559 m_frame->loader().icon().continueLoadWithDecision(decision);
1562 static void iconDataCallback(SharedBuffer*, void*)
1564 // FIXME: Implement this once we know what parts of WebCore actually need the icon data returned.
1567 void DocumentLoader::getIconDataForIconURL(const String& urlString)
1569 if (m_iconDataCallback)
1570 m_iconDataCallback->invalidate();
1571 m_iconDataCallback = IconDataCallback::create(this, iconDataCallback);
1572 iconDatabase().iconDataForIconURL(urlString, m_iconDataCallback);
1575 void DocumentLoader::handledOnloadEvents()
1577 m_wasOnloadHandled = true;
1578 applicationCacheHost()->stopDeferringEvents();
1581 void DocumentLoader::setTriggeringAction(const NavigationAction& action)
1583 m_triggeringAction = action.copyWithShouldOpenExternalURLsPolicy(m_frame ? shouldOpenExternalURLsPolicyToPropagate() : m_shouldOpenExternalURLsPolicy);
1586 ShouldOpenExternalURLsPolicy DocumentLoader::shouldOpenExternalURLsPolicyToPropagate() const
1588 if (!m_frame || !m_frame->isMainFrame())
1589 return ShouldOpenExternalURLsPolicy::ShouldNotAllow;
1591 return m_shouldOpenExternalURLsPolicy;
1594 void DocumentLoader::becomeMainResourceClient()
1596 #if ENABLE(CONTENT_FILTERING)
1597 if (m_contentFilter && m_contentFilter->state() == ContentFilter::State::Initialized) {
1598 // ContentFilter will synthesize CachedRawResourceClient callbacks.
1599 m_contentFilter->startFilteringMainResource(*m_mainResource);
1603 m_mainResource->addClient(this);
1606 #if ENABLE(CONTENT_EXTENSIONS)
1607 void DocumentLoader::addPendingContentExtensionSheet(const String& identifier, StyleSheetContents& sheet)
1609 ASSERT(!m_gotFirstByte);
1610 m_pendingNamedContentExtensionStyleSheets.set(identifier, &sheet);
1613 void DocumentLoader::addPendingContentExtensionDisplayNoneSelector(const String& identifier, const String& selector, uint32_t selectorID)
1615 ASSERT(!m_gotFirstByte);
1616 auto addResult = m_pendingContentExtensionDisplayNoneSelectors.add(identifier, Vector<std::pair<String, uint32_t>>());
1617 addResult.iterator->value.append(std::make_pair(selector, selectorID));
1621 #if ENABLE(CONTENT_FILTERING)
1622 void DocumentLoader::installContentFilterUnblockHandler(ContentFilter& contentFilter)
1624 ContentFilterUnblockHandler unblockHandler { contentFilter.unblockHandler() };
1625 unblockHandler.setUnreachableURL(documentURL());
1626 RefPtr<Frame> frame { this->frame() };
1627 String unblockRequestDeniedScript { contentFilter.unblockRequestDeniedScript() };
1628 if (!unblockRequestDeniedScript.isEmpty() && frame) {
1629 static_assert(std::is_base_of<ThreadSafeRefCounted<Frame>, Frame>::value, "Frame must be ThreadSafeRefCounted.");
1630 StringCapture capturedScript { unblockRequestDeniedScript };
1631 unblockHandler.wrapWithDecisionHandler([frame, capturedScript](bool unblocked) {
1633 frame->script().executeScript(capturedScript.string());
1636 frameLoader()->client().contentFilterDidBlockLoad(WTF::move(unblockHandler));
1639 void DocumentLoader::contentFilterDidDecide()
1641 using State = ContentFilter::State;
1642 ASSERT(m_contentFilter);
1643 ASSERT(m_contentFilter->state() == State::Blocked || m_contentFilter->state() == State::Allowed);
1644 if (m_contentFilter->state() == State::Allowed)
1647 installContentFilterUnblockHandler(*m_contentFilter);
1650 blockedURL.setProtocol(ContentFilter::urlScheme());
1651 blockedURL.setHost(ASCIILiteral("blocked-page"));
1652 auto replacementData = m_contentFilter->replacementData();
1653 ResourceResponse response(URL(), ASCIILiteral("text/html"), replacementData->size(), ASCIILiteral("UTF-8"));
1654 SubstituteData substituteData { adoptRef(&replacementData.leakRef()), documentURL(), response, SubstituteData::SessionHistoryVisibility::Hidden };
1655 frame()->navigationScheduler().scheduleSubstituteDataLoad(blockedURL, substituteData);
1660 } // namespace WebCore