2 * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
3 * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
4 * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
5 * Copyright (C) 2008 Alp Toker <alp@atoker.com>
6 * Copyright (C) Research In Motion Limited 2009. All rights reserved.
7 * Copyright (C) 2011 Kris Jordan <krisjordan@gmail.com>
8 * Copyright (C) 2011 Google Inc. All rights reserved.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. Neither the name of Apple Inc. ("Apple") nor the names of
20 * its contributors may be used to endorse or promote products derived
21 * from this software without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
24 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
25 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
27 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
30 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
32 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 #include "FrameLoader.h"
38 #include "AXObjectCache.h"
39 #include "ApplicationCacheHost.h"
40 #include "BackForwardController.h"
41 #include "BeforeUnloadEvent.h"
42 #include "CachedPage.h"
43 #include "CachedResourceLoader.h"
45 #include "ChromeClient.h"
46 #include "ContentSecurityPolicy.h"
47 #include "DOMImplementation.h"
48 #include "DOMWindow.h"
49 #include "DatabaseManager.h"
50 #include "DiagnosticLoggingClient.h"
51 #include "DiagnosticLoggingKeys.h"
53 #include "DocumentLoadTiming.h"
54 #include "DocumentLoader.h"
56 #include "EditorClient.h"
59 #include "EventHandler.h"
60 #include "EventNames.h"
61 #include "FloatRect.h"
62 #include "FormState.h"
63 #include "FormSubmission.h"
64 #include "FrameLoadRequest.h"
65 #include "FrameLoaderClient.h"
66 #include "FrameNetworkingContext.h"
67 #include "FrameTree.h"
68 #include "FrameView.h"
69 #include "HTMLAnchorElement.h"
70 #include "HTMLFormElement.h"
71 #include "HTMLInputElement.h"
72 #include "HTMLNames.h"
73 #include "HTMLObjectElement.h"
74 #include "HTMLParserIdioms.h"
75 #include "HTTPHeaderNames.h"
76 #include "HTTPParsers.h"
77 #include "HistoryController.h"
78 #include "HistoryItem.h"
79 #include "IconController.h"
80 #include "InspectorController.h"
81 #include "InspectorInstrumentation.h"
82 #include "LoaderStrategy.h"
84 #include "MIMETypeRegistry.h"
85 #include "MainFrame.h"
86 #include "MemoryCache.h"
88 #include "PageCache.h"
89 #include "PageThrottler.h"
90 #include "PageTransitionEvent.h"
91 #include "PlatformStrategies.h"
92 #include "PluginData.h"
93 #include "PluginDocument.h"
94 #include "PolicyChecker.h"
95 #include "ProgressTracker.h"
96 #include "ResourceHandle.h"
97 #include "ResourceRequest.h"
98 #include "SVGDocument.h"
99 #include "SVGLocatable.h"
100 #include "SVGNames.h"
101 #include "SVGPreserveAspectRatio.h"
102 #include "SVGSVGElement.h"
103 #include "SVGViewElement.h"
104 #include "SVGViewSpec.h"
105 #include "SchemeRegistry.h"
106 #include "ScriptController.h"
107 #include "ScriptSourceCode.h"
108 #include "ScrollAnimator.h"
109 #include "SecurityOrigin.h"
110 #include "SecurityPolicy.h"
111 #include "SegmentedString.h"
112 #include "SerializedScriptValue.h"
113 #include "Settings.h"
114 #include "SubframeLoader.h"
115 #include "TextResourceDecoder.h"
116 #include "WindowFeatures.h"
117 #include "XMLDocumentParser.h"
118 #include <wtf/CurrentTime.h>
120 #include <wtf/StdLibExtras.h>
121 #include <wtf/text/CString.h>
122 #include <wtf/text/WTFString.h>
124 #if ENABLE(WEB_ARCHIVE) || ENABLE(MHTML)
129 #include "DocumentType.h"
130 #include "MemoryPressureHandler.h"
131 #include "ResourceLoader.h"
132 #include "RuntimeApplicationChecksIOS.h"
133 #include "SystemMemory.h"
134 #include "WKContentObservation.h"
139 using namespace HTMLNames;
140 using namespace SVGNames;
142 static const char defaultAcceptHeader[] = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";
145 const int memoryLevelThresholdToPrunePageCache = 20;
148 bool isBackForwardLoadType(FrameLoadType type)
151 case FrameLoadType::Standard:
152 case FrameLoadType::Reload:
153 case FrameLoadType::ReloadFromOrigin:
154 case FrameLoadType::Same:
155 case FrameLoadType::RedirectWithLockedBackForwardList:
156 case FrameLoadType::Replace:
158 case FrameLoadType::Back:
159 case FrameLoadType::Forward:
160 case FrameLoadType::IndexedBackForward:
163 ASSERT_NOT_REACHED();
167 // This is not in the FrameLoader class to emphasize that it does not depend on
168 // private FrameLoader data, and to avoid increasing the number of public functions
169 // with access to private data. Since only this .cpp file needs it, making it
170 // non-member lets us exclude it from the header file, thus keeping FrameLoader.h's
173 static bool isDocumentSandboxed(Frame* frame, SandboxFlags mask)
175 return frame->document() && frame->document()->isSandboxed(mask);
178 class FrameLoader::FrameProgressTracker {
180 explicit FrameProgressTracker(Frame& frame)
182 , m_inProgress(false)
186 ~FrameProgressTracker()
188 if (m_inProgress && m_frame.page())
189 m_frame.page()->progress().progressCompleted(m_frame);
192 void progressStarted()
194 ASSERT(m_frame.page());
196 m_frame.page()->progress().progressStarted(m_frame);
200 void progressCompleted()
202 ASSERT(m_inProgress);
203 ASSERT(m_frame.page());
204 m_inProgress = false;
205 m_frame.page()->progress().progressCompleted(m_frame);
213 FrameLoader::FrameLoader(Frame& frame, FrameLoaderClient& client)
216 , m_policyChecker(std::make_unique<PolicyChecker>(frame))
217 , m_history(std::make_unique<HistoryController>(frame))
219 , m_subframeLoader(std::make_unique<SubframeLoader>(frame))
220 , m_icon(std::make_unique<IconController>(frame))
221 , m_mixedContentChecker(frame)
222 , m_state(FrameStateProvisional)
223 , m_loadType(FrameLoadType::Standard)
224 , m_delegateIsHandlingProvisionalLoadError(false)
225 , m_quickRedirectComing(false)
226 , m_sentRedirectNotification(false)
227 , m_inStopAllLoaders(false)
228 , m_isExecutingJavaScriptFormAction(false)
229 , m_didCallImplicitClose(true)
230 , m_wasUnloadEventEmitted(false)
231 , m_pageDismissalEventBeingDispatched(NoDismissal)
232 , m_isComplete(false)
233 , m_needsClear(false)
234 , m_checkTimer(*this, &FrameLoader::checkTimerFired)
235 , m_shouldCallCheckCompleted(false)
236 , m_shouldCallCheckLoadComplete(false)
238 , m_loadingFromCachedPage(false)
239 , m_suppressOpenerInNewFrame(false)
240 , m_currentNavigationHasShownBeforeUnloadConfirmPanel(false)
241 , m_loadsSynchronously(false)
242 , m_forcedSandboxFlags(SandboxNone)
246 FrameLoader::~FrameLoader()
250 HashSet<Frame*>::iterator end = m_openedFrames.end();
251 for (HashSet<Frame*>::iterator it = m_openedFrames.begin(); it != end; ++it)
252 (*it)->loader().m_opener = 0;
254 m_client.frameLoaderDestroyed();
256 if (m_networkingContext)
257 m_networkingContext->invalidate();
260 void FrameLoader::init()
262 // This somewhat odd set of steps gives the frame an initial empty document.
263 setPolicyDocumentLoader(m_client.createDocumentLoader(ResourceRequest(URL(ParsedURLString, emptyString())), SubstituteData()).get());
264 setProvisionalDocumentLoader(m_policyDocumentLoader.get());
265 m_provisionalDocumentLoader->startLoadingMainResource();
267 Ref<Frame> protect(m_frame);
268 m_frame.document()->cancelParsing();
269 m_stateMachine.advanceTo(FrameLoaderStateMachine::DisplayingInitialEmptyDocument);
271 m_networkingContext = m_client.createNetworkingContext();
272 m_progressTracker = std::make_unique<FrameProgressTracker>(m_frame);
276 void FrameLoader::initForSynthesizedDocument(const URL&)
278 // FIXME: We need to initialize the document URL to the specified URL. Currently the URL is empty and hence
279 // FrameLoader::checkCompleted() will overwrite the URL of the document to be activeDocumentLoader()->documentURL().
281 RefPtr<DocumentLoader> loader = m_client.createDocumentLoader(ResourceRequest(URL(ParsedURLString, emptyString())), SubstituteData());
282 loader->setFrame(&m_frame);
283 loader->setResponse(ResourceResponse(URL(), ASCIILiteral("text/html"), 0, String()));
284 loader->setCommitted(true);
285 setDocumentLoader(loader.get());
287 m_stateMachine.advanceTo(FrameLoaderStateMachine::DisplayingInitialEmptyDocument);
288 m_stateMachine.advanceTo(FrameLoaderStateMachine::DisplayingInitialEmptyDocumentPostCommit);
289 m_stateMachine.advanceTo(FrameLoaderStateMachine::CommittedFirstRealLoad);
290 m_client.transitionToCommittedForNewPage();
292 m_didCallImplicitClose = true;
294 m_state = FrameStateComplete;
297 m_networkingContext = m_client.createNetworkingContext();
298 m_progressTracker = std::make_unique<FrameProgressTracker>(m_frame);
302 void FrameLoader::setDefersLoading(bool defers)
304 if (m_documentLoader)
305 m_documentLoader->setDefersLoading(defers);
306 if (m_provisionalDocumentLoader)
307 m_provisionalDocumentLoader->setDefersLoading(defers);
308 if (m_policyDocumentLoader)
309 m_policyDocumentLoader->setDefersLoading(defers);
310 history().setDefersLoading(defers);
313 m_frame.navigationScheduler().startTimer();
314 startCheckCompleteTimer();
318 void FrameLoader::changeLocation(SecurityOrigin* securityOrigin, const URL& url, const String& referrer, LockHistory lockHistory, LockBackForwardList lockBackForwardList, bool refresh, AllowNavigationToInvalidURL allowNavigationToInvalidURL)
320 urlSelected(FrameLoadRequest(securityOrigin, ResourceRequest(url, referrer, refresh ? ReloadIgnoringCacheData : UseProtocolCachePolicy), "_self"),
321 0, lockHistory, lockBackForwardList, MaybeSendReferrer, ReplaceDocumentIfJavaScriptURL, allowNavigationToInvalidURL);
324 void FrameLoader::urlSelected(const URL& url, const String& passedTarget, PassRefPtr<Event> triggeringEvent, LockHistory lockHistory, LockBackForwardList lockBackForwardList, ShouldSendReferrer shouldSendReferrer)
326 urlSelected(FrameLoadRequest(m_frame.document()->securityOrigin(), ResourceRequest(url), passedTarget),
327 triggeringEvent, lockHistory, lockBackForwardList, shouldSendReferrer, DoNotReplaceDocumentIfJavaScriptURL, AllowNavigationToInvalidURL::Yes);
330 // The shouldReplaceDocumentIfJavaScriptURL parameter will go away when the FIXME to eliminate the
331 // corresponding parameter from ScriptController::executeIfJavaScriptURL() is addressed.
332 void FrameLoader::urlSelected(const FrameLoadRequest& passedRequest, PassRefPtr<Event> triggeringEvent, LockHistory lockHistory, LockBackForwardList lockBackForwardList, ShouldSendReferrer shouldSendReferrer, ShouldReplaceDocumentIfJavaScriptURL shouldReplaceDocumentIfJavaScriptURL, AllowNavigationToInvalidURL allowNavigationToInvalidURL)
334 ASSERT(!m_suppressOpenerInNewFrame);
336 Ref<Frame> protect(m_frame);
337 FrameLoadRequest frameRequest(passedRequest);
339 if (m_frame.script().executeIfJavaScriptURL(frameRequest.resourceRequest().url(), shouldReplaceDocumentIfJavaScriptURL))
342 if (frameRequest.frameName().isEmpty())
343 frameRequest.setFrameName(m_frame.document()->baseTarget());
345 if (shouldSendReferrer == NeverSendReferrer)
346 m_suppressOpenerInNewFrame = true;
347 addHTTPOriginIfNeeded(frameRequest.resourceRequest(), outgoingOrigin());
349 loadFrameRequest(frameRequest, lockHistory, lockBackForwardList, triggeringEvent, 0, shouldSendReferrer, allowNavigationToInvalidURL);
351 m_suppressOpenerInNewFrame = false;
354 void FrameLoader::submitForm(PassRefPtr<FormSubmission> submission)
356 ASSERT(submission->method() == FormSubmission::PostMethod || submission->method() == FormSubmission::GetMethod);
358 // FIXME: Find a good spot for these.
359 ASSERT(submission->data());
360 ASSERT(submission->state());
361 ASSERT(!submission->state()->sourceDocument()->frame() || submission->state()->sourceDocument()->frame() == &m_frame);
366 if (submission->action().isEmpty())
369 if (isDocumentSandboxed(&m_frame, SandboxForms)) {
370 // FIXME: This message should be moved off the console once a solution to https://bugs.webkit.org/show_bug.cgi?id=103274 exists.
371 m_frame.document()->addConsoleMessage(MessageSource::Security, MessageLevel::Error, "Blocked form submission to '" + submission->action().stringCenterEllipsizedToLength() + "' because the form's frame is sandboxed and the 'allow-forms' permission is not set.");
375 if (protocolIsJavaScript(submission->action())) {
376 if (!m_frame.document()->contentSecurityPolicy()->allowFormAction(URL(submission->action())))
378 m_isExecutingJavaScriptFormAction = true;
379 Ref<Frame> protect(m_frame);
380 m_frame.script().executeIfJavaScriptURL(submission->action(), DoNotReplaceDocumentIfJavaScriptURL);
381 m_isExecutingJavaScriptFormAction = false;
385 Frame* targetFrame = findFrameForNavigation(submission->target(), submission->state()->sourceDocument());
387 if (!DOMWindow::allowPopUp(&m_frame) && !ScriptController::processingUserGesture())
390 // FIXME: targetFrame can be 0 for two distinct reasons:
391 // 1. The frame was not found by name, so we should try opening a new window.
392 // 2. The frame was found, but navigating it was not allowed, e.g. by HTML5 sandbox or by origin checks.
393 // Continuing form submission makes no sense in the latter case.
394 // There is a repeat check after timer fires, so this is not a correctness issue.
396 targetFrame = &m_frame;
398 submission->clearTarget();
400 if (!targetFrame->page())
403 // FIXME: We'd like to remove this altogether and fix the multiple form submission issue another way.
405 // We do not want to submit more than one form from the same page, nor do we want to submit a single
406 // form more than once. This flag prevents these from happening; not sure how other browsers prevent this.
407 // The flag is reset in each time we start handle a new mouse or key down event, and
408 // also in setView since this part may get reused for a page from the back/forward cache.
409 // The form multi-submit logic here is only needed when we are submitting a form that affects this frame.
411 // FIXME: Frame targeting is only one of the ways the submission could end up doing something other
412 // than replacing this frame's content, so this check is flawed. On the other hand, the check is hardly
413 // needed any more now that we reset m_submittedFormURL on each mouse or key down event.
415 if (m_frame.tree().isDescendantOf(targetFrame)) {
416 if (m_submittedFormURL == submission->requestURL())
418 m_submittedFormURL = submission->requestURL();
421 submission->data()->generateFiles(m_frame.document());
422 submission->setReferrer(outgoingReferrer());
423 submission->setOrigin(outgoingOrigin());
425 targetFrame->navigationScheduler().scheduleFormSubmission(submission);
428 void FrameLoader::stopLoading(UnloadEventPolicy unloadEventPolicy)
430 if (m_frame.document() && m_frame.document()->parser())
431 m_frame.document()->parser()->stopParsing();
433 if (unloadEventPolicy != UnloadEventPolicyNone) {
434 if (m_frame.document()) {
435 if (m_didCallImplicitClose && !m_wasUnloadEventEmitted) {
436 Element* currentFocusedElement = m_frame.document()->focusedElement();
437 if (currentFocusedElement && currentFocusedElement->toInputElement())
438 currentFocusedElement->toInputElement()->endEditing();
439 if (m_pageDismissalEventBeingDispatched == NoDismissal) {
440 if (unloadEventPolicy == UnloadEventPolicyUnloadAndPageHide) {
441 m_pageDismissalEventBeingDispatched = PageHideDismissal;
442 m_frame.document()->domWindow()->dispatchEvent(PageTransitionEvent::create(eventNames().pagehideEvent, m_frame.document()->inPageCache()), m_frame.document());
445 // FIXME: update Page Visibility state here.
446 // https://bugs.webkit.org/show_bug.cgi?id=116770
448 if (!m_frame.document()->inPageCache()) {
449 RefPtr<Event> unloadEvent(Event::create(eventNames().unloadEvent, false, false));
450 // The DocumentLoader (and thus its DocumentLoadTiming) might get destroyed
451 // while dispatching the event, so protect it to prevent writing the end
452 // time into freed memory.
453 RefPtr<DocumentLoader> documentLoader = m_provisionalDocumentLoader;
454 m_pageDismissalEventBeingDispatched = UnloadDismissal;
455 if (documentLoader && !documentLoader->timing()->unloadEventStart() && !documentLoader->timing()->unloadEventEnd()) {
456 DocumentLoadTiming* timing = documentLoader->timing();
457 ASSERT(timing->navigationStart());
458 timing->markUnloadEventStart();
459 m_frame.document()->domWindow()->dispatchEvent(unloadEvent, m_frame.document());
460 timing->markUnloadEventEnd();
462 m_frame.document()->domWindow()->dispatchEvent(unloadEvent, m_frame.document());
465 m_pageDismissalEventBeingDispatched = NoDismissal;
466 if (m_frame.document())
467 m_frame.document()->updateStyleIfNeeded();
468 m_wasUnloadEventEmitted = true;
472 // Dispatching the unload event could have made m_frame.document() null.
473 if (m_frame.document() && !m_frame.document()->inPageCache()) {
474 // Don't remove event listeners from a transitional empty document (see bug 28716 for more information).
475 bool keepEventListeners = m_stateMachine.isDisplayingInitialEmptyDocument() && m_provisionalDocumentLoader
476 && m_frame.document()->isSecureTransitionTo(m_provisionalDocumentLoader->url());
478 if (!keepEventListeners)
479 m_frame.document()->removeAllEventListeners();
483 m_isComplete = true; // to avoid calling completed() in finishedParsing()
484 m_didCallImplicitClose = true; // don't want that one either
486 if (m_frame.document() && m_frame.document()->parsing()) {
488 m_frame.document()->setParsing(false);
491 if (Document* doc = m_frame.document()) {
492 // FIXME: HTML5 doesn't tell us to set the state to complete when aborting, but we do anyway to match legacy behavior.
493 // http://www.w3.org/Bugs/Public/show_bug.cgi?id=10537
494 doc->setReadyState(Document::Complete);
496 // FIXME: Should the DatabaseManager watch for something like ActiveDOMObject::stop() rather than being special-cased here?
497 DatabaseManager::manager().stopDatabases(doc, 0);
500 // FIXME: This will cancel redirection timer, which really needs to be restarted when restoring the frame from b/f cache.
501 m_frame.navigationScheduler().cancel();
504 void FrameLoader::stop()
506 // http://bugs.webkit.org/show_bug.cgi?id=10854
507 // The frame's last ref may be removed and it will be deleted by checkCompleted().
508 Ref<Frame> protect(m_frame);
510 if (DocumentParser* parser = m_frame.document()->parser()) {
511 parser->stopParsing();
518 void FrameLoader::willTransitionToCommitted()
520 // This function is called when a frame is still fully in place (not cached, not detached), but will be replaced.
522 if (m_frame.editor().hasComposition()) {
523 // The text was already present in DOM, so it's better to confirm than to cancel the composition.
524 m_frame.editor().confirmComposition();
525 if (EditorClient* editorClient = m_frame.editor().client()) {
526 editorClient->respondToChangedSelection(&m_frame);
527 editorClient->discardedComposition(&m_frame);
532 bool FrameLoader::closeURL()
534 history().saveDocumentState();
536 Document* currentDocument = m_frame.document();
537 UnloadEventPolicy unloadEventPolicy;
538 if (m_frame.page() && m_frame.page()->chrome().client().isSVGImageChromeClient()) {
539 // If this is the SVGDocument of an SVGImage, no need to dispatch events or recalcStyle.
540 unloadEventPolicy = UnloadEventPolicyNone;
542 // Should only send the pagehide event here if the current document exists and has not been placed in the page cache.
543 unloadEventPolicy = currentDocument && !currentDocument->inPageCache() ? UnloadEventPolicyUnloadAndPageHide : UnloadEventPolicyUnloadOnly;
546 stopLoading(unloadEventPolicy);
548 m_frame.editor().clearUndoRedoOperations();
552 bool FrameLoader::didOpenURL()
554 if (m_frame.navigationScheduler().redirectScheduledDuringLoad()) {
555 // A redirect was scheduled before the document was created.
556 // This can happen when one frame changes another frame's location.
560 m_frame.navigationScheduler().cancel();
561 m_frame.editor().clearLastEditCommand();
563 m_isComplete = false;
564 m_didCallImplicitClose = false;
566 // If we are still in the process of initializing an empty document then
567 // its frame is not in a consistent state for rendering, so avoid setJSStatusBarText
568 // since it may cause clients to attempt to render the frame.
569 if (!m_stateMachine.creatingInitialEmptyDocument()) {
570 DOMWindow* window = m_frame.document()->domWindow();
571 window->setStatus(String());
572 window->setDefaultStatus(String());
580 void FrameLoader::didExplicitOpen()
582 m_isComplete = false;
583 m_didCallImplicitClose = false;
585 // Calling document.open counts as committing the first real document load.
586 if (!m_stateMachine.committedFirstRealDocumentLoad())
587 m_stateMachine.advanceTo(FrameLoaderStateMachine::DisplayingInitialEmptyDocumentPostCommit);
589 // Prevent window.open(url) -- eg window.open("about:blank") -- from blowing away results
590 // from a subsequent window.document.open / window.document.write call.
591 // Canceling redirection here works for all cases because document.open
592 // implicitly precedes document.write.
593 m_frame.navigationScheduler().cancel();
597 void FrameLoader::cancelAndClear()
599 m_frame.navigationScheduler().cancel();
604 clear(m_frame.document(), false);
605 m_frame.script().updatePlatformScriptObjects();
608 void FrameLoader::clear(Document* newDocument, bool clearWindowProperties, bool clearScriptObjects, bool clearFrameView)
610 m_frame.editor().clear();
614 m_needsClear = false;
616 if (!m_frame.document()->inPageCache()) {
617 m_frame.document()->cancelParsing();
618 m_frame.document()->stopActiveDOMObjects();
619 bool hadLivingRenderTree = m_frame.document()->hasLivingRenderTree();
620 m_frame.document()->prepareForDestruction();
621 if (hadLivingRenderTree)
622 m_frame.document()->removeFocusedNodeOfSubtree(m_frame.document());
625 // Do this after detaching the document so that the unload event works.
626 if (clearWindowProperties) {
627 InspectorInstrumentation::frameWindowDiscarded(&m_frame, m_frame.document()->domWindow());
628 m_frame.document()->domWindow()->resetUnlessSuspendedForPageCache();
629 m_frame.script().clearWindowShell(newDocument->domWindow(), m_frame.document()->inPageCache());
632 m_frame.selection().prepareForDestruction();
633 m_frame.eventHandler().clear();
634 if (clearFrameView && m_frame.view())
635 m_frame.view()->clear();
637 // Do not drop the document before the ScriptController and view are cleared
638 // as some destructors might still try to access the document.
639 m_frame.setDocument(0);
641 subframeLoader().clear();
643 if (clearScriptObjects)
644 m_frame.script().clearScriptObjects();
646 m_frame.script().enableEval();
648 m_frame.navigationScheduler().clear();
651 m_shouldCallCheckCompleted = false;
652 m_shouldCallCheckLoadComplete = false;
654 if (m_stateMachine.isDisplayingInitialEmptyDocument() && m_stateMachine.committedFirstRealDocumentLoad())
655 m_stateMachine.advanceTo(FrameLoaderStateMachine::CommittedFirstRealLoad);
658 void FrameLoader::receivedFirstData()
660 dispatchDidCommitLoad();
661 dispatchDidClearWindowObjectsInAllWorlds();
662 dispatchGlobalObjectAvailableInAllWorlds();
664 if (m_documentLoader) {
665 StringWithDirection ptitle = m_documentLoader->title();
666 // If we have a title let the WebView know about it.
667 if (!ptitle.isNull())
668 m_client.dispatchDidReceiveTitle(ptitle);
671 if (!m_documentLoader)
676 if (!parseHTTPRefresh(m_documentLoader->response().httpHeaderField(HTTPHeaderName::Refresh), false, delay, urlString))
679 if (urlString.isEmpty())
680 completedURL = m_frame.document()->url();
682 completedURL = m_frame.document()->completeURL(urlString);
684 if (!protocolIsJavaScript(completedURL))
685 m_frame.navigationScheduler().scheduleRedirect(delay, completedURL);
687 String message = "Refused to refresh " + m_frame.document()->url().stringCenterEllipsizedToLength() + " to a javascript: URL";
688 m_frame.document()->addConsoleMessage(MessageSource::Security, MessageLevel::Error, message);
692 void FrameLoader::setOutgoingReferrer(const URL& url)
694 m_outgoingReferrer = url.strippedForUseAsReferrer();
697 void FrameLoader::didBeginDocument(bool dispatch)
700 m_isComplete = false;
701 m_didCallImplicitClose = false;
702 m_frame.document()->setReadyState(Document::Loading);
704 if (m_pendingStateObject) {
705 m_frame.document()->statePopped(m_pendingStateObject.get());
706 m_pendingStateObject.clear();
710 dispatchDidClearWindowObjectsInAllWorlds();
712 updateFirstPartyForCookies();
713 m_frame.document()->initContentSecurityPolicy();
715 const Settings& settings = m_frame.settings();
716 m_frame.document()->cachedResourceLoader()->setImagesEnabled(settings.areImagesEnabled());
717 m_frame.document()->cachedResourceLoader()->setAutoLoadImages(settings.loadsImagesAutomatically());
719 if (m_documentLoader) {
720 String dnsPrefetchControl = m_documentLoader->response().httpHeaderField(HTTPHeaderName::XDNSPrefetchControl);
721 if (!dnsPrefetchControl.isEmpty())
722 m_frame.document()->parseDNSPrefetchControlHeader(dnsPrefetchControl);
724 String policyValue = m_documentLoader->response().httpHeaderField(HTTPHeaderName::ContentSecurityPolicy);
725 if (!policyValue.isEmpty())
726 m_frame.document()->contentSecurityPolicy()->didReceiveHeader(policyValue, ContentSecurityPolicy::Enforce);
728 policyValue = m_documentLoader->response().httpHeaderField(HTTPHeaderName::ContentSecurityPolicyReportOnly);
729 if (!policyValue.isEmpty())
730 m_frame.document()->contentSecurityPolicy()->didReceiveHeader(policyValue, ContentSecurityPolicy::Report);
732 policyValue = m_documentLoader->response().httpHeaderField(HTTPHeaderName::XWebKitCSP);
733 if (!policyValue.isEmpty())
734 m_frame.document()->contentSecurityPolicy()->didReceiveHeader(policyValue, ContentSecurityPolicy::PrefixedEnforce);
736 policyValue = m_documentLoader->response().httpHeaderField(HTTPHeaderName::XWebKitCSPReportOnly);
737 if (!policyValue.isEmpty())
738 m_frame.document()->contentSecurityPolicy()->didReceiveHeader(policyValue, ContentSecurityPolicy::PrefixedReport);
740 String headerContentLanguage = m_documentLoader->response().httpHeaderField(HTTPHeaderName::ContentLanguage);
741 if (!headerContentLanguage.isEmpty()) {
742 size_t commaIndex = headerContentLanguage.find(',');
743 headerContentLanguage.truncate(commaIndex); // notFound == -1 == don't truncate
744 headerContentLanguage = headerContentLanguage.stripWhiteSpace(isHTMLSpace);
745 if (!headerContentLanguage.isEmpty())
746 m_frame.document()->setContentLanguage(headerContentLanguage);
750 history().restoreDocumentState();
753 void FrameLoader::finishedParsing()
755 m_frame.injectUserScripts(InjectAtDocumentEnd);
757 if (m_stateMachine.creatingInitialEmptyDocument())
760 // This can be called from the Frame's destructor, in which case we shouldn't protect ourselves
761 // because doing so will cause us to re-enter the destructor when protector goes out of scope.
762 // Null-checking the FrameView indicates whether or not we're in the destructor.
763 RefPtr<Frame> protector = m_frame.view() ? &m_frame : 0;
765 m_client.dispatchDidFinishDocumentLoad();
770 return; // We are being destroyed by something checkCompleted called.
772 // Check if the scrollbars are really needed for the content.
773 // If not, remove them, relayout, and repaint.
774 m_frame.view()->restoreScrollbar();
775 scrollToFragmentWithParentBoundary(m_frame.document()->url());
778 void FrameLoader::loadDone()
783 bool FrameLoader::allChildrenAreComplete() const
785 for (Frame* child = m_frame.tree().firstChild(); child; child = child->tree().nextSibling()) {
786 if (!child->loader().m_isComplete)
792 bool FrameLoader::allAncestorsAreComplete() const
794 for (Frame* ancestor = &m_frame; ancestor; ancestor = ancestor->tree().parent()) {
795 if (!ancestor->loader().m_isComplete)
801 void FrameLoader::checkCompleted()
803 m_shouldCallCheckCompleted = false;
805 // Have we completed before?
809 // Are we still parsing?
810 if (m_frame.document()->parsing())
813 // Still waiting for images/scripts?
814 if (m_frame.document()->cachedResourceLoader()->requestCount())
817 // Still waiting for elements that don't go through a FrameLoader?
818 if (m_frame.document()->isDelayingLoadEvent())
821 // Any frame that hasn't completed yet?
822 if (!allChildrenAreComplete())
825 // Important not to protect earlier in this function, because earlier parts
826 // of this function can be called in the frame's destructor, and it's not legal
827 // to ref an object while it's being destroyed.
828 Ref<Frame> protect(m_frame);
832 m_requestedHistoryItem = 0;
833 m_frame.document()->setReadyState(Document::Complete);
836 if (m_frame.document()->url().isEmpty()) {
837 // We need to update the document URL of a PDF document to be non-empty so that both back/forward history navigation
838 // between PDF pages and fragment navigation works. See <rdar://problem/9544769> for more details.
839 // FIXME: Is there a better place for this code, say DocumentLoader? Also, we should explicitly only update the URL
840 // of the document when it's a PDFDocument object instead of assuming that a Document object with an empty URL is a PDFDocument.
841 // FIXME: This code is incorrect for a synthesized document (which also has an empty URL). The URL for a synthesized
842 // document should be the URL specified to FrameLoader::initForSynthesizedDocument().
843 m_frame.document()->setURL(activeDocumentLoader()->documentURL());
847 checkCallImplicitClose(); // if we didn't do it before
849 m_frame.navigationScheduler().startTimer();
856 void FrameLoader::checkTimerFired()
858 Ref<Frame> protect(m_frame);
860 if (Page* page = m_frame.page()) {
861 if (page->defersLoading())
864 if (m_shouldCallCheckCompleted)
866 if (m_shouldCallCheckLoadComplete)
870 void FrameLoader::startCheckCompleteTimer()
872 if (!(m_shouldCallCheckCompleted || m_shouldCallCheckLoadComplete))
874 if (m_checkTimer.isActive())
876 m_checkTimer.startOneShot(0);
879 void FrameLoader::scheduleCheckCompleted()
881 m_shouldCallCheckCompleted = true;
882 startCheckCompleteTimer();
885 void FrameLoader::scheduleCheckLoadComplete()
887 m_shouldCallCheckLoadComplete = true;
888 startCheckCompleteTimer();
891 void FrameLoader::checkCallImplicitClose()
893 if (m_didCallImplicitClose || m_frame.document()->parsing() || m_frame.document()->isDelayingLoadEvent())
896 if (!allChildrenAreComplete())
897 return; // still got a frame running -> too early
899 m_didCallImplicitClose = true;
900 m_wasUnloadEventEmitted = false;
901 m_frame.document()->implicitClose();
904 void FrameLoader::loadURLIntoChildFrame(const URL& url, const String& referer, Frame* childFrame)
908 #if ENABLE(WEB_ARCHIVE) || ENABLE(MHTML)
909 RefPtr<Archive> subframeArchive = activeDocumentLoader()->popArchiveForSubframe(childFrame->tree().uniqueName(), url);
910 if (subframeArchive) {
911 childFrame->loader().loadArchive(subframeArchive.release());
914 #endif // ENABLE(WEB_ARCHIVE)
916 HistoryItem* parentItem = history().currentItem();
917 // If we're moving in the back/forward list, we might want to replace the content
918 // of this child frame with whatever was there at that point.
919 if (parentItem && parentItem->children().size() && isBackForwardLoadType(loadType())
920 && !m_frame.document()->loadEventFinished()) {
921 HistoryItem* childItem = parentItem->childItemWithTarget(childFrame->tree().uniqueName());
923 childFrame->loader().m_requestedHistoryItem = childItem;
924 childFrame->loader().loadDifferentDocumentItem(childItem, loadType(), MayAttemptCacheOnlyLoadForFormSubmissionItem);
929 childFrame->loader().loadURL(url, referer, "_self", LockHistory::No, FrameLoadType::RedirectWithLockedBackForwardList, 0, 0, AllowNavigationToInvalidURL::Yes);
932 #if ENABLE(WEB_ARCHIVE) || ENABLE(MHTML)
933 void FrameLoader::loadArchive(PassRefPtr<Archive> archive)
935 ArchiveResource* mainResource = archive->mainResource();
936 ASSERT(mainResource);
940 SubstituteData substituteData(mainResource->data(), mainResource->mimeType(), mainResource->textEncoding(), URL());
942 ResourceRequest request(mainResource->url());
944 request.applyWebArchiveHackForMail();
947 RefPtr<DocumentLoader> documentLoader = m_client.createDocumentLoader(request, substituteData);
948 documentLoader->setArchive(archive.get());
949 load(documentLoader.get());
951 #endif // ENABLE(WEB_ARCHIVE) || ENABLE(MHTML)
953 String FrameLoader::outgoingReferrer() const
955 // See http://www.whatwg.org/specs/web-apps/current-work/#fetching-resources
956 // for why we walk the parent chain for srcdoc documents.
957 Frame* frame = &m_frame;
958 while (frame->document()->isSrcdocDocument()) {
959 frame = frame->tree().parent();
960 // Srcdoc documents cannot be top-level documents, by definition,
961 // because they need to be contained in iframes with the srcdoc.
964 return frame->loader().m_outgoingReferrer;
967 String FrameLoader::outgoingOrigin() const
969 return m_frame.document()->securityOrigin()->toString();
972 bool FrameLoader::checkIfFormActionAllowedByCSP(const URL& url) const
974 if (m_submittedFormURL.isEmpty())
977 return m_frame.document()->contentSecurityPolicy()->allowFormAction(url);
980 Frame* FrameLoader::opener()
985 void FrameLoader::setOpener(Frame* opener)
987 if (m_opener && !opener)
988 m_client.didDisownOpener();
991 m_opener->loader().m_openedFrames.remove(&m_frame);
993 opener->loader().m_openedFrames.add(&m_frame);
996 if (m_frame.document())
997 m_frame.document()->initSecurityContext();
1000 // FIXME: This does not belong in FrameLoader!
1001 void FrameLoader::handleFallbackContent()
1003 HTMLFrameOwnerElement* owner = m_frame.ownerElement();
1004 if (!is<HTMLObjectElement>(owner))
1006 downcast<HTMLObjectElement>(*owner).renderFallbackContent();
1009 void FrameLoader::provisionalLoadStarted()
1011 if (m_stateMachine.firstLayoutDone())
1012 m_stateMachine.advanceTo(FrameLoaderStateMachine::CommittedFirstRealLoad);
1013 m_frame.navigationScheduler().cancel(true);
1014 m_client.provisionalLoadStarted();
1017 void FrameLoader::resetMultipleFormSubmissionProtection()
1019 m_submittedFormURL = URL();
1022 void FrameLoader::updateFirstPartyForCookies()
1024 if (m_frame.tree().parent())
1025 setFirstPartyForCookies(m_frame.tree().parent()->document()->firstPartyForCookies());
1027 setFirstPartyForCookies(m_frame.document()->url());
1030 void FrameLoader::setFirstPartyForCookies(const URL& url)
1032 for (Frame* frame = &m_frame; frame; frame = frame->tree().traverseNext(&m_frame))
1033 frame->document()->setFirstPartyForCookies(url);
1036 // This does the same kind of work that didOpenURL does, except it relies on the fact
1037 // that a higher level already checked that the URLs match and the scrolling is the right thing to do.
1038 void FrameLoader::loadInSameDocument(const URL& url, PassRefPtr<SerializedScriptValue> stateObject, bool isNewNavigation)
1040 // If we have a state object, we cannot also be a new navigation.
1041 ASSERT(!stateObject || (stateObject && !isNewNavigation));
1043 // Update the data source's request with the new URL to fake the URL change
1044 URL oldURL = m_frame.document()->url();
1045 m_frame.document()->setURL(url);
1046 setOutgoingReferrer(url);
1047 documentLoader()->replaceRequestURLForSameDocumentNavigation(url);
1048 if (isNewNavigation && !shouldTreatURLAsSameAsCurrent(url) && !stateObject) {
1049 // NB: must happen after replaceRequestURLForSameDocumentNavigation(), since we add
1050 // based on the current request. Must also happen before we openURL and displace the
1051 // scroll position, since adding the BF item will save away scroll state.
1053 // NB2: If we were loading a long, slow doc, and the user fragment navigated before
1054 // it was done, currItem is now set the that slow doc, and prevItem is whatever was
1055 // before it. Adding the b/f item will bump the slow doc down to prevItem, even
1056 // though its load is not yet done. I think this all works out OK, for one because
1057 // we have already saved away the scroll and doc state for the long slow load,
1058 // but it's not an obvious case.
1060 history().updateBackForwardListForFragmentScroll();
1063 bool hashChange = equalIgnoringFragmentIdentifier(url, oldURL) && url.fragmentIdentifier() != oldURL.fragmentIdentifier();
1065 history().updateForSameDocumentNavigation();
1067 // If we were in the autoscroll/panScroll mode we want to stop it before following the link to the anchor
1069 m_frame.eventHandler().stopAutoscrollTimer();
1071 // It's important to model this as a load that starts and immediately finishes.
1072 // Otherwise, the parent frame may think we never finished loading.
1075 // We need to scroll to the fragment whether or not a hash change occurred, since
1076 // the user might have scrolled since the previous navigation.
1077 scrollToFragmentWithParentBoundary(url);
1079 m_isComplete = false;
1082 if (isNewNavigation) {
1083 // This will clear previousItem from the rest of the frame tree that didn't
1084 // doing any loading. We need to make a pass on this now, since for fragment
1085 // navigation we'll not go through a real load and reach Completed state.
1086 checkLoadComplete();
1089 m_client.dispatchDidNavigateWithinPage();
1091 m_frame.document()->statePopped(stateObject ? stateObject : SerializedScriptValue::nullValue());
1092 m_client.dispatchDidPopStateWithinPage();
1095 m_frame.document()->enqueueHashchangeEvent(oldURL, url);
1096 m_client.dispatchDidChangeLocationWithinPage();
1099 // FrameLoaderClient::didFinishLoad() tells the internal load delegate the load finished with no error
1100 m_client.didFinishLoad();
1103 bool FrameLoader::isComplete() const
1105 return m_isComplete;
1108 void FrameLoader::completed()
1110 Ref<Frame> protect(m_frame);
1112 for (Frame* descendant = m_frame.tree().traverseNext(&m_frame); descendant; descendant = descendant->tree().traverseNext(&m_frame))
1113 descendant->navigationScheduler().startTimer();
1115 if (Frame* parent = m_frame.tree().parent())
1116 parent->loader().checkCompleted();
1119 m_frame.view()->maintainScrollPositionAtAnchor(nullptr);
1120 m_activityAssertion = nullptr;
1123 void FrameLoader::started()
1126 m_activityAssertion = m_frame.page()->pageThrottler().pageLoadActivityToken();
1127 for (Frame* frame = &m_frame; frame; frame = frame->tree().parent())
1128 frame->loader().m_isComplete = false;
1131 void FrameLoader::prepareForLoadStart()
1133 m_progressTracker->progressStarted();
1134 m_client.dispatchDidStartProvisionalLoad();
1136 if (AXObjectCache::accessibilityEnabled()) {
1137 if (AXObjectCache* cache = m_frame.document()->existingAXObjectCache()) {
1138 AXObjectCache::AXLoadingEvent loadingEvent = loadType() == FrameLoadType::Reload ? AXObjectCache::AXLoadingReloaded : AXObjectCache::AXLoadingStarted;
1139 cache->frameLoadingEventNotification(&m_frame, loadingEvent);
1144 void FrameLoader::setupForReplace()
1146 m_client.revertToProvisionalState(m_documentLoader.get());
1147 setState(FrameStateProvisional);
1148 m_provisionalDocumentLoader = m_documentLoader;
1149 m_documentLoader = 0;
1153 void FrameLoader::loadFrameRequest(const FrameLoadRequest& request, LockHistory lockHistory, LockBackForwardList lockBackForwardList,
1154 PassRefPtr<Event> event, PassRefPtr<FormState> formState, ShouldSendReferrer shouldSendReferrer, AllowNavigationToInvalidURL allowNavigationToInvalidURL)
1156 // Protect frame from getting blown away inside dispatchBeforeLoadEvent in loadWithDocumentLoader.
1157 Ref<Frame> protect(m_frame);
1159 URL url = request.resourceRequest().url();
1161 ASSERT(m_frame.document());
1162 if (!request.requester()->canDisplay(url)) {
1163 reportLocalLoadFailed(&m_frame, url.stringCenterEllipsizedToLength());
1167 String argsReferrer = request.resourceRequest().httpReferrer();
1168 if (argsReferrer.isEmpty())
1169 argsReferrer = outgoingReferrer();
1171 String referrer = SecurityPolicy::generateReferrerHeader(m_frame.document()->referrerPolicy(), url, argsReferrer);
1172 if (shouldSendReferrer == NeverSendReferrer)
1173 referrer = String();
1175 FrameLoadType loadType;
1176 if (request.resourceRequest().cachePolicy() == ReloadIgnoringCacheData)
1177 loadType = FrameLoadType::Reload;
1178 else if (lockBackForwardList == LockBackForwardList::Yes)
1179 loadType = FrameLoadType::RedirectWithLockedBackForwardList;
1181 loadType = FrameLoadType::Standard;
1183 if (request.resourceRequest().httpMethod() == "POST")
1184 loadPostRequest(request.resourceRequest(), referrer, request.frameName(), lockHistory, loadType, event, formState.get(), allowNavigationToInvalidURL);
1186 loadURL(request.resourceRequest().url(), referrer, request.frameName(), lockHistory, loadType, event, formState.get(), allowNavigationToInvalidURL);
1188 // FIXME: It's possible this targetFrame will not be the same frame that was targeted by the actual
1189 // load if frame names have changed.
1190 Frame* sourceFrame = formState ? formState->sourceDocument()->frame() : &m_frame;
1192 sourceFrame = &m_frame;
1193 Frame* targetFrame = sourceFrame->loader().findFrameForNavigation(request.frameName());
1194 if (targetFrame && targetFrame != sourceFrame) {
1195 if (Page* page = targetFrame->page())
1196 page->chrome().focus();
1200 void FrameLoader::loadURL(const URL& newURL, const String& referrer, const String& frameName, LockHistory lockHistory, FrameLoadType newLoadType,
1201 PassRefPtr<Event> event, PassRefPtr<FormState> prpFormState, AllowNavigationToInvalidURL allowNavigationToInvalidURL)
1203 if (m_inStopAllLoaders)
1206 Ref<Frame> protect(m_frame);
1208 RefPtr<FormState> formState = prpFormState;
1209 bool isFormSubmission = formState;
1211 ResourceRequest request(newURL);
1212 if (!referrer.isEmpty()) {
1213 request.setHTTPReferrer(referrer);
1214 RefPtr<SecurityOrigin> referrerOrigin = SecurityOrigin::createFromString(referrer);
1215 addHTTPOriginIfNeeded(request, referrerOrigin->toString());
1217 #if ENABLE(CACHE_PARTITIONING)
1218 if (&m_frame.tree().top() != &m_frame)
1219 request.setDomainForCachePartition(m_frame.tree().top().document()->securityOrigin()->domainForCachePartition());
1221 addExtraFieldsToRequest(request, newLoadType, true);
1222 if (newLoadType == FrameLoadType::Reload || newLoadType == FrameLoadType::ReloadFromOrigin)
1223 request.setCachePolicy(ReloadIgnoringCacheData);
1225 ASSERT(newLoadType != FrameLoadType::Same);
1227 // The search for a target frame is done earlier in the case of form submission.
1228 Frame* targetFrame = isFormSubmission ? 0 : findFrameForNavigation(frameName);
1229 if (targetFrame && targetFrame != &m_frame) {
1230 targetFrame->loader().loadURL(newURL, referrer, "_self", lockHistory, newLoadType, event, formState.release(), allowNavigationToInvalidURL);
1234 if (m_pageDismissalEventBeingDispatched != NoDismissal)
1237 NavigationAction action(request, newLoadType, isFormSubmission, event);
1239 if (!targetFrame && !frameName.isEmpty()) {
1240 policyChecker().checkNewWindowPolicy(action, request, formState.release(), frameName, [this, allowNavigationToInvalidURL](const ResourceRequest& request, PassRefPtr<FormState> formState, const String& frameName, const NavigationAction& action, bool shouldContinue) {
1241 continueLoadAfterNewWindowPolicy(request, formState, frameName, action, shouldContinue, allowNavigationToInvalidURL);
1246 RefPtr<DocumentLoader> oldDocumentLoader = m_documentLoader;
1248 bool sameURL = shouldTreatURLAsSameAsCurrent(newURL);
1249 const String& httpMethod = request.httpMethod();
1251 // Make sure to do scroll to fragment processing even if the URL is
1252 // exactly the same so pages with '#' links and DHTML side effects
1254 if (shouldPerformFragmentNavigation(isFormSubmission, httpMethod, newLoadType, newURL)) {
1255 oldDocumentLoader->setTriggeringAction(action);
1256 oldDocumentLoader->setLastCheckedRequest(ResourceRequest());
1257 policyChecker().stopCheck();
1258 policyChecker().setLoadType(newLoadType);
1259 policyChecker().checkNavigationPolicy(request, oldDocumentLoader.get(), formState.release(), [this](const ResourceRequest& request, PassRefPtr<FormState>, bool shouldContinue) {
1260 continueFragmentScrollAfterNavigationPolicy(request, shouldContinue);
1265 // must grab this now, since this load may stop the previous load and clear this flag
1266 bool isRedirect = m_quickRedirectComing;
1267 loadWithNavigationAction(request, action, lockHistory, newLoadType, formState.release(), allowNavigationToInvalidURL);
1269 m_quickRedirectComing = false;
1270 if (m_provisionalDocumentLoader)
1271 m_provisionalDocumentLoader->setIsClientRedirect(true);
1272 } else if (sameURL && newLoadType != FrameLoadType::Reload && newLoadType != FrameLoadType::ReloadFromOrigin) {
1273 // Example of this case are sites that reload the same URL with a different cookie
1274 // driving the generated content, or a master frame with links that drive a target
1275 // frame, where the user has clicked on the same link repeatedly.
1276 m_loadType = FrameLoadType::Same;
1280 SubstituteData FrameLoader::defaultSubstituteDataForURL(const URL& url)
1282 if (!shouldTreatURLAsSrcdocDocument(url))
1283 return SubstituteData();
1284 String srcdoc = m_frame.ownerElement()->fastGetAttribute(srcdocAttr);
1285 ASSERT(!srcdoc.isNull());
1286 CString encodedSrcdoc = srcdoc.utf8();
1287 return SubstituteData(SharedBuffer::create(encodedSrcdoc.data(), encodedSrcdoc.length()), "text/html", "UTF-8", URL());
1290 void FrameLoader::load(const FrameLoadRequest& passedRequest)
1292 FrameLoadRequest request(passedRequest);
1294 if (m_inStopAllLoaders)
1297 if (!request.frameName().isEmpty()) {
1298 Frame* frame = findFrameForNavigation(request.frameName());
1300 request.setShouldCheckNewWindowPolicy(false);
1301 if (&frame->loader() != this) {
1302 frame->loader().load(request);
1308 if (request.shouldCheckNewWindowPolicy()) {
1309 policyChecker().checkNewWindowPolicy(NavigationAction(request.resourceRequest(), NavigationTypeOther), request.resourceRequest(), nullptr, request.frameName(), [this](const ResourceRequest& request, PassRefPtr<FormState> formState, const String& frameName, const NavigationAction& action, bool shouldContinue) {
1310 continueLoadAfterNewWindowPolicy(request, formState, frameName, action, shouldContinue, AllowNavigationToInvalidURL::Yes);
1316 if (!request.hasSubstituteData())
1317 request.setSubstituteData(defaultSubstituteDataForURL(request.resourceRequest().url()));
1319 RefPtr<DocumentLoader> loader = m_client.createDocumentLoader(request.resourceRequest(), request.substituteData());
1323 void FrameLoader::loadWithNavigationAction(const ResourceRequest& request, const NavigationAction& action, LockHistory lockHistory, FrameLoadType type, PassRefPtr<FormState> formState, AllowNavigationToInvalidURL allowNavigationToInvalidURL)
1325 RefPtr<DocumentLoader> loader = m_client.createDocumentLoader(request, defaultSubstituteDataForURL(request.url()));
1326 if (lockHistory == LockHistory::Yes && m_documentLoader)
1327 loader->setClientRedirectSourceForHistory(m_documentLoader->didCreateGlobalHistoryEntry() ? m_documentLoader->urlForHistory().string() : m_documentLoader->clientRedirectSourceForHistory());
1329 loader->setTriggeringAction(action);
1330 if (m_documentLoader)
1331 loader->setOverrideEncoding(m_documentLoader->overrideEncoding());
1333 loadWithDocumentLoader(loader.get(), type, formState, allowNavigationToInvalidURL);
1336 void FrameLoader::load(DocumentLoader* newDocumentLoader)
1338 ResourceRequest& r = newDocumentLoader->request();
1339 addExtraFieldsToMainResourceRequest(r);
1342 if (shouldTreatURLAsSameAsCurrent(newDocumentLoader->originalRequest().url())) {
1343 r.setCachePolicy(ReloadIgnoringCacheData);
1344 type = FrameLoadType::Same;
1345 } else if (shouldTreatURLAsSameAsCurrent(newDocumentLoader->unreachableURL()) && m_loadType == FrameLoadType::Reload)
1346 type = FrameLoadType::Reload;
1348 type = FrameLoadType::Standard;
1350 if (m_documentLoader)
1351 newDocumentLoader->setOverrideEncoding(m_documentLoader->overrideEncoding());
1353 // When we loading alternate content for an unreachable URL that we're
1354 // visiting in the history list, we treat it as a reload so the history list
1355 // is appropriately maintained.
1357 // FIXME: This seems like a dangerous overloading of the meaning of "FrameLoadType::Reload" ...
1358 // shouldn't a more explicit type of reload be defined, that means roughly
1359 // "load without affecting history" ?
1360 if (shouldReloadToHandleUnreachableURL(newDocumentLoader)) {
1361 // shouldReloadToHandleUnreachableURL() returns true only when the original load type is back-forward.
1362 // In this case we should save the document state now. Otherwise the state can be lost because load type is
1363 // changed and updateForBackForwardNavigation() will not be called when loading is committed.
1364 history().saveDocumentAndScrollState();
1366 ASSERT(type == FrameLoadType::Standard);
1367 type = FrameLoadType::Reload;
1370 loadWithDocumentLoader(newDocumentLoader, type, 0, AllowNavigationToInvalidURL::Yes);
1373 static void logNavigation(MainFrame& frame, FrameLoadType type)
1375 String navigationDescription;
1377 case FrameLoadType::Standard:
1378 navigationDescription = ASCIILiteral("standard");
1380 case FrameLoadType::Back:
1381 navigationDescription = ASCIILiteral("back");
1383 case FrameLoadType::Forward:
1384 navigationDescription = ASCIILiteral("forward");
1386 case FrameLoadType::IndexedBackForward:
1387 navigationDescription = ASCIILiteral("indexedBackForward");
1389 case FrameLoadType::Reload:
1390 navigationDescription = ASCIILiteral("reload");
1392 case FrameLoadType::Same:
1393 navigationDescription = ASCIILiteral("same");
1395 case FrameLoadType::ReloadFromOrigin:
1396 navigationDescription = ASCIILiteral("reloadFromOrigin");
1398 case FrameLoadType::Replace:
1399 case FrameLoadType::RedirectWithLockedBackForwardList:
1400 // Not logging those for now.
1403 frame.diagnosticLoggingClient().logDiagnosticMessage(DiagnosticLoggingKeys::navigationKey(), navigationDescription);
1406 void FrameLoader::loadWithDocumentLoader(DocumentLoader* loader, FrameLoadType type, PassRefPtr<FormState> prpFormState, AllowNavigationToInvalidURL allowNavigationToInvalidURL)
1408 // Retain because dispatchBeforeLoadEvent may release the last reference to it.
1409 Ref<Frame> protect(m_frame);
1411 ASSERT(m_client.hasWebView());
1413 // Unfortunately the view must be non-nil, this is ultimately due
1414 // to parser requiring a FrameView. We should fix this dependency.
1416 ASSERT(m_frame.view());
1418 if (m_pageDismissalEventBeingDispatched != NoDismissal)
1421 if (m_frame.document())
1422 m_previousURL = m_frame.document()->url();
1424 // Log main frame navigation types.
1425 if (m_frame.isMainFrame())
1426 logNavigation(static_cast<MainFrame&>(m_frame), type);
1428 policyChecker().setLoadType(type);
1429 RefPtr<FormState> formState = prpFormState;
1430 bool isFormSubmission = formState;
1432 const URL& newURL = loader->request().url();
1433 const String& httpMethod = loader->request().httpMethod();
1435 if (shouldPerformFragmentNavigation(isFormSubmission, httpMethod, policyChecker().loadType(), newURL)) {
1436 RefPtr<DocumentLoader> oldDocumentLoader = m_documentLoader;
1437 NavigationAction action(loader->request(), policyChecker().loadType(), isFormSubmission);
1439 oldDocumentLoader->setTriggeringAction(action);
1440 oldDocumentLoader->setLastCheckedRequest(ResourceRequest());
1441 policyChecker().stopCheck();
1442 policyChecker().checkNavigationPolicy(loader->request(), oldDocumentLoader.get(), formState, [this](const ResourceRequest& request, PassRefPtr<FormState>, bool shouldContinue) {
1443 continueFragmentScrollAfterNavigationPolicy(request, shouldContinue);
1448 if (Frame* parent = m_frame.tree().parent())
1449 loader->setOverrideEncoding(parent->loader().documentLoader()->overrideEncoding());
1451 policyChecker().stopCheck();
1452 setPolicyDocumentLoader(loader);
1453 if (loader->triggeringAction().isEmpty())
1454 loader->setTriggeringAction(NavigationAction(loader->request(), policyChecker().loadType(), isFormSubmission));
1456 if (Element* ownerElement = m_frame.ownerElement()) {
1457 // We skip dispatching the beforeload event if we've already
1458 // committed a real document load because the event would leak
1459 // subsequent activity by the frame which the parent frame isn't
1460 // supposed to learn. For example, if the child frame navigated to
1461 // a new URL, the parent frame shouldn't learn the URL.
1462 if (!m_stateMachine.committedFirstRealDocumentLoad()
1463 && !ownerElement->dispatchBeforeLoadEvent(loader->request().url().string())) {
1464 continueLoadAfterNavigationPolicy(loader->request(), formState, false, allowNavigationToInvalidURL);
1469 policyChecker().checkNavigationPolicy(loader->request(), loader, formState, [this, allowNavigationToInvalidURL](const ResourceRequest& request, PassRefPtr<FormState> formState, bool shouldContinue) {
1470 continueLoadAfterNavigationPolicy(request, formState, shouldContinue, allowNavigationToInvalidURL);
1474 void FrameLoader::reportLocalLoadFailed(Frame* frame, const String& url)
1476 ASSERT(!url.isEmpty());
1480 frame->document()->addConsoleMessage(MessageSource::Security, MessageLevel::Error, "Not allowed to load local resource: " + url);
1483 const ResourceRequest& FrameLoader::initialRequest() const
1485 return activeDocumentLoader()->originalRequest();
1488 bool FrameLoader::willLoadMediaElementURL(URL& url)
1491 // MobileStore depends on the iOS 4.0 era client delegate method because webView:resource:willSendRequest:redirectResponse:fromDataSource
1492 // doesn't let them tell when a load request is coming from a media element. See <rdar://problem/8266916> for more details.
1493 if (applicationIsMobileStore())
1494 return m_client.shouldLoadMediaElementURL(url);
1497 ResourceRequest request(url);
1499 unsigned long identifier;
1500 ResourceError error;
1501 requestFromDelegate(request, identifier, error);
1502 notifier().sendRemainingDelegateMessages(m_documentLoader.get(), identifier, request, ResourceResponse(url, String(), -1, String()), 0, -1, -1, error);
1504 url = request.url();
1506 return error.isNull();
1509 bool FrameLoader::shouldReloadToHandleUnreachableURL(DocumentLoader* docLoader)
1511 URL unreachableURL = docLoader->unreachableURL();
1513 if (unreachableURL.isEmpty())
1516 if (!isBackForwardLoadType(policyChecker().loadType()))
1519 // We only treat unreachableURLs specially during the delegate callbacks
1520 // for provisional load errors and navigation policy decisions. The former
1521 // case handles well-formed URLs that can't be loaded, and the latter
1522 // case handles malformed URLs and unknown schemes. Loading alternate content
1523 // at other times behaves like a standard load.
1524 DocumentLoader* compareDocumentLoader = 0;
1525 if (policyChecker().delegateIsDecidingNavigationPolicy() || policyChecker().delegateIsHandlingUnimplementablePolicy())
1526 compareDocumentLoader = m_policyDocumentLoader.get();
1527 else if (m_delegateIsHandlingProvisionalLoadError)
1528 compareDocumentLoader = m_provisionalDocumentLoader.get();
1530 return compareDocumentLoader && unreachableURL == compareDocumentLoader->request().url();
1533 void FrameLoader::reloadWithOverrideEncoding(const String& encoding)
1535 if (!m_documentLoader)
1538 ResourceRequest request = m_documentLoader->request();
1539 URL unreachableURL = m_documentLoader->unreachableURL();
1540 if (!unreachableURL.isEmpty())
1541 request.setURL(unreachableURL);
1543 // FIXME: If the resource is a result of form submission and is not cached, the form will be silently resubmitted.
1544 // We should ask the user for confirmation in this case.
1545 request.setCachePolicy(ReturnCacheDataElseLoad);
1547 RefPtr<DocumentLoader> loader = m_client.createDocumentLoader(request, defaultSubstituteDataForURL(request.url()));
1548 setPolicyDocumentLoader(loader.get());
1550 loader->setOverrideEncoding(encoding);
1552 loadWithDocumentLoader(loader.get(), FrameLoadType::Reload, 0, AllowNavigationToInvalidURL::Yes);
1555 void FrameLoader::reload(bool endToEndReload)
1557 if (!m_documentLoader)
1560 // If a window is created by javascript, its main frame can have an empty but non-nil URL.
1561 // Reloading in this case will lose the current contents (see 4151001).
1562 if (m_documentLoader->request().url().isEmpty())
1565 // Replace error-page URL with the URL we were trying to reach.
1566 ResourceRequest initialRequest = m_documentLoader->request();
1567 URL unreachableURL = m_documentLoader->unreachableURL();
1568 if (!unreachableURL.isEmpty())
1569 initialRequest.setURL(unreachableURL);
1571 // Create a new document loader for the reload, this will become m_documentLoader eventually,
1572 // but first it has to be the "policy" document loader, and then the "provisional" document loader.
1573 RefPtr<DocumentLoader> loader = m_client.createDocumentLoader(initialRequest, defaultSubstituteDataForURL(initialRequest.url()));
1575 ResourceRequest& request = loader->request();
1577 // FIXME: We don't have a mechanism to revalidate the main resource without reloading at the moment.
1578 request.setCachePolicy(ReloadIgnoringCacheData);
1580 // If we're about to re-post, set up action so the application can warn the user.
1581 if (request.httpMethod() == "POST")
1582 loader->setTriggeringAction(NavigationAction(request, NavigationTypeFormResubmitted));
1584 loader->setOverrideEncoding(m_documentLoader->overrideEncoding());
1586 loadWithDocumentLoader(loader.get(), endToEndReload ? FrameLoadType::ReloadFromOrigin : FrameLoadType::Reload, 0, AllowNavigationToInvalidURL::Yes);
1589 void FrameLoader::stopAllLoaders(ClearProvisionalItemPolicy clearProvisionalItemPolicy)
1591 ASSERT(!m_frame.document() || !m_frame.document()->inPageCache());
1592 if (m_pageDismissalEventBeingDispatched != NoDismissal)
1595 // If this method is called from within this method, infinite recursion can occur (3442218). Avoid this.
1596 if (m_inStopAllLoaders)
1599 // Calling stopLoading() on the provisional document loader can blow away
1600 // the frame from underneath.
1601 Ref<Frame> protect(m_frame);
1603 m_inStopAllLoaders = true;
1605 policyChecker().stopCheck();
1607 // If no new load is in progress, we should clear the provisional item from history
1608 // before we call stopLoading.
1609 if (clearProvisionalItemPolicy == ShouldClearProvisionalItem)
1610 history().setProvisionalItem(0);
1612 for (RefPtr<Frame> child = m_frame.tree().firstChild(); child; child = child->tree().nextSibling())
1613 child->loader().stopAllLoaders(clearProvisionalItemPolicy);
1614 if (m_provisionalDocumentLoader)
1615 m_provisionalDocumentLoader->stopLoading();
1616 if (m_documentLoader)
1617 m_documentLoader->stopLoading();
1619 setProvisionalDocumentLoader(0);
1621 m_checkTimer.stop();
1623 m_inStopAllLoaders = false;
1626 void FrameLoader::stopForUserCancel(bool deferCheckLoadComplete)
1631 // Lay out immediately when stopping to immediately clear the old page if we just committed this one
1632 // but haven't laid out/painted yet.
1633 // FIXME: Is this behavior specific to iOS? Or should we expose a setting to toggle this behavior?
1634 if (m_frame.view() && !m_frame.view()->didFirstLayout())
1635 m_frame.view()->layout();
1638 if (deferCheckLoadComplete)
1639 scheduleCheckLoadComplete();
1640 else if (m_frame.page())
1641 checkLoadComplete();
1644 DocumentLoader* FrameLoader::activeDocumentLoader() const
1646 if (m_state == FrameStateProvisional)
1647 return m_provisionalDocumentLoader.get();
1648 return m_documentLoader.get();
1651 bool FrameLoader::isLoading() const
1653 DocumentLoader* docLoader = activeDocumentLoader();
1656 return docLoader->isLoading();
1659 bool FrameLoader::frameHasLoaded() const
1661 return m_stateMachine.committedFirstRealDocumentLoad() || (m_provisionalDocumentLoader && !m_stateMachine.creatingInitialEmptyDocument());
1664 void FrameLoader::setDocumentLoader(DocumentLoader* loader)
1666 if (!loader && !m_documentLoader)
1669 ASSERT(loader != m_documentLoader);
1670 ASSERT(!loader || loader->frameLoader() == this);
1672 m_client.prepareForDataSourceReplacement();
1675 // detachChildren() can trigger this frame's unload event, and therefore
1676 // script can run and do just about anything. For example, an unload event that calls
1677 // document.write("") on its parent frame can lead to a recursive detachChildren()
1678 // invocation for this frame. In that case, we can end up at this point with a
1679 // loader that hasn't been deleted but has been detached from its frame. Such a
1680 // DocumentLoader has been sufficiently detached that we'll end up in an inconsistent
1681 // state if we try to use it.
1682 if (loader && !loader->frame())
1685 if (m_documentLoader)
1686 m_documentLoader->detachFromFrame();
1688 m_documentLoader = loader;
1691 void FrameLoader::setPolicyDocumentLoader(DocumentLoader* loader)
1693 if (m_policyDocumentLoader == loader)
1697 loader->setFrame(&m_frame);
1698 if (m_policyDocumentLoader
1699 && m_policyDocumentLoader != m_provisionalDocumentLoader
1700 && m_policyDocumentLoader != m_documentLoader)
1701 m_policyDocumentLoader->detachFromFrame();
1703 m_policyDocumentLoader = loader;
1706 void FrameLoader::setProvisionalDocumentLoader(DocumentLoader* loader)
1708 ASSERT(!loader || !m_provisionalDocumentLoader);
1709 ASSERT(!loader || loader->frameLoader() == this);
1711 if (m_provisionalDocumentLoader && m_provisionalDocumentLoader != m_documentLoader)
1712 m_provisionalDocumentLoader->detachFromFrame();
1714 m_provisionalDocumentLoader = loader;
1717 void FrameLoader::setState(FrameState newState)
1721 if (newState == FrameStateProvisional)
1722 provisionalLoadStarted();
1723 else if (newState == FrameStateComplete) {
1724 frameLoadCompleted();
1725 if (m_documentLoader)
1726 m_documentLoader->stopRecordingResponses();
1730 void FrameLoader::clearProvisionalLoad()
1732 setProvisionalDocumentLoader(0);
1733 m_progressTracker->progressCompleted();
1734 setState(FrameStateComplete);
1737 void FrameLoader::commitProvisionalLoad()
1739 RefPtr<DocumentLoader> pdl = m_provisionalDocumentLoader;
1740 Ref<Frame> protect(m_frame);
1742 std::unique_ptr<CachedPage> cachedPage;
1743 if (m_loadingFromCachedPage)
1744 cachedPage = pageCache()->take(history().provisionalItem(), m_frame.page());
1746 LOG(PageCache, "WebCoreLoading %s: About to commit provisional load from previous URL '%s' to new URL '%s'", m_frame.tree().uniqueName().string().utf8().data(),
1747 m_frame.document() ? m_frame.document()->url().stringCenterEllipsizedToLength().utf8().data() : "",
1748 pdl ? pdl->url().stringCenterEllipsizedToLength().utf8().data() : "<no provisional DocumentLoader>");
1751 // In the case where we are not navigating to a cached page, and the system is under (speculative) memory pressure,
1752 // we can try to preemptively release some of the pages in the cache.
1753 // FIXME: Right now the capacity is 1 on iOS devices with 256 MB of RAM, so this will always blow away the whole
1754 // page cache. We could still preemptively prune the page cache while navigating to a cached page if capacity > 1.
1755 // See <rdar://problem/11779846> for more details.
1757 if (memoryPressureHandler().isUnderMemoryPressure()) {
1758 LOG(MemoryPressure, "Pruning page cache because under memory pressure at: %s", __PRETTY_FUNCTION__);
1759 LOG(PageCache, "Pruning page cache to 0 due to memory pressure");
1760 // Don't cache any page if we are under memory pressure.
1761 pageCache()->pruneToCapacityNow(0, PruningReason::MemoryPressure);
1762 } else if (systemMemoryLevel() <= memoryLevelThresholdToPrunePageCache) {
1763 LOG(MemoryPressure, "Pruning page cache because system memory level is %d at: %s", systemMemoryLevel(), __PRETTY_FUNCTION__);
1764 LOG(PageCache, "Pruning page cache to %d due to low memory (level %d less or equal to %d threshold)", pageCache()->capacity() / 2, systemMemoryLevel(), memoryLevelThresholdToPrunePageCache);
1765 pageCache()->pruneToCapacityNow(pageCache()->capacity() / 2, PruningReason::MemoryPressure);
1770 willTransitionToCommitted();
1772 // Check to see if we need to cache the page we are navigating away from into the back/forward cache.
1773 // We are doing this here because we know for sure that a new page is about to be loaded.
1774 HistoryItem* item = history().currentItem();
1775 if (!m_frame.tree().parent() && pageCache()->canCache(m_frame.page()) && !item->isInPageCache())
1776 pageCache()->add(item, *m_frame.page());
1778 if (m_loadType != FrameLoadType::Replace)
1779 closeOldDataSources();
1781 if (!cachedPage && !m_stateMachine.creatingInitialEmptyDocument())
1782 m_client.makeRepresentation(pdl.get());
1784 transitionToCommitted(cachedPage.get());
1786 if (pdl && m_documentLoader) {
1787 // Check if the destination page is allowed to access the previous page's timing information.
1788 Ref<SecurityOrigin> securityOrigin(SecurityOrigin::create(pdl->request().url()));
1789 m_documentLoader->timing()->setHasSameOriginAsPreviousDocument(securityOrigin.get().canRequest(m_previousURL));
1792 // Call clientRedirectCancelledOrFinished() here so that the frame load delegate is notified that the redirect's
1793 // status has changed, if there was a redirect. The frame load delegate may have saved some state about
1794 // the redirect in its -webView:willPerformClientRedirectToURL:delay:fireDate:forFrame:. Since we are
1795 // just about to commit a new page, there cannot possibly be a pending redirect at this point.
1796 if (m_sentRedirectNotification)
1797 clientRedirectCancelledOrFinished(false);
1799 if (cachedPage && cachedPage->document()) {
1801 // FIXME: CachedPage::restore() would dispatch viewport change notification. However UIKit expects load
1802 // commit to happen before any changes to viewport arguments and dealing with this there is difficult.
1803 m_frame.page()->chrome().setDispatchViewportDataDidChangeSuppressed(true);
1805 prepareForCachedPageRestore();
1807 // FIXME: This API should be turned around so that we ground CachedPage into the Page.
1808 cachedPage->restore(*m_frame.page());
1810 dispatchDidCommitLoad();
1812 m_frame.page()->chrome().setDispatchViewportDataDidChangeSuppressed(false);
1813 m_frame.page()->chrome().dispatchViewportPropertiesDidChange(m_frame.page()->viewportArguments());
1815 // If we have a title let the WebView know about it.
1816 StringWithDirection title = m_documentLoader->title();
1817 if (!title.isNull())
1818 m_client.dispatchDidReceiveTitle(title);
1824 LOG(Loading, "WebCoreLoading %s: Finished committing provisional load to URL %s", m_frame.tree().uniqueName().string().utf8().data(),
1825 m_frame.document() ? m_frame.document()->url().stringCenterEllipsizedToLength().utf8().data() : "");
1827 if (m_loadType == FrameLoadType::Standard && m_documentLoader->isClientRedirect())
1828 history().updateForClientRedirect();
1830 if (m_loadingFromCachedPage) {
1832 // Note, didReceiveDocType is expected to be called for cached pages. See <rdar://problem/5906758> for more details.
1833 if (m_frame.document()->doctype() && m_frame.page())
1834 m_frame.page()->chrome().didReceiveDocType(&m_frame);
1836 m_frame.document()->documentDidResumeFromPageCache();
1838 // Force a layout to update view size and thereby update scrollbars.
1840 if (!m_client.forceLayoutOnRestoreFromPageCache())
1841 m_frame.view()->forceLayout();
1843 m_frame.view()->forceLayout();
1846 const ResponseVector& responses = m_documentLoader->responses();
1847 size_t count = responses.size();
1848 for (size_t i = 0; i < count; i++) {
1849 const ResourceResponse& response = responses[i];
1850 // FIXME: If the WebKit client changes or cancels the request, this is not respected.
1851 ResourceError error;
1852 unsigned long identifier;
1853 ResourceRequest request(response.url());
1854 requestFromDelegate(request, identifier, error);
1855 // FIXME: If we get a resource with more than 2B bytes, this code won't do the right thing.
1856 // However, with today's computers and networking speeds, this won't happen in practice.
1857 // Could be an issue with a giant local file.
1858 notifier().sendRemainingDelegateMessages(m_documentLoader.get(), identifier, request, response, 0, static_cast<int>(response.expectedContentLength()), 0, error);
1861 // FIXME: Why only this frame and not parent frames?
1862 checkLoadCompleteForThisFrame();
1866 void FrameLoader::transitionToCommitted(CachedPage* cachedPage)
1868 ASSERT(m_client.hasWebView());
1869 ASSERT(m_state == FrameStateProvisional);
1871 if (m_state != FrameStateProvisional)
1874 if (FrameView* view = m_frame.view()) {
1875 if (ScrollAnimator* scrollAnimator = view->existingScrollAnimator())
1876 scrollAnimator->cancelAnimations();
1879 m_client.setCopiesOnScroll();
1880 history().updateForCommit();
1882 // The call to closeURL() invokes the unload event handler, which can execute arbitrary
1883 // JavaScript. If the script initiates a new load, we need to abandon the current load,
1884 // or the two will stomp each other.
1885 DocumentLoader* pdl = m_provisionalDocumentLoader.get();
1886 if (m_documentLoader)
1888 if (pdl != m_provisionalDocumentLoader)
1891 // Nothing else can interupt this commit - set the Provisional->Committed transition in stone
1892 if (m_documentLoader)
1893 m_documentLoader->stopLoadingSubresources();
1894 if (m_documentLoader)
1895 m_documentLoader->stopLoadingPlugIns();
1897 setDocumentLoader(m_provisionalDocumentLoader.get());
1898 setProvisionalDocumentLoader(0);
1900 if (pdl != m_documentLoader) {
1901 ASSERT(m_state == FrameStateComplete);
1905 setState(FrameStateCommittedPage);
1907 #if ENABLE(TOUCH_EVENTS) && !PLATFORM(IOS)
1908 if (m_frame.isMainFrame())
1909 m_frame.page()->chrome().client().needTouchEvents(false);
1912 // Handle adding the URL to the back/forward list.
1913 DocumentLoader* dl = m_documentLoader.get();
1915 switch (m_loadType) {
1916 case FrameLoadType::Forward:
1917 case FrameLoadType::Back:
1918 case FrameLoadType::IndexedBackForward:
1919 if (m_frame.page()) {
1920 // If the first load within a frame is a navigation within a back/forward list that was attached
1921 // without any of the items being loaded then we need to update the history in a similar manner as
1922 // for a standard load with the exception of updating the back/forward list (<rdar://problem/8091103>).
1923 if (!m_stateMachine.committedFirstRealDocumentLoad() && m_frame.isMainFrame())
1924 history().updateForStandardLoad(HistoryController::UpdateAllExceptBackForwardList);
1926 history().updateForBackForwardNavigation();
1928 // For cached pages, CachedFrame::restore will take care of firing the popstate event with the history item's state object
1929 if (history().currentItem() && !cachedPage)
1930 m_pendingStateObject = history().currentItem()->stateObject();
1932 // Create a document view for this document, or used the cached view.
1934 DocumentLoader* cachedDocumentLoader = cachedPage->documentLoader();
1935 ASSERT(cachedDocumentLoader);
1936 cachedDocumentLoader->setFrame(&m_frame);
1937 m_client.transitionToCommittedFromCachedFrame(cachedPage->cachedMainFrame());
1939 m_client.transitionToCommittedForNewPage();
1943 case FrameLoadType::Reload:
1944 case FrameLoadType::ReloadFromOrigin:
1945 case FrameLoadType::Same:
1946 case FrameLoadType::Replace:
1947 history().updateForReload();
1948 m_client.transitionToCommittedForNewPage();
1951 case FrameLoadType::Standard:
1952 history().updateForStandardLoad();
1954 m_frame.view()->setScrollbarsSuppressed(true);
1955 m_client.transitionToCommittedForNewPage();
1958 case FrameLoadType::RedirectWithLockedBackForwardList:
1959 history().updateForRedirectWithLockedBackForwardList();
1960 m_client.transitionToCommittedForNewPage();
1963 // FIXME Remove this check when dummy ds is removed (whatever "dummy ds" is).
1964 // An exception should be thrown if we're in the FrameLoadTypeUninitialized state.
1966 ASSERT_NOT_REACHED();
1969 m_documentLoader->writer().setMIMEType(dl->responseMIMEType());
1971 // Tell the client we've committed this URL.
1972 ASSERT(m_frame.view());
1974 if (m_stateMachine.creatingInitialEmptyDocument())
1977 if (!m_stateMachine.committedFirstRealDocumentLoad())
1978 m_stateMachine.advanceTo(FrameLoaderStateMachine::DisplayingInitialEmptyDocumentPostCommit);
1981 void FrameLoader::clientRedirectCancelledOrFinished(bool cancelWithLoadInProgress)
1983 // Note that -webView:didCancelClientRedirectForFrame: is called on the frame load delegate even if
1984 // the redirect succeeded. We should either rename this API, or add a new method, like
1985 // -webView:didFinishClientRedirectForFrame:
1986 m_client.dispatchDidCancelClientRedirect();
1988 if (!cancelWithLoadInProgress)
1989 m_quickRedirectComing = false;
1991 m_sentRedirectNotification = false;
1994 void FrameLoader::clientRedirected(const URL& url, double seconds, double fireDate, LockBackForwardList lockBackForwardList)
1996 m_client.dispatchWillPerformClientRedirect(url, seconds, fireDate);
1998 // Remember that we sent a redirect notification to the frame load delegate so that when we commit
1999 // the next provisional load, we can send a corresponding -webView:didCancelClientRedirectForFrame:
2000 m_sentRedirectNotification = true;
2002 // If a "quick" redirect comes in, we set a special mode so we treat the next
2003 // load as part of the original navigation. If we don't have a document loader, we have
2004 // no "original" load on which to base a redirect, so we treat the redirect as a normal load.
2005 // Loads triggered by JavaScript form submissions never count as quick redirects.
2006 m_quickRedirectComing = (lockBackForwardList == LockBackForwardList::Yes || history().currentItemShouldBeReplaced()) && m_documentLoader && !m_isExecutingJavaScriptFormAction;
2009 bool FrameLoader::shouldReload(const URL& currentURL, const URL& destinationURL)
2011 // This function implements the rule: "Don't reload if navigating by fragment within
2012 // the same URL, but do reload if going to a new URL or to the same URL with no
2013 // fragment identifier at all."
2014 if (!destinationURL.hasFragmentIdentifier())
2016 return !equalIgnoringFragmentIdentifier(currentURL, destinationURL);
2019 void FrameLoader::closeOldDataSources()
2021 // FIXME: Is it important for this traversal to be postorder instead of preorder?
2022 // If so, add helpers for postorder traversal, and use them. If not, then lets not
2023 // use a recursive algorithm here.
2024 for (Frame* child = m_frame.tree().firstChild(); child; child = child->tree().nextSibling())
2025 child->loader().closeOldDataSources();
2027 if (m_documentLoader)
2028 m_client.dispatchWillClose();
2030 m_client.setMainFrameDocumentReady(false); // stop giving out the actual DOMDocument to observers
2033 void FrameLoader::prepareForCachedPageRestore()
2035 ASSERT(!m_frame.tree().parent());
2036 ASSERT(m_frame.page());
2037 ASSERT(m_frame.isMainFrame());
2039 m_frame.navigationScheduler().cancel();
2041 // We still have to close the previous part page.
2044 // Delete old status bar messages (if it _was_ activated on last URL).
2045 if (m_frame.script().canExecuteScripts(NotAboutToExecuteScript)) {
2046 DOMWindow* window = m_frame.document()->domWindow();
2047 window->setStatus(String());
2048 window->setDefaultStatus(String());
2052 void FrameLoader::open(CachedFrameBase& cachedFrame)
2054 m_isComplete = false;
2056 // Don't re-emit the load event.
2057 m_didCallImplicitClose = true;
2059 URL url = cachedFrame.url();
2061 // FIXME: I suspect this block of code doesn't do anything.
2062 if (url.protocolIsInHTTPFamily() && !url.host().isEmpty() && url.path().isEmpty())
2066 Document* document = cachedFrame.document();
2068 ASSERT(document->domWindow());
2070 clear(document, true, true, cachedFrame.isMainFrame());
2072 document->setInPageCache(false);
2074 m_needsClear = true;
2075 m_isComplete = false;
2076 m_didCallImplicitClose = false;
2077 m_outgoingReferrer = url.string();
2079 FrameView* view = cachedFrame.view();
2081 // When navigating to a CachedFrame its FrameView should never be null. If it is we'll crash in creative ways downstream.
2083 view->setWasScrolledByUser(false);
2085 // Use the current ScrollView's frame rect.
2087 view->setFrameRect(m_frame.view()->frameRect());
2088 m_frame.setView(view);
2090 m_frame.setDocument(document);
2091 document->domWindow()->resumeFromPageCache();
2093 updateFirstPartyForCookies();
2095 cachedFrame.restore();
2098 bool FrameLoader::isHostedByObjectElement() const
2100 HTMLFrameOwnerElement* owner = m_frame.ownerElement();
2101 return owner && owner->hasTagName(objectTag);
2104 bool FrameLoader::isReplacing() const
2106 return m_loadType == FrameLoadType::Replace;
2109 void FrameLoader::setReplacing()
2111 m_loadType = FrameLoadType::Replace;
2114 bool FrameLoader::subframeIsLoading() const
2116 // It's most likely that the last added frame is the last to load so we walk backwards.
2117 for (Frame* child = m_frame.tree().lastChild(); child; child = child->tree().previousSibling()) {
2118 FrameLoader& childLoader = child->loader();
2119 DocumentLoader* documentLoader = childLoader.documentLoader();
2120 if (documentLoader && documentLoader->isLoadingInAPISense())
2122 documentLoader = childLoader.provisionalDocumentLoader();
2123 if (documentLoader && documentLoader->isLoadingInAPISense())
2125 documentLoader = childLoader.policyDocumentLoader();
2132 void FrameLoader::willChangeTitle(DocumentLoader* loader)
2134 m_client.willChangeTitle(loader);
2137 FrameLoadType FrameLoader::loadType() const
2142 CachePolicy FrameLoader::subresourceCachePolicy() const
2145 return CachePolicyVerify;
2147 if (m_loadType == FrameLoadType::ReloadFromOrigin)
2148 return CachePolicyReload;
2150 if (Frame* parentFrame = m_frame.tree().parent()) {
2151 CachePolicy parentCachePolicy = parentFrame->loader().subresourceCachePolicy();
2152 if (parentCachePolicy != CachePolicyVerify)
2153 return parentCachePolicy;
2156 switch (m_loadType) {
2157 case FrameLoadType::Reload:
2158 return CachePolicyRevalidate;
2159 case FrameLoadType::Back:
2160 case FrameLoadType::Forward:
2161 case FrameLoadType::IndexedBackForward:
2162 return CachePolicyHistoryBuffer;
2163 case FrameLoadType::ReloadFromOrigin:
2164 ASSERT_NOT_REACHED(); // Already handled above.
2165 return CachePolicyReload;
2166 case FrameLoadType::RedirectWithLockedBackForwardList:
2167 case FrameLoadType::Replace:
2168 case FrameLoadType::Same:
2169 case FrameLoadType::Standard:
2170 return CachePolicyVerify;
2173 RELEASE_ASSERT_NOT_REACHED();
2174 return CachePolicyVerify;
2177 void FrameLoader::checkLoadCompleteForThisFrame()
2179 ASSERT(m_client.hasWebView());
2182 case FrameStateProvisional: {
2183 if (m_delegateIsHandlingProvisionalLoadError)
2186 RefPtr<DocumentLoader> pdl = m_provisionalDocumentLoader;
2190 // If we've received any errors we may be stuck in the provisional state and actually complete.
2191 const ResourceError& error = pdl->mainDocumentError();
2195 // Check all children first.
2196 RefPtr<HistoryItem> item;
2197 if (Page* page = m_frame.page())
2198 if (isBackForwardLoadType(loadType()))
2199 // Reset the back forward list to the last committed history item at the top level.
2200 item = page->mainFrame().loader().history().currentItem();
2202 // Only reset if we aren't already going to a new provisional item.
2203 bool shouldReset = !history().provisionalItem();
2204 if (!pdl->isLoadingInAPISense() || pdl->isStopping()) {
2205 m_delegateIsHandlingProvisionalLoadError = true;
2206 m_client.dispatchDidFailProvisionalLoad(error);
2207 m_delegateIsHandlingProvisionalLoadError = false;
2209 ASSERT(!pdl->isLoading());
2211 // If we're in the middle of loading multipart data, we need to restore the document loader.
2212 if (isReplacing() && !m_documentLoader.get())
2213 setDocumentLoader(m_provisionalDocumentLoader.get());
2215 // Finish resetting the load state, but only if another load hasn't been started by the
2216 // delegate callback.
2217 if (pdl == m_provisionalDocumentLoader)
2218 clearProvisionalLoad();
2219 else if (activeDocumentLoader()) {
2220 URL unreachableURL = activeDocumentLoader()->unreachableURL();
2221 if (!unreachableURL.isEmpty() && unreachableURL == pdl->request().url())
2222 shouldReset = false;
2225 if (shouldReset && item)
2226 if (Page* page = m_frame.page()) {
2227 page->backForward().setCurrentItem(item.get());
2228 m_frame.loader().client().updateGlobalHistoryItemForPage();
2233 case FrameStateCommittedPage: {
2234 DocumentLoader* dl = m_documentLoader.get();
2235 if (!dl || (dl->isLoadingInAPISense() && !dl->isStopping()))
2238 setState(FrameStateComplete);
2240 // FIXME: Is this subsequent work important if we already navigated away?
2241 // Maybe there are bugs because of that, or extra work we can skip because
2242 // the new page is ready.
2244 m_client.forceLayoutForNonHTML();
2246 // If the user had a scroll point, scroll to it, overriding the anchor point if any.
2247 if (m_frame.page()) {
2248 if (isBackForwardLoadType(m_loadType) || m_loadType == FrameLoadType::Reload || m_loadType == FrameLoadType::ReloadFromOrigin)
2249 history().restoreScrollPositionAndViewState();
2252 if (m_stateMachine.creatingInitialEmptyDocument() || !m_stateMachine.committedFirstRealDocumentLoad())
2255 m_progressTracker->progressCompleted();
2256 Page* page = m_frame.page();
2258 if (m_frame.isMainFrame())
2259 page->resetRelevantPaintedObjectCounter();
2262 const ResourceError& error = dl->mainDocumentError();
2264 AXObjectCache::AXLoadingEvent loadingEvent;
2265 if (!error.isNull()) {
2266 m_client.dispatchDidFailLoad(error);
2267 loadingEvent = AXObjectCache::AXLoadingFailed;
2269 m_client.dispatchDidFinishLoad();
2270 loadingEvent = AXObjectCache::AXLoadingFinished;
2273 // Notify accessibility.
2274 if (AXObjectCache* cache = m_frame.document()->existingAXObjectCache())
2275 cache->frameLoadingEventNotification(&m_frame, loadingEvent);
2278 page->mainFrame().diagnosticLoggingClient().logDiagnosticMessageWithResult(DiagnosticLoggingKeys::pageLoadedKey(), emptyString(), error.isNull() ? DiagnosticLoggingResultPass : DiagnosticLoggingResultFail);
2283 case FrameStateComplete:
2284 m_loadType = FrameLoadType::Standard;
2285 frameLoadCompleted();
2289 ASSERT_NOT_REACHED();
2292 void FrameLoader::continueLoadAfterWillSubmitForm()
2294 if (!m_provisionalDocumentLoader)
2297 prepareForLoadStart();
2299 // The load might be cancelled inside of prepareForLoadStart(), nulling out the m_provisionalDocumentLoader,
2300 // so we need to null check it again.
2301 if (!m_provisionalDocumentLoader)
2304 DocumentLoader* activeDocLoader = activeDocumentLoader();
2305 if (activeDocLoader && activeDocLoader->isLoadingMainResource())
2308 m_loadingFromCachedPage = false;
2309 m_provisionalDocumentLoader->startLoadingMainResource();
2312 static URL originatingURLFromBackForwardList(Page* page)
2314 // FIXME: Can this logic be replaced with m_frame.document()->firstPartyForCookies()?
2315 // It has the same meaning of "page a user thinks is the current one".
2318 int backCount = page->backForward().backCount();
2319 for (int backIndex = 0; backIndex <= backCount; backIndex++) {
2320 // FIXME: At one point we had code here to check a "was user gesture" flag.
2321 // Do we need to restore that logic?
2322 HistoryItem* historyItem = page->backForward().itemAtIndex(-backIndex);
2326 originalURL = historyItem->originalURL();
2327 if (!originalURL.isNull())
2334 void FrameLoader::setOriginalURLForDownloadRequest(ResourceRequest& request)
2338 // If there is no referrer, assume that the download was initiated directly, so current document is
2339 // completely unrelated to it. See <rdar://problem/5294691>.
2340 // FIXME: Referrer is not sent in many other cases, so we will often miss this important information.
2341 // Find a better way to decide whether the download was unrelated to current document.
2342 if (!request.httpReferrer().isNull()) {
2343 // find the first item in the history that was originated by the user
2344 originalURL = originatingURLFromBackForwardList(m_frame.page());
2347 if (originalURL.isNull())
2348 originalURL = request.url();
2350 if (!originalURL.protocol().isEmpty() && !originalURL.host().isEmpty()) {
2351 unsigned port = originalURL.port();
2353 // Original URL is needed to show the user where a file was downloaded from. We should make a URL that won't result in downloading the file again.
2354 // FIXME: Using host-only URL is a very heavy-handed approach. We should attempt to provide the actual page where the download was initiated from, as a reminder to the user.
2355 String hostOnlyURLString;
2357 hostOnlyURLString = makeString(originalURL.protocol(), "://", originalURL.host(), ':', String::number(port));
2359 hostOnlyURLString = makeString(originalURL.protocol(), "://", originalURL.host());
2361 // FIXME: Rename firstPartyForCookies back to mainDocumentURL. It was a mistake to think that it was only used for cookies.
2362 request.setFirstPartyForCookies(URL(URL(), hostOnlyURLString));
2366 void FrameLoader::didLayout(LayoutMilestones milestones)
2368 ASSERT(m_frame.isMainFrame());
2370 m_client.dispatchDidLayout(milestones);
2373 void FrameLoader::didFirstLayout()
2376 // Only send layout-related delegate callbacks synchronously for the main frame to
2377 // avoid reentering layout for the main frame while delivering a layout-related delegate
2378 // callback for a subframe.
2379 if (&m_frame != &m_frame.page()->mainFrame())
2382 if (m_frame.page() && isBackForwardLoadType(m_loadType))
2383 history().restoreScrollPositionAndViewState();
2385 if (m_stateMachine.committedFirstRealDocumentLoad() && !m_stateMachine.isDisplayingInitialEmptyDocument() && !m_stateMachine.firstLayoutDone())
2386 m_stateMachine.advanceTo(FrameLoaderStateMachine::FirstLayoutDone);
2389 void FrameLoader::frameLoadCompleted()
2391 // Note: Can be called multiple times.
2393 m_client.frameLoadCompleted();
2395 history().updateForFrameLoadCompleted();
2397 // After a canceled provisional load, firstLayoutDone is false.
2398 // Reset it to true if we're displaying a page.
2399 if (m_documentLoader && m_stateMachine.committedFirstRealDocumentLoad() && !m_stateMachine.isDisplayingInitialEmptyDocument() && !m_stateMachine.firstLayoutDone())
2400 m_stateMachine.advanceTo(FrameLoaderStateMachine::FirstLayoutDone);
2403 void FrameLoader::detachChildren()
2405 Vector<Ref<Frame>, 16> childrenToDetach;
2406 childrenToDetach.reserveInitialCapacity(m_frame.tree().childCount());
2407 for (Frame* child = m_frame.tree().lastChild(); child; child = child->tree().previousSibling())
2408 childrenToDetach.uncheckedAppend(*child);
2409 for (unsigned i = 0; i < childrenToDetach.size(); ++i)
2410 childrenToDetach[i]->loader().detachFromParent();
2413 void FrameLoader::closeAndRemoveChild(Frame* child)
2415 child->tree().detachFromParent();
2418 if (child->ownerElement() && child->page())
2419 child->page()->decrementSubframeCount();
2420 child->willDetachPage();
2421 child->detachFromPage();
2423 m_frame.tree().removeChild(child);
2426 // Called every time a resource is completely loaded or an error is received.
2427 void FrameLoader::checkLoadComplete()
2429 ASSERT(m_client.hasWebView());
2431 m_shouldCallCheckLoadComplete = false;
2433 if (!m_frame.page())
2436 // FIXME: Always traversing the entire frame tree is a bit inefficient, but
2437 // is currently needed in order to null out the previous history item for all frames.
2438 Vector<Ref<Frame>, 16> frames;
2439 for (Frame* frame = &m_frame.mainFrame(); frame; frame = frame->tree().traverseNext())
2440 frames.append(*frame);
2442 // To process children before their parents, iterate the vector backwards.
2443 for (unsigned i = frames.size(); i; --i)
2444 frames[i - 1]->loader().checkLoadCompleteForThisFrame();
2447 int FrameLoader::numPendingOrLoadingRequests(bool recurse) const
2450 return m_frame.document()->cachedResourceLoader()->requestCount();
2453 for (Frame* frame = &m_frame; frame; frame = frame->tree().traverseNext(&m_frame))
2454 count += frame->document()->cachedResourceLoader()->requestCount();
2458 String FrameLoader::userAgent(const URL& url) const
2460 return m_client.userAgent(url);
2463 void FrameLoader::handledOnloadEvents()
2465 m_client.dispatchDidHandleOnloadEvents();
2467 if (documentLoader())
2468 documentLoader()->handledOnloadEvents();
2471 void FrameLoader::frameDetached()
2474 m_frame.document()->stopActiveDOMObjects();
2478 void FrameLoader::detachFromParent()
2480 Ref<Frame> protect(m_frame);
2483 history().saveScrollPositionAndViewStateToItem(history().currentItem());
2485 // stopAllLoaders() needs to be called after detachChildren(), because detachedChildren()
2486 // will trigger the unload event handlers of any child frames, and those event
2487 // handlers might start a new subresource load in this frame.
2490 InspectorInstrumentation::frameDetachedFromParent(m_frame);
2492 detachViewsAndDocumentLoader();
2494 m_progressTracker = nullptr;
2496 if (Frame* parent = m_frame.tree().parent()) {
2497 parent->loader().closeAndRemoveChild(&m_frame);
2498 parent->loader().scheduleCheckCompleted();
2501 m_frame.willDetachPage();
2502 m_frame.detachFromPage();
2506 void FrameLoader::detachViewsAndDocumentLoader()
2508 m_client.detachedFromParent2();
2509 setDocumentLoader(0);
2510 m_client.detachedFromParent3();
2513 void FrameLoader::addExtraFieldsToSubresourceRequest(ResourceRequest& request)
2515 addExtraFieldsToRequest(request, m_loadType, false);
2518 void FrameLoader::addExtraFieldsToMainResourceRequest(ResourceRequest& request)
2520 // FIXME: Using m_loadType seems wrong for some callers.
2521 // If we are only preparing to load the main resource, that is previous load's load type!
2522 addExtraFieldsToRequest(request, m_loadType, true);
2525 void FrameLoader::addExtraFieldsToRequest(ResourceRequest& request, FrameLoadType loadType, bool mainResource)
2527 // Don't set the cookie policy URL if it's already been set.
2528 // But make sure to set it on all requests regardless of protocol, as it has significance beyond the cookie policy (<rdar://problem/6616664>).
2529 if (request.firstPartyForCookies().isEmpty()) {
2530 if (mainResource && m_frame.isMainFrame())
2531 request.setFirstPartyForCookies(request.url());
2532 else if (Document* document = m_frame.document())
2533 request.setFirstPartyForCookies(document->firstPartyForCookies());
2536 // The remaining modifications are only necessary for HTTP and HTTPS.
2537 if (!request.url().isEmpty() && !request.url().protocolIsInHTTPFamily())
2540 applyUserAgent(request);
2542 if (!mainResource) {
2543 if (request.isConditional())
2544 request.setCachePolicy(ReloadIgnoringCacheData);
2545 else if (documentLoader()->isLoadingInAPISense()) {
2546 // If we inherit cache policy from a main resource, we use the DocumentLoader's
2547 // original request cache policy for two reasons:
2548 // 1. For POST requests, we mutate the cache policy for the main resource,
2549 // but we do not want this to apply to subresources
2550 // 2. Delegates that modify the cache policy using willSendRequest: should
2551 // not affect any other resources. Such changes need to be done
2553 ResourceRequestCachePolicy mainDocumentOriginalCachePolicy = documentLoader()->originalRequest().cachePolicy();
2554 // Back-forward navigations try to load main resource from cache only to avoid re-submitting form data, and start over (with a warning dialog) if that fails.
2555 // This policy is set on initial request too, but should not be inherited.
2556 ResourceRequestCachePolicy subresourceCachePolicy = (mainDocumentOriginalCachePolicy == ReturnCacheDataDontLoad) ? ReturnCacheDataElseLoad : mainDocumentOriginalCachePolicy;
2557 request.setCachePolicy(subresourceCachePolicy);
2559 request.setCachePolicy(UseProtocolCachePolicy);
2561 // FIXME: Other FrameLoader functions have duplicated code for setting cache policy of main request when reloading.
2562 // It seems better to manage it explicitly than to hide the logic inside addExtraFieldsToRequest().
2563 } else if (loadType == FrameLoadType::Reload || loadType == FrameLoadType::ReloadFromOrigin || request.isConditional())
2564 request.setCachePolicy(ReloadIgnoringCacheData);
2566 if (request.cachePolicy() == ReloadIgnoringCacheData) {
2567 if (loadType == FrameLoadType::Reload)
2568 request.setHTTPHeaderField(HTTPHeaderName::CacheControl, "max-age=0");
2569 else if (loadType == FrameLoadType::ReloadFromOrigin) {
2570 request.setHTTPHeaderField(HTTPHeaderName::CacheControl, "no-cache");
2571 request.setHTTPHeaderField(HTTPHeaderName::Pragma, "no-cache");
2576 request.setHTTPAccept(defaultAcceptHeader);
2578 // Make sure we send the Origin header.
2579 addHTTPOriginIfNeeded(request, String());
2581 // Only set fallback array if it's still empty (later attempts may be incorrect, see bug 117818).
2582 if (request.responseContentDispositionEncodingFallbackArray().isEmpty()) {
2583 // Always try UTF-8. If that fails, try frame encoding (if any) and then the default.
2584 request.setResponseContentDispositionEncodingFallbackArray("UTF-8", m_frame.document()->encoding(), m_frame.settings().defaultTextEncodingName());
2588 void FrameLoader::addHTTPOriginIfNeeded(ResourceRequest& request, const String& origin)
2590 if (!request.httpOrigin().isEmpty())
2591 return; // Request already has an Origin header.
2593 // Don't send an Origin header for GET or HEAD to avoid privacy issues.
2594 // For example, if an intranet page has a hyperlink to an external web
2595 // site, we don't want to include the Origin of the request because it
2596 // will leak the internal host name. Similar privacy concerns have lead
2597 // to the widespread suppression of the Referer header at the network
2599 if (request.httpMethod() == "GET" || request.httpMethod() == "HEAD")
2602 // For non-GET and non-HEAD methods, always send an Origin header so the
2603 // server knows we support this feature.
2605 if (origin.isEmpty()) {
2606 // If we don't know what origin header to attach, we attach the value
2607 // for an empty origin.
2608 request.setHTTPOrigin(SecurityOrigin::createUnique()->toString());
2612 request.setHTTPOrigin(origin);
2615 void FrameLoader::loadPostRequest(const ResourceRequest& inRequest, const String& referrer, const String& frameName, LockHistory lockHistory, FrameLoadType loadType, PassRefPtr<Event> event, PassRefPtr<FormState> prpFormState, AllowNavigationToInvalidURL allowNavigationToInvalidURL)
2617 RefPtr<FormState> formState = prpFormState;
2619 // Previously when this method was reached, the original FrameLoadRequest had been deconstructed to build a
2620 // bunch of parameters that would come in here and then be built back up to a ResourceRequest. In case
2621 // any caller depends on the immutability of the original ResourceRequest, I'm rebuilding a ResourceRequest
2622 // from scratch as it did all along.
2623 const URL& url = inRequest.url();
2624 RefPtr<FormData> formData = inRequest.httpBody();
2625 const String& contentType = inRequest.httpContentType();
2626 String origin = inRequest.httpOrigin();
2628 ResourceRequest workingResourceRequest(url);
2630 if (!referrer.isEmpty())
2631 workingResourceRequest.setHTTPReferrer(referrer);
2632 workingResourceRequest.setHTTPOrigin(origin);
2633 workingResourceRequest.setHTTPMethod("POST");
2634 workingResourceRequest.setHTTPBody(formData);
2635 workingResourceRequest.setHTTPContentType(contentType);
2636 addExtraFieldsToRequest(workingResourceRequest, loadType, true);
2638 NavigationAction action(workingResourceRequest, loadType, true, event);
2640 if (!frameName.isEmpty()) {
2641 // The search for a target frame is done earlier in the case of form submission.
2642 if (Frame* targetFrame = formState ? 0 : findFrameForNavigation(frameName)) {
2643 targetFrame->loader().loadWithNavigationAction(workingResourceRequest, action, lockHistory, loadType, formState.release(), allowNavigationToInvalidURL);
2647 policyChecker().checkNewWindowPolicy(action, workingResourceRequest, formState.release(), frameName, [this, allowNavigationToInvalidURL](const ResourceRequest& request, PassRefPtr<FormState> formState, const String& frameName, const NavigationAction& action, bool shouldContinue) {
2648 continueLoadAfterNewWindowPolicy(request, formState, frameName, action, shouldContinue, allowNavigationToInvalidURL);
2653 // must grab this now, since this load may stop the previous load and clear this flag
2654 bool isRedirect = m_quickRedirectComing;
2655 loadWithNavigationAction(workingResourceRequest, action, lockHistory, loadType, formState.release(), allowNavigationToInvalidURL);
2657 m_quickRedirectComing = false;
2658 if (m_provisionalDocumentLoader)
2659 m_provisionalDocumentLoader->setIsClientRedirect(true);
2663 unsigned long FrameLoader::loadResourceSynchronously(const ResourceRequest& request, StoredCredentials storedCredentials, ClientCredentialPolicy clientCredentialPolicy, ResourceError& error, ResourceResponse& response, Vector<char>& data)
2665 ASSERT(m_frame.document());
2666 String referrer = SecurityPolicy::generateReferrerHeader(m_frame.document()->referrerPolicy(), request.url(), outgoingReferrer());
2668 ResourceRequest initialRequest = request;
2669 initialRequest.setTimeoutInterval(10);
2671 if (!referrer.isEmpty())
2672 initialRequest.setHTTPReferrer(referrer);
2673 addHTTPOriginIfNeeded(initialRequest, outgoingOrigin());
2675 initialRequest.setFirstPartyForCookies(m_frame.mainFrame().loader().documentLoader()->request().url());
2677 addExtraFieldsToSubresourceRequest(initialRequest);
2679 unsigned long identifier = 0;
2680 ResourceRequest newRequest(initialRequest);
2681 requestFromDelegate(newRequest, identifier, error);
2683 if (error.isNull()) {
2684 ASSERT(!newRequest.isNull());
2686 if (!documentLoader()->applicationCacheHost()->maybeLoadSynchronously(newRequest, error, response, data)) {
2687 platformStrategies()->loaderStrategy()->loadResourceSynchronously(networkingContext(), identifier, newRequest, storedCredentials, clientCredentialPolicy, error, response, data);
2688 documentLoader()->applicationCacheHost()->maybeLoadFallbackSynchronously(newRequest, error, response, data);
2691 notifier().sendRemainingDelegateMessages(m_documentLoader.get(), identifier, request, response, data.data(), data.size(), -1, error);
2695 const ResourceRequest& FrameLoader::originalRequest() const
2697 return activeDocumentLoader()->originalRequestCopy();
2700 void FrameLoader::receivedMainResourceError(const ResourceError& error)
2702 // Retain because the stop may release the last reference to it.
2703 Ref<Frame> protect(m_frame);
2705 RefPtr<DocumentLoader> loader = activeDocumentLoader();
2706 // FIXME: Don't want to do this if an entirely new load is going, so should check
2707 // that both data sources on the frame are either this or nil.
2709 if (m_client.shouldFallBack(error))
2710 handleFallbackContent();
2712 if (m_state == FrameStateProvisional && m_provisionalDocumentLoader) {
2713 if (m_submittedFormURL == m_provisionalDocumentLoader->originalRequestCopy().url())
2714 m_submittedFormURL = URL();
2716 // We might have made a page cache item, but now we're bailing out due to an error before we ever
2717 // transitioned to the new page (before WebFrameState == commit). The goal here is to restore any state
2718 // so that the existing view (that wenever got far enough to replace) can continue being used.
2719 history().invalidateCurrentItemCachedPage();
2721 // Call clientRedirectCancelledOrFinished here so that the frame load delegate is notified that the redirect's
2722 // status has changed, if there was a redirect. The frame load delegate may have saved some state about
2723 // the redirect in its -webView:willPerformClientRedirectToURL:delay:fireDate:forFrame:. Since we are definitely
2724 // not going to use this provisional resource, as it was cancelled, notify the frame load delegate that the redirect
2726 if (m_sentRedirectNotification)
2727 clientRedirectCancelledOrFinished(false);
2732 checkLoadComplete();
2735 void FrameLoader::continueFragmentScrollAfterNavigationPolicy(const ResourceRequest& request, bool shouldContinue)
2737 m_quickRedirectComing = false;
2739 if (!shouldContinue)
2742 // If we have a provisional request for a different document, a fragment scroll should cancel it.
2743 if (m_provisionalDocumentLoader && !equalIgnoringFragmentIdentifier(m_provisionalDocumentLoader->request().url(), request.url())) {
2744 m_provisionalDocumentLoader->stopLoading();
2745 setProvisionalDocumentLoader(0);
2748 bool isRedirect = m_quickRedirectComing || policyChecker().loadType() == FrameLoadType::RedirectWithLockedBackForwardList;
2749 loadInSameDocument(request.url(), 0, !isRedirect);
2752 bool FrameLoader::shouldPerformFragmentNavigation(bool isFormSubmission, const String& httpMethod, FrameLoadType loadType, const URL& url)
2754 // We don't do this if we are submitting a form with method other than "GET", explicitly reloading,
2755 // currently displaying a frameset, or if the URL does not have a fragment.
2756 // These rules were originally based on what KHTML was doing in KHTMLPart::openURL.
2758 // FIXME: What about load types other than Standard and Reload?
2760 return (!isFormSubmission || equalIgnoringCase(httpMethod, "GET"))
2761 && loadType != FrameLoadType::Reload
2762 && loadType != FrameLoadType::ReloadFromOrigin
2763 && loadType != FrameLoadType::Same
2764 && !shouldReload(m_frame.document()->url(), url)
2765 // We don't want to just scroll if a link from within a
2766 // frameset is trying to reload the frameset into _top.
2767 && !m_frame.document()->isFrameSet();
2770 void FrameLoader::scrollToFragmentWithParentBoundary(const URL& url)
2772 FrameView* view = m_frame.view();
2776 // Leaking scroll position to a cross-origin ancestor would permit the so-called "framesniffing" attack.
2777 RefPtr<Frame> boundaryFrame(url.hasFragmentIdentifier() ? m_frame.document()->findUnsafeParentScrollPropagationBoundary() : 0);
2780 boundaryFrame->view()->setSafeToPropagateScrollToParent(false);
2782 view->scrollToFragment(url);
2785 boundaryFrame->view()->setSafeToPropagateScrollToParent(true);
2788 bool FrameLoader::shouldClose()
2790 Page* page = m_frame.page();
2793 if (!page->chrome().canRunBeforeUnloadConfirmPanel())
2796 // Store all references to each subframe in advance since beforeunload's event handler may modify frame
2797 Vector<Ref<Frame>, 16> targetFrames;
2798 targetFrames.append(m_frame);
2799 for (Frame* child = m_frame.tree().firstChild(); child; child = child->tree().traverseNext(&m_frame))
2800 targetFrames.append(*child);
2802 bool shouldClose = false;
2804 NavigationDisablerForBeforeUnload navigationDisabler;
2807 for (i = 0; i < targetFrames.size(); i++) {
2808 if (!targetFrames[i]->tree().isDescendantOf(&m_frame))
2810 if (!targetFrames[i]->loader().handleBeforeUnloadEvent(page->chrome(), this))
2814 if (i == targetFrames.size())
2819 m_submittedFormURL = URL();
2821 m_currentNavigationHasShownBeforeUnloadConfirmPanel = false;
2825 bool FrameLoader::handleBeforeUnloadEvent(Chrome& chrome, FrameLoader* frameLoaderBeingNavigated)
2827 DOMWindow* domWindow = m_frame.document()->domWindow();
2831 RefPtr<Document> document = m_frame.document();
2832 if (!document->body())
2835 RefPtr<BeforeUnloadEvent> beforeUnloadEvent = BeforeUnloadEvent::create();
2836 m_pageDismissalEventBeingDispatched = BeforeUnloadDismissal;
2838 // We store the frame's page in a local variable because the frame might get detached inside dispatchEvent.
2839 Page* page = m_frame.page();
2840 page->incrementFrameHandlingBeforeUnloadEventCount();
2841 domWindow->dispatchEvent(beforeUnloadEvent.get(), domWindow->document());
2842 page->decrementFrameHandlingBeforeUnloadEventCount();
2844 m_pageDismissalEventBeingDispatched = NoDismissal;
2846 if (!beforeUnloadEvent->defaultPrevented())
2847 document->defaultEventHandler(beforeUnloadEvent.get());
2848 if (beforeUnloadEvent->returnValue().isNull())
2851 // If the navigating FrameLoader has already shown a beforeunload confirmation panel for the current navigation attempt,
2852 // this frame is not allowed to cause another one to be shown.
2853 if (frameLoaderBeingNavigated->m_currentNavigationHasShownBeforeUnloadConfirmPanel) {
2854 document->addConsoleMessage(MessageSource::JS, MessageLevel::Error, ASCIILiteral("Blocked attempt to show multiple beforeunload confirmation dialogs for the same navigation."));
2858 // We should only display the beforeunload dialog for an iframe if its SecurityOrigin matches all
2859 // ancestor frame SecurityOrigins up through the navigating FrameLoader.
2860 if (frameLoaderBeingNavigated != this) {
2861 Frame* parentFrame = m_frame.tree().parent();
2862 while (parentFrame) {
2863 Document* parentDocument = parentFrame->document();
2864 if (!parentDocument)
2866 if (!m_frame.document() || !m_frame.document()->securityOrigin()->canAccess(parentDocument->securityOrigin())) {
2867 document->addConsoleMessage(MessageSource::JS, MessageLevel::Error, ASCIILiteral("Blocked attempt to show beforeunload confirmation dialog on behalf of a frame with different security origin. Protocols, domains, and ports must match."));
2871 if (&parentFrame->loader() == frameLoaderBeingNavigated)
2874 parentFrame = parentFrame->tree().parent();
2877 // The navigatingFrameLoader should always be in our ancestory.
2878 ASSERT(parentFrame);
2879 ASSERT(&parentFrame->loader() == frameLoaderBeingNavigated);
2882 frameLoaderBeingNavigated->m_currentNavigationHasShownBeforeUnloadConfirmPanel = true;
2884 String text = document->displayStringModifiedByEncoding(beforeUnloadEvent->returnValue());
2885 return chrome.runBeforeUnloadConfirmPanel(text, &m_frame);
2888 void FrameLoader::continueLoadAfterNavigationPolicy(const ResourceRequest& request, PassRefPtr<FormState> formState, bool shouldContinue, AllowNavigationToInvalidURL allowNavigationToInvalidURL)
2890 // If we loaded an alternate page to replace an unreachableURL, we'll get in here with a
2891 // nil policyDataSource because loading the alternate page will have passed
2892 // through this method already, nested; otherwise, policyDataSource should still be set.
2893 ASSERT(m_policyDocumentLoader || !m_provisionalDocumentLoader->unreachableURL().isEmpty());
2895 bool isTargetItem = history().provisionalItem() ? history().provisionalItem()->isTargetItem() : false;
2897 bool urlIsDisallowed = allowNavigationToInvalidURL == AllowNavigationToInvalidURL::No && !request.url().isValid();
2899 // Three reasons we can't continue:
2900 // 1) Navigation policy delegate said we can't so request is nil. A primary case of this
2901 // is the user responding Cancel to the form repost nag sheet.
2902 // 2) User responded Cancel to an alert popped up by the before unload event handler.
2903 // 3) The request's URL is invalid and navigation to invalid URLs is disallowed.
2904 bool canContinue = shouldContinue && shouldClose() && !urlIsDisallowed;
2907 // If we were waiting for a quick redirect, but the policy delegate decided to ignore it, then we
2908 // need to report that the client redirect was cancelled.
2909 // FIXME: The client should be told about ignored non-quick redirects, too.
2910 if (m_quickRedirectComing)
2911 clientRedirectCancelledOrFinished(false);
2913 setPolicyDocumentLoader(0);
2915 // If the navigation request came from the back/forward menu, and we punt on it, we have the
2916 // problem that we have optimistically moved the b/f cursor already, so move it back. For sanity,
2917 // we only do this when punting a navigation for the target frame or top-level frame.
2918 if ((isTargetItem || m_frame.isMainFrame()) && isBackForwardLoadType(policyChecker().loadType())) {
2919 if (Page* page = m_frame.page()) {
2920 if (HistoryItem* resetItem = m_frame.mainFrame().loader().history().currentItem()) {
2921 page->backForward().setCurrentItem(resetItem);
2922 m_frame.loader().client().updateGlobalHistoryItemForPage();
2929 FrameLoadType type = policyChecker().loadType();
2930 // A new navigation is in progress, so don't clear the history's provisional item.
2931 stopAllLoaders(ShouldNotClearProvisionalItem);
2933 // <rdar://problem/6250856> - In certain circumstances on pages with multiple frames, stopAllLoaders()
2934 // might detach the current FrameLoader, in which case we should bail on this newly defunct load.
2935 if (!m_frame.page())
2938 if (Page* page = m_frame.page()) {
2939 if (m_frame.isMainFrame())
2940 page->inspectorController().resume();
2943 setProvisionalDocumentLoader(m_policyDocumentLoader.get());
2945 setState(FrameStateProvisional);
2947 setPolicyDocumentLoader(0);
2949 if (isBackForwardLoadType(type) && history().provisionalItem()->isInPageCache()) {
2950 loadProvisionalItemFromCachedPage();
2955 continueLoadAfterWillSubmitForm();
2959 m_client.dispatchWillSubmitForm(formState, [this](PolicyAction action) {
2960 policyChecker().continueLoadAfterWillSubmitForm(action);
2964 void FrameLoader::continueLoadAfterNewWindowPolicy(const ResourceRequest& request,
2965 PassRefPtr<FormState> formState, const String& frameName, const NavigationAction& action, bool shouldContinue, AllowNavigationToInvalidURL allowNavigationToInvalidURL)
2967 if (!shouldContinue)
2970 Ref<Frame> frame(m_frame);
2971 RefPtr<Frame> mainFrame = m_client.dispatchCreatePage(action);
2975 if (frameName != "_blank")
2976 mainFrame->tree().setName(frameName);
2978 mainFrame->page()->setOpenedByDOM();
2979 mainFrame->loader().m_client.dispatchShow();
2980 if (!m_suppressOpenerInNewFrame) {
2981 mainFrame->loader().setOpener(frame.ptr());
2982 mainFrame->document()->setReferrerPolicy(frame->document()->referrerPolicy());
2984 mainFrame->loader().loadWithNavigationAction(request, NavigationAction(request), LockHistory::No, FrameLoadType::Standard, formState, allowNavigationToInvalidURL);
2987 void FrameLoader::requestFromDelegate(ResourceRequest& request, unsigned long& identifier, ResourceError& error)
2989 ASSERT(!request.isNull());
2992 if (Page* page = m_frame.page()) {
2993 identifier = page->progress().createUniqueIdentifier();
2994 notifier().assignIdentifierToInitialRequest(identifier, m_documentLoader.get(), request);
2997 ResourceRequest newRequest(request);
2998 notifier().dispatchWillSendRequest(m_documentLoader.get(), identifier, newRequest, ResourceResponse());
3000 if (newRequest.isNull())
3001 error = cancelledError(request);
3003 error = ResourceError();
3005 request = newRequest;
3008 void FrameLoader::loadedResourceFromMemoryCache(CachedResource* resource, ResourceRequest& newRequest)
3010 Page* page = m_frame.page();
3014 if (!resource->shouldSendResourceLoadCallbacks() || m_documentLoader->haveToldClientAboutLoad(resource->url()))
3017 // Main resource delegate messages are synthesized in MainResourceLoader, so we must not send them here.
3018 if (resource->type() == CachedResource::MainResource)
3021 if (!page->areMemoryCacheClientCallsEnabled()) {
3022 InspectorInstrumentation::didLoadResourceFromMemoryCache(*page, m_documentLoader.get(), resource);
3023 m_documentLoader->recordMemoryCacheLoadForFutureClientNotification(resource->resourceRequest());
3024 m_documentLoader->didTellClientAboutLoad(resource->url());
3028 if (m_client.dispatchDidLoadResourceFromMemoryCache(m_documentLoader.get(), newRequest, resource->response(), resource->encodedSize())) {
3029 InspectorInstrumentation::didLoadResourceFromMemoryCache(*page, m_documentLoader.get(), resource);
3030 m_documentLoader->didTellClientAboutLoad(resource->url());
3034 unsigned long identifier;
3035 ResourceError error;
3036 requestFromDelegate(newRequest, identifier, error);
3037 InspectorInstrumentation::markResourceAsCached(*page, identifier);
3038 notifier().sendRemainingDelegateMessages(m_documentLoader.get(), identifier, newRequest, resource->response(), 0, resource->encodedSize(), 0, error);
3041 void FrameLoader::applyUserAgent(ResourceRequest& request)
3043 String userAgent = this->userAgent(request.url());
3044 ASSERT(!userAgent.isNull());
3045 request.setHTTPUserAgent(userAgent);
3048 bool FrameLoader::shouldInterruptLoadForXFrameOptions(const String& content, const URL& url, unsigned long requestIdentifier)
3050 Frame& topFrame = m_frame.tree().top();
3051 if (&m_frame == &topFrame)
3054 XFrameOptionsDisposition disposition = parseXFrameOptionsHeader(content);
3056 switch (disposition) {
3057 case XFrameOptionsSameOrigin: {
3058 RefPtr<SecurityOrigin> origin = SecurityOrigin::create(url);
3059 if (!origin->isSameSchemeHostPort(topFrame.document()->securityOrigin()))
3061 for (Frame* frame = m_frame.tree().parent(); frame; frame = frame->tree().parent()) {
3062 if (!origin->isSameSchemeHostPort(frame->document()->securityOrigin()))
3067 case XFrameOptionsDeny:
3069 case XFrameOptionsAllowAll:
3071 case XFrameOptionsConflict:
3072 m_frame.document()->addConsoleMessage(MessageSource::JS, MessageLevel::Error, "Multiple 'X-Frame-Options' headers with conflicting values ('" + content + "') encountered when loading '" + url.stringCenterEllipsizedToLength() + "'. Falling back to 'DENY'.", requestIdentifier);
3074 case XFrameOptionsInvalid:
3075 m_frame.document()->addConsoleMessage(MessageSource::JS, MessageLevel::Error, "Invalid 'X-Frame-Options' header encountered when loading '" + url.stringCenterEllipsizedToLength() + "': '" + content + "' is not a recognized directive. The header will be ignored.", requestIdentifier);
3077 case XFrameOptionsNone:
3080 ASSERT_NOT_REACHED();
3084 void FrameLoader::loadProvisionalItemFromCachedPage()
3086 DocumentLoader* provisionalLoader = provisionalDocumentLoader();
3087 LOG(PageCache, "WebCorePageCache: Loading provisional DocumentLoader %p with URL '%s' from CachedPage", provisionalDocumentLoader(), provisionalDocumentLoader()->url().stringCenterEllipsizedToLength().utf8().data());
3089 prepareForLoadStart();
3091 m_loadingFromCachedPage = true;
3093 // Should have timing data from previous time(s) the page was shown.
3094 ASSERT(provisionalLoader->timing()->navigationStart());
3095 provisionalLoader->resetTiming();
3096 provisionalLoader->timing()->markNavigationStart();
3098 provisionalLoader->setCommitted(true);
3099 commitProvisionalLoad();
3102 bool FrameLoader::shouldTreatURLAsSameAsCurrent(const URL& url) const
3104 if (!history().currentItem())
3106 return url == history().currentItem()->url() || url == history().currentItem()->originalURL();
3109 bool FrameLoader::shouldTreatURLAsSrcdocDocument(const URL& url) const
3111 if (!equalIgnoringCase(url.string(), "about:srcdoc"))
3113 HTMLFrameOwnerElement* ownerElement = m_frame.ownerElement();
3116 if (!ownerElement->hasTagName(iframeTag))
3118 return ownerElement->fastHasAttribute(srcdocAttr);
3121 Frame* FrameLoader::findFrameForNavigation(const AtomicString& name, Document* activeDocument)
3123 Frame* frame = m_frame.tree().find(name);
3125 // FIXME: Eventually all callers should supply the actual activeDocument so we can call canNavigate with the right document.
3126 if (!activeDocument)
3127 activeDocument = m_frame.document();
3129 if (!activeDocument->canNavigate(frame))
3135 void FrameLoader::loadSameDocumentItem(HistoryItem* item)
3137 ASSERT(item->documentSequenceNumber() == history().currentItem()->documentSequenceNumber());
3139 // Save user view state to the current history item here since we don't do a normal load.
3140 // FIXME: Does form state need to be saved here too?
3141 history().saveScrollPositionAndViewStateToItem(history().currentItem());
3142 if (FrameView* view = m_frame.view())
3143 view->setWasScrolledByUser(false);
3145 history().setCurrentItem(item);
3147 // loadInSameDocument() actually changes the URL and notifies load delegates of a "fake" load
3148 loadInSameDocument(item->url(), item->stateObject(), false);
3150 // Restore user view state from the current history item here since we don't do a normal load.
3151 history().restoreScrollPositionAndViewState();
3154 // FIXME: This function should really be split into a couple pieces, some of
3155 // which should be methods of HistoryController and some of which should be
3156 // methods of FrameLoader.
3157 void FrameLoader::loadDifferentDocumentItem(HistoryItem* item, FrameLoadType loadType, FormSubmissionCacheLoadPolicy cacheLoadPolicy)
3159 // Remember this item so we can traverse any child items as child frames load
3160 history().setProvisionalItem(item);
3162 if (CachedPage* cachedPage = pageCache()->get(item, m_frame.page())) {
3163 auto documentLoader = cachedPage->documentLoader();
3164 documentLoader->setTriggeringAction(NavigationAction(documentLoader->request(), loadType, false));
3165 documentLoader->setLastCheckedRequest(ResourceRequest());
3166 loadWithDocumentLoader(documentLoader, loadType, 0, AllowNavigationToInvalidURL::Yes);
3170 URL itemURL = item->url();
3171 URL itemOriginalURL = item->originalURL();
3173 if (documentLoader())
3174 currentURL = documentLoader()->url();
3175 RefPtr<FormData> formData = item->formData();
3177 ResourceRequest request(itemURL);
3179 if (!item->referrer().isNull())
3180 request.setHTTPReferrer(item->referrer());
3182 // If this was a repost that failed the page cache, we might try to repost the form.
3183 NavigationAction action;
3185 formData->generateFiles(m_frame.document());
3187 request.setHTTPMethod("POST");
3188 request.setHTTPBody(formData);
3189 request.setHTTPContentType(item->formContentType());
3190 RefPtr<SecurityOrigin> securityOrigin = SecurityOrigin::createFromString(item->referrer());
3191 addHTTPOriginIfNeeded(request, securityOrigin->toString());
3193 // Make sure to add extra fields to the request after the Origin header is added for the FormData case.
3194 // See https://bugs.webkit.org/show_bug.cgi?id=22194 for more discussion.
3195 addExtraFieldsToRequest(request, loadType, true);
3197 // FIXME: Slight hack to test if the NSURL cache contains the page we're going to.
3198 // We want to know this before talking to the policy delegate, since it affects whether
3199 // we show the DoYouReallyWantToRepost nag.
3201 // This trick has a small bug (3123893) where we might find a cache hit, but then
3202 // have the item vanish when we try to use it in the ensuing nav. This should be
3203 // extremely rare, but in that case the user will get an error on the navigation.
3205 if (cacheLoadPolicy == MayAttemptCacheOnlyLoadForFormSubmissionItem) {
3206 request.setCachePolicy(ReturnCacheDataDontLoad);
3207 action = NavigationAction(request, loadType, false);
3209 request.setCachePolicy(ReturnCacheDataElseLoad);
3210 action = NavigationAction(request, NavigationTypeFormResubmitted);
3214 case FrameLoadType::Reload:
3215 case FrameLoadType::ReloadFromOrigin:
3216 request.setCachePolicy(ReloadIgnoringCacheData);
3218 case FrameLoadType::Back:
3219 case FrameLoadType::Forward:
3220 case FrameLoadType::IndexedBackForward:
3221 // If the first load within a frame is a navigation within a back/forward list that was attached
3222 // without any of the items being loaded then we should use the default caching policy (<rdar://problem/8131355>).
3223 if (m_stateMachine.committedFirstRealDocumentLoad())
3224 request.setCachePolicy(ReturnCacheDataElseLoad);
3226 case FrameLoadType::Standard:
3227 case FrameLoadType::RedirectWithLockedBackForwardList:
3229 case FrameLoadType::Same:
3231 ASSERT_NOT_REACHED();
3234 addExtraFieldsToRequest(request, loadType, true);
3236 ResourceRequest requestForOriginalURL(request);
3237 requestForOriginalURL.setURL(itemOriginalURL);
3238 action = NavigationAction(requestForOriginalURL, loadType, false);
3241 loadWithNavigationAction(request, action, LockHistory::No, loadType, 0, AllowNavigationToInvalidURL::Yes);
3244 // Loads content into this frame, as specified by history item
3245 void FrameLoader::loadItem(HistoryItem* item, FrameLoadType loadType)
3247 m_requestedHistoryItem = item;
3248 HistoryItem* currentItem = history().currentItem();
3249 bool sameDocumentNavigation = currentItem && item->shouldDoSameDocumentNavigationTo(currentItem);
3251 if (sameDocumentNavigation)
3252 loadSameDocumentItem(item);
3254 loadDifferentDocumentItem(item, loadType, MayAttemptCacheOnlyLoadForFormSubmissionItem);
3257 void FrameLoader::retryAfterFailedCacheOnlyMainResourceLoad()
3259 ASSERT(m_state == FrameStateProvisional);
3260 ASSERT(!m_loadingFromCachedPage);
3261 // We only use cache-only loads to avoid resubmitting forms.
3262 ASSERT(isBackForwardLoadType(m_loadType));
3263 ASSERT(history().provisionalItem()->formData());
3264 ASSERT(history().provisionalItem() == m_requestedHistoryItem.get());
3266 FrameLoadType loadType = m_loadType;
3267 HistoryItem* item = history().provisionalItem();
3269 stopAllLoaders(ShouldNotClearProvisionalItem);
3270 loadDifferentDocumentItem(item, loadType, MayNotAttemptCacheOnlyLoadForFormSubmissionItem);
3273 ResourceError FrameLoader::cancelledError(const ResourceRequest& request) const
3275 ResourceError error = m_client.cancelledError(request);
3276 error.setIsCancellation(true);
3281 RetainPtr<CFDictionaryRef> FrameLoader::connectionProperties(ResourceLoader* loader)
3283 return m_client.connectionProperties(loader->documentLoader(), loader->identifier());
3287 String FrameLoader::referrer() const
3289 return m_documentLoader ? m_documentLoader->request().httpReferrer() : "";
3292 void FrameLoader::dispatchDidClearWindowObjectsInAllWorlds()
3294 if (!m_frame.script().canExecuteScripts(NotAboutToExecuteScript))
3297 Vector<Ref<DOMWrapperWorld>> worlds;
3298 ScriptController::getAllWorlds(worlds);
3299 for (auto& world : worlds)
3300 dispatchDidClearWindowObjectInWorld(world);
3303 void FrameLoader::dispatchDidClearWindowObjectInWorld(DOMWrapperWorld& world)
3305 if (!m_frame.script().canExecuteScripts(NotAboutToExecuteScript) || !m_frame.script().existingWindowShell(world))
3308 m_client.dispatchDidClearWindowObjectInWorld(world);
3310 if (Page* page = m_frame.page())
3311 page->inspectorController().didClearWindowObjectInWorld(m_frame, world);
3313 InspectorInstrumentation::didClearWindowObjectInWorld(m_frame, world);
3316 void FrameLoader::dispatchGlobalObjectAvailableInAllWorlds()
3318 Vector<Ref<DOMWrapperWorld>> worlds;
3319 ScriptController::getAllWorlds(worlds);
3320 for (auto& world : worlds)
3321 m_client.dispatchGlobalObjectAvailable(world);
3324 SandboxFlags FrameLoader::effectiveSandboxFlags() const
3326 SandboxFlags flags = m_forcedSandboxFlags;
3327 if (Frame* parentFrame = m_frame.tree().parent())
3328 flags |= parentFrame->document()->sandboxFlags();
3329 if (HTMLFrameOwnerElement* ownerElement = m_frame.ownerElement())
3330 flags |= ownerElement->sandboxFlags();
3334 void FrameLoader::didChangeTitle(DocumentLoader* loader)
3336 m_client.didChangeTitle(loader);
3338 if (loader == m_documentLoader) {
3339 // Must update the entries in the back-forward list too.
3340 history().setCurrentItemTitle(loader->title());
3341 // This must go through the WebFrame because it has the right notion of the current b/f item.
3342 m_client.setTitle(loader->title(), loader->urlForHistory());
3343 m_client.setMainFrameDocumentReady(true); // update observers with new DOMDocument
3344 m_client.dispatchDidReceiveTitle(loader->title());
3347 #if ENABLE(REMOTE_INSPECTOR)
3348 if (m_frame.isMainFrame())
3349 m_frame.page()->remoteInspectorInformationDidChange();
3353 void FrameLoader::didChangeIcons(IconType type)
3355 m_client.dispatchDidChangeIcons(type);
3358 void FrameLoader::dispatchDidCommitLoad()
3360 if (m_stateMachine.creatingInitialEmptyDocument())
3363 m_client.dispatchDidCommitLoad();
3365 if (m_frame.isMainFrame()) {
3366 m_frame.page()->resetSeenPlugins();
3367 m_frame.page()->resetSeenMediaEngines();
3370 InspectorInstrumentation::didCommitLoad(m_frame, m_documentLoader.get());
3372 #if ENABLE(REMOTE_INSPECTOR)
3373 if (m_frame.isMainFrame())
3374 m_frame.page()->remoteInspectorInformationDidChange();
3378 void FrameLoader::tellClientAboutPastMemoryCacheLoads()
3380 ASSERT(m_frame.page());
3381 ASSERT(m_frame.page()->areMemoryCacheClientCallsEnabled());
3383 if (!m_documentLoader)
3386 Vector<ResourceRequest> pastLoads;
3387 m_documentLoader->takeMemoryCacheLoadsForClientNotification(pastLoads);
3389 size_t size = pastLoads.size();
3390 for (size_t i = 0; i < size; ++i) {
3391 CachedResource* resource = memoryCache().resourceForRequest(pastLoads[i], m_frame.page()->sessionID());
3393 // FIXME: These loads, loaded from cache, but now gone from the cache by the time
3394 // Page::setMemoryCacheClientCallsEnabled(true) is called, will not be seen by the client.
3395 // Consider if there's some efficient way of remembering enough to deliver this client call.
3396 // We have the URL, but not the rest of the response or the length.
3400 ResourceRequest request(resource->url());
3401 m_client.dispatchDidLoadResourceFromMemoryCache(m_documentLoader.get(), request, resource->response(), resource->encodedSize());
3405 NetworkingContext* FrameLoader::networkingContext() const
3407 return m_networkingContext.get();
3410 void FrameLoader::loadProgressingStatusChanged()
3412 if (auto* view = m_frame.mainFrame().view())
3413 view->loadProgressingStatusChanged();
3416 void FrameLoader::forcePageTransitionIfNeeded()
3418 m_client.forcePageTransitionIfNeeded();
3421 bool FrameLoaderClient::hasHTMLView() const
3426 PassRefPtr<Frame> createWindow(Frame* openerFrame, Frame* lookupFrame, const FrameLoadRequest& request, const WindowFeatures& features, bool& created)
3428 ASSERT(!features.dialog || request.frameName().isEmpty());
3432 if (!request.frameName().isEmpty() && request.frameName() != "_blank") {
3433 if (RefPtr<Frame> frame = lookupFrame->loader().findFrameForNavigation(request.frameName(), openerFrame->document())) {
3434 if (request.frameName() != "_self") {
3435 if (Page* page = frame->page())
3436 page->chrome().focus();
3438 return frame.release();
3442 // Sandboxed frames cannot open new auxiliary browsing contexts.
3443 if (isDocumentSandboxed(openerFrame, SandboxPopups)) {
3444 // FIXME: This message should be moved off the console once a solution to https://bugs.webkit.org/show_bug.cgi?id=103274 exists.
3445 openerFrame->document()->addConsoleMessage(MessageSource::Security, MessageLevel::Error, "Blocked opening '" + request.resourceRequest().url().stringCenterEllipsizedToLength() + "' in a new window because the request was made in a sandboxed frame whose 'allow-popups' permission is not set.");
3449 // FIXME: Setting the referrer should be the caller's responsibility.
3450 FrameLoadRequest requestWithReferrer = request;
3451 String referrer = SecurityPolicy::generateReferrerHeader(openerFrame->document()->referrerPolicy(), request.resourceRequest().url(), openerFrame->loader().outgoingReferrer());
3452 if (!referrer.isEmpty())
3453 requestWithReferrer.resourceRequest().setHTTPReferrer(referrer);
3454 FrameLoader::addHTTPOriginIfNeeded(requestWithReferrer.resourceRequest(), openerFrame->loader().outgoingOrigin());
3456 Page* oldPage = openerFrame->page();
3460 Page* page = oldPage->chrome().createWindow(openerFrame, requestWithReferrer, features, NavigationAction(requestWithReferrer.resourceRequest()));
3464 RefPtr<Frame> frame = &page->mainFrame();
3466 frame->loader().forceSandboxFlags(openerFrame->document()->sandboxFlags());
3468 if (request.frameName() != "_blank")
3469 frame->tree().setName(request.frameName());
3471 page->chrome().setToolbarsVisible(features.toolBarVisible || features.locationBarVisible);
3475 page->chrome().setStatusbarVisible(features.statusBarVisible);
3479 page->chrome().setScrollbarsVisible(features.scrollbarsVisible);
3483 page->chrome().setMenubarVisible(features.menuBarVisible);
3487 page->chrome().setResizable(features.resizable);
3489 // 'x' and 'y' specify the location of the window, while 'width' and 'height'
3490 // specify the size of the viewport. We can only resize the window, so adjust
3491 // for the difference between the window size and the viewport size.
3493 // FIXME: We should reconcile the initialization of viewport arguments between iOS and non-IOS.
3495 FloatSize viewportSize = page->chrome().pageRect().size();
3496 FloatRect windowRect = page->chrome().windowRect();
3498 windowRect.setX(features.x);
3500 windowRect.setY(features.y);
3501 // Zero width and height mean using default size, not minumum one.
3502 if (features.widthSet && features.width)
3503 windowRect.setWidth(features.width + (windowRect.width() - viewportSize.width()));
3504 if (features.heightSet && features.height)
3505 windowRect.setHeight(features.height + (windowRect.height() - viewportSize.height()));
3507 // Ensure non-NaN values, minimum size as well as being within valid screen area.
3508 FloatRect newWindowRect = DOMWindow::adjustWindowRect(page, windowRect);
3512 page->chrome().setWindowRect(newWindowRect);
3514 // On iOS, width and height refer to the viewport dimensions.
3515 ViewportArguments arguments;
3516 // Zero width and height mean using default size, not minimum one.
3517 if (features.widthSet && features.width)
3518 arguments.width = features.width;
3519 if (features.heightSet && features.height)
3520 arguments.height = features.height;
3521 frame->setViewportArguments(arguments);
3526 page->chrome().show();
3529 return frame.release();
3532 } // namespace WebCore