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"
51 #include "DocumentLoadTiming.h"
52 #include "DocumentLoader.h"
54 #include "EditorClient.h"
57 #include "EventHandler.h"
58 #include "EventNames.h"
59 #include "FloatRect.h"
60 #include "FormState.h"
61 #include "FormSubmission.h"
62 #include "FrameLoadRequest.h"
63 #include "FrameLoaderClient.h"
64 #include "FrameNetworkingContext.h"
65 #include "FrameTree.h"
66 #include "FrameView.h"
67 #include "HTMLAnchorElement.h"
68 #include "HTMLFormElement.h"
69 #include "HTMLInputElement.h"
70 #include "HTMLNames.h"
71 #include "HTMLObjectElement.h"
72 #include "HTMLParserIdioms.h"
73 #include "HTTPHeaderNames.h"
74 #include "HTTPParsers.h"
75 #include "HistoryController.h"
76 #include "HistoryItem.h"
77 #include "IconController.h"
78 #include "InspectorController.h"
79 #include "InspectorInstrumentation.h"
80 #include "LoaderStrategy.h"
82 #include "MIMETypeRegistry.h"
83 #include "MainFrame.h"
84 #include "MemoryCache.h"
86 #include "PageActivityAssertionToken.h"
87 #include "PageCache.h"
88 #include "PageThrottler.h"
89 #include "PageTransitionEvent.h"
90 #include "PlatformStrategies.h"
91 #include "PluginData.h"
92 #include "PluginDatabase.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(SHARED_WORKERS)
125 #include "SharedWorkerRepository.h"
128 #if ENABLE(WEB_ARCHIVE) || ENABLE(MHTML)
133 #include "DocumentType.h"
134 #include "MemoryPressureHandler.h"
135 #include "ResourceLoader.h"
136 #include "RuntimeApplicationChecksIOS.h"
137 #include "SystemMemory.h"
138 #include "WKContentObservation.h"
143 using namespace HTMLNames;
144 using namespace SVGNames;
146 static const char defaultAcceptHeader[] = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";
149 const int memoryLevelThresholdToPrunePageCache = 20;
152 bool isBackForwardLoadType(FrameLoadType type)
155 case FrameLoadType::Standard:
156 case FrameLoadType::Reload:
157 case FrameLoadType::ReloadFromOrigin:
158 case FrameLoadType::Same:
159 case FrameLoadType::RedirectWithLockedBackForwardList:
160 case FrameLoadType::Replace:
162 case FrameLoadType::Back:
163 case FrameLoadType::Forward:
164 case FrameLoadType::IndexedBackForward:
167 ASSERT_NOT_REACHED();
171 // This is not in the FrameLoader class to emphasize that it does not depend on
172 // private FrameLoader data, and to avoid increasing the number of public functions
173 // with access to private data. Since only this .cpp file needs it, making it
174 // non-member lets us exclude it from the header file, thus keeping FrameLoader.h's
177 static bool isDocumentSandboxed(Frame* frame, SandboxFlags mask)
179 return frame->document() && frame->document()->isSandboxed(mask);
182 class FrameLoader::FrameProgressTracker {
184 explicit FrameProgressTracker(Frame& frame)
186 , m_inProgress(false)
190 ~FrameProgressTracker()
192 ASSERT(!m_inProgress || m_frame.page());
194 m_frame.page()->progress().progressCompleted(m_frame);
197 void progressStarted()
199 ASSERT(m_frame.page());
201 m_frame.page()->progress().progressStarted(m_frame);
205 void progressCompleted()
207 ASSERT(m_inProgress);
208 ASSERT(m_frame.page());
209 m_inProgress = false;
210 m_frame.page()->progress().progressCompleted(m_frame);
218 FrameLoader::FrameLoader(Frame& frame, FrameLoaderClient& client)
221 , m_policyChecker(std::make_unique<PolicyChecker>(frame))
222 , m_history(std::make_unique<HistoryController>(frame))
224 , m_subframeLoader(std::make_unique<SubframeLoader>(frame))
225 , m_icon(std::make_unique<IconController>(frame))
226 , m_mixedContentChecker(frame)
227 , m_state(FrameStateProvisional)
228 , m_loadType(FrameLoadType::Standard)
229 , m_delegateIsHandlingProvisionalLoadError(false)
230 , m_quickRedirectComing(false)
231 , m_sentRedirectNotification(false)
232 , m_inStopAllLoaders(false)
233 , m_isExecutingJavaScriptFormAction(false)
234 , m_didCallImplicitClose(true)
235 , m_wasUnloadEventEmitted(false)
236 , m_pageDismissalEventBeingDispatched(NoDismissal)
237 , m_isComplete(false)
238 , m_needsClear(false)
239 , m_checkTimer(this, &FrameLoader::checkTimerFired)
240 , m_shouldCallCheckCompleted(false)
241 , m_shouldCallCheckLoadComplete(false)
243 , m_loadingFromCachedPage(false)
244 , m_suppressOpenerInNewFrame(false)
245 , m_currentNavigationHasShownBeforeUnloadConfirmPanel(false)
246 , m_loadsSynchronously(false)
247 , m_forcedSandboxFlags(SandboxNone)
251 FrameLoader::~FrameLoader()
255 HashSet<Frame*>::iterator end = m_openedFrames.end();
256 for (HashSet<Frame*>::iterator it = m_openedFrames.begin(); it != end; ++it)
257 (*it)->loader().m_opener = 0;
259 m_client.frameLoaderDestroyed();
261 if (m_networkingContext)
262 m_networkingContext->invalidate();
265 void FrameLoader::init()
267 // This somewhat odd set of steps gives the frame an initial empty document.
268 setPolicyDocumentLoader(m_client.createDocumentLoader(ResourceRequest(URL(ParsedURLString, emptyString())), SubstituteData()).get());
269 setProvisionalDocumentLoader(m_policyDocumentLoader.get());
270 m_provisionalDocumentLoader->startLoadingMainResource();
272 Ref<Frame> protect(m_frame);
273 m_frame.document()->cancelParsing();
274 m_stateMachine.advanceTo(FrameLoaderStateMachine::DisplayingInitialEmptyDocument);
276 m_networkingContext = m_client.createNetworkingContext();
277 m_progressTracker = std::make_unique<FrameProgressTracker>(m_frame);
281 void FrameLoader::initForSynthesizedDocument(const URL&)
283 // FIXME: We need to initialize the document URL to the specified URL. Currently the URL is empty and hence
284 // FrameLoader::checkCompleted() will overwrite the URL of the document to be activeDocumentLoader()->documentURL().
286 RefPtr<DocumentLoader> loader = m_client.createDocumentLoader(ResourceRequest(URL(ParsedURLString, emptyString())), SubstituteData());
287 loader->setFrame(&m_frame);
288 loader->setResponse(ResourceResponse(URL(), ASCIILiteral("text/html"), 0, String(), String()));
289 loader->setCommitted(true);
290 setDocumentLoader(loader.get());
292 m_stateMachine.advanceTo(FrameLoaderStateMachine::DisplayingInitialEmptyDocument);
293 m_stateMachine.advanceTo(FrameLoaderStateMachine::DisplayingInitialEmptyDocumentPostCommit);
294 m_stateMachine.advanceTo(FrameLoaderStateMachine::CommittedFirstRealLoad);
295 m_client.transitionToCommittedForNewPage();
297 m_didCallImplicitClose = true;
299 m_state = FrameStateComplete;
302 m_networkingContext = m_client.createNetworkingContext();
303 m_progressTracker = std::make_unique<FrameProgressTracker>(m_frame);
307 void FrameLoader::setDefersLoading(bool defers)
309 if (m_documentLoader)
310 m_documentLoader->setDefersLoading(defers);
311 if (m_provisionalDocumentLoader)
312 m_provisionalDocumentLoader->setDefersLoading(defers);
313 if (m_policyDocumentLoader)
314 m_policyDocumentLoader->setDefersLoading(defers);
315 history().setDefersLoading(defers);
318 m_frame.navigationScheduler().startTimer();
319 startCheckCompleteTimer();
323 void FrameLoader::changeLocation(SecurityOrigin* securityOrigin, const URL& url, const String& referrer, LockHistory lockHistory, LockBackForwardList lockBackForwardList, bool refresh, AllowNavigationToInvalidURL allowNavigationToInvalidURL)
325 urlSelected(FrameLoadRequest(securityOrigin, ResourceRequest(url, referrer, refresh ? ReloadIgnoringCacheData : UseProtocolCachePolicy), "_self"),
326 0, lockHistory, lockBackForwardList, MaybeSendReferrer, ReplaceDocumentIfJavaScriptURL, allowNavigationToInvalidURL);
329 void FrameLoader::urlSelected(const URL& url, const String& passedTarget, PassRefPtr<Event> triggeringEvent, LockHistory lockHistory, LockBackForwardList lockBackForwardList, ShouldSendReferrer shouldSendReferrer)
331 urlSelected(FrameLoadRequest(m_frame.document()->securityOrigin(), ResourceRequest(url), passedTarget),
332 triggeringEvent, lockHistory, lockBackForwardList, shouldSendReferrer, DoNotReplaceDocumentIfJavaScriptURL, AllowNavigationToInvalidURL::Yes);
335 // The shouldReplaceDocumentIfJavaScriptURL parameter will go away when the FIXME to eliminate the
336 // corresponding parameter from ScriptController::executeIfJavaScriptURL() is addressed.
337 void FrameLoader::urlSelected(const FrameLoadRequest& passedRequest, PassRefPtr<Event> triggeringEvent, LockHistory lockHistory, LockBackForwardList lockBackForwardList, ShouldSendReferrer shouldSendReferrer, ShouldReplaceDocumentIfJavaScriptURL shouldReplaceDocumentIfJavaScriptURL, AllowNavigationToInvalidURL allowNavigationToInvalidURL)
339 ASSERT(!m_suppressOpenerInNewFrame);
341 Ref<Frame> protect(m_frame);
342 FrameLoadRequest frameRequest(passedRequest);
344 if (m_frame.script().executeIfJavaScriptURL(frameRequest.resourceRequest().url(), shouldReplaceDocumentIfJavaScriptURL))
347 if (frameRequest.frameName().isEmpty())
348 frameRequest.setFrameName(m_frame.document()->baseTarget());
350 if (shouldSendReferrer == NeverSendReferrer)
351 m_suppressOpenerInNewFrame = true;
352 addHTTPOriginIfNeeded(frameRequest.resourceRequest(), outgoingOrigin());
354 loadFrameRequest(frameRequest, lockHistory, lockBackForwardList, triggeringEvent, 0, shouldSendReferrer, allowNavigationToInvalidURL);
356 m_suppressOpenerInNewFrame = false;
359 void FrameLoader::submitForm(PassRefPtr<FormSubmission> submission)
361 ASSERT(submission->method() == FormSubmission::PostMethod || submission->method() == FormSubmission::GetMethod);
363 // FIXME: Find a good spot for these.
364 ASSERT(submission->data());
365 ASSERT(submission->state());
366 ASSERT(!submission->state()->sourceDocument()->frame() || submission->state()->sourceDocument()->frame() == &m_frame);
371 if (submission->action().isEmpty())
374 if (isDocumentSandboxed(&m_frame, SandboxForms)) {
375 // FIXME: This message should be moved off the console once a solution to https://bugs.webkit.org/show_bug.cgi?id=103274 exists.
376 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.");
380 if (protocolIsJavaScript(submission->action())) {
381 if (!m_frame.document()->contentSecurityPolicy()->allowFormAction(URL(submission->action())))
383 m_isExecutingJavaScriptFormAction = true;
384 Ref<Frame> protect(m_frame);
385 m_frame.script().executeIfJavaScriptURL(submission->action(), DoNotReplaceDocumentIfJavaScriptURL);
386 m_isExecutingJavaScriptFormAction = false;
390 Frame* targetFrame = findFrameForNavigation(submission->target(), submission->state()->sourceDocument());
392 if (!DOMWindow::allowPopUp(&m_frame) && !ScriptController::processingUserGesture())
395 // FIXME: targetFrame can be 0 for two distinct reasons:
396 // 1. The frame was not found by name, so we should try opening a new window.
397 // 2. The frame was found, but navigating it was not allowed, e.g. by HTML5 sandbox or by origin checks.
398 // Continuing form submission makes no sense in the latter case.
399 // There is a repeat check after timer fires, so this is not a correctness issue.
401 targetFrame = &m_frame;
403 submission->clearTarget();
405 if (!targetFrame->page())
408 // FIXME: We'd like to remove this altogether and fix the multiple form submission issue another way.
410 // We do not want to submit more than one form from the same page, nor do we want to submit a single
411 // form more than once. This flag prevents these from happening; not sure how other browsers prevent this.
412 // The flag is reset in each time we start handle a new mouse or key down event, and
413 // also in setView since this part may get reused for a page from the back/forward cache.
414 // The form multi-submit logic here is only needed when we are submitting a form that affects this frame.
416 // FIXME: Frame targeting is only one of the ways the submission could end up doing something other
417 // than replacing this frame's content, so this check is flawed. On the other hand, the check is hardly
418 // needed any more now that we reset m_submittedFormURL on each mouse or key down event.
420 if (m_frame.tree().isDescendantOf(targetFrame)) {
421 if (m_submittedFormURL == submission->requestURL())
423 m_submittedFormURL = submission->requestURL();
426 submission->data()->generateFiles(m_frame.document());
427 submission->setReferrer(outgoingReferrer());
428 submission->setOrigin(outgoingOrigin());
430 targetFrame->navigationScheduler().scheduleFormSubmission(submission);
433 void FrameLoader::stopLoading(UnloadEventPolicy unloadEventPolicy)
435 if (m_frame.document() && m_frame.document()->parser())
436 m_frame.document()->parser()->stopParsing();
438 if (unloadEventPolicy != UnloadEventPolicyNone) {
439 if (m_frame.document()) {
440 if (m_didCallImplicitClose && !m_wasUnloadEventEmitted) {
441 Element* currentFocusedElement = m_frame.document()->focusedElement();
442 if (currentFocusedElement && currentFocusedElement->toInputElement())
443 currentFocusedElement->toInputElement()->endEditing();
444 if (m_pageDismissalEventBeingDispatched == NoDismissal) {
445 if (unloadEventPolicy == UnloadEventPolicyUnloadAndPageHide) {
446 m_pageDismissalEventBeingDispatched = PageHideDismissal;
447 m_frame.document()->domWindow()->dispatchEvent(PageTransitionEvent::create(eventNames().pagehideEvent, m_frame.document()->inPageCache()), m_frame.document());
450 // FIXME: update Page Visibility state here.
451 // https://bugs.webkit.org/show_bug.cgi?id=116770
453 if (!m_frame.document()->inPageCache()) {
454 RefPtr<Event> unloadEvent(Event::create(eventNames().unloadEvent, false, false));
455 // The DocumentLoader (and thus its DocumentLoadTiming) might get destroyed
456 // while dispatching the event, so protect it to prevent writing the end
457 // time into freed memory.
458 RefPtr<DocumentLoader> documentLoader = m_provisionalDocumentLoader;
459 m_pageDismissalEventBeingDispatched = UnloadDismissal;
460 if (documentLoader && !documentLoader->timing()->unloadEventStart() && !documentLoader->timing()->unloadEventEnd()) {
461 DocumentLoadTiming* timing = documentLoader->timing();
462 ASSERT(timing->navigationStart());
463 timing->markUnloadEventStart();
464 m_frame.document()->domWindow()->dispatchEvent(unloadEvent, m_frame.document());
465 timing->markUnloadEventEnd();
467 m_frame.document()->domWindow()->dispatchEvent(unloadEvent, m_frame.document());
470 m_pageDismissalEventBeingDispatched = NoDismissal;
471 if (m_frame.document())
472 m_frame.document()->updateStyleIfNeeded();
473 m_wasUnloadEventEmitted = true;
477 // Dispatching the unload event could have made m_frame.document() null.
478 if (m_frame.document() && !m_frame.document()->inPageCache()) {
479 // Don't remove event listeners from a transitional empty document (see bug 28716 for more information).
480 bool keepEventListeners = m_stateMachine.isDisplayingInitialEmptyDocument() && m_provisionalDocumentLoader
481 && m_frame.document()->isSecureTransitionTo(m_provisionalDocumentLoader->url());
483 if (!keepEventListeners)
484 m_frame.document()->removeAllEventListeners();
488 m_isComplete = true; // to avoid calling completed() in finishedParsing()
489 m_didCallImplicitClose = true; // don't want that one either
491 if (m_frame.document() && m_frame.document()->parsing()) {
493 m_frame.document()->setParsing(false);
496 if (Document* doc = m_frame.document()) {
497 // FIXME: HTML5 doesn't tell us to set the state to complete when aborting, but we do anyway to match legacy behavior.
498 // http://www.w3.org/Bugs/Public/show_bug.cgi?id=10537
499 doc->setReadyState(Document::Complete);
501 #if ENABLE(SQL_DATABASE)
502 // FIXME: Should the DatabaseManager watch for something like ActiveDOMObject::stop() rather than being special-cased here?
503 DatabaseManager::manager().stopDatabases(doc, 0);
507 // FIXME: This will cancel redirection timer, which really needs to be restarted when restoring the frame from b/f cache.
508 m_frame.navigationScheduler().cancel();
511 void FrameLoader::stop()
513 // http://bugs.webkit.org/show_bug.cgi?id=10854
514 // The frame's last ref may be removed and it will be deleted by checkCompleted().
515 Ref<Frame> protect(m_frame);
517 if (DocumentParser* parser = m_frame.document()->parser()) {
518 parser->stopParsing();
525 void FrameLoader::willTransitionToCommitted()
527 // This function is called when a frame is still fully in place (not cached, not detached), but will be replaced.
529 if (m_frame.editor().hasComposition()) {
530 // The text was already present in DOM, so it's better to confirm than to cancel the composition.
531 m_frame.editor().confirmComposition();
532 if (EditorClient* editorClient = m_frame.editor().client())
533 editorClient->respondToChangedSelection(&m_frame);
537 bool FrameLoader::closeURL()
539 history().saveDocumentState();
541 // Should only send the pagehide event here if the current document exists and has not been placed in the page cache.
542 Document* currentDocument = m_frame.document();
543 stopLoading(currentDocument && !currentDocument->inPageCache() ? UnloadEventPolicyUnloadAndPageHide : UnloadEventPolicyUnloadOnly);
545 m_frame.editor().clearUndoRedoOperations();
549 bool FrameLoader::didOpenURL()
551 if (m_frame.navigationScheduler().redirectScheduledDuringLoad()) {
552 // A redirect was scheduled before the document was created.
553 // This can happen when one frame changes another frame's location.
557 m_frame.navigationScheduler().cancel();
558 m_frame.editor().clearLastEditCommand();
560 m_isComplete = false;
561 m_didCallImplicitClose = false;
563 // If we are still in the process of initializing an empty document then
564 // its frame is not in a consistent state for rendering, so avoid setJSStatusBarText
565 // since it may cause clients to attempt to render the frame.
566 if (!m_stateMachine.creatingInitialEmptyDocument()) {
567 DOMWindow* window = m_frame.document()->domWindow();
568 window->setStatus(String());
569 window->setDefaultStatus(String());
577 void FrameLoader::didExplicitOpen()
579 m_isComplete = false;
580 m_didCallImplicitClose = false;
582 // Calling document.open counts as committing the first real document load.
583 if (!m_stateMachine.committedFirstRealDocumentLoad())
584 m_stateMachine.advanceTo(FrameLoaderStateMachine::DisplayingInitialEmptyDocumentPostCommit);
586 // Prevent window.open(url) -- eg window.open("about:blank") -- from blowing away results
587 // from a subsequent window.document.open / window.document.write call.
588 // Canceling redirection here works for all cases because document.open
589 // implicitly precedes document.write.
590 m_frame.navigationScheduler().cancel();
594 void FrameLoader::cancelAndClear()
596 m_frame.navigationScheduler().cancel();
601 clear(m_frame.document(), false);
602 m_frame.script().updatePlatformScriptObjects();
605 void FrameLoader::clear(Document* newDocument, bool clearWindowProperties, bool clearScriptObjects, bool clearFrameView)
607 m_frame.editor().clear();
611 m_needsClear = false;
613 if (!m_frame.document()->inPageCache()) {
614 m_frame.document()->cancelParsing();
615 m_frame.document()->stopActiveDOMObjects();
616 bool hadLivingRenderTree = m_frame.document()->hasLivingRenderTree();
617 m_frame.document()->prepareForDestruction();
618 if (hadLivingRenderTree)
619 m_frame.document()->removeFocusedNodeOfSubtree(m_frame.document());
622 // Do this after detaching the document so that the unload event works.
623 if (clearWindowProperties) {
624 InspectorInstrumentation::frameWindowDiscarded(&m_frame, m_frame.document()->domWindow());
625 m_frame.document()->domWindow()->resetUnlessSuspendedForPageCache();
626 m_frame.script().clearWindowShell(newDocument->domWindow(), m_frame.document()->inPageCache());
629 m_frame.selection().prepareForDestruction();
630 m_frame.eventHandler().clear();
631 if (clearFrameView && m_frame.view())
632 m_frame.view()->clear();
634 // Do not drop the document before the ScriptController and view are cleared
635 // as some destructors might still try to access the document.
636 m_frame.setDocument(0);
638 subframeLoader().clear();
640 if (clearScriptObjects)
641 m_frame.script().clearScriptObjects();
643 m_frame.script().enableEval();
645 m_frame.navigationScheduler().clear();
648 m_shouldCallCheckCompleted = false;
649 m_shouldCallCheckLoadComplete = false;
651 if (m_stateMachine.isDisplayingInitialEmptyDocument() && m_stateMachine.committedFirstRealDocumentLoad())
652 m_stateMachine.advanceTo(FrameLoaderStateMachine::CommittedFirstRealLoad);
655 void FrameLoader::receivedFirstData()
657 dispatchDidCommitLoad();
658 dispatchDidClearWindowObjectsInAllWorlds();
659 dispatchGlobalObjectAvailableInAllWorlds();
661 if (m_documentLoader) {
662 StringWithDirection ptitle = m_documentLoader->title();
663 // If we have a title let the WebView know about it.
664 if (!ptitle.isNull())
665 m_client.dispatchDidReceiveTitle(ptitle);
668 if (!m_documentLoader)
673 if (!parseHTTPRefresh(m_documentLoader->response().httpHeaderField(HTTPHeaderName::Refresh), false, delay, urlString))
676 if (urlString.isEmpty())
677 completedURL = m_frame.document()->url();
679 completedURL = m_frame.document()->completeURL(urlString);
681 if (!protocolIsJavaScript(completedURL))
682 m_frame.navigationScheduler().scheduleRedirect(delay, completedURL);
684 String message = "Refused to refresh " + m_frame.document()->url().stringCenterEllipsizedToLength() + " to a javascript: URL";
685 m_frame.document()->addConsoleMessage(MessageSource::Security, MessageLevel::Error, message);
689 void FrameLoader::setOutgoingReferrer(const URL& url)
691 m_outgoingReferrer = url.strippedForUseAsReferrer();
694 void FrameLoader::didBeginDocument(bool dispatch)
697 m_isComplete = false;
698 m_didCallImplicitClose = false;
699 m_frame.document()->setReadyState(Document::Loading);
701 if (m_pendingStateObject) {
702 m_frame.document()->statePopped(m_pendingStateObject.get());
703 m_pendingStateObject.clear();
707 dispatchDidClearWindowObjectsInAllWorlds();
709 updateFirstPartyForCookies();
710 m_frame.document()->initContentSecurityPolicy();
712 const Settings& settings = m_frame.settings();
713 m_frame.document()->cachedResourceLoader()->setImagesEnabled(settings.areImagesEnabled());
714 m_frame.document()->cachedResourceLoader()->setAutoLoadImages(settings.loadsImagesAutomatically());
716 if (m_documentLoader) {
717 String dnsPrefetchControl = m_documentLoader->response().httpHeaderField(HTTPHeaderName::XDNSPrefetchControl);
718 if (!dnsPrefetchControl.isEmpty())
719 m_frame.document()->parseDNSPrefetchControlHeader(dnsPrefetchControl);
721 String policyValue = m_documentLoader->response().httpHeaderField(HTTPHeaderName::ContentSecurityPolicy);
722 if (!policyValue.isEmpty())
723 m_frame.document()->contentSecurityPolicy()->didReceiveHeader(policyValue, ContentSecurityPolicy::Enforce);
725 policyValue = m_documentLoader->response().httpHeaderField(HTTPHeaderName::ContentSecurityPolicyReportOnly);
726 if (!policyValue.isEmpty())
727 m_frame.document()->contentSecurityPolicy()->didReceiveHeader(policyValue, ContentSecurityPolicy::Report);
729 policyValue = m_documentLoader->response().httpHeaderField(HTTPHeaderName::XWebKitCSP);
730 if (!policyValue.isEmpty())
731 m_frame.document()->contentSecurityPolicy()->didReceiveHeader(policyValue, ContentSecurityPolicy::PrefixedEnforce);
733 policyValue = m_documentLoader->response().httpHeaderField(HTTPHeaderName::XWebKitCSPReportOnly);
734 if (!policyValue.isEmpty())
735 m_frame.document()->contentSecurityPolicy()->didReceiveHeader(policyValue, ContentSecurityPolicy::PrefixedReport);
737 String headerContentLanguage = m_documentLoader->response().httpHeaderField(HTTPHeaderName::ContentLanguage);
738 if (!headerContentLanguage.isEmpty()) {
739 size_t commaIndex = headerContentLanguage.find(',');
740 headerContentLanguage.truncate(commaIndex); // notFound == -1 == don't truncate
741 headerContentLanguage = headerContentLanguage.stripWhiteSpace(isHTMLSpace);
742 if (!headerContentLanguage.isEmpty())
743 m_frame.document()->setContentLanguage(headerContentLanguage);
747 history().restoreDocumentState();
750 void FrameLoader::finishedParsing()
752 m_frame.injectUserScripts(InjectAtDocumentEnd);
754 if (m_stateMachine.creatingInitialEmptyDocument())
757 // This can be called from the Frame's destructor, in which case we shouldn't protect ourselves
758 // because doing so will cause us to re-enter the destructor when protector goes out of scope.
759 // Null-checking the FrameView indicates whether or not we're in the destructor.
760 RefPtr<Frame> protector = m_frame.view() ? &m_frame : 0;
762 m_client.dispatchDidFinishDocumentLoad();
767 return; // We are being destroyed by something checkCompleted called.
769 // Check if the scrollbars are really needed for the content.
770 // If not, remove them, relayout, and repaint.
771 m_frame.view()->restoreScrollbar();
772 scrollToFragmentWithParentBoundary(m_frame.document()->url());
775 void FrameLoader::loadDone()
780 bool FrameLoader::allChildrenAreComplete() const
782 for (Frame* child = m_frame.tree().firstChild(); child; child = child->tree().nextSibling()) {
783 if (!child->loader().m_isComplete)
789 bool FrameLoader::allAncestorsAreComplete() const
791 for (Frame* ancestor = &m_frame; ancestor; ancestor = ancestor->tree().parent()) {
792 if (!ancestor->loader().m_isComplete)
798 void FrameLoader::checkCompleted()
800 m_shouldCallCheckCompleted = false;
802 // Have we completed before?
806 // Are we still parsing?
807 if (m_frame.document()->parsing())
810 // Still waiting for images/scripts?
811 if (m_frame.document()->cachedResourceLoader()->requestCount())
814 // Still waiting for elements that don't go through a FrameLoader?
815 if (m_frame.document()->isDelayingLoadEvent())
818 // Any frame that hasn't completed yet?
819 if (!allChildrenAreComplete())
822 // Important not to protect earlier in this function, because earlier parts
823 // of this function can be called in the frame's destructor, and it's not legal
824 // to ref an object while it's being destroyed.
825 Ref<Frame> protect(m_frame);
829 m_requestedHistoryItem = 0;
830 m_frame.document()->setReadyState(Document::Complete);
833 if (m_frame.document()->url().isEmpty()) {
834 // We need to update the document URL of a PDF document to be non-empty so that both back/forward history navigation
835 // between PDF pages and fragment navigation works. See <rdar://problem/9544769> for more details.
836 // FIXME: Is there a better place for this code, say DocumentLoader? Also, we should explicitly only update the URL
837 // of the document when it's a PDFDocument object instead of assuming that a Document object with an empty URL is a PDFDocument.
838 // FIXME: This code is incorrect for a synthesized document (which also has an empty URL). The URL for a synthesized
839 // document should be the URL specified to FrameLoader::initForSynthesizedDocument().
840 m_frame.document()->setURL(activeDocumentLoader()->documentURL());
844 checkCallImplicitClose(); // if we didn't do it before
846 m_frame.navigationScheduler().startTimer();
853 void FrameLoader::checkTimerFired(Timer<FrameLoader>&)
855 Ref<Frame> protect(m_frame);
857 if (Page* page = m_frame.page()) {
858 if (page->defersLoading())
861 if (m_shouldCallCheckCompleted)
863 if (m_shouldCallCheckLoadComplete)
867 void FrameLoader::startCheckCompleteTimer()
869 if (!(m_shouldCallCheckCompleted || m_shouldCallCheckLoadComplete))
871 if (m_checkTimer.isActive())
873 m_checkTimer.startOneShot(0);
876 void FrameLoader::scheduleCheckCompleted()
878 m_shouldCallCheckCompleted = true;
879 startCheckCompleteTimer();
882 void FrameLoader::scheduleCheckLoadComplete()
884 m_shouldCallCheckLoadComplete = true;
885 startCheckCompleteTimer();
888 void FrameLoader::checkCallImplicitClose()
890 if (m_didCallImplicitClose || m_frame.document()->parsing() || m_frame.document()->isDelayingLoadEvent())
893 if (!allChildrenAreComplete())
894 return; // still got a frame running -> too early
896 m_didCallImplicitClose = true;
897 m_wasUnloadEventEmitted = false;
898 m_frame.document()->implicitClose();
901 void FrameLoader::loadURLIntoChildFrame(const URL& url, const String& referer, Frame* childFrame)
905 #if ENABLE(WEB_ARCHIVE) || ENABLE(MHTML)
906 RefPtr<Archive> subframeArchive = activeDocumentLoader()->popArchiveForSubframe(childFrame->tree().uniqueName(), url);
907 if (subframeArchive) {
908 childFrame->loader().loadArchive(subframeArchive.release());
911 #endif // ENABLE(WEB_ARCHIVE)
913 HistoryItem* parentItem = history().currentItem();
914 // If we're moving in the back/forward list, we might want to replace the content
915 // of this child frame with whatever was there at that point.
916 if (parentItem && parentItem->children().size() && isBackForwardLoadType(loadType())
917 && !m_frame.document()->loadEventFinished()) {
918 HistoryItem* childItem = parentItem->childItemWithTarget(childFrame->tree().uniqueName());
920 childFrame->loader().m_requestedHistoryItem = childItem;
921 childFrame->loader().loadDifferentDocumentItem(childItem, loadType(), MayAttemptCacheOnlyLoadForFormSubmissionItem);
926 childFrame->loader().loadURL(url, referer, "_self", LockHistory::No, FrameLoadType::RedirectWithLockedBackForwardList, 0, 0, AllowNavigationToInvalidURL::Yes);
929 #if ENABLE(WEB_ARCHIVE) || ENABLE(MHTML)
930 void FrameLoader::loadArchive(PassRefPtr<Archive> archive)
932 ArchiveResource* mainResource = archive->mainResource();
933 ASSERT(mainResource);
937 SubstituteData substituteData(mainResource->data(), mainResource->mimeType(), mainResource->textEncoding(), URL());
939 ResourceRequest request(mainResource->url());
941 request.applyWebArchiveHackForMail();
944 RefPtr<DocumentLoader> documentLoader = m_client.createDocumentLoader(request, substituteData);
945 documentLoader->setArchive(archive.get());
946 load(documentLoader.get());
948 #endif // ENABLE(WEB_ARCHIVE) || ENABLE(MHTML)
950 ObjectContentType FrameLoader::defaultObjectContentType(const URL& url, const String& mimeTypeIn, bool shouldPreferPlugInsForImages)
952 String mimeType = mimeTypeIn;
954 if (mimeType.isEmpty())
955 mimeType = mimeTypeFromURL(url);
957 #if !PLATFORM(COCOA) && !PLATFORM(EFL) // Mac has no PluginDatabase, nor does EFL
958 if (mimeType.isEmpty()) {
959 String decodedPath = decodeURLEscapeSequences(url.path());
960 mimeType = PluginDatabase::installedPlugins()->MIMETypeForExtension(decodedPath.substring(decodedPath.reverseFind('.') + 1));
964 if (mimeType.isEmpty())
965 return ObjectContentFrame; // Go ahead and hope that we can display the content.
967 #if !PLATFORM(COCOA) && !PLATFORM(EFL) // Mac has no PluginDatabase, nor does EFL
968 bool plugInSupportsMIMEType = PluginDatabase::installedPlugins()->isMIMETypeRegistered(mimeType);
970 bool plugInSupportsMIMEType = false;
973 if (MIMETypeRegistry::isSupportedImageMIMEType(mimeType))
974 return shouldPreferPlugInsForImages && plugInSupportsMIMEType ? WebCore::ObjectContentNetscapePlugin : WebCore::ObjectContentImage;
976 if (plugInSupportsMIMEType)
977 return WebCore::ObjectContentNetscapePlugin;
979 if (MIMETypeRegistry::isSupportedNonImageMIMEType(mimeType))
980 return WebCore::ObjectContentFrame;
982 return WebCore::ObjectContentNone;
985 String FrameLoader::outgoingReferrer() const
987 // See http://www.whatwg.org/specs/web-apps/current-work/#fetching-resources
988 // for why we walk the parent chain for srcdoc documents.
989 Frame* frame = &m_frame;
990 while (frame->document()->isSrcdocDocument()) {
991 frame = frame->tree().parent();
992 // Srcdoc documents cannot be top-level documents, by definition,
993 // because they need to be contained in iframes with the srcdoc.
996 return frame->loader().m_outgoingReferrer;
999 String FrameLoader::outgoingOrigin() const
1001 return m_frame.document()->securityOrigin()->toString();
1004 bool FrameLoader::checkIfFormActionAllowedByCSP(const URL& url) const
1006 if (m_submittedFormURL.isEmpty())
1009 return m_frame.document()->contentSecurityPolicy()->allowFormAction(url);
1012 Frame* FrameLoader::opener()
1017 void FrameLoader::setOpener(Frame* opener)
1019 if (m_opener && !opener)
1020 m_client.didDisownOpener();
1023 m_opener->loader().m_openedFrames.remove(&m_frame);
1025 opener->loader().m_openedFrames.add(&m_frame);
1028 if (m_frame.document())
1029 m_frame.document()->initSecurityContext();
1032 // FIXME: This does not belong in FrameLoader!
1033 void FrameLoader::handleFallbackContent()
1035 HTMLFrameOwnerElement* owner = m_frame.ownerElement();
1036 if (!owner || !owner->hasTagName(objectTag))
1038 toHTMLObjectElement(owner)->renderFallbackContent();
1041 void FrameLoader::provisionalLoadStarted()
1043 if (m_stateMachine.firstLayoutDone())
1044 m_stateMachine.advanceTo(FrameLoaderStateMachine::CommittedFirstRealLoad);
1045 m_frame.navigationScheduler().cancel(true);
1046 m_client.provisionalLoadStarted();
1049 void FrameLoader::resetMultipleFormSubmissionProtection()
1051 m_submittedFormURL = URL();
1054 void FrameLoader::updateFirstPartyForCookies()
1056 if (m_frame.tree().parent())
1057 setFirstPartyForCookies(m_frame.tree().parent()->document()->firstPartyForCookies());
1059 setFirstPartyForCookies(m_frame.document()->url());
1062 void FrameLoader::setFirstPartyForCookies(const URL& url)
1064 for (Frame* frame = &m_frame; frame; frame = frame->tree().traverseNext(&m_frame))
1065 frame->document()->setFirstPartyForCookies(url);
1068 // This does the same kind of work that didOpenURL does, except it relies on the fact
1069 // that a higher level already checked that the URLs match and the scrolling is the right thing to do.
1070 void FrameLoader::loadInSameDocument(const URL& url, PassRefPtr<SerializedScriptValue> stateObject, bool isNewNavigation)
1072 // If we have a state object, we cannot also be a new navigation.
1073 ASSERT(!stateObject || (stateObject && !isNewNavigation));
1075 // Update the data source's request with the new URL to fake the URL change
1076 URL oldURL = m_frame.document()->url();
1077 m_frame.document()->setURL(url);
1078 setOutgoingReferrer(url);
1079 documentLoader()->replaceRequestURLForSameDocumentNavigation(url);
1080 if (isNewNavigation && !shouldTreatURLAsSameAsCurrent(url) && !stateObject) {
1081 // NB: must happen after replaceRequestURLForSameDocumentNavigation(), since we add
1082 // based on the current request. Must also happen before we openURL and displace the
1083 // scroll position, since adding the BF item will save away scroll state.
1085 // NB2: If we were loading a long, slow doc, and the user fragment navigated before
1086 // it was done, currItem is now set the that slow doc, and prevItem is whatever was
1087 // before it. Adding the b/f item will bump the slow doc down to prevItem, even
1088 // though its load is not yet done. I think this all works out OK, for one because
1089 // we have already saved away the scroll and doc state for the long slow load,
1090 // but it's not an obvious case.
1092 history().updateBackForwardListForFragmentScroll();
1095 bool hashChange = equalIgnoringFragmentIdentifier(url, oldURL) && url.fragmentIdentifier() != oldURL.fragmentIdentifier();
1097 history().updateForSameDocumentNavigation();
1099 // If we were in the autoscroll/panScroll mode we want to stop it before following the link to the anchor
1101 m_frame.eventHandler().stopAutoscrollTimer();
1103 // It's important to model this as a load that starts and immediately finishes.
1104 // Otherwise, the parent frame may think we never finished loading.
1107 // We need to scroll to the fragment whether or not a hash change occurred, since
1108 // the user might have scrolled since the previous navigation.
1109 scrollToFragmentWithParentBoundary(url);
1111 m_isComplete = false;
1114 if (isNewNavigation) {
1115 // This will clear previousItem from the rest of the frame tree that didn't
1116 // doing any loading. We need to make a pass on this now, since for fragment
1117 // navigation we'll not go through a real load and reach Completed state.
1118 checkLoadComplete();
1121 m_client.dispatchDidNavigateWithinPage();
1123 m_frame.document()->statePopped(stateObject ? stateObject : SerializedScriptValue::nullValue());
1124 m_client.dispatchDidPopStateWithinPage();
1127 m_frame.document()->enqueueHashchangeEvent(oldURL, url);
1128 m_client.dispatchDidChangeLocationWithinPage();
1131 // FrameLoaderClient::didFinishLoad() tells the internal load delegate the load finished with no error
1132 m_client.didFinishLoad();
1135 bool FrameLoader::isComplete() const
1137 return m_isComplete;
1140 void FrameLoader::completed()
1142 Ref<Frame> protect(m_frame);
1144 for (Frame* descendant = m_frame.tree().traverseNext(&m_frame); descendant; descendant = descendant->tree().traverseNext(&m_frame))
1145 descendant->navigationScheduler().startTimer();
1147 if (Frame* parent = m_frame.tree().parent())
1148 parent->loader().checkCompleted();
1151 m_frame.view()->maintainScrollPositionAtAnchor(0);
1152 m_activityAssertion = nullptr;
1155 void FrameLoader::started()
1157 if (m_frame.page() && m_frame.page()->pageThrottler())
1158 m_activityAssertion = m_frame.page()->pageThrottler()->pageLoadActivityToken();
1159 for (Frame* frame = &m_frame; frame; frame = frame->tree().parent())
1160 frame->loader().m_isComplete = false;
1163 void FrameLoader::prepareForHistoryNavigation()
1165 // If there is no currentItem, but we still want to engage in
1166 // history navigation we need to manufacture one, and update
1167 // the state machine of this frame to impersonate having
1169 RefPtr<HistoryItem> currentItem = history().currentItem();
1171 currentItem = HistoryItem::create();
1172 currentItem->setLastVisitWasFailure(true);
1173 history().setCurrentItem(currentItem.get());
1174 m_frame.page()->backForward().setCurrentItem(currentItem.get());
1176 ASSERT(stateMachine().isDisplayingInitialEmptyDocument());
1177 stateMachine().advanceTo(FrameLoaderStateMachine::DisplayingInitialEmptyDocumentPostCommit);
1178 stateMachine().advanceTo(FrameLoaderStateMachine::CommittedFirstRealLoad);
1182 void FrameLoader::prepareForLoadStart()
1184 m_progressTracker->progressStarted();
1185 m_client.dispatchDidStartProvisionalLoad();
1187 if (AXObjectCache::accessibilityEnabled()) {
1188 if (AXObjectCache* cache = m_frame.document()->existingAXObjectCache()) {
1189 AXObjectCache::AXLoadingEvent loadingEvent = loadType() == FrameLoadType::Reload ? AXObjectCache::AXLoadingReloaded : AXObjectCache::AXLoadingStarted;
1190 cache->frameLoadingEventNotification(&m_frame, loadingEvent);
1195 void FrameLoader::setupForReplace()
1197 m_client.revertToProvisionalState(m_documentLoader.get());
1198 setState(FrameStateProvisional);
1199 m_provisionalDocumentLoader = m_documentLoader;
1200 m_documentLoader = 0;
1204 void FrameLoader::loadFrameRequest(const FrameLoadRequest& request, LockHistory lockHistory, LockBackForwardList lockBackForwardList,
1205 PassRefPtr<Event> event, PassRefPtr<FormState> formState, ShouldSendReferrer shouldSendReferrer, AllowNavigationToInvalidURL allowNavigationToInvalidURL)
1207 // Protect frame from getting blown away inside dispatchBeforeLoadEvent in loadWithDocumentLoader.
1208 Ref<Frame> protect(m_frame);
1210 URL url = request.resourceRequest().url();
1212 ASSERT(m_frame.document());
1213 if (!request.requester()->canDisplay(url)) {
1214 reportLocalLoadFailed(&m_frame, url.stringCenterEllipsizedToLength());
1218 String argsReferrer = request.resourceRequest().httpReferrer();
1219 if (argsReferrer.isEmpty())
1220 argsReferrer = outgoingReferrer();
1222 String referrer = SecurityPolicy::generateReferrerHeader(m_frame.document()->referrerPolicy(), url, argsReferrer);
1223 if (shouldSendReferrer == NeverSendReferrer)
1224 referrer = String();
1226 FrameLoadType loadType;
1227 if (request.resourceRequest().cachePolicy() == ReloadIgnoringCacheData)
1228 loadType = FrameLoadType::Reload;
1229 else if (lockBackForwardList == LockBackForwardList::Yes)
1230 loadType = FrameLoadType::RedirectWithLockedBackForwardList;
1232 loadType = FrameLoadType::Standard;
1234 if (request.resourceRequest().httpMethod() == "POST")
1235 loadPostRequest(request.resourceRequest(), referrer, request.frameName(), lockHistory, loadType, event, formState.get(), allowNavigationToInvalidURL);
1237 loadURL(request.resourceRequest().url(), referrer, request.frameName(), lockHistory, loadType, event, formState.get(), allowNavigationToInvalidURL);
1239 // FIXME: It's possible this targetFrame will not be the same frame that was targeted by the actual
1240 // load if frame names have changed.
1241 Frame* sourceFrame = formState ? formState->sourceDocument()->frame() : &m_frame;
1243 sourceFrame = &m_frame;
1244 Frame* targetFrame = sourceFrame->loader().findFrameForNavigation(request.frameName());
1245 if (targetFrame && targetFrame != sourceFrame) {
1246 if (Page* page = targetFrame->page())
1247 page->chrome().focus();
1251 void FrameLoader::loadURL(const URL& newURL, const String& referrer, const String& frameName, LockHistory lockHistory, FrameLoadType newLoadType,
1252 PassRefPtr<Event> event, PassRefPtr<FormState> prpFormState, AllowNavigationToInvalidURL allowNavigationToInvalidURL)
1254 if (m_inStopAllLoaders)
1257 Ref<Frame> protect(m_frame);
1259 RefPtr<FormState> formState = prpFormState;
1260 bool isFormSubmission = formState;
1262 ResourceRequest request(newURL);
1263 if (!referrer.isEmpty()) {
1264 request.setHTTPReferrer(referrer);
1265 RefPtr<SecurityOrigin> referrerOrigin = SecurityOrigin::createFromString(referrer);
1266 addHTTPOriginIfNeeded(request, referrerOrigin->toString());
1268 #if ENABLE(CACHE_PARTITIONING)
1269 if (&m_frame.tree().top() != &m_frame)
1270 request.setCachePartition(m_frame.tree().top().document()->securityOrigin()->cachePartition());
1272 addExtraFieldsToRequest(request, newLoadType, true);
1273 if (newLoadType == FrameLoadType::Reload || newLoadType == FrameLoadType::ReloadFromOrigin)
1274 request.setCachePolicy(ReloadIgnoringCacheData);
1276 ASSERT(newLoadType != FrameLoadType::Same);
1278 // The search for a target frame is done earlier in the case of form submission.
1279 Frame* targetFrame = isFormSubmission ? 0 : findFrameForNavigation(frameName);
1280 if (targetFrame && targetFrame != &m_frame) {
1281 targetFrame->loader().loadURL(newURL, referrer, "_self", lockHistory, newLoadType, event, formState.release(), allowNavigationToInvalidURL);
1285 if (m_pageDismissalEventBeingDispatched != NoDismissal)
1288 NavigationAction action(request, newLoadType, isFormSubmission, event);
1290 if (!targetFrame && !frameName.isEmpty()) {
1291 policyChecker().checkNewWindowPolicy(action, request, formState.release(), frameName, [this, allowNavigationToInvalidURL](const ResourceRequest& request, PassRefPtr<FormState> formState, const String& frameName, const NavigationAction& action, bool shouldContinue) {
1292 continueLoadAfterNewWindowPolicy(request, formState, frameName, action, shouldContinue, allowNavigationToInvalidURL);
1297 RefPtr<DocumentLoader> oldDocumentLoader = m_documentLoader;
1299 bool sameURL = shouldTreatURLAsSameAsCurrent(newURL);
1300 const String& httpMethod = request.httpMethod();
1302 // Make sure to do scroll to fragment processing even if the URL is
1303 // exactly the same so pages with '#' links and DHTML side effects
1305 if (shouldPerformFragmentNavigation(isFormSubmission, httpMethod, newLoadType, newURL)) {
1306 oldDocumentLoader->setTriggeringAction(action);
1307 oldDocumentLoader->setLastCheckedRequest(ResourceRequest());
1308 policyChecker().stopCheck();
1309 policyChecker().setLoadType(newLoadType);
1310 policyChecker().checkNavigationPolicy(request, oldDocumentLoader.get(), formState.release(), [this](const ResourceRequest& request, PassRefPtr<FormState>, bool shouldContinue) {
1311 continueFragmentScrollAfterNavigationPolicy(request, shouldContinue);
1316 // must grab this now, since this load may stop the previous load and clear this flag
1317 bool isRedirect = m_quickRedirectComing;
1318 loadWithNavigationAction(request, action, lockHistory, newLoadType, formState.release(), allowNavigationToInvalidURL);
1320 m_quickRedirectComing = false;
1321 if (m_provisionalDocumentLoader)
1322 m_provisionalDocumentLoader->setIsClientRedirect(true);
1323 } else if (sameURL && newLoadType != FrameLoadType::Reload && newLoadType != FrameLoadType::ReloadFromOrigin) {
1324 // Example of this case are sites that reload the same URL with a different cookie
1325 // driving the generated content, or a master frame with links that drive a target
1326 // frame, where the user has clicked on the same link repeatedly.
1327 m_loadType = FrameLoadType::Same;
1331 SubstituteData FrameLoader::defaultSubstituteDataForURL(const URL& url)
1333 if (!shouldTreatURLAsSrcdocDocument(url))
1334 return SubstituteData();
1335 String srcdoc = m_frame.ownerElement()->fastGetAttribute(srcdocAttr);
1336 ASSERT(!srcdoc.isNull());
1337 CString encodedSrcdoc = srcdoc.utf8();
1338 return SubstituteData(SharedBuffer::create(encodedSrcdoc.data(), encodedSrcdoc.length()), "text/html", "UTF-8", URL());
1341 void FrameLoader::load(const FrameLoadRequest& passedRequest)
1343 FrameLoadRequest request(passedRequest);
1345 if (m_inStopAllLoaders)
1348 if (!request.frameName().isEmpty()) {
1349 Frame* frame = findFrameForNavigation(request.frameName());
1351 request.setShouldCheckNewWindowPolicy(false);
1352 if (&frame->loader() != this) {
1353 frame->loader().load(request);
1359 if (request.shouldCheckNewWindowPolicy()) {
1360 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) {
1361 continueLoadAfterNewWindowPolicy(request, formState, frameName, action, shouldContinue, AllowNavigationToInvalidURL::Yes);
1367 if (!request.hasSubstituteData())
1368 request.setSubstituteData(defaultSubstituteDataForURL(request.resourceRequest().url()));
1370 RefPtr<DocumentLoader> loader = m_client.createDocumentLoader(request.resourceRequest(), request.substituteData());
1374 void FrameLoader::loadWithNavigationAction(const ResourceRequest& request, const NavigationAction& action, LockHistory lockHistory, FrameLoadType type, PassRefPtr<FormState> formState, AllowNavigationToInvalidURL allowNavigationToInvalidURL)
1376 RefPtr<DocumentLoader> loader = m_client.createDocumentLoader(request, defaultSubstituteDataForURL(request.url()));
1377 if (lockHistory == LockHistory::Yes && m_documentLoader)
1378 loader->setClientRedirectSourceForHistory(m_documentLoader->didCreateGlobalHistoryEntry() ? m_documentLoader->urlForHistory().string() : m_documentLoader->clientRedirectSourceForHistory());
1380 loader->setTriggeringAction(action);
1381 if (m_documentLoader)
1382 loader->setOverrideEncoding(m_documentLoader->overrideEncoding());
1384 loadWithDocumentLoader(loader.get(), type, formState, allowNavigationToInvalidURL);
1387 void FrameLoader::load(DocumentLoader* newDocumentLoader)
1389 ResourceRequest& r = newDocumentLoader->request();
1390 addExtraFieldsToMainResourceRequest(r);
1393 if (shouldTreatURLAsSameAsCurrent(newDocumentLoader->originalRequest().url())) {
1394 r.setCachePolicy(ReloadIgnoringCacheData);
1395 type = FrameLoadType::Same;
1396 } else if (shouldTreatURLAsSameAsCurrent(newDocumentLoader->unreachableURL()) && m_loadType == FrameLoadType::Reload)
1397 type = FrameLoadType::Reload;
1399 type = FrameLoadType::Standard;
1401 if (m_documentLoader)
1402 newDocumentLoader->setOverrideEncoding(m_documentLoader->overrideEncoding());
1404 // When we loading alternate content for an unreachable URL that we're
1405 // visiting in the history list, we treat it as a reload so the history list
1406 // is appropriately maintained.
1408 // FIXME: This seems like a dangerous overloading of the meaning of "FrameLoadType::Reload" ...
1409 // shouldn't a more explicit type of reload be defined, that means roughly
1410 // "load without affecting history" ?
1411 if (shouldReloadToHandleUnreachableURL(newDocumentLoader)) {
1412 // shouldReloadToHandleUnreachableURL() returns true only when the original load type is back-forward.
1413 // In this case we should save the document state now. Otherwise the state can be lost because load type is
1414 // changed and updateForBackForwardNavigation() will not be called when loading is committed.
1415 history().saveDocumentAndScrollState();
1417 ASSERT(type == FrameLoadType::Standard);
1418 type = FrameLoadType::Reload;
1421 loadWithDocumentLoader(newDocumentLoader, type, 0, AllowNavigationToInvalidURL::Yes);
1424 void FrameLoader::loadWithDocumentLoader(DocumentLoader* loader, FrameLoadType type, PassRefPtr<FormState> prpFormState, AllowNavigationToInvalidURL allowNavigationToInvalidURL)
1426 // Retain because dispatchBeforeLoadEvent may release the last reference to it.
1427 Ref<Frame> protect(m_frame);
1429 ASSERT(m_client.hasWebView());
1431 // Unfortunately the view must be non-nil, this is ultimately due
1432 // to parser requiring a FrameView. We should fix this dependency.
1434 ASSERT(m_frame.view());
1436 if (m_pageDismissalEventBeingDispatched != NoDismissal)
1439 if (m_frame.document())
1440 m_previousURL = m_frame.document()->url();
1442 policyChecker().setLoadType(type);
1443 RefPtr<FormState> formState = prpFormState;
1444 bool isFormSubmission = formState;
1446 const URL& newURL = loader->request().url();
1447 const String& httpMethod = loader->request().httpMethod();
1449 if (shouldPerformFragmentNavigation(isFormSubmission, httpMethod, policyChecker().loadType(), newURL)) {
1450 RefPtr<DocumentLoader> oldDocumentLoader = m_documentLoader;
1451 NavigationAction action(loader->request(), policyChecker().loadType(), isFormSubmission);
1453 oldDocumentLoader->setTriggeringAction(action);
1454 oldDocumentLoader->setLastCheckedRequest(ResourceRequest());
1455 policyChecker().stopCheck();
1456 policyChecker().checkNavigationPolicy(loader->request(), oldDocumentLoader.get(), formState, [this](const ResourceRequest& request, PassRefPtr<FormState>, bool shouldContinue) {
1457 continueFragmentScrollAfterNavigationPolicy(request, shouldContinue);
1462 if (Frame* parent = m_frame.tree().parent())
1463 loader->setOverrideEncoding(parent->loader().documentLoader()->overrideEncoding());
1465 policyChecker().stopCheck();
1466 setPolicyDocumentLoader(loader);
1467 if (loader->triggeringAction().isEmpty())
1468 loader->setTriggeringAction(NavigationAction(loader->request(), policyChecker().loadType(), isFormSubmission));
1470 if (Element* ownerElement = m_frame.ownerElement()) {
1471 // We skip dispatching the beforeload event if we've already
1472 // committed a real document load because the event would leak
1473 // subsequent activity by the frame which the parent frame isn't
1474 // supposed to learn. For example, if the child frame navigated to
1475 // a new URL, the parent frame shouldn't learn the URL.
1476 if (!m_stateMachine.committedFirstRealDocumentLoad()
1477 && !ownerElement->dispatchBeforeLoadEvent(loader->request().url().string())) {
1478 continueLoadAfterNavigationPolicy(loader->request(), formState, false, allowNavigationToInvalidURL);
1483 policyChecker().checkNavigationPolicy(loader->request(), loader, formState, [this, allowNavigationToInvalidURL](const ResourceRequest& request, PassRefPtr<FormState> formState, bool shouldContinue) {
1484 continueLoadAfterNavigationPolicy(request, formState, shouldContinue, allowNavigationToInvalidURL);
1488 void FrameLoader::reportLocalLoadFailed(Frame* frame, const String& url)
1490 ASSERT(!url.isEmpty());
1494 frame->document()->addConsoleMessage(MessageSource::Security, MessageLevel::Error, "Not allowed to load local resource: " + url);
1497 const ResourceRequest& FrameLoader::initialRequest() const
1499 return activeDocumentLoader()->originalRequest();
1502 bool FrameLoader::willLoadMediaElementURL(URL& url)
1505 // MobileStore depends on the iOS 4.0 era client delegate method because webView:resource:willSendRequest:redirectResponse:fromDataSource
1506 // doesn't let them tell when a load request is coming from a media element. See <rdar://problem/8266916> for more details.
1507 if (applicationIsMobileStore())
1508 return m_client.shouldLoadMediaElementURL(url);
1511 ResourceRequest request(url);
1513 unsigned long identifier;
1514 ResourceError error;
1515 requestFromDelegate(request, identifier, error);
1516 notifier().sendRemainingDelegateMessages(m_documentLoader.get(), identifier, request, ResourceResponse(url, String(), -1, String(), String()), 0, -1, -1, error);
1518 url = request.url();
1520 return error.isNull();
1523 bool FrameLoader::shouldReloadToHandleUnreachableURL(DocumentLoader* docLoader)
1525 URL unreachableURL = docLoader->unreachableURL();
1527 if (unreachableURL.isEmpty())
1530 if (!isBackForwardLoadType(policyChecker().loadType()))
1533 // We only treat unreachableURLs specially during the delegate callbacks
1534 // for provisional load errors and navigation policy decisions. The former
1535 // case handles well-formed URLs that can't be loaded, and the latter
1536 // case handles malformed URLs and unknown schemes. Loading alternate content
1537 // at other times behaves like a standard load.
1538 DocumentLoader* compareDocumentLoader = 0;
1539 if (policyChecker().delegateIsDecidingNavigationPolicy() || policyChecker().delegateIsHandlingUnimplementablePolicy())
1540 compareDocumentLoader = m_policyDocumentLoader.get();
1541 else if (m_delegateIsHandlingProvisionalLoadError)
1542 compareDocumentLoader = m_provisionalDocumentLoader.get();
1544 return compareDocumentLoader && unreachableURL == compareDocumentLoader->request().url();
1547 void FrameLoader::reloadWithOverrideEncoding(const String& encoding)
1549 if (!m_documentLoader)
1552 ResourceRequest request = m_documentLoader->request();
1553 URL unreachableURL = m_documentLoader->unreachableURL();
1554 if (!unreachableURL.isEmpty())
1555 request.setURL(unreachableURL);
1557 // FIXME: If the resource is a result of form submission and is not cached, the form will be silently resubmitted.
1558 // We should ask the user for confirmation in this case.
1559 request.setCachePolicy(ReturnCacheDataElseLoad);
1561 RefPtr<DocumentLoader> loader = m_client.createDocumentLoader(request, defaultSubstituteDataForURL(request.url()));
1562 setPolicyDocumentLoader(loader.get());
1564 loader->setOverrideEncoding(encoding);
1566 loadWithDocumentLoader(loader.get(), FrameLoadType::Reload, 0, AllowNavigationToInvalidURL::Yes);
1569 void FrameLoader::reload(bool endToEndReload)
1571 if (!m_documentLoader)
1574 // If a window is created by javascript, its main frame can have an empty but non-nil URL.
1575 // Reloading in this case will lose the current contents (see 4151001).
1576 if (m_documentLoader->request().url().isEmpty())
1579 // Replace error-page URL with the URL we were trying to reach.
1580 ResourceRequest initialRequest = m_documentLoader->request();
1581 URL unreachableURL = m_documentLoader->unreachableURL();
1582 if (!unreachableURL.isEmpty())
1583 initialRequest.setURL(unreachableURL);
1585 // Create a new document loader for the reload, this will become m_documentLoader eventually,
1586 // but first it has to be the "policy" document loader, and then the "provisional" document loader.
1587 RefPtr<DocumentLoader> loader = m_client.createDocumentLoader(initialRequest, defaultSubstituteDataForURL(initialRequest.url()));
1589 ResourceRequest& request = loader->request();
1591 // FIXME: We don't have a mechanism to revalidate the main resource without reloading at the moment.
1592 request.setCachePolicy(ReloadIgnoringCacheData);
1594 // If we're about to re-post, set up action so the application can warn the user.
1595 if (request.httpMethod() == "POST")
1596 loader->setTriggeringAction(NavigationAction(request, NavigationTypeFormResubmitted));
1598 loader->setOverrideEncoding(m_documentLoader->overrideEncoding());
1600 loadWithDocumentLoader(loader.get(), endToEndReload ? FrameLoadType::ReloadFromOrigin : FrameLoadType::Reload, 0, AllowNavigationToInvalidURL::Yes);
1603 void FrameLoader::stopAllLoaders(ClearProvisionalItemPolicy clearProvisionalItemPolicy)
1605 ASSERT(!m_frame.document() || !m_frame.document()->inPageCache());
1606 if (m_pageDismissalEventBeingDispatched != NoDismissal)
1609 // If this method is called from within this method, infinite recursion can occur (3442218). Avoid this.
1610 if (m_inStopAllLoaders)
1613 // Calling stopLoading() on the provisional document loader can blow away
1614 // the frame from underneath.
1615 Ref<Frame> protect(m_frame);
1617 m_inStopAllLoaders = true;
1619 policyChecker().stopCheck();
1621 // If no new load is in progress, we should clear the provisional item from history
1622 // before we call stopLoading.
1623 if (clearProvisionalItemPolicy == ShouldClearProvisionalItem)
1624 history().setProvisionalItem(0);
1626 for (RefPtr<Frame> child = m_frame.tree().firstChild(); child; child = child->tree().nextSibling())
1627 child->loader().stopAllLoaders(clearProvisionalItemPolicy);
1628 if (m_provisionalDocumentLoader)
1629 m_provisionalDocumentLoader->stopLoading();
1630 if (m_documentLoader)
1631 m_documentLoader->stopLoading();
1633 setProvisionalDocumentLoader(0);
1635 m_checkTimer.stop();
1637 m_inStopAllLoaders = false;
1640 void FrameLoader::stopForUserCancel(bool deferCheckLoadComplete)
1645 // Lay out immediately when stopping to immediately clear the old page if we just committed this one
1646 // but haven't laid out/painted yet.
1647 // FIXME: Is this behavior specific to iOS? Or should we expose a setting to toggle this behavior?
1648 if (m_frame.view() && !m_frame.view()->didFirstLayout())
1649 m_frame.view()->layout();
1652 if (deferCheckLoadComplete)
1653 scheduleCheckLoadComplete();
1654 else if (m_frame.page())
1655 checkLoadComplete();
1658 DocumentLoader* FrameLoader::activeDocumentLoader() const
1660 if (m_state == FrameStateProvisional)
1661 return m_provisionalDocumentLoader.get();
1662 return m_documentLoader.get();
1665 bool FrameLoader::isLoading() const
1667 DocumentLoader* docLoader = activeDocumentLoader();
1670 return docLoader->isLoading();
1673 bool FrameLoader::frameHasLoaded() const
1675 return m_stateMachine.committedFirstRealDocumentLoad() || (m_provisionalDocumentLoader && !m_stateMachine.creatingInitialEmptyDocument());
1678 void FrameLoader::setDocumentLoader(DocumentLoader* loader)
1680 if (!loader && !m_documentLoader)
1683 ASSERT(loader != m_documentLoader);
1684 ASSERT(!loader || loader->frameLoader() == this);
1686 m_client.prepareForDataSourceReplacement();
1689 // detachChildren() can trigger this frame's unload event, and therefore
1690 // script can run and do just about anything. For example, an unload event that calls
1691 // document.write("") on its parent frame can lead to a recursive detachChildren()
1692 // invocation for this frame. In that case, we can end up at this point with a
1693 // loader that hasn't been deleted but has been detached from its frame. Such a
1694 // DocumentLoader has been sufficiently detached that we'll end up in an inconsistent
1695 // state if we try to use it.
1696 if (loader && !loader->frame())
1699 if (m_documentLoader)
1700 m_documentLoader->detachFromFrame();
1702 m_documentLoader = loader;
1705 void FrameLoader::setPolicyDocumentLoader(DocumentLoader* loader)
1707 if (m_policyDocumentLoader == loader)
1711 loader->setFrame(&m_frame);
1712 if (m_policyDocumentLoader
1713 && m_policyDocumentLoader != m_provisionalDocumentLoader
1714 && m_policyDocumentLoader != m_documentLoader)
1715 m_policyDocumentLoader->detachFromFrame();
1717 m_policyDocumentLoader = loader;
1720 void FrameLoader::setProvisionalDocumentLoader(DocumentLoader* loader)
1722 ASSERT(!loader || !m_provisionalDocumentLoader);
1723 ASSERT(!loader || loader->frameLoader() == this);
1725 if (m_provisionalDocumentLoader && m_provisionalDocumentLoader != m_documentLoader)
1726 m_provisionalDocumentLoader->detachFromFrame();
1728 m_provisionalDocumentLoader = loader;
1731 void FrameLoader::setState(FrameState newState)
1735 if (newState == FrameStateProvisional)
1736 provisionalLoadStarted();
1737 else if (newState == FrameStateComplete) {
1738 frameLoadCompleted();
1739 if (m_documentLoader)
1740 m_documentLoader->stopRecordingResponses();
1744 void FrameLoader::clearProvisionalLoad()
1746 setProvisionalDocumentLoader(0);
1747 m_progressTracker->progressCompleted();
1748 setState(FrameStateComplete);
1751 void FrameLoader::commitProvisionalLoad()
1753 RefPtr<DocumentLoader> pdl = m_provisionalDocumentLoader;
1754 Ref<Frame> protect(m_frame);
1756 std::unique_ptr<CachedPage> cachedPage;
1757 if (m_loadingFromCachedPage)
1758 cachedPage = pageCache()->take(history().provisionalItem());
1760 LOG(PageCache, "WebCoreLoading %s: About to commit provisional load from previous URL '%s' to new URL '%s'", m_frame.tree().uniqueName().string().utf8().data(),
1761 m_frame.document() ? m_frame.document()->url().stringCenterEllipsizedToLength().utf8().data() : "",
1762 pdl ? pdl->url().stringCenterEllipsizedToLength().utf8().data() : "<no provisional DocumentLoader>");
1765 // In the case where we are not navigating to a cached page, and the system is under (speculative) memory pressure,
1766 // we can try to preemptively release some of the pages in the cache.
1767 // FIXME: Right now the capacity is 1 on iOS devices with 256 MB of RAM, so this will always blow away the whole
1768 // page cache. We could still preemptively prune the page cache while navigating to a cached page if capacity > 1.
1769 // See <rdar://problem/11779846> for more details.
1771 if (memoryPressureHandler().isUnderMemoryPressure()) {
1772 LOG(MemoryPressure, "Pruning page cache because under memory pressure at: %s", __PRETTY_FUNCTION__);
1773 LOG(PageCache, "Pruning page cache to 0 due to memory pressure");
1774 // Don't cache any page if we are under memory pressure.
1775 pageCache()->pruneToCapacityNow(0);
1776 } else if (systemMemoryLevel() <= memoryLevelThresholdToPrunePageCache) {
1777 LOG(MemoryPressure, "Pruning page cache because system memory level is %d at: %s", systemMemoryLevel(), __PRETTY_FUNCTION__);
1778 LOG(PageCache, "Pruning page cache to %d due to low memory (level %d less or equal to %d threshold)", pageCache()->capacity() / 2, systemMemoryLevel(), memoryLevelThresholdToPrunePageCache);
1779 pageCache()->pruneToCapacityNow(pageCache()->capacity() / 2);
1784 willTransitionToCommitted();
1786 // Check to see if we need to cache the page we are navigating away from into the back/forward cache.
1787 // We are doing this here because we know for sure that a new page is about to be loaded.
1788 HistoryItem* item = history().currentItem();
1789 if (!m_frame.tree().parent() && pageCache()->canCache(m_frame.page()) && !item->isInPageCache())
1790 pageCache()->add(item, *m_frame.page());
1792 if (m_loadType != FrameLoadType::Replace)
1793 closeOldDataSources();
1795 if (!cachedPage && !m_stateMachine.creatingInitialEmptyDocument())
1796 m_client.makeRepresentation(pdl.get());
1798 transitionToCommitted(cachedPage.get());
1800 if (pdl && m_documentLoader) {
1801 // Check if the destination page is allowed to access the previous page's timing information.
1802 RefPtr<SecurityOrigin> securityOrigin = SecurityOrigin::create(pdl->request().url());
1803 m_documentLoader->timing()->setHasSameOriginAsPreviousDocument(securityOrigin->canRequest(m_previousURL));
1806 // Call clientRedirectCancelledOrFinished() here so that the frame load delegate is notified that the redirect's
1807 // status has changed, if there was a redirect. The frame load delegate may have saved some state about
1808 // the redirect in its -webView:willPerformClientRedirectToURL:delay:fireDate:forFrame:. Since we are
1809 // just about to commit a new page, there cannot possibly be a pending redirect at this point.
1810 if (m_sentRedirectNotification)
1811 clientRedirectCancelledOrFinished(false);
1813 if (cachedPage && cachedPage->document()) {
1815 // FIXME: CachedPage::restore() would dispatch viewport change notification. However UIKit expects load
1816 // commit to happen before any changes to viewport arguments and dealing with this there is difficult.
1817 m_frame.page()->chrome().setDispatchViewportDataDidChangeSuppressed(true);
1819 prepareForCachedPageRestore();
1821 // FIXME: This API should be turned around so that we ground CachedPage into the Page.
1822 cachedPage->restore(*m_frame.page());
1824 dispatchDidCommitLoad();
1826 m_frame.page()->chrome().setDispatchViewportDataDidChangeSuppressed(false);
1827 m_frame.page()->chrome().dispatchViewportPropertiesDidChange(m_frame.page()->viewportArguments());
1829 // If we have a title let the WebView know about it.
1830 StringWithDirection title = m_documentLoader->title();
1831 if (!title.isNull())
1832 m_client.dispatchDidReceiveTitle(title);
1838 LOG(Loading, "WebCoreLoading %s: Finished committing provisional load to URL %s", m_frame.tree().uniqueName().string().utf8().data(),
1839 m_frame.document() ? m_frame.document()->url().stringCenterEllipsizedToLength().utf8().data() : "");
1841 if (m_loadType == FrameLoadType::Standard && m_documentLoader->isClientRedirect())
1842 history().updateForClientRedirect();
1844 if (m_loadingFromCachedPage) {
1846 // Note, didReceiveDocType is expected to be called for cached pages. See <rdar://problem/5906758> for more details.
1847 if (m_frame.document()->doctype() && m_frame.page())
1848 m_frame.page()->chrome().didReceiveDocType(&m_frame);
1850 m_frame.document()->documentDidResumeFromPageCache();
1852 // Force a layout to update view size and thereby update scrollbars.
1854 if (!m_client.forceLayoutOnRestoreFromPageCache())
1855 m_frame.view()->forceLayout();
1857 m_frame.view()->forceLayout();
1860 const ResponseVector& responses = m_documentLoader->responses();
1861 size_t count = responses.size();
1862 for (size_t i = 0; i < count; i++) {
1863 const ResourceResponse& response = responses[i];
1864 // FIXME: If the WebKit client changes or cancels the request, this is not respected.
1865 ResourceError error;
1866 unsigned long identifier;
1867 ResourceRequest request(response.url());
1868 requestFromDelegate(request, identifier, error);
1869 // FIXME: If we get a resource with more than 2B bytes, this code won't do the right thing.
1870 // However, with today's computers and networking speeds, this won't happen in practice.
1871 // Could be an issue with a giant local file.
1872 notifier().sendRemainingDelegateMessages(m_documentLoader.get(), identifier, request, response, 0, static_cast<int>(response.expectedContentLength()), 0, error);
1875 // FIXME: Why only this frame and not parent frames?
1876 checkLoadCompleteForThisFrame();
1880 void FrameLoader::transitionToCommitted(CachedPage* cachedPage)
1882 ASSERT(m_client.hasWebView());
1883 ASSERT(m_state == FrameStateProvisional);
1885 if (m_state != FrameStateProvisional)
1888 if (FrameView* view = m_frame.view()) {
1889 if (ScrollAnimator* scrollAnimator = view->existingScrollAnimator())
1890 scrollAnimator->cancelAnimations();
1893 m_client.setCopiesOnScroll();
1894 history().updateForCommit();
1896 // The call to closeURL() invokes the unload event handler, which can execute arbitrary
1897 // JavaScript. If the script initiates a new load, we need to abandon the current load,
1898 // or the two will stomp each other.
1899 DocumentLoader* pdl = m_provisionalDocumentLoader.get();
1900 if (m_documentLoader)
1902 if (pdl != m_provisionalDocumentLoader)
1905 // Nothing else can interupt this commit - set the Provisional->Committed transition in stone
1906 if (m_documentLoader)
1907 m_documentLoader->stopLoadingSubresources();
1908 if (m_documentLoader)
1909 m_documentLoader->stopLoadingPlugIns();
1911 setDocumentLoader(m_provisionalDocumentLoader.get());
1912 setProvisionalDocumentLoader(0);
1914 if (pdl != m_documentLoader) {
1915 ASSERT(m_state == FrameStateComplete);
1919 setState(FrameStateCommittedPage);
1921 #if ENABLE(TOUCH_EVENTS) && !PLATFORM(IOS)
1922 if (m_frame.isMainFrame())
1923 m_frame.page()->chrome().client().needTouchEvents(false);
1926 // Handle adding the URL to the back/forward list.
1927 DocumentLoader* dl = m_documentLoader.get();
1929 switch (m_loadType) {
1930 case FrameLoadType::Forward:
1931 case FrameLoadType::Back:
1932 case FrameLoadType::IndexedBackForward:
1933 if (m_frame.page()) {
1934 // If the first load within a frame is a navigation within a back/forward list that was attached
1935 // without any of the items being loaded then we need to update the history in a similar manner as
1936 // for a standard load with the exception of updating the back/forward list (<rdar://problem/8091103>).
1937 if (!m_stateMachine.committedFirstRealDocumentLoad() && m_frame.isMainFrame())
1938 history().updateForStandardLoad(HistoryController::UpdateAllExceptBackForwardList);
1940 history().updateForBackForwardNavigation();
1942 // For cached pages, CachedFrame::restore will take care of firing the popstate event with the history item's state object
1943 if (history().currentItem() && !cachedPage)
1944 m_pendingStateObject = history().currentItem()->stateObject();
1946 // Create a document view for this document, or used the cached view.
1948 DocumentLoader* cachedDocumentLoader = cachedPage->documentLoader();
1949 ASSERT(cachedDocumentLoader);
1950 cachedDocumentLoader->setFrame(&m_frame);
1951 m_client.transitionToCommittedFromCachedFrame(cachedPage->cachedMainFrame());
1953 m_client.transitionToCommittedForNewPage();
1957 case FrameLoadType::Reload:
1958 case FrameLoadType::ReloadFromOrigin:
1959 case FrameLoadType::Same:
1960 case FrameLoadType::Replace:
1961 history().updateForReload();
1962 m_client.transitionToCommittedForNewPage();
1965 case FrameLoadType::Standard:
1966 history().updateForStandardLoad();
1968 m_frame.view()->setScrollbarsSuppressed(true);
1969 m_client.transitionToCommittedForNewPage();
1972 case FrameLoadType::RedirectWithLockedBackForwardList:
1973 history().updateForRedirectWithLockedBackForwardList();
1974 m_client.transitionToCommittedForNewPage();
1977 // FIXME Remove this check when dummy ds is removed (whatever "dummy ds" is).
1978 // An exception should be thrown if we're in the FrameLoadTypeUninitialized state.
1980 ASSERT_NOT_REACHED();
1983 m_documentLoader->writer().setMIMEType(dl->responseMIMEType());
1985 // Tell the client we've committed this URL.
1986 ASSERT(m_frame.view());
1988 if (m_stateMachine.creatingInitialEmptyDocument())
1991 if (!m_stateMachine.committedFirstRealDocumentLoad())
1992 m_stateMachine.advanceTo(FrameLoaderStateMachine::DisplayingInitialEmptyDocumentPostCommit);
1995 void FrameLoader::clientRedirectCancelledOrFinished(bool cancelWithLoadInProgress)
1997 // Note that -webView:didCancelClientRedirectForFrame: is called on the frame load delegate even if
1998 // the redirect succeeded. We should either rename this API, or add a new method, like
1999 // -webView:didFinishClientRedirectForFrame:
2000 m_client.dispatchDidCancelClientRedirect();
2002 if (!cancelWithLoadInProgress)
2003 m_quickRedirectComing = false;
2005 m_sentRedirectNotification = false;
2008 void FrameLoader::clientRedirected(const URL& url, double seconds, double fireDate, LockBackForwardList lockBackForwardList)
2010 m_client.dispatchWillPerformClientRedirect(url, seconds, fireDate);
2012 // Remember that we sent a redirect notification to the frame load delegate so that when we commit
2013 // the next provisional load, we can send a corresponding -webView:didCancelClientRedirectForFrame:
2014 m_sentRedirectNotification = true;
2016 // If a "quick" redirect comes in, we set a special mode so we treat the next
2017 // load as part of the original navigation. If we don't have a document loader, we have
2018 // no "original" load on which to base a redirect, so we treat the redirect as a normal load.
2019 // Loads triggered by JavaScript form submissions never count as quick redirects.
2020 m_quickRedirectComing = (lockBackForwardList == LockBackForwardList::Yes || history().currentItemShouldBeReplaced()) && m_documentLoader && !m_isExecutingJavaScriptFormAction;
2023 bool FrameLoader::shouldReload(const URL& currentURL, const URL& destinationURL)
2025 // This function implements the rule: "Don't reload if navigating by fragment within
2026 // the same URL, but do reload if going to a new URL or to the same URL with no
2027 // fragment identifier at all."
2028 if (!destinationURL.hasFragmentIdentifier())
2030 return !equalIgnoringFragmentIdentifier(currentURL, destinationURL);
2033 void FrameLoader::closeOldDataSources()
2035 // FIXME: Is it important for this traversal to be postorder instead of preorder?
2036 // If so, add helpers for postorder traversal, and use them. If not, then lets not
2037 // use a recursive algorithm here.
2038 for (Frame* child = m_frame.tree().firstChild(); child; child = child->tree().nextSibling())
2039 child->loader().closeOldDataSources();
2041 if (m_documentLoader)
2042 m_client.dispatchWillClose();
2044 m_client.setMainFrameDocumentReady(false); // stop giving out the actual DOMDocument to observers
2047 void FrameLoader::prepareForCachedPageRestore()
2049 ASSERT(!m_frame.tree().parent());
2050 ASSERT(m_frame.page());
2051 ASSERT(m_frame.isMainFrame());
2053 m_frame.navigationScheduler().cancel();
2055 // We still have to close the previous part page.
2058 // Delete old status bar messages (if it _was_ activated on last URL).
2059 if (m_frame.script().canExecuteScripts(NotAboutToExecuteScript)) {
2060 DOMWindow* window = m_frame.document()->domWindow();
2061 window->setStatus(String());
2062 window->setDefaultStatus(String());
2066 void FrameLoader::open(CachedFrameBase& cachedFrame)
2068 m_isComplete = false;
2070 // Don't re-emit the load event.
2071 m_didCallImplicitClose = true;
2073 URL url = cachedFrame.url();
2075 // FIXME: I suspect this block of code doesn't do anything.
2076 if (url.protocolIsInHTTPFamily() && !url.host().isEmpty() && url.path().isEmpty())
2080 Document* document = cachedFrame.document();
2082 ASSERT(document->domWindow());
2084 clear(document, true, true, cachedFrame.isMainFrame());
2086 document->setInPageCache(false);
2088 m_needsClear = true;
2089 m_isComplete = false;
2090 m_didCallImplicitClose = false;
2091 m_outgoingReferrer = url.string();
2093 FrameView* view = cachedFrame.view();
2095 // When navigating to a CachedFrame its FrameView should never be null. If it is we'll crash in creative ways downstream.
2097 view->setWasScrolledByUser(false);
2099 // Use the current ScrollView's frame rect.
2101 view->setFrameRect(m_frame.view()->frameRect());
2102 m_frame.setView(view);
2104 m_frame.setDocument(document);
2105 document->domWindow()->resumeFromPageCache();
2107 updateFirstPartyForCookies();
2109 cachedFrame.restore();
2112 bool FrameLoader::isHostedByObjectElement() const
2114 HTMLFrameOwnerElement* owner = m_frame.ownerElement();
2115 return owner && owner->hasTagName(objectTag);
2118 bool FrameLoader::isReplacing() const
2120 return m_loadType == FrameLoadType::Replace;
2123 void FrameLoader::setReplacing()
2125 m_loadType = FrameLoadType::Replace;
2128 bool FrameLoader::subframeIsLoading() const
2130 // It's most likely that the last added frame is the last to load so we walk backwards.
2131 for (Frame* child = m_frame.tree().lastChild(); child; child = child->tree().previousSibling()) {
2132 FrameLoader& childLoader = child->loader();
2133 DocumentLoader* documentLoader = childLoader.documentLoader();
2134 if (documentLoader && documentLoader->isLoadingInAPISense())
2136 documentLoader = childLoader.provisionalDocumentLoader();
2137 if (documentLoader && documentLoader->isLoadingInAPISense())
2139 documentLoader = childLoader.policyDocumentLoader();
2146 void FrameLoader::willChangeTitle(DocumentLoader* loader)
2148 m_client.willChangeTitle(loader);
2151 FrameLoadType FrameLoader::loadType() const
2156 CachePolicy FrameLoader::subresourceCachePolicy() const
2159 return CachePolicyVerify;
2161 if (m_loadType == FrameLoadType::ReloadFromOrigin)
2162 return CachePolicyReload;
2164 if (Frame* parentFrame = m_frame.tree().parent()) {
2165 CachePolicy parentCachePolicy = parentFrame->loader().subresourceCachePolicy();
2166 if (parentCachePolicy != CachePolicyVerify)
2167 return parentCachePolicy;
2170 if (m_loadType == FrameLoadType::Reload)
2171 return CachePolicyRevalidate;
2173 const ResourceRequest& request(documentLoader()->request());
2175 if (request.cachePolicy() == ReloadIgnoringCacheData && !equalIgnoringCase(request.httpMethod(), "post") && ResourceRequest::useQuickLookResourceCachingQuirks())
2176 return CachePolicyRevalidate;
2179 if (request.cachePolicy() == ReturnCacheDataElseLoad)
2180 return CachePolicyHistoryBuffer;
2182 return CachePolicyVerify;
2185 void FrameLoader::checkLoadCompleteForThisFrame()
2187 ASSERT(m_client.hasWebView());
2190 case FrameStateProvisional: {
2191 if (m_delegateIsHandlingProvisionalLoadError)
2194 RefPtr<DocumentLoader> pdl = m_provisionalDocumentLoader;
2198 // If we've received any errors we may be stuck in the provisional state and actually complete.
2199 const ResourceError& error = pdl->mainDocumentError();
2203 // Check all children first.
2204 RefPtr<HistoryItem> item;
2205 if (Page* page = m_frame.page())
2206 if (isBackForwardLoadType(loadType()))
2207 // Reset the back forward list to the last committed history item at the top level.
2208 item = page->mainFrame().loader().history().currentItem();
2210 // Only reset if we aren't already going to a new provisional item.
2211 bool shouldReset = !history().provisionalItem();
2212 if (!pdl->isLoadingInAPISense() || pdl->isStopping()) {
2213 m_delegateIsHandlingProvisionalLoadError = true;
2214 m_client.dispatchDidFailProvisionalLoad(error);
2215 m_delegateIsHandlingProvisionalLoadError = false;
2217 ASSERT(!pdl->isLoading());
2219 // If we're in the middle of loading multipart data, we need to restore the document loader.
2220 if (isReplacing() && !m_documentLoader.get())
2221 setDocumentLoader(m_provisionalDocumentLoader.get());
2223 // Finish resetting the load state, but only if another load hasn't been started by the
2224 // delegate callback.
2225 if (pdl == m_provisionalDocumentLoader)
2226 clearProvisionalLoad();
2227 else if (activeDocumentLoader()) {
2228 URL unreachableURL = activeDocumentLoader()->unreachableURL();
2229 if (!unreachableURL.isEmpty() && unreachableURL == pdl->request().url())
2230 shouldReset = false;
2233 if (shouldReset && item)
2234 if (Page* page = m_frame.page()) {
2235 page->backForward().setCurrentItem(item.get());
2236 m_frame.loader().client().updateGlobalHistoryItemForPage();
2241 case FrameStateCommittedPage: {
2242 DocumentLoader* dl = m_documentLoader.get();
2243 if (!dl || (dl->isLoadingInAPISense() && !dl->isStopping()))
2246 setState(FrameStateComplete);
2248 // FIXME: Is this subsequent work important if we already navigated away?
2249 // Maybe there are bugs because of that, or extra work we can skip because
2250 // the new page is ready.
2252 m_client.forceLayoutForNonHTML();
2254 // If the user had a scroll point, scroll to it, overriding the anchor point if any.
2255 if (m_frame.page()) {
2256 if (isBackForwardLoadType(m_loadType) || m_loadType == FrameLoadType::Reload || m_loadType == FrameLoadType::ReloadFromOrigin)
2257 history().restoreScrollPositionAndViewState();
2260 if (m_stateMachine.creatingInitialEmptyDocument() || !m_stateMachine.committedFirstRealDocumentLoad())
2263 m_progressTracker->progressCompleted();
2264 if (Page* page = m_frame.page()) {
2265 if (m_frame.isMainFrame())
2266 page->resetRelevantPaintedObjectCounter();
2269 const ResourceError& error = dl->mainDocumentError();
2271 AXObjectCache::AXLoadingEvent loadingEvent;
2272 if (!error.isNull()) {
2273 m_client.dispatchDidFailLoad(error);
2274 loadingEvent = AXObjectCache::AXLoadingFailed;
2276 m_client.dispatchDidFinishLoad();
2277 loadingEvent = AXObjectCache::AXLoadingFinished;
2280 // Notify accessibility.
2281 if (AXObjectCache* cache = m_frame.document()->existingAXObjectCache())
2282 cache->frameLoadingEventNotification(&m_frame, loadingEvent);
2287 case FrameStateComplete:
2288 m_loadType = FrameLoadType::Standard;
2289 frameLoadCompleted();
2293 ASSERT_NOT_REACHED();
2296 void FrameLoader::continueLoadAfterWillSubmitForm()
2298 if (!m_provisionalDocumentLoader)
2301 prepareForLoadStart();
2303 // The load might be cancelled inside of prepareForLoadStart(), nulling out the m_provisionalDocumentLoader,
2304 // so we need to null check it again.
2305 if (!m_provisionalDocumentLoader)
2308 DocumentLoader* activeDocLoader = activeDocumentLoader();
2309 if (activeDocLoader && activeDocLoader->isLoadingMainResource())
2312 m_loadingFromCachedPage = false;
2313 m_provisionalDocumentLoader->startLoadingMainResource();
2316 static URL originatingURLFromBackForwardList(Page* page)
2318 // FIXME: Can this logic be replaced with m_frame.document()->firstPartyForCookies()?
2319 // It has the same meaning of "page a user thinks is the current one".
2322 int backCount = page->backForward().backCount();
2323 for (int backIndex = 0; backIndex <= backCount; backIndex++) {
2324 // FIXME: At one point we had code here to check a "was user gesture" flag.
2325 // Do we need to restore that logic?
2326 HistoryItem* historyItem = page->backForward().itemAtIndex(-backIndex);
2330 originalURL = historyItem->originalURL();
2331 if (!originalURL.isNull())
2338 void FrameLoader::setOriginalURLForDownloadRequest(ResourceRequest& request)
2342 // If there is no referrer, assume that the download was initiated directly, so current document is
2343 // completely unrelated to it. See <rdar://problem/5294691>.
2344 // FIXME: Referrer is not sent in many other cases, so we will often miss this important information.
2345 // Find a better way to decide whether the download was unrelated to current document.
2346 if (!request.httpReferrer().isNull()) {
2347 // find the first item in the history that was originated by the user
2348 originalURL = originatingURLFromBackForwardList(m_frame.page());
2351 if (originalURL.isNull())
2352 originalURL = request.url();
2354 if (!originalURL.protocol().isEmpty() && !originalURL.host().isEmpty()) {
2355 unsigned port = originalURL.port();
2357 // 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.
2358 // 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.
2359 String hostOnlyURLString;
2361 hostOnlyURLString = makeString(originalURL.protocol(), "://", originalURL.host(), ':', String::number(port));
2363 hostOnlyURLString = makeString(originalURL.protocol(), "://", originalURL.host());
2365 // FIXME: Rename firstPartyForCookies back to mainDocumentURL. It was a mistake to think that it was only used for cookies.
2366 request.setFirstPartyForCookies(URL(URL(), hostOnlyURLString));
2370 void FrameLoader::didLayout(LayoutMilestones milestones)
2372 ASSERT(m_frame.isMainFrame());
2374 m_client.dispatchDidLayout(milestones);
2377 void FrameLoader::didFirstLayout()
2380 // Only send layout-related delegate callbacks synchronously for the main frame to
2381 // avoid reentering layout for the main frame while delivering a layout-related delegate
2382 // callback for a subframe.
2383 if (&m_frame != &m_frame.page()->mainFrame())
2386 if (m_frame.page() && isBackForwardLoadType(m_loadType))
2387 history().restoreScrollPositionAndViewState();
2389 if (m_stateMachine.committedFirstRealDocumentLoad() && !m_stateMachine.isDisplayingInitialEmptyDocument() && !m_stateMachine.firstLayoutDone())
2390 m_stateMachine.advanceTo(FrameLoaderStateMachine::FirstLayoutDone);
2393 void FrameLoader::frameLoadCompleted()
2395 // Note: Can be called multiple times.
2397 m_client.frameLoadCompleted();
2399 history().updateForFrameLoadCompleted();
2401 // After a canceled provisional load, firstLayoutDone is false.
2402 // Reset it to true if we're displaying a page.
2403 if (m_documentLoader && m_stateMachine.committedFirstRealDocumentLoad() && !m_stateMachine.isDisplayingInitialEmptyDocument() && !m_stateMachine.firstLayoutDone())
2404 m_stateMachine.advanceTo(FrameLoaderStateMachine::FirstLayoutDone);
2407 void FrameLoader::detachChildren()
2409 Vector<Ref<Frame>, 16> childrenToDetach;
2410 childrenToDetach.reserveInitialCapacity(m_frame.tree().childCount());
2411 for (Frame* child = m_frame.tree().lastChild(); child; child = child->tree().previousSibling())
2412 childrenToDetach.uncheckedAppend(*child);
2413 for (unsigned i = 0; i < childrenToDetach.size(); ++i)
2414 childrenToDetach[i]->loader().detachFromParent();
2417 void FrameLoader::closeAndRemoveChild(Frame* child)
2419 child->tree().detachFromParent();
2422 if (child->ownerElement() && child->page())
2423 child->page()->decrementSubframeCount();
2424 child->willDetachPage();
2425 child->detachFromPage();
2427 m_frame.tree().removeChild(child);
2430 // Called every time a resource is completely loaded or an error is received.
2431 void FrameLoader::checkLoadComplete()
2433 ASSERT(m_client.hasWebView());
2435 m_shouldCallCheckLoadComplete = false;
2437 if (!m_frame.page())
2440 // FIXME: Always traversing the entire frame tree is a bit inefficient, but
2441 // is currently needed in order to null out the previous history item for all frames.
2442 Vector<Ref<Frame>, 16> frames;
2443 for (Frame* frame = &m_frame.mainFrame(); frame; frame = frame->tree().traverseNext())
2444 frames.append(*frame);
2446 // To process children before their parents, iterate the vector backwards.
2447 for (unsigned i = frames.size(); i; --i)
2448 frames[i - 1]->loader().checkLoadCompleteForThisFrame();
2451 int FrameLoader::numPendingOrLoadingRequests(bool recurse) const
2454 return m_frame.document()->cachedResourceLoader()->requestCount();
2457 for (Frame* frame = &m_frame; frame; frame = frame->tree().traverseNext(&m_frame))
2458 count += frame->document()->cachedResourceLoader()->requestCount();
2462 String FrameLoader::userAgent(const URL& url) const
2464 return m_client.userAgent(url);
2467 void FrameLoader::handledOnloadEvents()
2469 m_client.dispatchDidHandleOnloadEvents();
2471 if (documentLoader())
2472 documentLoader()->handledOnloadEvents();
2475 void FrameLoader::frameDetached()
2478 m_frame.document()->stopActiveDOMObjects();
2482 void FrameLoader::detachFromParent()
2484 Ref<Frame> protect(m_frame);
2487 history().saveScrollPositionAndViewStateToItem(history().currentItem());
2489 // stopAllLoaders() needs to be called after detachChildren(), because detachedChildren()
2490 // will trigger the unload event handlers of any child frames, and those event
2491 // handlers might start a new subresource load in this frame.
2494 InspectorInstrumentation::frameDetachedFromParent(&m_frame);
2496 detachViewsAndDocumentLoader();
2498 m_progressTracker = nullptr;
2500 if (Frame* parent = m_frame.tree().parent()) {
2501 parent->loader().closeAndRemoveChild(&m_frame);
2502 parent->loader().scheduleCheckCompleted();
2505 m_frame.willDetachPage();
2506 m_frame.detachFromPage();
2510 void FrameLoader::detachViewsAndDocumentLoader()
2512 m_client.detachedFromParent2();
2513 setDocumentLoader(0);
2514 m_client.detachedFromParent3();
2517 void FrameLoader::addExtraFieldsToSubresourceRequest(ResourceRequest& request)
2519 addExtraFieldsToRequest(request, m_loadType, false);
2522 void FrameLoader::addExtraFieldsToMainResourceRequest(ResourceRequest& request)
2524 // FIXME: Using m_loadType seems wrong for some callers.
2525 // If we are only preparing to load the main resource, that is previous load's load type!
2526 addExtraFieldsToRequest(request, m_loadType, true);
2529 void FrameLoader::addExtraFieldsToRequest(ResourceRequest& request, FrameLoadType loadType, bool mainResource)
2531 // Don't set the cookie policy URL if it's already been set.
2532 // But make sure to set it on all requests regardless of protocol, as it has significance beyond the cookie policy (<rdar://problem/6616664>).
2533 if (request.firstPartyForCookies().isEmpty()) {
2534 if (mainResource && m_frame.isMainFrame())
2535 request.setFirstPartyForCookies(request.url());
2536 else if (Document* document = m_frame.document())
2537 request.setFirstPartyForCookies(document->firstPartyForCookies());
2540 // The remaining modifications are only necessary for HTTP and HTTPS.
2541 if (!request.url().isEmpty() && !request.url().protocolIsInHTTPFamily())
2544 applyUserAgent(request);
2546 if (!mainResource) {
2547 if (request.isConditional())
2548 request.setCachePolicy(ReloadIgnoringCacheData);
2549 else if (documentLoader()->isLoadingInAPISense()) {
2550 // If we inherit cache policy from a main resource, we use the DocumentLoader's
2551 // original request cache policy for two reasons:
2552 // 1. For POST requests, we mutate the cache policy for the main resource,
2553 // but we do not want this to apply to subresources
2554 // 2. Delegates that modify the cache policy using willSendRequest: should
2555 // not affect any other resources. Such changes need to be done
2557 ResourceRequestCachePolicy mainDocumentOriginalCachePolicy = documentLoader()->originalRequest().cachePolicy();
2558 // 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.
2559 // This policy is set on initial request too, but should not be inherited.
2560 ResourceRequestCachePolicy subresourceCachePolicy = (mainDocumentOriginalCachePolicy == ReturnCacheDataDontLoad) ? ReturnCacheDataElseLoad : mainDocumentOriginalCachePolicy;
2561 request.setCachePolicy(subresourceCachePolicy);
2563 request.setCachePolicy(UseProtocolCachePolicy);
2565 // FIXME: Other FrameLoader functions have duplicated code for setting cache policy of main request when reloading.
2566 // It seems better to manage it explicitly than to hide the logic inside addExtraFieldsToRequest().
2567 } else if (loadType == FrameLoadType::Reload || loadType == FrameLoadType::ReloadFromOrigin || request.isConditional())
2568 request.setCachePolicy(ReloadIgnoringCacheData);
2570 if (request.cachePolicy() == ReloadIgnoringCacheData) {
2571 if (loadType == FrameLoadType::Reload)
2572 request.setHTTPHeaderField(HTTPHeaderName::CacheControl, "max-age=0");
2573 else if (loadType == FrameLoadType::ReloadFromOrigin) {
2574 request.setHTTPHeaderField(HTTPHeaderName::CacheControl, "no-cache");
2575 request.setHTTPHeaderField(HTTPHeaderName::Pragma, "no-cache");
2580 request.setHTTPAccept(defaultAcceptHeader);
2582 // Make sure we send the Origin header.
2583 addHTTPOriginIfNeeded(request, String());
2585 // Only set fallback array if it's still empty (later attempts may be incorrect, see bug 117818).
2586 if (request.responseContentDispositionEncodingFallbackArray().isEmpty()) {
2587 // Always try UTF-8. If that fails, try frame encoding (if any) and then the default.
2588 request.setResponseContentDispositionEncodingFallbackArray("UTF-8", m_frame.document()->encoding(), m_frame.settings().defaultTextEncodingName());
2592 void FrameLoader::addHTTPOriginIfNeeded(ResourceRequest& request, const String& origin)
2594 if (!request.httpOrigin().isEmpty())
2595 return; // Request already has an Origin header.
2597 // Don't send an Origin header for GET or HEAD to avoid privacy issues.
2598 // For example, if an intranet page has a hyperlink to an external web
2599 // site, we don't want to include the Origin of the request because it
2600 // will leak the internal host name. Similar privacy concerns have lead
2601 // to the widespread suppression of the Referer header at the network
2603 if (request.httpMethod() == "GET" || request.httpMethod() == "HEAD")
2606 // For non-GET and non-HEAD methods, always send an Origin header so the
2607 // server knows we support this feature.
2609 if (origin.isEmpty()) {
2610 // If we don't know what origin header to attach, we attach the value
2611 // for an empty origin.
2612 request.setHTTPOrigin(SecurityOrigin::createUnique()->toString());
2616 request.setHTTPOrigin(origin);
2619 void FrameLoader::loadPostRequest(const ResourceRequest& inRequest, const String& referrer, const String& frameName, LockHistory lockHistory, FrameLoadType loadType, PassRefPtr<Event> event, PassRefPtr<FormState> prpFormState, AllowNavigationToInvalidURL allowNavigationToInvalidURL)
2621 RefPtr<FormState> formState = prpFormState;
2623 // Previously when this method was reached, the original FrameLoadRequest had been deconstructed to build a
2624 // bunch of parameters that would come in here and then be built back up to a ResourceRequest. In case
2625 // any caller depends on the immutability of the original ResourceRequest, I'm rebuilding a ResourceRequest
2626 // from scratch as it did all along.
2627 const URL& url = inRequest.url();
2628 RefPtr<FormData> formData = inRequest.httpBody();
2629 const String& contentType = inRequest.httpContentType();
2630 String origin = inRequest.httpOrigin();
2632 ResourceRequest workingResourceRequest(url);
2634 if (!referrer.isEmpty())
2635 workingResourceRequest.setHTTPReferrer(referrer);
2636 workingResourceRequest.setHTTPOrigin(origin);
2637 workingResourceRequest.setHTTPMethod("POST");
2638 workingResourceRequest.setHTTPBody(formData);
2639 workingResourceRequest.setHTTPContentType(contentType);
2640 addExtraFieldsToRequest(workingResourceRequest, loadType, true);
2642 NavigationAction action(workingResourceRequest, loadType, true, event);
2644 if (!frameName.isEmpty()) {
2645 // The search for a target frame is done earlier in the case of form submission.
2646 if (Frame* targetFrame = formState ? 0 : findFrameForNavigation(frameName)) {
2647 targetFrame->loader().loadWithNavigationAction(workingResourceRequest, action, lockHistory, loadType, formState.release(), allowNavigationToInvalidURL);
2651 policyChecker().checkNewWindowPolicy(action, workingResourceRequest, formState.release(), frameName, [this, allowNavigationToInvalidURL](const ResourceRequest& request, PassRefPtr<FormState> formState, const String& frameName, const NavigationAction& action, bool shouldContinue) {
2652 continueLoadAfterNewWindowPolicy(request, formState, frameName, action, shouldContinue, allowNavigationToInvalidURL);
2657 // must grab this now, since this load may stop the previous load and clear this flag
2658 bool isRedirect = m_quickRedirectComing;
2659 loadWithNavigationAction(workingResourceRequest, action, lockHistory, loadType, formState.release(), allowNavigationToInvalidURL);
2661 m_quickRedirectComing = false;
2662 if (m_provisionalDocumentLoader)
2663 m_provisionalDocumentLoader->setIsClientRedirect(true);
2667 unsigned long FrameLoader::loadResourceSynchronously(const ResourceRequest& request, StoredCredentials storedCredentials, ClientCredentialPolicy clientCredentialPolicy, ResourceError& error, ResourceResponse& response, Vector<char>& data)
2669 ASSERT(m_frame.document());
2670 String referrer = SecurityPolicy::generateReferrerHeader(m_frame.document()->referrerPolicy(), request.url(), outgoingReferrer());
2672 ResourceRequest initialRequest = request;
2673 initialRequest.setTimeoutInterval(10);
2675 if (!referrer.isEmpty())
2676 initialRequest.setHTTPReferrer(referrer);
2677 addHTTPOriginIfNeeded(initialRequest, outgoingOrigin());
2679 initialRequest.setFirstPartyForCookies(m_frame.mainFrame().loader().documentLoader()->request().url());
2681 addExtraFieldsToSubresourceRequest(initialRequest);
2683 unsigned long identifier = 0;
2684 ResourceRequest newRequest(initialRequest);
2685 requestFromDelegate(newRequest, identifier, error);
2687 if (error.isNull()) {
2688 ASSERT(!newRequest.isNull());
2690 if (!documentLoader()->applicationCacheHost()->maybeLoadSynchronously(newRequest, error, response, data)) {
2691 platformStrategies()->loaderStrategy()->loadResourceSynchronously(networkingContext(), identifier, newRequest, storedCredentials, clientCredentialPolicy, error, response, data);
2692 documentLoader()->applicationCacheHost()->maybeLoadFallbackSynchronously(newRequest, error, response, data);
2695 notifier().sendRemainingDelegateMessages(m_documentLoader.get(), identifier, request, response, data.data(), data.size(), -1, error);
2699 const ResourceRequest& FrameLoader::originalRequest() const
2701 return activeDocumentLoader()->originalRequestCopy();
2704 void FrameLoader::receivedMainResourceError(const ResourceError& error)
2706 // Retain because the stop may release the last reference to it.
2707 Ref<Frame> protect(m_frame);
2709 RefPtr<DocumentLoader> loader = activeDocumentLoader();
2710 // FIXME: Don't want to do this if an entirely new load is going, so should check
2711 // that both data sources on the frame are either this or nil.
2713 if (m_client.shouldFallBack(error))
2714 handleFallbackContent();
2716 if (m_state == FrameStateProvisional && m_provisionalDocumentLoader) {
2717 if (m_submittedFormURL == m_provisionalDocumentLoader->originalRequestCopy().url())
2718 m_submittedFormURL = URL();
2720 // We might have made a page cache item, but now we're bailing out due to an error before we ever
2721 // transitioned to the new page (before WebFrameState == commit). The goal here is to restore any state
2722 // so that the existing view (that wenever got far enough to replace) can continue being used.
2723 history().invalidateCurrentItemCachedPage();
2725 // Call clientRedirectCancelledOrFinished here so that the frame load delegate is notified that the redirect's
2726 // status has changed, if there was a redirect. The frame load delegate may have saved some state about
2727 // the redirect in its -webView:willPerformClientRedirectToURL:delay:fireDate:forFrame:. Since we are definitely
2728 // not going to use this provisional resource, as it was cancelled, notify the frame load delegate that the redirect
2730 if (m_sentRedirectNotification)
2731 clientRedirectCancelledOrFinished(false);
2736 checkLoadComplete();
2739 void FrameLoader::continueFragmentScrollAfterNavigationPolicy(const ResourceRequest& request, bool shouldContinue)
2741 m_quickRedirectComing = false;
2743 if (!shouldContinue)
2746 // If we have a provisional request for a different document, a fragment scroll should cancel it.
2747 if (m_provisionalDocumentLoader && !equalIgnoringFragmentIdentifier(m_provisionalDocumentLoader->request().url(), request.url())) {
2748 m_provisionalDocumentLoader->stopLoading();
2749 setProvisionalDocumentLoader(0);
2752 bool isRedirect = m_quickRedirectComing || policyChecker().loadType() == FrameLoadType::RedirectWithLockedBackForwardList;
2753 loadInSameDocument(request.url(), 0, !isRedirect);
2756 bool FrameLoader::shouldPerformFragmentNavigation(bool isFormSubmission, const String& httpMethod, FrameLoadType loadType, const URL& url)
2758 // We don't do this if we are submitting a form with method other than "GET", explicitly reloading,
2759 // currently displaying a frameset, or if the URL does not have a fragment.
2760 // These rules were originally based on what KHTML was doing in KHTMLPart::openURL.
2762 // FIXME: What about load types other than Standard and Reload?
2764 return (!isFormSubmission || equalIgnoringCase(httpMethod, "GET"))
2765 && loadType != FrameLoadType::Reload
2766 && loadType != FrameLoadType::ReloadFromOrigin
2767 && loadType != FrameLoadType::Same
2768 && !shouldReload(m_frame.document()->url(), url)
2769 // We don't want to just scroll if a link from within a
2770 // frameset is trying to reload the frameset into _top.
2771 && !m_frame.document()->isFrameSet();
2774 void FrameLoader::scrollToFragmentWithParentBoundary(const URL& url)
2776 FrameView* view = m_frame.view();
2780 // Leaking scroll position to a cross-origin ancestor would permit the so-called "framesniffing" attack.
2781 RefPtr<Frame> boundaryFrame(url.hasFragmentIdentifier() ? m_frame.document()->findUnsafeParentScrollPropagationBoundary() : 0);
2784 boundaryFrame->view()->setSafeToPropagateScrollToParent(false);
2786 view->scrollToFragment(url);
2789 boundaryFrame->view()->setSafeToPropagateScrollToParent(true);
2792 bool FrameLoader::shouldClose()
2794 Page* page = m_frame.page();
2797 if (!page->chrome().canRunBeforeUnloadConfirmPanel())
2800 // Store all references to each subframe in advance since beforeunload's event handler may modify frame
2801 Vector<Ref<Frame>, 16> targetFrames;
2802 targetFrames.append(m_frame);
2803 for (Frame* child = m_frame.tree().firstChild(); child; child = child->tree().traverseNext(&m_frame))
2804 targetFrames.append(*child);
2806 bool shouldClose = false;
2808 NavigationDisablerForBeforeUnload navigationDisabler;
2811 for (i = 0; i < targetFrames.size(); i++) {
2812 if (!targetFrames[i]->tree().isDescendantOf(&m_frame))
2814 if (!targetFrames[i]->loader().handleBeforeUnloadEvent(page->chrome(), this))
2818 if (i == targetFrames.size())
2823 m_submittedFormURL = URL();
2825 m_currentNavigationHasShownBeforeUnloadConfirmPanel = false;
2829 bool FrameLoader::handleBeforeUnloadEvent(Chrome& chrome, FrameLoader* frameLoaderBeingNavigated)
2831 DOMWindow* domWindow = m_frame.document()->domWindow();
2835 RefPtr<Document> document = m_frame.document();
2836 if (!document->body())
2839 RefPtr<BeforeUnloadEvent> beforeUnloadEvent = BeforeUnloadEvent::create();
2840 m_pageDismissalEventBeingDispatched = BeforeUnloadDismissal;
2842 // We store the frame's page in a local variable because the frame might get detached inside dispatchEvent.
2843 Page* page = m_frame.page();
2844 page->incrementFrameHandlingBeforeUnloadEventCount();
2845 domWindow->dispatchEvent(beforeUnloadEvent.get(), domWindow->document());
2846 page->decrementFrameHandlingBeforeUnloadEventCount();
2848 m_pageDismissalEventBeingDispatched = NoDismissal;
2850 if (!beforeUnloadEvent->defaultPrevented())
2851 document->defaultEventHandler(beforeUnloadEvent.get());
2852 if (beforeUnloadEvent->returnValue().isNull())
2855 // If the navigating FrameLoader has already shown a beforeunload confirmation panel for the current navigation attempt,
2856 // this frame is not allowed to cause another one to be shown.
2857 if (frameLoaderBeingNavigated->m_currentNavigationHasShownBeforeUnloadConfirmPanel) {
2858 document->addConsoleMessage(MessageSource::JS, MessageLevel::Error, ASCIILiteral("Blocked attempt to show multiple beforeunload confirmation dialogs for the same navigation."));
2862 // We should only display the beforeunload dialog for an iframe if its SecurityOrigin matches all
2863 // ancestor frame SecurityOrigins up through the navigating FrameLoader.
2864 if (frameLoaderBeingNavigated != this) {
2865 Frame* parentFrame = m_frame.tree().parent();
2866 while (parentFrame) {
2867 Document* parentDocument = parentFrame->document();
2868 if (!parentDocument)
2870 if (!m_frame.document() || !m_frame.document()->securityOrigin()->canAccess(parentDocument->securityOrigin())) {
2871 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."));
2875 if (&parentFrame->loader() == frameLoaderBeingNavigated)
2878 parentFrame = parentFrame->tree().parent();
2881 // The navigatingFrameLoader should always be in our ancestory.
2882 ASSERT(parentFrame);
2883 ASSERT(&parentFrame->loader() == frameLoaderBeingNavigated);
2886 frameLoaderBeingNavigated->m_currentNavigationHasShownBeforeUnloadConfirmPanel = true;
2888 String text = document->displayStringModifiedByEncoding(beforeUnloadEvent->returnValue());
2889 return chrome.runBeforeUnloadConfirmPanel(text, &m_frame);
2892 void FrameLoader::continueLoadAfterNavigationPolicy(const ResourceRequest& request, PassRefPtr<FormState> formState, bool shouldContinue, AllowNavigationToInvalidURL allowNavigationToInvalidURL)
2894 // If we loaded an alternate page to replace an unreachableURL, we'll get in here with a
2895 // nil policyDataSource because loading the alternate page will have passed
2896 // through this method already, nested; otherwise, policyDataSource should still be set.
2897 ASSERT(m_policyDocumentLoader || !m_provisionalDocumentLoader->unreachableURL().isEmpty());
2899 bool isTargetItem = history().provisionalItem() ? history().provisionalItem()->isTargetItem() : false;
2901 bool urlIsDisallowed = allowNavigationToInvalidURL == AllowNavigationToInvalidURL::No && !request.url().isValid();
2903 // Three reasons we can't continue:
2904 // 1) Navigation policy delegate said we can't so request is nil. A primary case of this
2905 // is the user responding Cancel to the form repost nag sheet.
2906 // 2) User responded Cancel to an alert popped up by the before unload event handler.
2907 // 3) The request's URL is invalid and navigation to invalid URLs is disallowed.
2908 bool canContinue = shouldContinue && shouldClose() && !urlIsDisallowed;
2911 // If we were waiting for a quick redirect, but the policy delegate decided to ignore it, then we
2912 // need to report that the client redirect was cancelled.
2913 // FIXME: The client should be told about ignored non-quick redirects, too.
2914 if (m_quickRedirectComing)
2915 clientRedirectCancelledOrFinished(false);
2917 setPolicyDocumentLoader(0);
2919 // If the navigation request came from the back/forward menu, and we punt on it, we have the
2920 // problem that we have optimistically moved the b/f cursor already, so move it back. For sanity,
2921 // we only do this when punting a navigation for the target frame or top-level frame.
2922 if ((isTargetItem || m_frame.isMainFrame()) && isBackForwardLoadType(policyChecker().loadType())) {
2923 if (Page* page = m_frame.page()) {
2924 if (HistoryItem* resetItem = m_frame.mainFrame().loader().history().currentItem()) {
2925 page->backForward().setCurrentItem(resetItem);
2926 m_frame.loader().client().updateGlobalHistoryItemForPage();
2933 FrameLoadType type = policyChecker().loadType();
2934 // A new navigation is in progress, so don't clear the history's provisional item.
2935 stopAllLoaders(ShouldNotClearProvisionalItem);
2937 // <rdar://problem/6250856> - In certain circumstances on pages with multiple frames, stopAllLoaders()
2938 // might detach the current FrameLoader, in which case we should bail on this newly defunct load.
2939 if (!m_frame.page())
2942 #if ENABLE(INSPECTOR)
2943 if (Page* page = m_frame.page()) {
2944 if (m_frame.isMainFrame())
2945 page->inspectorController().resume();
2949 setProvisionalDocumentLoader(m_policyDocumentLoader.get());
2951 setState(FrameStateProvisional);
2953 setPolicyDocumentLoader(0);
2955 if (isBackForwardLoadType(type) && history().provisionalItem()->isInPageCache()) {
2956 loadProvisionalItemFromCachedPage();
2961 continueLoadAfterWillSubmitForm();
2965 m_client.dispatchWillSubmitForm(formState, [this](PolicyAction action) {
2966 policyChecker().continueLoadAfterWillSubmitForm(action);
2970 void FrameLoader::continueLoadAfterNewWindowPolicy(const ResourceRequest& request,
2971 PassRefPtr<FormState> formState, const String& frameName, const NavigationAction& action, bool shouldContinue, AllowNavigationToInvalidURL allowNavigationToInvalidURL)
2973 if (!shouldContinue)
2976 Ref<Frame> frame(m_frame);
2977 RefPtr<Frame> mainFrame = m_client.dispatchCreatePage(action);
2981 if (frameName != "_blank")
2982 mainFrame->tree().setName(frameName);
2984 mainFrame->page()->setOpenedByDOM();
2985 mainFrame->loader().m_client.dispatchShow();
2986 if (!m_suppressOpenerInNewFrame) {
2987 mainFrame->loader().setOpener(&frame.get());
2988 mainFrame->document()->setReferrerPolicy(frame->document()->referrerPolicy());
2990 mainFrame->loader().loadWithNavigationAction(request, NavigationAction(request), LockHistory::No, FrameLoadType::Standard, formState, allowNavigationToInvalidURL);
2993 void FrameLoader::requestFromDelegate(ResourceRequest& request, unsigned long& identifier, ResourceError& error)
2995 ASSERT(!request.isNull());
2998 if (Page* page = m_frame.page()) {
2999 identifier = page->progress().createUniqueIdentifier();
3000 notifier().assignIdentifierToInitialRequest(identifier, m_documentLoader.get(), request);
3003 ResourceRequest newRequest(request);
3004 notifier().dispatchWillSendRequest(m_documentLoader.get(), identifier, newRequest, ResourceResponse());
3006 if (newRequest.isNull())
3007 error = cancelledError(request);
3009 error = ResourceError();
3011 request = newRequest;
3014 void FrameLoader::loadedResourceFromMemoryCache(CachedResource* resource, ResourceRequest& newRequest)
3016 Page* page = m_frame.page();
3020 if (!resource->shouldSendResourceLoadCallbacks() || m_documentLoader->haveToldClientAboutLoad(resource->url()))
3023 // Main resource delegate messages are synthesized in MainResourceLoader, so we must not send them here.
3024 if (resource->type() == CachedResource::MainResource)
3027 if (!page->areMemoryCacheClientCallsEnabled()) {
3028 InspectorInstrumentation::didLoadResourceFromMemoryCache(page, m_documentLoader.get(), resource);
3029 m_documentLoader->recordMemoryCacheLoadForFutureClientNotification(resource->resourceRequest());
3030 m_documentLoader->didTellClientAboutLoad(resource->url());
3034 if (m_client.dispatchDidLoadResourceFromMemoryCache(m_documentLoader.get(), newRequest, resource->response(), resource->encodedSize())) {
3035 InspectorInstrumentation::didLoadResourceFromMemoryCache(page, m_documentLoader.get(), resource);
3036 m_documentLoader->didTellClientAboutLoad(resource->url());
3040 unsigned long identifier;
3041 ResourceError error;
3042 requestFromDelegate(newRequest, identifier, error);
3043 InspectorInstrumentation::markResourceAsCached(page, identifier);
3044 notifier().sendRemainingDelegateMessages(m_documentLoader.get(), identifier, newRequest, resource->response(), 0, resource->encodedSize(), 0, error);
3047 void FrameLoader::applyUserAgent(ResourceRequest& request)
3049 String userAgent = this->userAgent(request.url());
3050 ASSERT(!userAgent.isNull());
3051 request.setHTTPUserAgent(userAgent);
3054 bool FrameLoader::shouldInterruptLoadForXFrameOptions(const String& content, const URL& url, unsigned long requestIdentifier)
3056 Frame& topFrame = m_frame.tree().top();
3057 if (&m_frame == &topFrame)
3060 XFrameOptionsDisposition disposition = parseXFrameOptionsHeader(content);
3062 switch (disposition) {
3063 case XFrameOptionsSameOrigin: {
3064 RefPtr<SecurityOrigin> origin = SecurityOrigin::create(url);
3065 if (!origin->isSameSchemeHostPort(topFrame.document()->securityOrigin()))
3067 for (Frame* frame = m_frame.tree().parent(); frame; frame = frame->tree().parent()) {
3068 if (!origin->isSameSchemeHostPort(frame->document()->securityOrigin()))
3073 case XFrameOptionsDeny:
3075 case XFrameOptionsAllowAll:
3077 case XFrameOptionsConflict:
3078 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);
3080 case XFrameOptionsInvalid:
3081 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);
3083 case XFrameOptionsNone:
3086 ASSERT_NOT_REACHED();
3090 void FrameLoader::loadProvisionalItemFromCachedPage()
3092 DocumentLoader* provisionalLoader = provisionalDocumentLoader();
3093 LOG(PageCache, "WebCorePageCache: Loading provisional DocumentLoader %p with URL '%s' from CachedPage", provisionalDocumentLoader(), provisionalDocumentLoader()->url().stringCenterEllipsizedToLength().utf8().data());
3095 prepareForLoadStart();
3097 m_loadingFromCachedPage = true;
3099 // Should have timing data from previous time(s) the page was shown.
3100 ASSERT(provisionalLoader->timing()->navigationStart());
3101 provisionalLoader->resetTiming();
3102 provisionalLoader->timing()->markNavigationStart();
3104 provisionalLoader->setCommitted(true);
3105 commitProvisionalLoad();
3108 bool FrameLoader::shouldTreatURLAsSameAsCurrent(const URL& url) const
3110 if (!history().currentItem())
3112 return url == history().currentItem()->url() || url == history().currentItem()->originalURL();
3115 bool FrameLoader::shouldTreatURLAsSrcdocDocument(const URL& url) const
3117 if (!equalIgnoringCase(url.string(), "about:srcdoc"))
3119 HTMLFrameOwnerElement* ownerElement = m_frame.ownerElement();
3122 if (!ownerElement->hasTagName(iframeTag))
3124 return ownerElement->fastHasAttribute(srcdocAttr);
3127 Frame* FrameLoader::findFrameForNavigation(const AtomicString& name, Document* activeDocument)
3129 Frame* frame = m_frame.tree().find(name);
3131 // FIXME: Eventually all callers should supply the actual activeDocument so we can call canNavigate with the right document.
3132 if (!activeDocument)
3133 activeDocument = m_frame.document();
3135 if (!activeDocument->canNavigate(frame))
3141 void FrameLoader::loadSameDocumentItem(HistoryItem* item)
3143 ASSERT(item->documentSequenceNumber() == history().currentItem()->documentSequenceNumber());
3145 // Save user view state to the current history item here since we don't do a normal load.
3146 // FIXME: Does form state need to be saved here too?
3147 history().saveScrollPositionAndViewStateToItem(history().currentItem());
3148 if (FrameView* view = m_frame.view())
3149 view->setWasScrolledByUser(false);
3151 history().setCurrentItem(item);
3153 // loadInSameDocument() actually changes the URL and notifies load delegates of a "fake" load
3154 loadInSameDocument(item->url(), item->stateObject(), false);
3156 // Restore user view state from the current history item here since we don't do a normal load.
3157 history().restoreScrollPositionAndViewState();
3160 // FIXME: This function should really be split into a couple pieces, some of
3161 // which should be methods of HistoryController and some of which should be
3162 // methods of FrameLoader.
3163 void FrameLoader::loadDifferentDocumentItem(HistoryItem* item, FrameLoadType loadType, FormSubmissionCacheLoadPolicy cacheLoadPolicy)
3165 // Remember this item so we can traverse any child items as child frames load
3166 history().setProvisionalItem(item);
3168 if (CachedPage* cachedPage = pageCache()->get(item)) {
3169 loadWithDocumentLoader(cachedPage->documentLoader(), loadType, 0, AllowNavigationToInvalidURL::Yes);
3173 URL itemURL = item->url();
3174 URL itemOriginalURL = item->originalURL();
3176 if (documentLoader())
3177 currentURL = documentLoader()->url();
3178 RefPtr<FormData> formData = item->formData();
3180 ResourceRequest request(itemURL);
3182 if (!item->referrer().isNull())
3183 request.setHTTPReferrer(item->referrer());
3185 // If this was a repost that failed the page cache, we might try to repost the form.
3186 NavigationAction action;
3188 formData->generateFiles(m_frame.document());
3190 request.setHTTPMethod("POST");
3191 request.setHTTPBody(formData);
3192 request.setHTTPContentType(item->formContentType());
3193 RefPtr<SecurityOrigin> securityOrigin = SecurityOrigin::createFromString(item->referrer());
3194 addHTTPOriginIfNeeded(request, securityOrigin->toString());
3196 // Make sure to add extra fields to the request after the Origin header is added for the FormData case.
3197 // See https://bugs.webkit.org/show_bug.cgi?id=22194 for more discussion.
3198 addExtraFieldsToRequest(request, loadType, true);
3200 // FIXME: Slight hack to test if the NSURL cache contains the page we're going to.
3201 // We want to know this before talking to the policy delegate, since it affects whether
3202 // we show the DoYouReallyWantToRepost nag.
3204 // This trick has a small bug (3123893) where we might find a cache hit, but then
3205 // have the item vanish when we try to use it in the ensuing nav. This should be
3206 // extremely rare, but in that case the user will get an error on the navigation.
3208 if (cacheLoadPolicy == MayAttemptCacheOnlyLoadForFormSubmissionItem) {
3209 request.setCachePolicy(ReturnCacheDataDontLoad);
3210 action = NavigationAction(request, loadType, false);
3212 request.setCachePolicy(ReturnCacheDataElseLoad);
3213 action = NavigationAction(request, NavigationTypeFormResubmitted);
3217 case FrameLoadType::Reload:
3218 case FrameLoadType::ReloadFromOrigin:
3219 request.setCachePolicy(ReloadIgnoringCacheData);
3221 case FrameLoadType::Back:
3222 case FrameLoadType::Forward:
3223 case FrameLoadType::IndexedBackForward:
3224 // If the first load within a frame is a navigation within a back/forward list that was attached
3225 // without any of the items being loaded then we should use the default caching policy (<rdar://problem/8131355>).
3226 if (m_stateMachine.committedFirstRealDocumentLoad())
3227 request.setCachePolicy(ReturnCacheDataElseLoad);
3229 case FrameLoadType::Standard:
3230 case FrameLoadType::RedirectWithLockedBackForwardList:
3232 case FrameLoadType::Same:
3234 ASSERT_NOT_REACHED();
3237 addExtraFieldsToRequest(request, loadType, true);
3239 ResourceRequest requestForOriginalURL(request);
3240 requestForOriginalURL.setURL(itemOriginalURL);
3241 action = NavigationAction(requestForOriginalURL, loadType, false);
3244 loadWithNavigationAction(request, action, LockHistory::No, loadType, 0, AllowNavigationToInvalidURL::Yes);
3247 // Loads content into this frame, as specified by history item
3248 void FrameLoader::loadItem(HistoryItem* item, FrameLoadType loadType)
3250 m_requestedHistoryItem = item;
3251 HistoryItem* currentItem = history().currentItem();
3252 bool sameDocumentNavigation = currentItem && item->shouldDoSameDocumentNavigationTo(currentItem);
3254 if (sameDocumentNavigation)
3255 loadSameDocumentItem(item);
3257 loadDifferentDocumentItem(item, loadType, MayAttemptCacheOnlyLoadForFormSubmissionItem);
3260 void FrameLoader::retryAfterFailedCacheOnlyMainResourceLoad()
3262 ASSERT(m_state == FrameStateProvisional);
3263 ASSERT(!m_loadingFromCachedPage);
3264 // We only use cache-only loads to avoid resubmitting forms.
3265 ASSERT(isBackForwardLoadType(m_loadType));
3266 ASSERT(history().provisionalItem()->formData());
3267 ASSERT(history().provisionalItem() == m_requestedHistoryItem.get());
3269 FrameLoadType loadType = m_loadType;
3270 HistoryItem* item = history().provisionalItem();
3272 stopAllLoaders(ShouldNotClearProvisionalItem);
3273 loadDifferentDocumentItem(item, loadType, MayNotAttemptCacheOnlyLoadForFormSubmissionItem);
3276 ResourceError FrameLoader::cancelledError(const ResourceRequest& request) const
3278 ResourceError error = m_client.cancelledError(request);
3279 error.setIsCancellation(true);
3284 RetainPtr<CFDictionaryRef> FrameLoader::connectionProperties(ResourceLoader* loader)
3286 return m_client.connectionProperties(loader->documentLoader(), loader->identifier());
3290 String FrameLoader::referrer() const
3292 return m_documentLoader ? m_documentLoader->request().httpReferrer() : "";
3295 void FrameLoader::dispatchDidClearWindowObjectsInAllWorlds()
3297 if (!m_frame.script().canExecuteScripts(NotAboutToExecuteScript))
3300 Vector<Ref<DOMWrapperWorld>> worlds;
3301 ScriptController::getAllWorlds(worlds);
3302 for (size_t i = 0; i < worlds.size(); ++i)
3303 dispatchDidClearWindowObjectInWorld(worlds[i].get());
3306 void FrameLoader::dispatchDidClearWindowObjectInWorld(DOMWrapperWorld& world)
3308 if (!m_frame.script().canExecuteScripts(NotAboutToExecuteScript) || !m_frame.script().existingWindowShell(world))
3311 m_client.dispatchDidClearWindowObjectInWorld(world);
3313 #if ENABLE(INSPECTOR)
3314 if (Page* page = m_frame.page())
3315 page->inspectorController().didClearWindowObjectInWorld(&m_frame, world);
3318 InspectorInstrumentation::didClearWindowObjectInWorld(&m_frame, world);
3321 void FrameLoader::dispatchGlobalObjectAvailableInAllWorlds()
3323 Vector<Ref<DOMWrapperWorld>> worlds;
3324 ScriptController::getAllWorlds(worlds);
3325 for (size_t i = 0; i < worlds.size(); ++i)
3326 m_client.dispatchGlobalObjectAvailable(worlds[i].get());
3329 SandboxFlags FrameLoader::effectiveSandboxFlags() const
3331 SandboxFlags flags = m_forcedSandboxFlags;
3332 if (Frame* parentFrame = m_frame.tree().parent())
3333 flags |= parentFrame->document()->sandboxFlags();
3334 if (HTMLFrameOwnerElement* ownerElement = m_frame.ownerElement())
3335 flags |= ownerElement->sandboxFlags();
3339 void FrameLoader::didChangeTitle(DocumentLoader* loader)
3341 m_client.didChangeTitle(loader);
3343 if (loader == m_documentLoader) {
3344 // Must update the entries in the back-forward list too.
3345 history().setCurrentItemTitle(loader->title());
3346 // This must go through the WebFrame because it has the right notion of the current b/f item.
3347 m_client.setTitle(loader->title(), loader->urlForHistory());
3348 m_client.setMainFrameDocumentReady(true); // update observers with new DOMDocument
3349 m_client.dispatchDidReceiveTitle(loader->title());
3352 #if ENABLE(REMOTE_INSPECTOR)
3353 if (m_frame.isMainFrame())
3354 m_frame.page()->remoteInspectorInformationDidChange();
3358 void FrameLoader::didChangeIcons(IconType type)
3360 m_client.dispatchDidChangeIcons(type);
3363 void FrameLoader::dispatchDidCommitLoad()
3365 if (m_stateMachine.creatingInitialEmptyDocument())
3368 m_client.dispatchDidCommitLoad();
3370 if (m_frame.isMainFrame()) {
3371 m_frame.page()->resetSeenPlugins();
3372 m_frame.page()->resetSeenMediaEngines();
3375 InspectorInstrumentation::didCommitLoad(&m_frame, m_documentLoader.get());
3377 #if ENABLE(REMOTE_INSPECTOR)
3378 if (m_frame.isMainFrame())
3379 m_frame.page()->remoteInspectorInformationDidChange();
3383 void FrameLoader::tellClientAboutPastMemoryCacheLoads()
3385 ASSERT(m_frame.page());
3386 ASSERT(m_frame.page()->areMemoryCacheClientCallsEnabled());
3388 if (!m_documentLoader)
3391 Vector<ResourceRequest> pastLoads;
3392 m_documentLoader->takeMemoryCacheLoadsForClientNotification(pastLoads);
3394 size_t size = pastLoads.size();
3395 for (size_t i = 0; i < size; ++i) {
3396 CachedResource* resource = memoryCache()->resourceForRequest(pastLoads[i], m_frame.page()->sessionID());
3398 // FIXME: These loads, loaded from cache, but now gone from the cache by the time
3399 // Page::setMemoryCacheClientCallsEnabled(true) is called, will not be seen by the client.
3400 // Consider if there's some efficient way of remembering enough to deliver this client call.
3401 // We have the URL, but not the rest of the response or the length.
3405 ResourceRequest request(resource->url());
3406 m_client.dispatchDidLoadResourceFromMemoryCache(m_documentLoader.get(), request, resource->response(), resource->encodedSize());
3410 NetworkingContext* FrameLoader::networkingContext() const
3412 return m_networkingContext.get();
3415 void FrameLoader::loadProgressingStatusChanged()
3417 if (auto* view = m_frame.mainFrame().view())
3418 view->loadProgressingStatusChanged();
3421 void FrameLoader::forcePageTransitionIfNeeded()
3423 m_client.forcePageTransitionIfNeeded();
3426 bool FrameLoaderClient::hasHTMLView() const
3431 PassRefPtr<Frame> createWindow(Frame* openerFrame, Frame* lookupFrame, const FrameLoadRequest& request, const WindowFeatures& features, bool& created)
3433 ASSERT(!features.dialog || request.frameName().isEmpty());
3437 if (!request.frameName().isEmpty() && request.frameName() != "_blank") {
3438 if (RefPtr<Frame> frame = lookupFrame->loader().findFrameForNavigation(request.frameName(), openerFrame->document())) {
3439 if (request.frameName() != "_self") {
3440 if (Page* page = frame->page())
3441 page->chrome().focus();
3443 return frame.release();
3447 // Sandboxed frames cannot open new auxiliary browsing contexts.
3448 if (isDocumentSandboxed(openerFrame, SandboxPopups)) {
3449 // FIXME: This message should be moved off the console once a solution to https://bugs.webkit.org/show_bug.cgi?id=103274 exists.
3450 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.");
3454 // FIXME: Setting the referrer should be the caller's responsibility.
3455 FrameLoadRequest requestWithReferrer = request;
3456 String referrer = SecurityPolicy::generateReferrerHeader(openerFrame->document()->referrerPolicy(), request.resourceRequest().url(), openerFrame->loader().outgoingReferrer());
3457 if (!referrer.isEmpty())
3458 requestWithReferrer.resourceRequest().setHTTPReferrer(referrer);
3459 FrameLoader::addHTTPOriginIfNeeded(requestWithReferrer.resourceRequest(), openerFrame->loader().outgoingOrigin());
3461 Page* oldPage = openerFrame->page();
3465 Page* page = oldPage->chrome().createWindow(openerFrame, requestWithReferrer, features, NavigationAction(requestWithReferrer.resourceRequest()));
3469 RefPtr<Frame> frame = &page->mainFrame();
3471 frame->loader().forceSandboxFlags(openerFrame->document()->sandboxFlags());
3473 if (request.frameName() != "_blank")
3474 frame->tree().setName(request.frameName());
3476 page->chrome().setToolbarsVisible(features.toolBarVisible || features.locationBarVisible);
3480 page->chrome().setStatusbarVisible(features.statusBarVisible);
3484 page->chrome().setScrollbarsVisible(features.scrollbarsVisible);
3488 page->chrome().setMenubarVisible(features.menuBarVisible);
3492 page->chrome().setResizable(features.resizable);
3494 // 'x' and 'y' specify the location of the window, while 'width' and 'height'
3495 // specify the size of the viewport. We can only resize the window, so adjust
3496 // for the difference between the window size and the viewport size.
3498 // FIXME: We should reconcile the initialization of viewport arguments between iOS and non-IOS.
3500 FloatSize viewportSize = page->chrome().pageRect().size();
3501 FloatRect windowRect = page->chrome().windowRect();
3503 windowRect.setX(features.x);
3505 windowRect.setY(features.y);
3506 // Zero width and height mean using default size, not minumum one.
3507 if (features.widthSet && features.width)
3508 windowRect.setWidth(features.width + (windowRect.width() - viewportSize.width()));
3509 if (features.heightSet && features.height)
3510 windowRect.setHeight(features.height + (windowRect.height() - viewportSize.height()));
3512 // Ensure non-NaN values, minimum size as well as being within valid screen area.
3513 FloatRect newWindowRect = DOMWindow::adjustWindowRect(page, windowRect);
3517 page->chrome().setWindowRect(newWindowRect);
3519 // On iOS, width and height refer to the viewport dimensions.
3520 ViewportArguments arguments;
3521 // Zero width and height mean using default size, not minimum one.
3522 if (features.widthSet && features.width)
3523 arguments.width = features.width;
3524 if (features.heightSet && features.height)
3525 arguments.height = features.height;
3526 frame->setViewportArguments(arguments);
3531 page->chrome().show();
3534 return frame.release();
3537 } // namespace WebCore