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 Computer, 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 "core/loader/FrameLoader.h"
38 #include "bindings/core/v8/DOMWrapperWorld.h"
39 #include "bindings/core/v8/ScriptController.h"
40 #include "bindings/core/v8/SerializedScriptValue.h"
41 #include "core/HTMLNames.h"
42 #include "core/dom/Document.h"
43 #include "core/dom/Element.h"
44 #include "core/dom/ViewportDescription.h"
45 #include "core/editing/Editor.h"
46 #include "core/editing/UndoStack.h"
47 #include "core/events/PageTransitionEvent.h"
48 #include "core/fetch/FetchContext.h"
49 #include "core/fetch/ResourceFetcher.h"
50 #include "core/fetch/ResourceLoader.h"
51 #include "core/frame/LocalDOMWindow.h"
52 #include "core/frame/FrameHost.h"
53 #include "core/frame/FrameView.h"
54 #include "core/frame/LocalFrame.h"
55 #include "core/frame/PinchViewport.h"
56 #include "core/frame/csp/ContentSecurityPolicy.h"
57 #include "core/html/HTMLFormElement.h"
58 #include "core/html/HTMLFrameOwnerElement.h"
59 #include "core/html/parser/HTMLParserIdioms.h"
60 #include "core/inspector/ConsoleMessage.h"
61 #include "core/inspector/InspectorController.h"
62 #include "core/inspector/InspectorInstrumentation.h"
63 #include "core/loader/DocumentLoadTiming.h"
64 #include "core/loader/DocumentLoader.h"
65 #include "core/loader/FormState.h"
66 #include "core/loader/FormSubmission.h"
67 #include "core/loader/FrameFetchContext.h"
68 #include "core/loader/FrameLoadRequest.h"
69 #include "core/loader/FrameLoaderClient.h"
70 #include "core/loader/ProgressTracker.h"
71 #include "core/loader/UniqueIdentifier.h"
72 #include "core/loader/appcache/ApplicationCacheHost.h"
73 #include "core/page/BackForwardClient.h"
74 #include "core/page/Chrome.h"
75 #include "core/page/ChromeClient.h"
76 #include "core/page/CreateWindow.h"
77 #include "core/page/EventHandler.h"
78 #include "core/page/FrameTree.h"
79 #include "core/page/Page.h"
80 #include "core/frame/Settings.h"
81 #include "core/page/WindowFeatures.h"
82 #include "core/page/scrolling/ScrollingCoordinator.h"
83 #include "core/xml/parser/XMLDocumentParser.h"
84 #include "platform/Logging.h"
85 #include "platform/UserGestureIndicator.h"
86 #include "platform/geometry/FloatRect.h"
87 #include "platform/network/ContentSecurityPolicyResponseHeaders.h"
88 #include "platform/network/HTTPParsers.h"
89 #include "platform/network/ResourceRequest.h"
90 #include "platform/scroll/ScrollAnimator.h"
91 #include "platform/weborigin/SecurityOrigin.h"
92 #include "platform/weborigin/SecurityPolicy.h"
93 #include "public/platform/WebURLRequest.h"
94 #include "wtf/TemporaryChange.h"
95 #include "wtf/text/CString.h"
96 #include "wtf/text/WTFString.h"
98 using blink::WebURLRequest;
102 using namespace HTMLNames;
104 bool isBackForwardLoadType(FrameLoadType type)
106 return type == FrameLoadTypeBackForward;
109 static bool needsHistoryItemRestore(FrameLoadType type)
111 return type == FrameLoadTypeBackForward || type == FrameLoadTypeReload || type == FrameLoadTypeReloadFromOrigin;
114 FrameLoader::FrameLoader(LocalFrame* frame)
116 , m_mixedContentChecker(frame)
117 , m_progressTracker(ProgressTracker::create(frame))
118 , m_state(FrameStateProvisional)
119 , m_loadType(FrameLoadTypeStandard)
120 , m_fetchContext(FrameFetchContext::create(frame))
121 , m_inStopAllLoaders(false)
122 , m_isComplete(false)
123 , m_checkTimer(this, &FrameLoader::checkTimerFired)
124 , m_didAccessInitialDocument(false)
125 , m_didAccessInitialDocumentTimer(this, &FrameLoader::didAccessInitialDocumentTimerFired)
126 , m_forcedSandboxFlags(SandboxNone)
127 , m_willDetachClient(false)
131 FrameLoader::~FrameLoader()
135 void FrameLoader::init()
137 ResourceRequest initialRequest(KURL(ParsedURLString, emptyString()));
138 initialRequest.setRequestContext(WebURLRequest::RequestContextInternal);
139 initialRequest.setFrameType(m_frame->isMainFrame() ? WebURLRequest::FrameTypeTopLevel : WebURLRequest::FrameTypeNested);
140 m_provisionalDocumentLoader = client()->createDocumentLoader(m_frame, initialRequest, SubstituteData());
141 m_provisionalDocumentLoader->startLoadingMainResource();
142 m_frame->document()->cancelParsing();
143 m_stateMachine.advanceTo(FrameLoaderStateMachine::DisplayingInitialEmptyDocument);
146 FrameLoaderClient* FrameLoader::client() const
148 return static_cast<FrameLoaderClient*>(m_frame->client());
151 void FrameLoader::setDefersLoading(bool defers)
153 if (m_documentLoader)
154 m_documentLoader->setDefersLoading(defers);
155 if (m_provisionalDocumentLoader)
156 m_provisionalDocumentLoader->setDefersLoading(defers);
157 if (m_policyDocumentLoader)
158 m_policyDocumentLoader->setDefersLoading(defers);
161 if (m_deferredHistoryLoad.isValid()) {
162 loadHistoryItem(m_deferredHistoryLoad.m_item.get(), m_deferredHistoryLoad.m_type, m_deferredHistoryLoad.m_cachePolicy);
163 m_deferredHistoryLoad = DeferredHistoryLoad();
165 m_frame->navigationScheduler().startTimer();
166 scheduleCheckCompleted();
170 void FrameLoader::stopLoading()
172 m_isComplete = true; // to avoid calling completed() in finishedParsing()
174 if (m_frame->document() && m_frame->document()->parsing()) {
176 m_frame->document()->setParsing(false);
179 if (Document* doc = m_frame->document()) {
180 // FIXME: HTML5 doesn't tell us to set the state to complete when aborting, but we do anyway to match legacy behavior.
181 // http://www.w3.org/Bugs/Public/show_bug.cgi?id=10537
182 doc->setReadyState(Document::Complete);
185 // FIXME: This will cancel redirection timer, which really needs to be restarted when restoring the frame from b/f cache.
186 m_frame->navigationScheduler().cancel();
189 void FrameLoader::saveScrollState()
191 if (!m_currentItem || !m_frame->view())
194 // Shouldn't clobber anything if we might still restore later.
195 if (needsHistoryItemRestore(m_loadType) && !m_frame->view()->wasScrolledByUser())
198 m_currentItem->setScrollPoint(m_frame->view()->scrollPosition());
200 if (m_frame->settings()->pinchVirtualViewportEnabled())
201 m_currentItem->setPinchViewportScrollPoint(m_frame->host()->pinchViewport().visibleRect().location());
203 m_currentItem->setPinchViewportScrollPoint(FloatPoint(-1, -1));
205 if (m_frame->isMainFrame())
206 m_currentItem->setPageScaleFactor(m_frame->page()->pageScaleFactor());
208 client()->didUpdateCurrentHistoryItem();
211 void FrameLoader::clearScrollPositionAndViewState()
213 ASSERT(m_frame->isMainFrame());
216 m_currentItem->clearScrollPoint();
217 m_currentItem->setPageScaleFactor(0);
220 bool FrameLoader::closeURL()
224 // Should only send the pagehide event here if the current document exists.
225 if (m_frame->document())
226 m_frame->document()->dispatchUnloadEvents();
229 if (Page* page = m_frame->page())
230 page->undoStack().didUnloadFrame(*m_frame);
234 void FrameLoader::didExplicitOpen()
236 m_isComplete = false;
238 // Calling document.open counts as committing the first real document load.
239 if (!m_stateMachine.committedFirstRealDocumentLoad())
240 m_stateMachine.advanceTo(FrameLoaderStateMachine::CommittedFirstRealLoad);
242 // Prevent window.open(url) -- eg window.open("about:blank") -- from blowing away results
243 // from a subsequent window.document.open / window.document.write call.
244 // Canceling redirection here works for all cases because document.open
245 // implicitly precedes document.write.
246 m_frame->navigationScheduler().cancel();
249 void FrameLoader::clear()
251 if (m_stateMachine.creatingInitialEmptyDocument())
254 m_frame->editor().clear();
255 m_frame->document()->cancelParsing();
256 m_frame->document()->prepareForDestruction();
257 m_frame->document()->removeFocusedElementOfSubtree(m_frame->document());
259 m_frame->selection().prepareForDestruction();
260 m_frame->eventHandler().clear();
262 m_frame->view()->clear();
264 m_frame->script().enableEval();
266 m_frame->navigationScheduler().cancel();
270 if (m_stateMachine.isDisplayingInitialEmptyDocument())
271 m_stateMachine.advanceTo(FrameLoaderStateMachine::CommittedFirstRealLoad);
274 void FrameLoader::setHistoryItemStateForCommit(HistoryCommitType historyCommitType, bool isPushOrReplaceState, PassRefPtr<SerializedScriptValue> stateObject)
276 if (m_provisionalItem)
277 m_currentItem = m_provisionalItem.release();
279 if (!m_currentItem || historyCommitType == StandardCommit) {
280 m_currentItem = HistoryItem::create();
281 } else if (!isPushOrReplaceState && m_documentLoader->url() != m_currentItem->url()) {
282 m_currentItem->generateNewItemSequenceNumber();
283 if (!equalIgnoringFragmentIdentifier(m_documentLoader->url(), m_currentItem->url()))
284 m_currentItem->generateNewDocumentSequenceNumber();
287 m_currentItem->setURL(m_documentLoader->urlForHistory());
288 m_currentItem->setDocumentState(m_frame->document()->formElementsState());
289 m_currentItem->setTarget(m_frame->tree().uniqueName());
290 if (isPushOrReplaceState)
291 m_currentItem->setStateObject(stateObject);
292 m_currentItem->setReferrer(Referrer(m_documentLoader->request().httpReferrer(), m_documentLoader->request().referrerPolicy()));
293 m_currentItem->setFormInfoFromRequest(m_documentLoader->request());
296 static HistoryCommitType loadTypeToCommitType(FrameLoadType type)
299 case FrameLoadTypeStandard:
300 return StandardCommit;
301 case FrameLoadTypeInitialInChildFrame:
302 return InitialCommitInChildFrame;
303 case FrameLoadTypeBackForward:
304 return BackForwardCommit;
308 return HistoryInertCommit;
311 void FrameLoader::receivedFirstData()
313 if (m_stateMachine.creatingInitialEmptyDocument())
316 HistoryCommitType historyCommitType = loadTypeToCommitType(m_loadType);
317 if (historyCommitType == StandardCommit && (m_documentLoader->urlForHistory().isEmpty() || (opener() && !m_currentItem && m_documentLoader->originalRequest().url().isEmpty())))
318 historyCommitType = HistoryInertCommit;
319 else if (historyCommitType == InitialCommitInChildFrame && (!m_frame->tree().top()->isLocalFrame() || MixedContentChecker::isMixedContent(toLocalFrame(m_frame->tree().top())->document()->securityOrigin(), m_documentLoader->url())))
320 historyCommitType = HistoryInertCommit;
321 setHistoryItemStateForCommit(historyCommitType);
323 if (!m_stateMachine.committedMultipleRealLoads() && m_loadType == FrameLoadTypeStandard)
324 m_stateMachine.advanceTo(FrameLoaderStateMachine::CommittedMultipleRealLoads);
326 client()->dispatchDidCommitLoad(m_frame, m_currentItem.get(), historyCommitType);
328 InspectorInstrumentation::didCommitLoad(m_frame, m_documentLoader.get());
329 m_frame->page()->didCommitLoad(m_frame);
330 dispatchDidClearDocumentOfWindowObject();
333 static void didFailContentSecurityPolicyCheck(FrameLoader* loader)
335 // load event and stopAllLoaders can detach the LocalFrame, so protect it.
336 RefPtr<LocalFrame> frame(loader->frame());
338 // Move the page to a unique origin, and cancel the load.
339 frame->document()->enforceSandboxFlags(SandboxOrigin);
340 loader->stopAllLoaders();
342 // Fire a load event, as timing attacks would otherwise reveal that the
343 // frame was blocked. This way, it looks like every other cross-origin
345 if (FrameOwner* frameOwner = frame->owner())
346 frameOwner->dispatchLoad();
349 void FrameLoader::didBeginDocument(bool dispatch)
351 m_isComplete = false;
352 m_frame->document()->setReadyState(Document::Loading);
354 if (m_provisionalItem && m_loadType == FrameLoadTypeBackForward)
355 m_frame->domWindow()->statePopped(m_provisionalItem->stateObject());
358 dispatchDidClearDocumentOfWindowObject();
360 m_frame->document()->initContentSecurityPolicy(m_documentLoader ? ContentSecurityPolicyResponseHeaders(m_documentLoader->response()) : ContentSecurityPolicyResponseHeaders());
362 if (!m_frame->document()->contentSecurityPolicy()->allowAncestors(m_frame)) {
363 didFailContentSecurityPolicyCheck(this);
367 Settings* settings = m_frame->document()->settings();
369 m_frame->document()->fetcher()->setImagesEnabled(settings->imagesEnabled());
370 m_frame->document()->fetcher()->setAutoLoadImages(settings->loadsImagesAutomatically());
373 if (m_documentLoader) {
374 const AtomicString& dnsPrefetchControl = m_documentLoader->response().httpHeaderField("X-DNS-Prefetch-Control");
375 if (!dnsPrefetchControl.isEmpty())
376 m_frame->document()->parseDNSPrefetchControlHeader(dnsPrefetchControl);
378 String headerContentLanguage = m_documentLoader->response().httpHeaderField("Content-Language");
379 if (!headerContentLanguage.isEmpty()) {
380 size_t commaIndex = headerContentLanguage.find(',');
381 headerContentLanguage.truncate(commaIndex); // kNotFound == -1 == don't truncate
382 headerContentLanguage = headerContentLanguage.stripWhiteSpace(isHTMLSpace<UChar>);
383 if (!headerContentLanguage.isEmpty())
384 m_frame->document()->setContentLanguage(AtomicString(headerContentLanguage));
388 if (m_provisionalItem && m_loadType == FrameLoadTypeBackForward)
389 m_frame->document()->setStateForNewFormElements(m_provisionalItem->documentState());
392 void FrameLoader::finishedParsing()
394 if (m_stateMachine.creatingInitialEmptyDocument())
397 // This can be called from the LocalFrame's destructor, in which case we shouldn't protect ourselves
398 // because doing so will cause us to re-enter the destructor when protector goes out of scope.
399 // Null-checking the FrameView indicates whether or not we're in the destructor.
400 RefPtr<LocalFrame> protector = m_frame->view() ? m_frame : 0;
403 client()->dispatchDidFinishDocumentLoad();
407 if (!m_frame->view())
408 return; // We are being destroyed by something checkCompleted called.
410 // Check if the scrollbars are really needed for the content.
411 // If not, remove them, relayout, and repaint.
412 m_frame->view()->restoreScrollbar();
413 scrollToFragmentWithParentBoundary(m_frame->document()->url());
416 void FrameLoader::loadDone()
421 bool FrameLoader::allChildrenAreComplete() const
423 for (Frame* child = m_frame->tree().firstChild(); child; child = child->tree().nextSibling()) {
424 if (child->isLocalFrame() && !toLocalFrame(child)->loader().m_isComplete)
430 bool FrameLoader::allAncestorsAreComplete() const
432 for (Frame* ancestor = m_frame; ancestor; ancestor = ancestor->tree().parent()) {
433 if (ancestor->isLocalFrame() && !toLocalFrame(ancestor)->document()->loadEventFinished())
439 void FrameLoader::checkCompleted()
441 RefPtr<LocalFrame> protect(m_frame);
444 m_frame->view()->handleLoadCompleted();
446 // Have we completed before?
450 // Are we still parsing?
451 if (m_frame->document()->parsing())
454 // Still waiting imports?
455 if (!m_frame->document()->haveImportsLoaded())
458 // Still waiting for images/scripts?
459 if (m_frame->document()->fetcher()->requestCount())
462 // Still waiting for elements that don't go through a FrameLoader?
463 if (m_frame->document()->isDelayingLoadEvent())
466 // Any frame that hasn't completed yet?
467 if (!allChildrenAreComplete())
472 m_frame->document()->setReadyState(Document::Complete);
473 if (m_frame->document()->loadEventStillNeeded())
474 m_frame->document()->implicitClose();
476 m_frame->navigationScheduler().startTimer();
483 m_frame->view()->handleLoadCompleted();
486 void FrameLoader::checkTimerFired(Timer<FrameLoader>*)
488 if (Page* page = m_frame->page()) {
489 if (page->defersLoading())
495 void FrameLoader::scheduleCheckCompleted()
497 if (!m_checkTimer.isActive())
498 m_checkTimer.startOneShot(0, FROM_HERE);
501 LocalFrame* FrameLoader::opener()
503 // FIXME: Temporary hack to stage converting locations that really should be Frame.
504 return client() ? toLocalFrame(client()->opener()) : 0;
507 void FrameLoader::setOpener(LocalFrame* opener)
509 // If the frame is already detached, the opener has already been cleared.
511 client()->setOpener(opener);
514 bool FrameLoader::allowPlugins(ReasonForCallingAllowPlugins reason)
516 Settings* settings = m_frame->settings();
517 bool allowed = client()->allowPlugins(settings && settings->pluginsEnabled());
518 if (!allowed && reason == AboutToInstantiatePlugin)
519 client()->didNotAllowPlugins();
523 void FrameLoader::updateForSameDocumentNavigation(const KURL& newURL, SameDocumentNavigationSource sameDocumentNavigationSource, PassRefPtr<SerializedScriptValue> data, FrameLoadType type)
525 // Update the data source's request with the new URL to fake the URL change
526 m_frame->document()->setURL(newURL);
527 documentLoader()->updateForSameDocumentNavigation(newURL, sameDocumentNavigationSource);
529 // Generate start and stop notifications only when loader is completed so that we
530 // don't fire them for fragment redirection that happens in window.onload handler.
531 // See https://bugs.webkit.org/show_bug.cgi?id=31838
532 if (m_frame->document()->loadEventFinished())
533 client()->didStartLoading(NavigationWithinSameDocument);
535 HistoryCommitType historyCommitType = loadTypeToCommitType(type);
537 historyCommitType = HistoryInertCommit;
539 setHistoryItemStateForCommit(historyCommitType, sameDocumentNavigationSource == SameDocumentNavigationHistoryApi, data);
540 client()->dispatchDidNavigateWithinPage(m_currentItem.get(), historyCommitType);
541 client()->dispatchDidReceiveTitle(m_frame->document()->title());
542 if (m_frame->document()->loadEventFinished())
543 client()->didStopLoading();
546 void FrameLoader::loadInSameDocument(const KURL& url, PassRefPtr<SerializedScriptValue> stateObject, FrameLoadType type, ClientRedirectPolicy clientRedirect)
548 // If we have a state object, we cannot also be a new navigation.
549 ASSERT(!stateObject || type == FrameLoadTypeBackForward);
551 // If we have a provisional request for a different document, a fragment scroll should cancel it.
552 if (m_provisionalDocumentLoader) {
553 m_provisionalDocumentLoader->stopLoading();
554 if (m_provisionalDocumentLoader)
555 m_provisionalDocumentLoader->detachFromFrame();
556 m_provisionalDocumentLoader = nullptr;
557 if (!m_frame->host())
563 KURL oldURL = m_frame->document()->url();
564 // If we were in the autoscroll/panScroll mode we want to stop it before following the link to the anchor
565 bool hashChange = equalIgnoringFragmentIdentifier(url, oldURL) && url.fragmentIdentifier() != oldURL.fragmentIdentifier();
567 m_frame->eventHandler().stopAutoscroll();
568 m_frame->domWindow()->enqueueHashchangeEvent(oldURL, url);
570 m_documentLoader->setIsClientRedirect(clientRedirect == ClientRedirect);
571 m_documentLoader->setReplacesCurrentHistoryItem(m_loadType == FrameLoadTypeStandard);
572 updateForSameDocumentNavigation(url, SameDocumentNavigationDefault, nullptr, type);
574 m_frame->view()->setWasScrolledByUser(false);
576 // It's important to model this as a load that starts and immediately finishes.
577 // Otherwise, the parent frame may think we never finished loading.
580 // We need to scroll to the fragment whether or not a hash change occurred, since
581 // the user might have scrolled since the previous navigation.
582 scrollToFragmentWithParentBoundary(url);
584 m_isComplete = false;
587 m_frame->domWindow()->statePopped(stateObject ? stateObject : SerializedScriptValue::nullValue());
590 void FrameLoader::completed()
592 RefPtr<LocalFrame> protect(m_frame);
594 for (Frame* descendant = m_frame->tree().traverseNext(m_frame); descendant; descendant = descendant->tree().traverseNext(m_frame)) {
595 if (descendant->isLocalFrame())
596 toLocalFrame(descendant)->navigationScheduler().startTimer();
599 Frame* parent = m_frame->tree().parent();
600 if (parent && parent->isLocalFrame())
601 toLocalFrame(parent)->loader().checkCompleted();
604 m_frame->view()->maintainScrollPositionAtAnchor(0);
607 void FrameLoader::started()
609 for (Frame* frame = m_frame; frame; frame = frame->tree().parent()) {
610 if (frame->isLocalFrame())
611 toLocalFrame(frame)->loader().m_isComplete = false;
615 void FrameLoader::setReferrerForFrameRequest(ResourceRequest& request, ShouldSendReferrer shouldSendReferrer, Document* originDocument)
617 if (shouldSendReferrer == NeverSendReferrer) {
618 request.clearHTTPReferrer();
622 // Always use the initiating document to generate the referrer.
623 // We need to generateReferrerHeader(), because we might not have enforced ReferrerPolicy or https->http
624 // referrer suppression yet.
625 String argsReferrer(request.httpReferrer());
626 if (argsReferrer.isEmpty())
627 argsReferrer = originDocument->outgoingReferrer();
628 String referrer = SecurityPolicy::generateReferrerHeader(originDocument->referrerPolicy(), request.url(), argsReferrer);
630 request.setHTTPReferrer(Referrer(referrer, originDocument->referrerPolicy()));
631 RefPtr<SecurityOrigin> referrerOrigin = SecurityOrigin::createFromString(referrer);
632 request.addHTTPOriginIfNeeded(referrerOrigin->toAtomicString());
635 bool FrameLoader::isScriptTriggeredFormSubmissionInChildFrame(const FrameLoadRequest& request) const
637 // If this is a child frame and the form submission was triggered by a script, lock the back/forward list
638 // to match IE and Opera.
639 // See https://bugs.webkit.org/show_bug.cgi?id=32383 for the original motivation for this.
640 if (!m_frame->tree().parent() || UserGestureIndicator::processingUserGesture())
642 return request.formState() && request.formState()->formSubmissionTrigger() == SubmittedByJavaScript;
645 FrameLoadType FrameLoader::determineFrameLoadType(const FrameLoadRequest& request)
647 if (m_frame->tree().parent() && !m_stateMachine.committedFirstRealDocumentLoad())
648 return FrameLoadTypeInitialInChildFrame;
649 if (!m_frame->tree().parent() && !m_frame->page()->backForward().backForwardListCount())
650 return FrameLoadTypeStandard;
651 if (m_provisionalDocumentLoader && request.substituteData().failingURL() == m_provisionalDocumentLoader->url() && m_loadType == FrameLoadTypeBackForward)
652 return FrameLoadTypeBackForward;
653 if (request.resourceRequest().cachePolicy() == ReloadIgnoringCacheData)
654 return FrameLoadTypeReload;
655 if (request.resourceRequest().cachePolicy() == ReloadBypassingCache)
656 return FrameLoadTypeReloadFromOrigin;
657 if (request.lockBackForwardList() || isScriptTriggeredFormSubmissionInChildFrame(request))
658 return FrameLoadTypeRedirectWithLockedBackForwardList;
659 if (!request.originDocument() && request.resourceRequest().url() == m_documentLoader->urlForHistory())
660 return FrameLoadTypeSame;
661 if (request.substituteData().failingURL() == m_documentLoader->urlForHistory() && m_loadType == FrameLoadTypeReload)
662 return FrameLoadTypeReload;
663 return FrameLoadTypeStandard;
666 bool FrameLoader::prepareRequestForThisFrame(FrameLoadRequest& request)
668 request.resourceRequest().setFrameType(m_frame->isMainFrame() ? WebURLRequest::FrameTypeTopLevel : WebURLRequest::FrameTypeNested);
670 // If no origin Document* was specified, skip remaining security checks and assume the caller has fully initialized the FrameLoadRequest.
671 if (!request.originDocument())
674 KURL url = request.resourceRequest().url();
675 if (m_frame->script().executeScriptIfJavaScriptURL(url))
678 if (!request.originDocument()->securityOrigin()->canDisplay(url)) {
679 reportLocalLoadFailed(m_frame, url.elidedString());
683 if (!request.formState() && request.frameName().isEmpty())
684 request.setFrameName(m_frame->document()->baseTarget());
686 setReferrerForFrameRequest(request.resourceRequest(), request.shouldSendReferrer(), request.originDocument());
690 static bool shouldOpenInNewWindow(LocalFrame* targetFrame, const FrameLoadRequest& request, const NavigationAction& action)
692 if (!targetFrame && !request.frameName().isEmpty())
694 // FIXME: This case is a workaround for the fact that ctrl+clicking a form submission incorrectly
695 // sends as a GET rather than a POST if it creates a new window in a different process.
696 return request.formState() && action.shouldOpenInNewWindow();
699 static WebURLRequest::RequestContext determineRequestContextFromNavigationType(const NavigationType navigationType)
701 switch (navigationType) {
702 case NavigationTypeLinkClicked:
703 return WebURLRequest::RequestContextHyperlink;
705 case NavigationTypeOther:
706 return WebURLRequest::RequestContextLocation;
708 case NavigationTypeFormResubmitted:
709 case NavigationTypeFormSubmitted:
710 return WebURLRequest::RequestContextForm;
712 case NavigationTypeBackForward:
713 case NavigationTypeReload:
714 return WebURLRequest::RequestContextInternal;
716 ASSERT_NOT_REACHED();
717 return WebURLRequest::RequestContextHyperlink;
720 void FrameLoader::load(const FrameLoadRequest& passedRequest)
722 ASSERT(m_frame->document());
724 RefPtr<LocalFrame> protect(m_frame);
726 if (m_inStopAllLoaders)
729 FrameLoadRequest request(passedRequest);
730 if (!prepareRequestForThisFrame(request))
733 RefPtr<LocalFrame> targetFrame = request.formState() ? 0 : findFrameForNavigation(AtomicString(request.frameName()), request.formState() ? request.formState()->sourceDocument() : m_frame->document());
734 if (targetFrame && targetFrame != m_frame) {
735 request.setFrameName("_self");
736 targetFrame->loader().load(request);
737 if (Page* page = targetFrame->page())
738 page->chrome().focus();
742 FrameLoadType newLoadType = determineFrameLoadType(request);
743 NavigationAction action(request.resourceRequest(), newLoadType, request.formState(), request.triggeringEvent());
744 if (action.resourceRequest().requestContext() == WebURLRequest::RequestContextUnspecified)
745 action.mutableResourceRequest().setRequestContext(determineRequestContextFromNavigationType(action.type()));
746 if (shouldOpenInNewWindow(targetFrame.get(), request, action)) {
747 if (action.policy() == NavigationPolicyDownload)
748 client()->loadURLExternally(action.resourceRequest(), NavigationPolicyDownload);
750 createWindowForRequest(request, *m_frame, action.policy(), request.shouldSendReferrer());
754 const KURL& url = request.resourceRequest().url();
755 if (!action.shouldOpenInNewWindow() && shouldPerformFragmentNavigation(request.formState(), request.resourceRequest().httpMethod(), newLoadType, url)) {
756 m_documentLoader->setTriggeringAction(action);
757 if (shouldTreatURLAsSameAsCurrent(url))
758 newLoadType = FrameLoadTypeRedirectWithLockedBackForwardList;
759 loadInSameDocument(url, nullptr, newLoadType, request.clientRedirect());
762 bool sameURL = url == m_documentLoader->urlForHistory();
763 loadWithNavigationAction(action, newLoadType, request.formState(), request.substituteData(), request.shouldCheckMainWorldContentSecurityPolicy(), request.clientRedirect());
764 // Example of this case are sites that reload the same URL with a different cookie
765 // driving the generated content, or a master frame with links that drive a target
766 // frame, where the user has clicked on the same link repeatedly.
767 if (sameURL && newLoadType != FrameLoadTypeReload && newLoadType != FrameLoadTypeReloadFromOrigin && request.resourceRequest().httpMethod() != "POST")
768 m_loadType = FrameLoadTypeSame;
771 SubstituteData FrameLoader::defaultSubstituteDataForURL(const KURL& url)
773 if (!shouldTreatURLAsSrcdocDocument(url))
774 return SubstituteData();
775 String srcdoc = m_frame->deprecatedLocalOwner()->fastGetAttribute(srcdocAttr);
776 ASSERT(!srcdoc.isNull());
777 CString encodedSrcdoc = srcdoc.utf8();
778 return SubstituteData(SharedBuffer::create(encodedSrcdoc.data(), encodedSrcdoc.length()), "text/html", "UTF-8", KURL());
781 void FrameLoader::reportLocalLoadFailed(LocalFrame* frame, const String& url)
783 ASSERT(!url.isEmpty());
787 frame->document()->addConsoleMessage(ConsoleMessage::create(SecurityMessageSource, ErrorMessageLevel, "Not allowed to load local resource: " + url));
791 ResourceRequest FrameLoader::requestFromHistoryItem(HistoryItem* item, ResourceRequestCachePolicy cachePolicy)
793 RefPtr<FormData> formData = item->formData();
794 ResourceRequest request(item->url(), item->referrer());
795 request.setCachePolicy(cachePolicy);
797 request.setHTTPMethod("POST");
798 request.setHTTPBody(formData);
799 request.setHTTPContentType(item->formContentType());
800 RefPtr<SecurityOrigin> securityOrigin = SecurityOrigin::createFromString(item->referrer().referrer);
801 request.addHTTPOriginIfNeeded(securityOrigin->toAtomicString());
806 void FrameLoader::reload(ReloadPolicy reloadPolicy, const KURL& overrideURL, const AtomicString& overrideEncoding, ClientRedirectPolicy clientRedirectPolicy)
811 ResourceRequestCachePolicy cachePolicy = reloadPolicy == EndToEndReload ? ReloadBypassingCache : ReloadIgnoringCacheData;
812 ResourceRequest request = requestFromHistoryItem(m_currentItem.get(), cachePolicy);
813 request.setFrameType(m_frame->isMainFrame() ? WebURLRequest::FrameTypeTopLevel : WebURLRequest::FrameTypeNested);
814 request.setRequestContext(WebURLRequest::RequestContextInternal);
816 // ClientRedirectPolicy is an indication that this load was triggered by
817 // some direct interaction with the page. If this reload is not a client
818 // redirect, we should reuse the referrer from the original load of the
819 // current document. If this reload is a client redirect (e.g., location.reload()),
820 // it was initiated by something in the current document and should
821 // therefore show the current document's url as the referrer.
822 if (clientRedirectPolicy == ClientRedirect)
823 request.setHTTPReferrer(Referrer(m_frame->document()->outgoingReferrer(), m_frame->document()->referrerPolicy()));
825 if (!overrideURL.isEmpty()) {
826 request.setURL(overrideURL);
827 request.clearHTTPReferrer();
830 FrameLoadType type = reloadPolicy == EndToEndReload ? FrameLoadTypeReloadFromOrigin : FrameLoadTypeReload;
831 loadWithNavigationAction(NavigationAction(request, type), type, nullptr, SubstituteData(), CheckContentSecurityPolicy, clientRedirectPolicy, overrideEncoding);
834 void FrameLoader::stopAllLoaders()
836 if (m_frame->document()->pageDismissalEventBeingDispatched() != Document::NoDismissal)
839 // If this method is called from within this method, infinite recursion can occur (3442218). Avoid this.
840 if (m_inStopAllLoaders)
843 // Calling stopLoading() on the provisional document loader can blow away
844 // the frame from underneath.
845 RefPtr<LocalFrame> protect(m_frame);
847 m_inStopAllLoaders = true;
849 for (RefPtr<Frame> child = m_frame->tree().firstChild(); child; child = child->tree().nextSibling()) {
850 if (child->isLocalFrame())
851 toLocalFrame(child.get())->loader().stopAllLoaders();
853 if (m_provisionalDocumentLoader)
854 m_provisionalDocumentLoader->stopLoading();
855 if (m_documentLoader)
856 m_documentLoader->stopLoading();
858 if (m_provisionalDocumentLoader)
859 m_provisionalDocumentLoader->detachFromFrame();
860 m_provisionalDocumentLoader = nullptr;
864 m_inStopAllLoaders = false;
866 // detachFromParent() can be called multiple times on same LocalFrame, which
867 // means we may no longer have a FrameLoaderClient to talk to.
869 client()->didStopAllLoaders();
872 void FrameLoader::didAccessInitialDocument()
874 // We only need to notify the client once, and only for the main frame.
875 if (isLoadingMainFrame() && !m_didAccessInitialDocument) {
876 m_didAccessInitialDocument = true;
877 // Notify asynchronously, since this is called within a JavaScript security check.
878 m_didAccessInitialDocumentTimer.startOneShot(0, FROM_HERE);
882 void FrameLoader::didAccessInitialDocumentTimerFired(Timer<FrameLoader>*)
884 client()->didAccessInitialDocument();
887 void FrameLoader::notifyIfInitialDocumentAccessed()
889 if (m_didAccessInitialDocumentTimer.isActive()) {
890 m_didAccessInitialDocumentTimer.stop();
891 didAccessInitialDocumentTimerFired(0);
895 bool FrameLoader::isLoading() const
897 if (m_provisionalDocumentLoader)
899 return m_documentLoader && m_documentLoader->isLoading();
902 void FrameLoader::commitProvisionalLoad()
904 ASSERT(client()->hasWebView());
905 ASSERT(m_state == FrameStateProvisional);
906 RefPtr<DocumentLoader> pdl = m_provisionalDocumentLoader;
907 RefPtr<LocalFrame> protect(m_frame);
909 // Check if the destination page is allowed to access the previous page's timing information.
910 if (m_frame->document()) {
911 RefPtr<SecurityOrigin> securityOrigin = SecurityOrigin::create(pdl->request().url());
912 pdl->timing()->setHasSameOriginAsPreviousDocument(securityOrigin->canRequest(m_frame->document()->url()));
915 // The call to closeURL() invokes the unload event handler, which can execute arbitrary
916 // JavaScript. If the script initiates a new load, we need to abandon the current load,
917 // or the two will stomp each other.
918 // detachChildren will similarly trigger child frame unload event handlers.
919 if (m_documentLoader) {
920 client()->dispatchWillClose();
923 m_frame->detachChildren();
924 if (pdl != m_provisionalDocumentLoader)
926 if (m_documentLoader)
927 m_documentLoader->detachFromFrame();
928 m_documentLoader = m_provisionalDocumentLoader.release();
929 m_state = FrameStateCommittedPage;
931 if (isLoadingMainFrame())
932 m_frame->page()->chrome().client().needTouchEvents(false);
934 client()->transitionToCommittedForNewPage();
935 m_frame->navigationScheduler().cancel();
936 m_frame->editor().clearLastEditCommand();
938 // If we are still in the process of initializing an empty document then
939 // its frame is not in a consistent state for rendering, so avoid setJSStatusBarText
940 // since it may cause clients to attempt to render the frame.
941 if (!m_stateMachine.creatingInitialEmptyDocument()) {
942 LocalDOMWindow* window = m_frame->domWindow();
943 window->setStatus(String());
944 window->setDefaultStatus(String());
949 bool FrameLoader::isLoadingMainFrame() const
951 return m_frame->isMainFrame();
954 FrameLoadType FrameLoader::loadType() const
959 // This function is an incomprehensible mess and is only used in checkLoadCompleteForThisFrame.
960 // If you're thinking of using it elsewhere, stop right now and reconsider your life.
961 static bool isDocumentDoneLoading(Document* document)
963 if (!document->loader())
965 if (document->loader()->isLoadingMainResource())
967 if (!document->loadEventFinished()) {
968 if (document->loader()->isLoading() || document->isDelayingLoadEvent())
971 if (document->fetcher()->requestCount())
973 if (document->processingLoadEvent())
975 if (document->hasActiveParser())
980 bool FrameLoader::checkLoadCompleteForThisFrame()
982 ASSERT(client()->hasWebView());
983 RefPtr<LocalFrame> protect(m_frame);
985 bool allChildrenAreDoneLoading = true;
986 for (RefPtr<Frame> child = m_frame->tree().firstChild(); child; child = child->tree().nextSibling()) {
987 if (child->isLocalFrame())
988 allChildrenAreDoneLoading &= toLocalFrame(child.get())->loader().checkLoadCompleteForThisFrame();
991 if (m_state == FrameStateProvisional && m_provisionalDocumentLoader) {
992 const ResourceError& error = m_provisionalDocumentLoader->mainDocumentError();
995 RefPtr<DocumentLoader> loader = m_provisionalDocumentLoader;
996 client()->dispatchDidFailProvisionalLoad(error);
997 if (loader != m_provisionalDocumentLoader)
999 m_provisionalDocumentLoader->detachFromFrame();
1000 m_provisionalDocumentLoader = nullptr;
1001 m_progressTracker->progressCompleted();
1002 m_state = FrameStateComplete;
1006 if (!allChildrenAreDoneLoading)
1009 if (m_state == FrameStateComplete)
1011 if (m_provisionalDocumentLoader || !m_documentLoader)
1013 if (!isDocumentDoneLoading(m_frame->document()) && !m_inStopAllLoaders)
1016 m_state = FrameStateComplete;
1018 // FIXME: Is this subsequent work important if we already navigated away?
1019 // Maybe there are bugs because of that, or extra work we can skip because
1020 // the new page is ready.
1022 // Retry restoring scroll offset since FrameStateComplete disables content
1024 restoreScrollPositionAndViewState();
1026 if (!m_stateMachine.committedFirstRealDocumentLoad())
1029 m_progressTracker->progressCompleted();
1030 m_frame->domWindow()->finishedLoading();
1032 const ResourceError& error = m_documentLoader->mainDocumentError();
1033 if (!error.isNull()) {
1034 client()->dispatchDidFailLoad(error);
1036 // Report mobile vs. desktop page statistics. This will only report on Android.
1037 if (m_frame->isMainFrame())
1038 m_frame->document()->viewportDescription().reportMobilePageStats(m_frame);
1040 client()->dispatchDidFinishLoad();
1042 m_loadType = FrameLoadTypeStandard;
1046 void FrameLoader::restoreScrollPositionAndViewState()
1048 FrameView* view = m_frame->view();
1049 if (!m_frame->page() || !view || !m_currentItem || !m_stateMachine.committedFirstRealDocumentLoad())
1052 if (!needsHistoryItemRestore(m_loadType))
1055 // This tries to balance 1. restoring as soon as possible, 2. detecting
1056 // clamping to avoid repeatedly popping the scroll position down as the
1057 // page height increases, 3. ignore clamp detection after load completes
1058 // because that may be because the page will never reach its previous
1060 float mainFrameScale = m_frame->settings()->pinchVirtualViewportEnabled() ? 1 : m_currentItem->pageScaleFactor();
1061 bool canRestoreWithoutClamping = view->clampOffsetAtScale(m_currentItem->scrollPoint(), mainFrameScale) == m_currentItem->scrollPoint();
1062 bool canRestoreWithoutAnnoyingUser = !view->wasScrolledByUser() && (canRestoreWithoutClamping || m_state == FrameStateComplete);
1063 if (!canRestoreWithoutAnnoyingUser)
1066 if (m_frame->isMainFrame() && m_currentItem->pageScaleFactor()) {
1067 FloatPoint pinchViewportOffset(m_currentItem->pinchViewportScrollPoint());
1068 IntPoint frameScrollOffset(m_currentItem->scrollPoint());
1070 m_frame->page()->setPageScaleFactor(m_currentItem->pageScaleFactor(), frameScrollOffset);
1072 if (m_frame->settings()->pinchVirtualViewportEnabled()) {
1073 // If the pinch viewport's offset is (-1, -1) it means the history item
1074 // is an old version of HistoryItem so distribute the scroll between
1075 // the main frame and the pinch viewport as best as we can.
1076 // FIXME(bokan): This legacy distribution can be removed once the virtual viewport
1077 // pinch path is enabled on all platforms for at least one release.
1078 if (pinchViewportOffset.x() == -1 && pinchViewportOffset.y() == -1)
1079 pinchViewportOffset = FloatPoint(frameScrollOffset - view->scrollPosition());
1081 m_frame->host()->pinchViewport().setLocation(pinchViewportOffset);
1084 view->setScrollPositionNonProgrammatically(m_currentItem->scrollPoint());
1087 if (m_frame->isMainFrame()) {
1088 if (ScrollingCoordinator* scrollingCoordinator = m_frame->page()->scrollingCoordinator())
1089 scrollingCoordinator->frameViewRootLayerDidChange(view);
1093 // Called every time a resource is completely loaded or an error is received.
1094 void FrameLoader::checkLoadComplete()
1096 ASSERT(client()->hasWebView());
1097 if (Page* page = m_frame->page()) {
1098 if (page->mainFrame()->isLocalFrame())
1099 page->deprecatedLocalMainFrame()->loader().checkLoadCompleteForThisFrame();
1103 String FrameLoader::userAgent(const KURL& url) const
1105 String userAgent = client()->userAgent(url);
1106 InspectorInstrumentation::applyUserAgentOverride(m_frame, &userAgent);
1110 void FrameLoader::detachFromParent()
1112 // Temporary explosions. We should never re-enter this code when this condition is true.
1113 RELEASE_ASSERT(!m_willDetachClient);
1114 // The caller must protect a reference to m_frame.
1115 ASSERT(m_frame->refCount() > 1);
1117 InspectorInstrumentation::frameDetachedFromParent(m_frame);
1119 if (m_documentLoader)
1120 m_documentLoader->detachFromFrame();
1121 m_documentLoader = nullptr;
1126 TemporaryChange<bool> willDetachClient(m_willDetachClient, true);
1128 // FIXME: All this code belongs up in Page.
1129 Frame* parent = m_frame->tree().parent();
1130 if (parent && parent->isLocalFrame()) {
1131 m_frame->setView(nullptr);
1132 // FIXME: Shouldn't need to check if page() is null here.
1133 if (m_frame->owner() && m_frame->page())
1134 m_frame->page()->decrementSubframeCount();
1135 m_frame->willDetachFrameHost();
1137 toLocalFrame(parent)->loader().scheduleCheckCompleted();
1139 m_frame->setView(nullptr);
1140 m_frame->willDetachFrameHost();
1143 m_frame->detachFromFrameHost();
1146 void FrameLoader::detachClient()
1150 // Finish all cleanup work that might require talking to the embedder.
1151 m_progressTracker.clear();
1153 // Notify ScriptController that the frame is closing, since its cleanup ends up calling
1154 // back to FrameLoaderClient via WindowProxy.
1155 m_frame->script().clearForClose();
1157 // client() should never be null because that means we somehow re-entered
1158 // the frame detach code... but it is sometimes.
1159 // FIXME: Understand why this is happening so we can document this insanity.
1161 // After this, we must no longer talk to the client since this clears
1162 // its owning reference back to our owning LocalFrame.
1163 client()->detachedFromParent();
1164 m_frame->clearClient();
1168 void FrameLoader::receivedMainResourceError(const ResourceError& error)
1170 // Retain because the stop may release the last reference to it.
1171 RefPtr<LocalFrame> protect(m_frame);
1173 if (m_frame->document()->parser())
1174 m_frame->document()->parser()->stopParsing();
1176 // FIXME: We really ought to be able to just check for isCancellation() here, but there are some
1177 // ResourceErrors that setIsCancellation() but aren't created by ResourceError::cancelledError().
1178 ResourceError c(ResourceError::cancelledError(KURL()));
1179 if ((error.errorCode() != c.errorCode() || error.domain() != c.domain()) && m_frame->owner()) {
1180 // FIXME: For now, fallback content doesn't work cross process.
1181 ASSERT(m_frame->owner()->isLocal());
1182 m_frame->deprecatedLocalOwner()->renderFallbackContent();
1186 if (m_frame->page())
1187 checkLoadComplete();
1190 bool FrameLoader::shouldPerformFragmentNavigation(bool isFormSubmission, const String& httpMethod, FrameLoadType loadType, const KURL& url)
1192 ASSERT(loadType != FrameLoadTypeReloadFromOrigin);
1193 // We don't do this if we are submitting a form with method other than "GET", explicitly reloading,
1194 // currently displaying a frameset, or if the URL does not have a fragment.
1195 return (!isFormSubmission || equalIgnoringCase(httpMethod, "GET"))
1196 && loadType != FrameLoadTypeReload
1197 && loadType != FrameLoadTypeSame
1198 && loadType != FrameLoadTypeBackForward
1199 && url.hasFragmentIdentifier()
1200 && equalIgnoringFragmentIdentifier(m_frame->document()->url(), url)
1201 // We don't want to just scroll if a link from within a
1202 // frameset is trying to reload the frameset into _top.
1203 && !m_frame->document()->isFrameSet();
1206 void FrameLoader::scrollToFragmentWithParentBoundary(const KURL& url)
1208 FrameView* view = m_frame->view();
1212 // Leaking scroll position to a cross-origin ancestor would permit the so-called "framesniffing" attack.
1213 RefPtr<LocalFrame> boundaryFrame(url.hasFragmentIdentifier() ? m_frame->document()->findUnsafeParentScrollPropagationBoundary() : 0);
1216 boundaryFrame->view()->setSafeToPropagateScrollToParent(false);
1218 view->scrollToFragment(url);
1221 boundaryFrame->view()->setSafeToPropagateScrollToParent(true);
1224 bool FrameLoader::shouldClose()
1226 Page* page = m_frame->page();
1227 if (!page || !page->chrome().canRunBeforeUnloadConfirmPanel())
1230 // Store all references to each subframe in advance since beforeunload's event handler may modify frame
1231 Vector<RefPtr<LocalFrame> > targetFrames;
1232 targetFrames.append(m_frame);
1233 for (Frame* child = m_frame->tree().firstChild(); child; child = child->tree().traverseNext(m_frame)) {
1234 // FIXME: There is not yet any way to dispatch events to out-of-process frames.
1235 if (child->isLocalFrame())
1236 targetFrames.append(toLocalFrame(child));
1239 bool shouldClose = false;
1241 NavigationDisablerForBeforeUnload navigationDisabler;
1244 bool didAllowNavigation = false;
1245 for (i = 0; i < targetFrames.size(); i++) {
1246 if (!targetFrames[i]->tree().isDescendantOf(m_frame))
1248 if (!targetFrames[i]->document()->dispatchBeforeUnloadEvent(page->chrome(), didAllowNavigation))
1252 if (i == targetFrames.size())
1258 bool FrameLoader::validateTransitionNavigationMode()
1260 if (frame()->document()->inQuirksMode()) {
1261 frame()->document()->addConsoleMessage(ConsoleMessage::create(JSMessageSource, ErrorMessageLevel, "Ignoring transition elements due to quirks mode."));
1265 // FIXME(oysteine): Also check for width=device-width here, to avoid zoom/scaling issues.
1269 bool FrameLoader::dispatchNavigationTransitionData()
1271 Vector<Document::TransitionElementData> elementData;
1272 frame()->document()->getTransitionElementData(elementData);
1273 if (elementData.isEmpty() || !validateTransitionNavigationMode())
1276 Vector<Document::TransitionElementData>::iterator iter = elementData.begin();
1277 for (; iter != elementData.end(); ++iter)
1278 client()->dispatchAddNavigationTransitionData(iter->scope, iter->selector, iter->markup);
1283 void FrameLoader::loadWithNavigationAction(const NavigationAction& action, FrameLoadType type, PassRefPtrWillBeRawPtr<FormState> formState, const SubstituteData& substituteData, ContentSecurityPolicyCheck shouldCheckMainWorldContentSecurityPolicy, ClientRedirectPolicy clientRedirect, const AtomicString& overrideEncoding)
1285 ASSERT(client()->hasWebView());
1286 if (m_frame->document()->pageDismissalEventBeingDispatched() != Document::NoDismissal)
1289 const ResourceRequest& request = action.resourceRequest();
1291 // The current load should replace the history item if it is the first real
1292 // load of the frame.
1293 bool replacesCurrentHistoryItem = false;
1294 if (type == FrameLoadTypeRedirectWithLockedBackForwardList
1295 || !m_stateMachine.committedFirstRealDocumentLoad()) {
1296 replacesCurrentHistoryItem = true;
1299 m_policyDocumentLoader = client()->createDocumentLoader(m_frame, request, substituteData.isValid() ? substituteData : defaultSubstituteDataForURL(request.url()));
1300 m_policyDocumentLoader->setTriggeringAction(action);
1301 m_policyDocumentLoader->setReplacesCurrentHistoryItem(replacesCurrentHistoryItem);
1302 m_policyDocumentLoader->setIsClientRedirect(clientRedirect == ClientRedirect);
1304 Frame* parent = m_frame->tree().parent();
1305 if (parent && parent->isLocalFrame())
1306 m_policyDocumentLoader->setOverrideEncoding(toLocalFrame(parent)->loader().documentLoader()->overrideEncoding());
1307 else if (!overrideEncoding.isEmpty())
1308 m_policyDocumentLoader->setOverrideEncoding(overrideEncoding);
1309 else if (m_documentLoader)
1310 m_policyDocumentLoader->setOverrideEncoding(m_documentLoader->overrideEncoding());
1313 bool isTransitionNavigation = false;
1314 if (RuntimeEnabledFeatures::navigationTransitionsEnabled())
1315 isTransitionNavigation = dispatchNavigationTransitionData();
1317 // stopAllLoaders can detach the LocalFrame, so protect it.
1318 RefPtr<LocalFrame> protect(m_frame);
1319 if ((!m_policyDocumentLoader->shouldContinueForNavigationPolicy(request, shouldCheckMainWorldContentSecurityPolicy, isTransitionNavigation) || !shouldClose()) && m_policyDocumentLoader) {
1320 m_policyDocumentLoader->detachFromFrame();
1321 m_policyDocumentLoader = nullptr;
1325 if (m_provisionalDocumentLoader) {
1326 m_provisionalDocumentLoader->stopLoading();
1327 if (m_provisionalDocumentLoader)
1328 m_provisionalDocumentLoader->detachFromFrame();
1329 m_provisionalDocumentLoader = nullptr;
1331 m_checkTimer.stop();
1333 // <rdar://problem/6250856> - In certain circumstances on pages with multiple frames, stopAllLoaders()
1334 // might detach the current FrameLoader, in which case we should bail on this newly defunct load.
1335 if (!m_frame->page() || !m_policyDocumentLoader)
1338 if (isLoadingMainFrame())
1339 m_frame->page()->inspectorController().resume();
1340 m_frame->navigationScheduler().cancel();
1342 m_provisionalDocumentLoader = m_policyDocumentLoader.release();
1344 m_state = FrameStateProvisional;
1347 client()->dispatchWillSubmitForm(formState->form());
1349 m_progressTracker->progressStarted();
1350 if (m_provisionalDocumentLoader->isClientRedirect())
1351 m_provisionalDocumentLoader->appendRedirect(m_frame->document()->url());
1352 m_provisionalDocumentLoader->appendRedirect(m_provisionalDocumentLoader->request().url());
1353 client()->dispatchDidStartProvisionalLoad(isTransitionNavigation);
1354 ASSERT(m_provisionalDocumentLoader);
1355 m_provisionalDocumentLoader->startLoadingMainResource();
1358 void FrameLoader::applyUserAgent(ResourceRequest& request)
1360 String userAgent = this->userAgent(request.url());
1361 ASSERT(!userAgent.isNull());
1362 request.setHTTPUserAgent(AtomicString(userAgent));
1365 bool FrameLoader::shouldInterruptLoadForXFrameOptions(const String& content, const KURL& url, unsigned long requestIdentifier)
1367 UseCounter::count(m_frame->domWindow()->document(), UseCounter::XFrameOptions);
1369 Frame* topFrame = m_frame->tree().top();
1370 if (m_frame == topFrame)
1373 XFrameOptionsDisposition disposition = parseXFrameOptionsHeader(content);
1375 switch (disposition) {
1376 case XFrameOptionsSameOrigin: {
1377 UseCounter::count(m_frame->domWindow()->document(), UseCounter::XFrameOptionsSameOrigin);
1378 RefPtr<SecurityOrigin> origin = SecurityOrigin::create(url);
1379 // Out-of-process ancestors are always a different origin.
1380 if (!topFrame->isLocalFrame() || !origin->isSameSchemeHostPort(toLocalFrame(topFrame)->document()->securityOrigin()))
1382 for (Frame* frame = m_frame->tree().parent(); frame; frame = frame->tree().parent()) {
1383 if (!frame->isLocalFrame() || !origin->isSameSchemeHostPort(toLocalFrame(frame)->document()->securityOrigin())) {
1384 UseCounter::count(m_frame->domWindow()->document(), UseCounter::XFrameOptionsSameOriginWithBadAncestorChain);
1390 case XFrameOptionsDeny:
1392 case XFrameOptionsAllowAll:
1394 case XFrameOptionsConflict: {
1395 RefPtrWillBeRawPtr<ConsoleMessage> consoleMessage = ConsoleMessage::create(JSMessageSource, ErrorMessageLevel, "Multiple 'X-Frame-Options' headers with conflicting values ('" + content + "') encountered when loading '" + url.elidedString() + "'. Falling back to 'DENY'.");
1396 consoleMessage->setRequestIdentifier(requestIdentifier);
1397 m_frame->document()->addMessage(consoleMessage.release());
1400 case XFrameOptionsInvalid: {
1401 RefPtrWillBeRawPtr<ConsoleMessage> consoleMessage = ConsoleMessage::create(JSMessageSource, ErrorMessageLevel, "Invalid 'X-Frame-Options' header encountered when loading '" + url.elidedString() + "': '" + content + "' is not a recognized directive. The header will be ignored.");
1402 consoleMessage->setRequestIdentifier(requestIdentifier);
1403 m_frame->document()->addMessage(consoleMessage.release());
1407 ASSERT_NOT_REACHED();
1412 bool FrameLoader::shouldTreatURLAsSameAsCurrent(const KURL& url) const
1414 return m_currentItem && url == m_currentItem->url();
1417 bool FrameLoader::shouldTreatURLAsSrcdocDocument(const KURL& url) const
1419 if (!equalIgnoringCase(url.string(), "about:srcdoc"))
1421 HTMLFrameOwnerElement* ownerElement = m_frame->deprecatedLocalOwner();
1422 if (!isHTMLIFrameElement(ownerElement))
1424 return ownerElement->fastHasAttribute(srcdocAttr);
1427 LocalFrame* FrameLoader::findFrameForNavigation(const AtomicString& name, Document* activeDocument)
1429 ASSERT(activeDocument);
1430 Frame* frame = m_frame->tree().find(name);
1431 if (!frame || !frame->isLocalFrame() || !activeDocument->canNavigate(toLocalFrame(*frame)))
1433 return toLocalFrame(frame);
1436 void FrameLoader::loadHistoryItem(HistoryItem* item, HistoryLoadType historyLoadType, ResourceRequestCachePolicy cachePolicy)
1438 RefPtr<LocalFrame> protect(m_frame);
1439 if (m_frame->page()->defersLoading()) {
1440 m_deferredHistoryLoad = DeferredHistoryLoad(item, historyLoadType, cachePolicy);
1444 m_provisionalItem = item;
1445 if (historyLoadType == HistorySameDocumentLoad) {
1446 loadInSameDocument(item->url(), item->stateObject(), FrameLoadTypeBackForward, NotClientRedirect);
1447 restoreScrollPositionAndViewState();
1451 ResourceRequest request = requestFromHistoryItem(item, cachePolicy);
1452 request.setFrameType(m_frame->isMainFrame() ? WebURLRequest::FrameTypeTopLevel : WebURLRequest::FrameTypeNested);
1453 request.setRequestContext(WebURLRequest::RequestContextInternal);
1454 loadWithNavigationAction(NavigationAction(request, FrameLoadTypeBackForward), FrameLoadTypeBackForward, nullptr, SubstituteData(), CheckContentSecurityPolicy);
1457 void FrameLoader::dispatchDocumentElementAvailable()
1459 client()->documentElementAvailable();
1462 void FrameLoader::dispatchDidClearDocumentOfWindowObject()
1464 if (!m_frame->script().canExecuteScripts(NotAboutToExecuteScript))
1467 if (Page* page = m_frame->page())
1468 page->inspectorController().didClearDocumentOfWindowObject(m_frame);
1469 InspectorInstrumentation::didClearDocumentOfWindowObject(m_frame);
1471 // We just cleared the document, not the entire window object, but for the
1472 // embedder that's close enough.
1473 client()->dispatchDidClearWindowObjectInMainWorld();
1476 void FrameLoader::dispatchDidClearWindowObjectInMainWorld()
1478 if (!m_frame->script().canExecuteScripts(NotAboutToExecuteScript))
1481 client()->dispatchDidClearWindowObjectInMainWorld();
1484 SandboxFlags FrameLoader::effectiveSandboxFlags() const
1486 SandboxFlags flags = m_forcedSandboxFlags;
1487 // FIXME: We need a way to propagate sandbox flags to out-of-process frames.
1488 Frame* parentFrame = m_frame->tree().parent();
1489 if (parentFrame && parentFrame->isLocalFrame())
1490 flags |= toLocalFrame(parentFrame)->document()->sandboxFlags();
1491 if (FrameOwner* frameOwner = m_frame->owner())
1492 flags |= frameOwner->sandboxFlags();
1496 } // namespace blink