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/Settings.h"
57 #include "core/frame/csp/ContentSecurityPolicy.h"
58 #include "core/html/HTMLFormElement.h"
59 #include "core/html/HTMLFrameOwnerElement.h"
60 #include "core/html/parser/HTMLParserIdioms.h"
61 #include "core/inspector/ConsoleMessage.h"
62 #include "core/inspector/InspectorController.h"
63 #include "core/inspector/InspectorInstrumentation.h"
64 #include "core/loader/DocumentLoadTiming.h"
65 #include "core/loader/DocumentLoader.h"
66 #include "core/loader/FormState.h"
67 #include "core/loader/FormSubmission.h"
68 #include "core/loader/FrameFetchContext.h"
69 #include "core/loader/FrameLoadRequest.h"
70 #include "core/loader/FrameLoaderClient.h"
71 #include "core/loader/ProgressTracker.h"
72 #include "core/loader/UniqueIdentifier.h"
73 #include "core/loader/appcache/ApplicationCacheHost.h"
74 #include "core/page/BackForwardClient.h"
75 #include "core/page/Chrome.h"
76 #include "core/page/ChromeClient.h"
77 #include "core/page/CreateWindow.h"
78 #include "core/page/EventHandler.h"
79 #include "core/page/FrameTree.h"
80 #include "core/page/Page.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/HTTPParsers.h"
88 #include "platform/network/ResourceRequest.h"
89 #include "platform/scroll/ScrollAnimator.h"
90 #include "platform/weborigin/SecurityOrigin.h"
91 #include "platform/weborigin/SecurityPolicy.h"
92 #include "public/platform/WebURLRequest.h"
93 #include "wtf/TemporaryChange.h"
94 #include "wtf/text/CString.h"
95 #include "wtf/text/WTFString.h"
97 using blink::WebURLRequest;
101 using namespace HTMLNames;
103 bool isBackForwardLoadType(FrameLoadType type)
105 return type == FrameLoadTypeBackForward;
108 static bool needsHistoryItemRestore(FrameLoadType type)
110 return type == FrameLoadTypeBackForward || type == FrameLoadTypeReload || type == FrameLoadTypeReloadFromOrigin;
113 FrameLoader::FrameLoader(LocalFrame* frame)
115 , m_mixedContentChecker(frame)
116 , m_progressTracker(ProgressTracker::create(frame))
117 , m_state(FrameStateProvisional)
118 , m_loadType(FrameLoadTypeStandard)
119 , m_fetchContext(FrameFetchContext::create(frame))
120 , m_inStopAllLoaders(false)
121 , m_checkTimer(this, &FrameLoader::checkTimerFired)
122 , m_didAccessInitialDocument(false)
123 , m_didAccessInitialDocumentTimer(this, &FrameLoader::didAccessInitialDocumentTimerFired)
124 , m_forcedSandboxFlags(SandboxNone)
128 FrameLoader::~FrameLoader()
130 // Verify that this FrameLoader has been detached.
131 ASSERT(!m_progressTracker);
134 void FrameLoader::trace(Visitor* visitor)
136 visitor->trace(m_frame);
137 visitor->trace(m_mixedContentChecker);
138 visitor->trace(m_progressTracker);
139 visitor->trace(m_fetchContext);
142 void FrameLoader::init()
144 ResourceRequest initialRequest(KURL(ParsedURLString, emptyString()));
145 initialRequest.setRequestContext(WebURLRequest::RequestContextInternal);
146 initialRequest.setFrameType(m_frame->isMainFrame() ? WebURLRequest::FrameTypeTopLevel : WebURLRequest::FrameTypeNested);
147 m_provisionalDocumentLoader = client()->createDocumentLoader(m_frame, initialRequest, SubstituteData());
148 m_provisionalDocumentLoader->startLoadingMainResource();
149 m_frame->document()->cancelParsing();
150 m_stateMachine.advanceTo(FrameLoaderStateMachine::DisplayingInitialEmptyDocument);
153 FrameLoaderClient* FrameLoader::client() const
155 return static_cast<FrameLoaderClient*>(m_frame->client());
158 void FrameLoader::setDefersLoading(bool defers)
160 if (m_documentLoader)
161 m_documentLoader->setDefersLoading(defers);
162 if (m_provisionalDocumentLoader)
163 m_provisionalDocumentLoader->setDefersLoading(defers);
164 if (m_policyDocumentLoader)
165 m_policyDocumentLoader->setDefersLoading(defers);
168 if (m_deferredHistoryLoad.isValid()) {
169 loadHistoryItem(m_deferredHistoryLoad.m_item.get(), m_deferredHistoryLoad.m_type, m_deferredHistoryLoad.m_cachePolicy);
170 m_deferredHistoryLoad = DeferredHistoryLoad();
172 m_frame->navigationScheduler().startTimer();
173 scheduleCheckCompleted();
177 void FrameLoader::stopLoading()
179 if (m_frame->document() && m_frame->document()->parsing()) {
181 m_frame->document()->setParsing(false);
184 if (Document* doc = m_frame->document()) {
185 // FIXME: HTML5 doesn't tell us to set the state to complete when aborting, but we do anyway to match legacy behavior.
186 // http://www.w3.org/Bugs/Public/show_bug.cgi?id=10537
187 doc->setReadyState(Document::Complete);
190 // FIXME: This will cancel redirection timer, which really needs to be restarted when restoring the frame from b/f cache.
191 m_frame->navigationScheduler().cancel();
194 void FrameLoader::saveScrollState()
196 if (!m_currentItem || !m_frame->view())
199 // Shouldn't clobber anything if we might still restore later.
200 if (needsHistoryItemRestore(m_loadType) && !m_frame->view()->wasScrolledByUser())
203 m_currentItem->setScrollPoint(m_frame->view()->scrollPosition());
205 if (m_frame->settings()->pinchVirtualViewportEnabled())
206 m_currentItem->setPinchViewportScrollPoint(m_frame->host()->pinchViewport().visibleRect().location());
208 m_currentItem->setPinchViewportScrollPoint(FloatPoint(-1, -1));
210 if (m_frame->isMainFrame())
211 m_currentItem->setPageScaleFactor(m_frame->page()->pageScaleFactor());
213 client()->didUpdateCurrentHistoryItem();
216 void FrameLoader::clearScrollPositionAndViewState()
218 ASSERT(m_frame->isMainFrame());
221 m_currentItem->clearScrollPoint();
222 m_currentItem->setPageScaleFactor(0);
225 bool FrameLoader::closeURL()
229 // Should only send the pagehide event here if the current document exists.
230 if (m_frame->document())
231 m_frame->document()->dispatchUnloadEvents();
234 if (Page* page = m_frame->page())
235 page->undoStack().didUnloadFrame(*m_frame);
239 void FrameLoader::didExplicitOpen()
241 // Calling document.open counts as committing the first real document load.
242 if (!m_stateMachine.committedFirstRealDocumentLoad())
243 m_stateMachine.advanceTo(FrameLoaderStateMachine::CommittedFirstRealLoad);
245 // Prevent window.open(url) -- eg window.open("about:blank") -- from blowing away results
246 // from a subsequent window.document.open / window.document.write call.
247 // Canceling redirection here works for all cases because document.open
248 // implicitly precedes document.write.
249 m_frame->navigationScheduler().cancel();
252 void FrameLoader::clear()
254 // clear() is called during (Local)Frame finalization and when creating
255 // a new Document within it (DocumentLoader::createWriterFor().)
256 if (m_stateMachine.creatingInitialEmptyDocument())
259 m_frame->editor().clear();
260 m_frame->document()->cancelParsing();
261 m_frame->document()->prepareForDestruction();
262 m_frame->document()->removeFocusedElementOfSubtree(m_frame->document());
263 m_frame->selection().prepareForDestruction();
264 m_frame->eventHandler().clear();
266 m_frame->view()->clear();
268 m_frame->script().enableEval();
270 m_frame->navigationScheduler().cancel();
274 if (m_stateMachine.isDisplayingInitialEmptyDocument())
275 m_stateMachine.advanceTo(FrameLoaderStateMachine::CommittedFirstRealLoad);
278 // This is only called by ScriptController::executeScriptIfJavaScriptURL
279 // and always contains the result of evaluating a javascript: url.
280 // This is the <iframe src="javascript:'html'"> case.
281 void FrameLoader::replaceDocumentWhileExecutingJavaScriptURL(const String& source, Document* ownerDocument)
283 if (!m_frame->document()->loader())
286 // DocumentWriter::replaceDocumentWhileExecutingJavaScriptURL can cause the DocumentLoader to get deref'ed and possible destroyed,
287 // so protect it with a RefPtr.
288 RefPtr<DocumentLoader> documentLoader(m_frame->document()->loader());
290 UseCounter::count(*m_frame->document(), UseCounter::ReplaceDocumentViaJavaScriptURL);
292 // Prepare a DocumentInit before clearing the frame, because it may need to
293 // inherit an aliased security context.
294 DocumentInit init(m_frame->document()->url(), m_frame);
295 init.withNewRegistrationContext();
300 // clear() potentially detaches the frame from the document. The
301 // loading cannot continue in that case.
302 if (!m_frame->page())
305 documentLoader->replaceDocumentWhileExecutingJavaScriptURL(init, source, ownerDocument);
308 void FrameLoader::setHistoryItemStateForCommit(HistoryCommitType historyCommitType, bool isPushOrReplaceState, PassRefPtr<SerializedScriptValue> stateObject)
310 if (m_provisionalItem)
311 m_currentItem = m_provisionalItem.release();
313 if (!m_currentItem || historyCommitType == StandardCommit) {
314 m_currentItem = HistoryItem::create();
315 } else if (!isPushOrReplaceState && m_documentLoader->url() != m_currentItem->url()) {
316 m_currentItem->generateNewItemSequenceNumber();
317 if (!equalIgnoringFragmentIdentifier(m_documentLoader->url(), m_currentItem->url()))
318 m_currentItem->generateNewDocumentSequenceNumber();
321 m_currentItem->setURL(m_documentLoader->urlForHistory());
322 m_currentItem->setDocumentState(m_frame->document()->formElementsState());
323 m_currentItem->setTarget(m_frame->tree().uniqueName());
324 if (isPushOrReplaceState)
325 m_currentItem->setStateObject(stateObject);
326 m_currentItem->setReferrer(Referrer(m_documentLoader->request().httpReferrer(), m_documentLoader->request().referrerPolicy()));
327 m_currentItem->setFormInfoFromRequest(m_documentLoader->request());
330 static HistoryCommitType loadTypeToCommitType(FrameLoadType type)
333 case FrameLoadTypeStandard:
334 return StandardCommit;
335 case FrameLoadTypeInitialInChildFrame:
336 return InitialCommitInChildFrame;
337 case FrameLoadTypeBackForward:
338 return BackForwardCommit;
342 return HistoryInertCommit;
345 void FrameLoader::receivedFirstData()
347 if (m_stateMachine.creatingInitialEmptyDocument())
350 HistoryCommitType historyCommitType = loadTypeToCommitType(m_loadType);
351 if (historyCommitType == StandardCommit && (m_documentLoader->urlForHistory().isEmpty() || (opener() && !m_currentItem && m_documentLoader->originalRequest().url().isEmpty())))
352 historyCommitType = HistoryInertCommit;
353 else if (historyCommitType == InitialCommitInChildFrame && (!m_frame->tree().top()->isLocalFrame() || MixedContentChecker::isMixedContent(toLocalFrame(m_frame->tree().top())->document()->securityOrigin(), m_documentLoader->url())))
354 historyCommitType = HistoryInertCommit;
355 setHistoryItemStateForCommit(historyCommitType);
357 if (!m_stateMachine.committedMultipleRealLoads() && m_loadType == FrameLoadTypeStandard)
358 m_stateMachine.advanceTo(FrameLoaderStateMachine::CommittedMultipleRealLoads);
360 client()->dispatchDidCommitLoad(m_frame, m_currentItem.get(), historyCommitType);
362 InspectorInstrumentation::didCommitLoad(m_frame, m_documentLoader.get());
363 m_frame->page()->didCommitLoad(m_frame);
364 dispatchDidClearDocumentOfWindowObject();
367 void FrameLoader::didBeginDocument(bool dispatch)
369 m_frame->document()->setReadyState(Document::Loading);
371 if (m_provisionalItem && m_loadType == FrameLoadTypeBackForward)
372 m_frame->domWindow()->statePopped(m_provisionalItem->stateObject());
375 dispatchDidClearDocumentOfWindowObject();
377 m_frame->document()->initContentSecurityPolicy(m_documentLoader ? m_documentLoader->releaseContentSecurityPolicy() : ContentSecurityPolicy::create());
379 Settings* settings = m_frame->document()->settings();
381 m_frame->document()->fetcher()->setImagesEnabled(settings->imagesEnabled());
382 m_frame->document()->fetcher()->setAutoLoadImages(settings->loadsImagesAutomatically());
385 if (m_documentLoader) {
386 const AtomicString& dnsPrefetchControl = m_documentLoader->response().httpHeaderField("X-DNS-Prefetch-Control");
387 if (!dnsPrefetchControl.isEmpty())
388 m_frame->document()->parseDNSPrefetchControlHeader(dnsPrefetchControl);
390 String headerContentLanguage = m_documentLoader->response().httpHeaderField("Content-Language");
391 if (!headerContentLanguage.isEmpty()) {
392 size_t commaIndex = headerContentLanguage.find(',');
393 headerContentLanguage.truncate(commaIndex); // kNotFound == -1 == don't truncate
394 headerContentLanguage = headerContentLanguage.stripWhiteSpace(isHTMLSpace<UChar>);
395 if (!headerContentLanguage.isEmpty())
396 m_frame->document()->setContentLanguage(AtomicString(headerContentLanguage));
400 if (m_provisionalItem && m_loadType == FrameLoadTypeBackForward)
401 m_frame->document()->setStateForNewFormElements(m_provisionalItem->documentState());
404 void FrameLoader::finishedParsing()
406 if (m_stateMachine.creatingInitialEmptyDocument())
409 // This can be called from the LocalFrame's destructor, in which case we shouldn't protect ourselves
410 // because doing so will cause us to re-enter the destructor when protector goes out of scope.
411 // Null-checking the FrameView indicates whether or not we're in the destructor.
412 RefPtrWillBeRawPtr<LocalFrame> protect(m_frame->view() ? m_frame.get() : nullptr);
415 client()->dispatchDidFinishDocumentLoad();
419 if (!m_frame->view())
420 return; // We are being destroyed by something checkCompleted called.
422 // Check if the scrollbars are really needed for the content.
423 // If not, remove them, relayout, and repaint.
424 m_frame->view()->restoreScrollbar();
425 scrollToFragmentWithParentBoundary(m_frame->document()->url());
428 void FrameLoader::loadDone()
433 bool FrameLoader::allChildrenAreComplete() const
435 for (Frame* child = m_frame->tree().firstChild(); child; child = child->tree().nextSibling()) {
436 if (!child->isLocalFrame())
438 LocalFrame* frame = toLocalFrame(child);
439 if (!frame->document()->isLoadCompleted() || frame->loader().m_provisionalDocumentLoader)
445 bool FrameLoader::allAncestorsAreComplete() const
447 for (Frame* ancestor = m_frame; ancestor; ancestor = ancestor->tree().parent()) {
448 if (ancestor->isLocalFrame() && !toLocalFrame(ancestor)->document()->loadEventFinished())
454 void FrameLoader::checkCompleted()
456 RefPtrWillBeRawPtr<LocalFrame> protect(m_frame.get());
459 m_frame->view()->handleLoadCompleted();
461 if (m_frame->document()->isLoadCompleted() && m_stateMachine.committedFirstRealDocumentLoad())
464 // Are we still parsing?
465 if (m_frame->document()->parsing())
468 // Still waiting imports?
469 if (!m_frame->document()->haveImportsLoaded())
472 // Still waiting for images/scripts?
473 if (m_frame->document()->fetcher()->requestCount())
476 // Still waiting for elements that don't go through a FrameLoader?
477 if (m_frame->document()->isDelayingLoadEvent())
480 // Any frame that hasn't completed yet?
481 if (!allChildrenAreComplete())
485 m_frame->document()->setReadyState(Document::Complete);
486 if (m_frame->document()->loadEventStillNeeded())
487 m_frame->document()->implicitClose();
489 m_frame->navigationScheduler().startTimer();
496 m_frame->view()->handleLoadCompleted();
499 void FrameLoader::checkTimerFired(Timer<FrameLoader>*)
501 if (Page* page = m_frame->page()) {
502 if (page->defersLoading())
508 void FrameLoader::scheduleCheckCompleted()
510 if (!m_checkTimer.isActive())
511 m_checkTimer.startOneShot(0, FROM_HERE);
514 Frame* FrameLoader::opener()
516 return client() ? client()->opener() : 0;
519 void FrameLoader::setOpener(LocalFrame* opener)
521 // If the frame is already detached, the opener has already been cleared.
523 client()->setOpener(opener);
526 bool FrameLoader::allowPlugins(ReasonForCallingAllowPlugins reason)
528 // With Oilpan, a FrameLoader might be accessed after the
529 // FrameHost has been detached. FrameClient will not be
530 // accessible, so bail early.
533 Settings* settings = m_frame->settings();
534 bool allowed = client()->allowPlugins(settings && settings->pluginsEnabled());
535 if (!allowed && reason == AboutToInstantiatePlugin)
536 client()->didNotAllowPlugins();
540 void FrameLoader::updateForSameDocumentNavigation(const KURL& newURL, SameDocumentNavigationSource sameDocumentNavigationSource, PassRefPtr<SerializedScriptValue> data, FrameLoadType type)
542 // Update the data source's request with the new URL to fake the URL change
543 m_frame->document()->setURL(newURL);
544 documentLoader()->updateForSameDocumentNavigation(newURL, sameDocumentNavigationSource);
546 // Generate start and stop notifications only when loader is completed so that we
547 // don't fire them for fragment redirection that happens in window.onload handler.
548 // See https://bugs.webkit.org/show_bug.cgi?id=31838
549 if (m_frame->document()->loadEventFinished())
550 client()->didStartLoading(NavigationWithinSameDocument);
552 HistoryCommitType historyCommitType = loadTypeToCommitType(type);
554 historyCommitType = HistoryInertCommit;
556 setHistoryItemStateForCommit(historyCommitType, sameDocumentNavigationSource == SameDocumentNavigationHistoryApi, data);
557 client()->dispatchDidNavigateWithinPage(m_currentItem.get(), historyCommitType);
558 client()->dispatchDidReceiveTitle(m_frame->document()->title());
559 if (m_frame->document()->loadEventFinished())
560 client()->didStopLoading();
563 void FrameLoader::loadInSameDocument(const KURL& url, PassRefPtr<SerializedScriptValue> stateObject, FrameLoadType type, ClientRedirectPolicy clientRedirect)
565 // If we have a state object, we cannot also be a new navigation.
566 ASSERT(!stateObject || type == FrameLoadTypeBackForward);
568 // If we have a provisional request for a different document, a fragment scroll should cancel it.
569 if (m_provisionalDocumentLoader) {
570 m_provisionalDocumentLoader->stopLoading();
571 if (m_provisionalDocumentLoader)
572 m_provisionalDocumentLoader->detachFromFrame();
573 m_provisionalDocumentLoader = nullptr;
574 if (!m_frame->host())
580 KURL oldURL = m_frame->document()->url();
581 // If we were in the autoscroll/panScroll mode we want to stop it before following the link to the anchor
582 bool hashChange = equalIgnoringFragmentIdentifier(url, oldURL) && url.fragmentIdentifier() != oldURL.fragmentIdentifier();
584 m_frame->eventHandler().stopAutoscroll();
585 m_frame->domWindow()->enqueueHashchangeEvent(oldURL, url);
587 m_documentLoader->setIsClientRedirect(clientRedirect == ClientRedirect);
588 m_documentLoader->setReplacesCurrentHistoryItem(m_loadType == FrameLoadTypeStandard);
589 updateForSameDocumentNavigation(url, SameDocumentNavigationDefault, nullptr, type);
591 m_frame->view()->setWasScrolledByUser(false);
593 // We need to scroll to the fragment whether or not a hash change occurred, since
594 // the user might have scrolled since the previous navigation.
595 scrollToFragmentWithParentBoundary(url);
598 m_frame->domWindow()->statePopped(stateObject ? stateObject : SerializedScriptValue::nullValue());
601 void FrameLoader::completed()
603 RefPtrWillBeRawPtr<LocalFrame> protect(m_frame.get());
605 for (Frame* descendant = m_frame->tree().traverseNext(m_frame); descendant; descendant = descendant->tree().traverseNext(m_frame)) {
606 if (descendant->isLocalFrame())
607 toLocalFrame(descendant)->navigationScheduler().startTimer();
610 Frame* parent = m_frame->tree().parent();
611 if (parent && parent->isLocalFrame())
612 toLocalFrame(parent)->loader().checkCompleted();
615 m_frame->view()->maintainScrollPositionAtAnchor(0);
618 void FrameLoader::setReferrerForFrameRequest(ResourceRequest& request, ShouldSendReferrer shouldSendReferrer, Document* originDocument)
620 if (shouldSendReferrer == NeverSendReferrer) {
621 request.clearHTTPReferrer();
625 // Always use the initiating document to generate the referrer.
626 // We need to generateReferrerHeader(), because we might not have enforced ReferrerPolicy or https->http
627 // referrer suppression yet.
628 String argsReferrer(request.httpReferrer());
629 if (argsReferrer.isEmpty())
630 argsReferrer = originDocument->outgoingReferrer();
631 String referrer = SecurityPolicy::generateReferrerHeader(originDocument->referrerPolicy(), request.url(), argsReferrer);
633 request.setHTTPReferrer(Referrer(referrer, originDocument->referrerPolicy()));
634 RefPtr<SecurityOrigin> referrerOrigin = SecurityOrigin::createFromString(referrer);
635 request.addHTTPOriginIfNeeded(referrerOrigin->toAtomicString());
638 bool FrameLoader::isScriptTriggeredFormSubmissionInChildFrame(const FrameLoadRequest& request) const
640 // If this is a child frame and the form submission was triggered by a script, lock the back/forward list
641 // to match IE and Opera.
642 // See https://bugs.webkit.org/show_bug.cgi?id=32383 for the original motivation for this.
643 if (!m_frame->tree().parent() || UserGestureIndicator::processingUserGesture())
645 return request.formState() && request.formState()->formSubmissionTrigger() == SubmittedByJavaScript;
648 FrameLoadType FrameLoader::determineFrameLoadType(const FrameLoadRequest& request)
650 if (m_frame->tree().parent() && !m_stateMachine.committedFirstRealDocumentLoad())
651 return FrameLoadTypeInitialInChildFrame;
652 if (!m_frame->tree().parent() && !m_frame->page()->backForward().backForwardListCount())
653 return FrameLoadTypeStandard;
654 if (m_provisionalDocumentLoader && request.substituteData().failingURL() == m_provisionalDocumentLoader->url() && m_loadType == FrameLoadTypeBackForward)
655 return FrameLoadTypeBackForward;
656 if (request.resourceRequest().cachePolicy() == ReloadIgnoringCacheData)
657 return FrameLoadTypeReload;
658 if (request.resourceRequest().cachePolicy() == ReloadBypassingCache)
659 return FrameLoadTypeReloadFromOrigin;
660 if (request.lockBackForwardList() || isScriptTriggeredFormSubmissionInChildFrame(request))
661 return FrameLoadTypeRedirectWithLockedBackForwardList;
662 if (!request.originDocument() && request.resourceRequest().url() == m_documentLoader->urlForHistory())
663 return FrameLoadTypeSame;
664 if (request.substituteData().failingURL() == m_documentLoader->urlForHistory() && m_loadType == FrameLoadTypeReload)
665 return FrameLoadTypeReload;
666 return FrameLoadTypeStandard;
669 bool FrameLoader::prepareRequestForThisFrame(FrameLoadRequest& request)
671 request.resourceRequest().setFrameType(m_frame->isMainFrame() ? WebURLRequest::FrameTypeTopLevel : WebURLRequest::FrameTypeNested);
673 // If no origin Document* was specified, skip remaining security checks and assume the caller has fully initialized the FrameLoadRequest.
674 if (!request.originDocument())
677 KURL url = request.resourceRequest().url();
678 if (m_frame->script().executeScriptIfJavaScriptURL(url))
681 if (!request.originDocument()->securityOrigin()->canDisplay(url)) {
682 reportLocalLoadFailed(m_frame, url.elidedString());
686 if (!request.formState() && request.frameName().isEmpty())
687 request.setFrameName(m_frame->document()->baseTarget());
689 setReferrerForFrameRequest(request.resourceRequest(), request.shouldSendReferrer(), request.originDocument());
693 static bool shouldOpenInNewWindow(LocalFrame* targetFrame, const FrameLoadRequest& request, const NavigationAction& action)
695 if (!targetFrame && !request.frameName().isEmpty())
697 // FIXME: This case is a workaround for the fact that ctrl+clicking a form submission incorrectly
698 // sends as a GET rather than a POST if it creates a new window in a different process.
699 return request.formState() && action.shouldOpenInNewWindow();
702 static WebURLRequest::RequestContext determineRequestContextFromNavigationType(const NavigationType navigationType)
704 switch (navigationType) {
705 case NavigationTypeLinkClicked:
706 return WebURLRequest::RequestContextHyperlink;
708 case NavigationTypeOther:
709 return WebURLRequest::RequestContextLocation;
711 case NavigationTypeFormResubmitted:
712 case NavigationTypeFormSubmitted:
713 return WebURLRequest::RequestContextForm;
715 case NavigationTypeBackForward:
716 case NavigationTypeReload:
717 return WebURLRequest::RequestContextInternal;
719 ASSERT_NOT_REACHED();
720 return WebURLRequest::RequestContextHyperlink;
723 void FrameLoader::load(const FrameLoadRequest& passedRequest)
725 ASSERT(m_frame->document());
727 RefPtrWillBeRawPtr<LocalFrame> protect(m_frame.get());
729 if (m_inStopAllLoaders)
732 FrameLoadRequest request(passedRequest);
733 if (!prepareRequestForThisFrame(request))
736 RefPtrWillBeRawPtr<LocalFrame> targetFrame = request.formState() ? 0 : findFrameForNavigation(AtomicString(request.frameName()), request.formState() ? request.formState()->sourceDocument() : m_frame->document());
737 if (targetFrame && targetFrame.get() != m_frame) {
738 request.setFrameName("_self");
739 targetFrame->loader().load(request);
740 if (Page* page = targetFrame->page())
741 page->chrome().focus();
745 FrameLoadType newLoadType = determineFrameLoadType(request);
746 NavigationAction action(request.resourceRequest(), newLoadType, request.formState(), request.triggeringEvent());
747 if (action.resourceRequest().requestContext() == WebURLRequest::RequestContextUnspecified)
748 action.mutableResourceRequest().setRequestContext(determineRequestContextFromNavigationType(action.type()));
749 if (shouldOpenInNewWindow(targetFrame.get(), request, action)) {
750 if (action.policy() == NavigationPolicyDownload)
751 client()->loadURLExternally(action.resourceRequest(), NavigationPolicyDownload);
753 createWindowForRequest(request, *m_frame, action.policy(), request.shouldSendReferrer());
757 const KURL& url = request.resourceRequest().url();
758 if (!action.shouldOpenInNewWindow() && shouldPerformFragmentNavigation(request.formState(), request.resourceRequest().httpMethod(), newLoadType, url)) {
759 m_documentLoader->setTriggeringAction(action);
760 if (shouldTreatURLAsSameAsCurrent(url))
761 newLoadType = FrameLoadTypeRedirectWithLockedBackForwardList;
762 loadInSameDocument(url, nullptr, newLoadType, request.clientRedirect());
765 bool sameURL = url == m_documentLoader->urlForHistory();
766 loadWithNavigationAction(action, newLoadType, request.formState(), request.substituteData(), request.shouldCheckMainWorldContentSecurityPolicy(), request.clientRedirect());
767 // Example of this case are sites that reload the same URL with a different cookie
768 // driving the generated content, or a master frame with links that drive a target
769 // frame, where the user has clicked on the same link repeatedly.
770 if (sameURL && newLoadType != FrameLoadTypeReload && newLoadType != FrameLoadTypeReloadFromOrigin && request.resourceRequest().httpMethod() != "POST")
771 m_loadType = FrameLoadTypeSame;
774 SubstituteData FrameLoader::defaultSubstituteDataForURL(const KURL& url)
776 if (!shouldTreatURLAsSrcdocDocument(url))
777 return SubstituteData();
778 String srcdoc = m_frame->deprecatedLocalOwner()->fastGetAttribute(srcdocAttr);
779 ASSERT(!srcdoc.isNull());
780 CString encodedSrcdoc = srcdoc.utf8();
781 return SubstituteData(SharedBuffer::create(encodedSrcdoc.data(), encodedSrcdoc.length()), "text/html", "UTF-8", KURL());
784 void FrameLoader::reportLocalLoadFailed(LocalFrame* frame, const String& url)
786 ASSERT(!url.isEmpty());
790 frame->document()->addConsoleMessage(ConsoleMessage::create(SecurityMessageSource, ErrorMessageLevel, "Not allowed to load local resource: " + url));
794 ResourceRequest FrameLoader::requestFromHistoryItem(HistoryItem* item, ResourceRequestCachePolicy cachePolicy)
796 RefPtr<FormData> formData = item->formData();
797 ResourceRequest request(item->url(), item->referrer());
798 request.setCachePolicy(cachePolicy);
800 request.setHTTPMethod("POST");
801 request.setHTTPBody(formData);
802 request.setHTTPContentType(item->formContentType());
803 RefPtr<SecurityOrigin> securityOrigin = SecurityOrigin::createFromString(item->referrer().referrer);
804 request.addHTTPOriginIfNeeded(securityOrigin->toAtomicString());
809 void FrameLoader::reload(ReloadPolicy reloadPolicy, const KURL& overrideURL, const AtomicString& overrideEncoding, ClientRedirectPolicy clientRedirectPolicy)
814 ResourceRequestCachePolicy cachePolicy = reloadPolicy == EndToEndReload ? ReloadBypassingCache : ReloadIgnoringCacheData;
815 ResourceRequest request = requestFromHistoryItem(m_currentItem.get(), cachePolicy);
816 request.setFrameType(m_frame->isMainFrame() ? WebURLRequest::FrameTypeTopLevel : WebURLRequest::FrameTypeNested);
817 request.setRequestContext(WebURLRequest::RequestContextInternal);
819 // ClientRedirectPolicy is an indication that this load was triggered by
820 // some direct interaction with the page. If this reload is not a client
821 // redirect, we should reuse the referrer from the original load of the
822 // current document. If this reload is a client redirect (e.g., location.reload()),
823 // it was initiated by something in the current document and should
824 // therefore show the current document's url as the referrer.
825 if (clientRedirectPolicy == ClientRedirect)
826 request.setHTTPReferrer(Referrer(m_frame->document()->outgoingReferrer(), m_frame->document()->referrerPolicy()));
828 if (!overrideURL.isEmpty()) {
829 request.setURL(overrideURL);
830 request.clearHTTPReferrer();
832 request.setSkipServiceWorker(reloadPolicy == EndToEndReload);
834 FrameLoadType type = reloadPolicy == EndToEndReload ? FrameLoadTypeReloadFromOrigin : FrameLoadTypeReload;
835 loadWithNavigationAction(NavigationAction(request, type), type, nullptr, SubstituteData(), CheckContentSecurityPolicy, clientRedirectPolicy, overrideEncoding);
838 void FrameLoader::stopAllLoaders()
840 if (m_frame->document()->pageDismissalEventBeingDispatched() != Document::NoDismissal)
843 // If this method is called from within this method, infinite recursion can occur (3442218). Avoid this.
844 if (m_inStopAllLoaders)
847 // Calling stopLoading() on the provisional document loader can blow away
848 // the frame from underneath.
849 RefPtrWillBeRawPtr<LocalFrame> protect(m_frame.get());
851 m_inStopAllLoaders = true;
853 for (RefPtrWillBeRawPtr<Frame> child = m_frame->tree().firstChild(); child; child = child->tree().nextSibling()) {
854 if (child->isLocalFrame())
855 toLocalFrame(child.get())->loader().stopAllLoaders();
857 if (m_provisionalDocumentLoader)
858 m_provisionalDocumentLoader->stopLoading();
859 if (m_documentLoader)
860 m_documentLoader->stopLoading();
862 if (m_provisionalDocumentLoader)
863 m_provisionalDocumentLoader->detachFromFrame();
864 m_provisionalDocumentLoader = nullptr;
868 m_inStopAllLoaders = false;
870 // detachFromParent() can be called multiple times on same LocalFrame, which
871 // means we may no longer have a FrameLoaderClient to talk to.
873 client()->didStopAllLoaders();
876 void FrameLoader::didAccessInitialDocument()
878 // We only need to notify the client once, and only for the main frame.
879 if (isLoadingMainFrame() && !m_didAccessInitialDocument) {
880 m_didAccessInitialDocument = true;
881 // Notify asynchronously, since this is called within a JavaScript security check.
882 m_didAccessInitialDocumentTimer.startOneShot(0, FROM_HERE);
886 void FrameLoader::didAccessInitialDocumentTimerFired(Timer<FrameLoader>*)
889 client()->didAccessInitialDocument();
892 void FrameLoader::notifyIfInitialDocumentAccessed()
894 if (m_didAccessInitialDocumentTimer.isActive()) {
895 m_didAccessInitialDocumentTimer.stop();
896 didAccessInitialDocumentTimerFired(0);
900 void FrameLoader::commitProvisionalLoad()
902 ASSERT(client()->hasWebView());
903 ASSERT(m_state == FrameStateProvisional);
904 RefPtr<DocumentLoader> pdl = m_provisionalDocumentLoader;
905 RefPtrWillBeRawPtr<LocalFrame> protect(m_frame.get());
907 // Check if the destination page is allowed to access the previous page's timing information.
908 if (m_frame->document()) {
909 RefPtr<SecurityOrigin> securityOrigin = SecurityOrigin::create(pdl->request().url());
910 pdl->timing()->setHasSameOriginAsPreviousDocument(securityOrigin->canRequest(m_frame->document()->url()));
913 // The call to closeURL() invokes the unload event handler, which can execute arbitrary
914 // JavaScript. If the script initiates a new load, we need to abandon the current load,
915 // or the two will stomp each other.
916 // detachChildren will similarly trigger child frame unload event handlers.
917 if (m_documentLoader) {
918 client()->dispatchWillClose();
921 m_frame->detachChildren();
922 if (pdl != m_provisionalDocumentLoader)
924 if (m_documentLoader)
925 m_documentLoader->detachFromFrame();
926 m_documentLoader = m_provisionalDocumentLoader.release();
927 m_state = FrameStateCommittedPage;
929 if (isLoadingMainFrame())
930 m_frame->page()->chrome().client().needTouchEvents(false);
932 client()->transitionToCommittedForNewPage();
933 m_frame->navigationScheduler().cancel();
934 m_frame->editor().clearLastEditCommand();
936 // If we are still in the process of initializing an empty document then
937 // its frame is not in a consistent state for rendering, so avoid setJSStatusBarText
938 // since it may cause clients to attempt to render the frame.
939 if (!m_stateMachine.creatingInitialEmptyDocument()) {
940 LocalDOMWindow* window = m_frame->domWindow();
941 window->setStatus(String());
942 window->setDefaultStatus(String());
946 bool FrameLoader::isLoadingMainFrame() const
948 return m_frame->isMainFrame();
951 FrameLoadType FrameLoader::loadType() const
956 // This function is an incomprehensible mess and is only used in checkLoadCompleteForThisFrame.
957 // If you're thinking of using it elsewhere, stop right now and reconsider your life.
958 static bool isDocumentDoneLoading(Document* document)
960 if (!document->loader())
962 if (document->loader()->isLoadingMainResource())
964 if (!document->loadEventFinished()) {
965 if (document->loader()->isLoading() || document->isDelayingLoadEvent())
968 if (document->fetcher()->requestCount())
970 if (document->processingLoadEvent())
972 if (document->hasActiveParser())
977 bool FrameLoader::checkLoadCompleteForThisFrame()
979 ASSERT(client()->hasWebView());
980 RefPtrWillBeRawPtr<LocalFrame> protect(m_frame.get());
982 bool allChildrenAreDoneLoading = true;
983 for (RefPtrWillBeRawPtr<Frame> child = m_frame->tree().firstChild(); child; child = child->tree().nextSibling()) {
984 if (child->isLocalFrame())
985 allChildrenAreDoneLoading &= toLocalFrame(child.get())->loader().checkLoadCompleteForThisFrame();
988 if (m_state == FrameStateProvisional && m_provisionalDocumentLoader) {
989 const ResourceError& error = m_provisionalDocumentLoader->mainDocumentError();
992 RefPtr<DocumentLoader> loader = m_provisionalDocumentLoader;
993 client()->dispatchDidFailProvisionalLoad(error);
994 if (loader != m_provisionalDocumentLoader)
996 m_provisionalDocumentLoader->detachFromFrame();
997 m_provisionalDocumentLoader = nullptr;
998 m_progressTracker->progressCompleted();
999 m_state = FrameStateComplete;
1004 if (!allChildrenAreDoneLoading)
1007 if (m_state == FrameStateComplete)
1009 if (m_provisionalDocumentLoader || !m_documentLoader)
1011 if (!isDocumentDoneLoading(m_frame->document()) && !m_inStopAllLoaders)
1014 m_state = FrameStateComplete;
1016 // FIXME: Is this subsequent work important if we already navigated away?
1017 // Maybe there are bugs because of that, or extra work we can skip because
1018 // the new page is ready.
1020 // Retry restoring scroll offset since FrameStateComplete disables content
1022 restoreScrollPositionAndViewState();
1024 if (!m_stateMachine.committedFirstRealDocumentLoad())
1027 m_progressTracker->progressCompleted();
1028 m_frame->domWindow()->finishedLoading();
1030 const ResourceError& error = m_documentLoader->mainDocumentError();
1031 if (!error.isNull()) {
1032 client()->dispatchDidFailLoad(error);
1034 // Report mobile vs. desktop page statistics. This will only report on Android.
1035 if (m_frame->isMainFrame())
1036 m_frame->document()->viewportDescription().reportMobilePageStats(m_frame);
1038 client()->dispatchDidFinishLoad();
1040 m_loadType = FrameLoadTypeStandard;
1044 void FrameLoader::restoreScrollPositionAndViewState()
1046 FrameView* view = m_frame->view();
1047 if (!m_frame->page() || !view || !m_currentItem || !m_stateMachine.committedFirstRealDocumentLoad())
1050 if (!needsHistoryItemRestore(m_loadType))
1053 // This tries to balance 1. restoring as soon as possible, 2. detecting
1054 // clamping to avoid repeatedly popping the scroll position down as the
1055 // page height increases, 3. ignore clamp detection after load completes
1056 // because that may be because the page will never reach its previous
1058 float mainFrameScale = m_frame->settings()->pinchVirtualViewportEnabled() ? 1 : m_currentItem->pageScaleFactor();
1059 bool canRestoreWithoutClamping = view->clampOffsetAtScale(m_currentItem->scrollPoint(), mainFrameScale) == m_currentItem->scrollPoint();
1060 bool canRestoreWithoutAnnoyingUser = !view->wasScrolledByUser() && (canRestoreWithoutClamping || m_state == FrameStateComplete);
1061 if (!canRestoreWithoutAnnoyingUser)
1064 if (m_frame->isMainFrame() && m_currentItem->pageScaleFactor()) {
1065 FloatPoint pinchViewportOffset(m_currentItem->pinchViewportScrollPoint());
1066 IntPoint frameScrollOffset(m_currentItem->scrollPoint());
1068 m_frame->page()->setPageScaleFactor(m_currentItem->pageScaleFactor(), frameScrollOffset);
1070 if (m_frame->settings()->pinchVirtualViewportEnabled()) {
1071 // If the pinch viewport's offset is (-1, -1) it means the history item
1072 // is an old version of HistoryItem so distribute the scroll between
1073 // the main frame and the pinch viewport as best as we can.
1074 // FIXME(bokan): This legacy distribution can be removed once the virtual viewport
1075 // pinch path is enabled on all platforms for at least one release.
1076 if (pinchViewportOffset.x() == -1 && pinchViewportOffset.y() == -1)
1077 pinchViewportOffset = FloatPoint(frameScrollOffset - view->scrollPosition());
1079 m_frame->host()->pinchViewport().setLocation(pinchViewportOffset);
1082 view->setScrollPositionNonProgrammatically(m_currentItem->scrollPoint());
1085 if (m_frame->isMainFrame()) {
1086 if (ScrollingCoordinator* scrollingCoordinator = m_frame->page()->scrollingCoordinator())
1087 scrollingCoordinator->frameViewRootLayerDidChange(view);
1091 // Called every time a resource is completely loaded or an error is received.
1092 void FrameLoader::checkLoadComplete()
1094 ASSERT(client()->hasWebView());
1095 if (Page* page = m_frame->page()) {
1096 if (page->mainFrame()->isLocalFrame())
1097 page->deprecatedLocalMainFrame()->loader().checkLoadCompleteForThisFrame();
1101 String FrameLoader::userAgent(const KURL& url) const
1103 String userAgent = client()->userAgent(url);
1104 InspectorInstrumentation::applyUserAgentOverride(m_frame, &userAgent);
1108 void FrameLoader::detachFromParent()
1111 // The caller must protect a reference to m_frame.
1112 ASSERT(m_frame->refCount() > 1);
1115 InspectorInstrumentation::frameDetachedFromParent(m_frame);
1117 if (m_documentLoader)
1118 m_documentLoader->detachFromFrame();
1119 m_documentLoader = nullptr;
1124 // FIXME: All this code belongs up in Page.
1125 Frame* parent = m_frame->tree().parent();
1126 if (parent && parent->isLocalFrame()) {
1127 m_frame->setView(nullptr);
1128 // FIXME: Shouldn't need to check if page() is null here.
1129 if (m_frame->owner() && m_frame->page())
1130 m_frame->page()->decrementSubframeCount();
1131 m_frame->willDetachFrameHost();
1133 toLocalFrame(parent)->loader().scheduleCheckCompleted();
1135 m_frame->setView(nullptr);
1136 m_frame->willDetachFrameHost();
1139 m_frame->detachFromFrameHost();
1142 void FrameLoader::detachClient()
1146 // Finish all cleanup work that might require talking to the embedder.
1147 m_progressTracker->dispose();
1148 m_progressTracker.clear();
1150 // Notify ScriptController that the frame is closing, since its cleanup ends up calling
1151 // back to FrameLoaderClient via WindowProxy.
1152 m_frame->script().clearForClose();
1154 // client() should never be null because that means we somehow re-entered
1155 // the frame detach code... but it is sometimes.
1156 // FIXME: Understand why this is happening so we can document this insanity.
1158 // After this, we must no longer talk to the client since this clears
1159 // its owning reference back to our owning LocalFrame.
1160 client()->detachedFromParent();
1161 m_frame->clearClient();
1165 void FrameLoader::receivedMainResourceError(const ResourceError& error)
1167 // Retain because the stop may release the last reference to it.
1168 RefPtrWillBeRawPtr<LocalFrame> protect(m_frame.get());
1170 if (m_frame->document()->parser())
1171 m_frame->document()->parser()->stopParsing();
1173 // FIXME: We really ought to be able to just check for isCancellation() here, but there are some
1174 // ResourceErrors that setIsCancellation() but aren't created by ResourceError::cancelledError().
1175 ResourceError c(ResourceError::cancelledError(KURL()));
1176 if ((error.errorCode() != c.errorCode() || error.domain() != c.domain()) && m_frame->owner()) {
1177 // FIXME: For now, fallback content doesn't work cross process.
1178 ASSERT(m_frame->owner()->isLocal());
1179 m_frame->deprecatedLocalOwner()->renderFallbackContent();
1183 if (m_frame->page())
1184 checkLoadComplete();
1187 bool FrameLoader::shouldPerformFragmentNavigation(bool isFormSubmission, const String& httpMethod, FrameLoadType loadType, const KURL& url)
1189 ASSERT(loadType != FrameLoadTypeReloadFromOrigin);
1190 // We don't do this if we are submitting a form with method other than "GET", explicitly reloading,
1191 // currently displaying a frameset, or if the URL does not have a fragment.
1192 return (!isFormSubmission || equalIgnoringCase(httpMethod, "GET"))
1193 && loadType != FrameLoadTypeReload
1194 && loadType != FrameLoadTypeSame
1195 && loadType != FrameLoadTypeBackForward
1196 && url.hasFragmentIdentifier()
1197 && equalIgnoringFragmentIdentifier(m_frame->document()->url(), url)
1198 // We don't want to just scroll if a link from within a
1199 // frameset is trying to reload the frameset into _top.
1200 && !m_frame->document()->isFrameSet();
1203 void FrameLoader::scrollToFragmentWithParentBoundary(const KURL& url)
1205 FrameView* view = m_frame->view();
1209 // Leaking scroll position to a cross-origin ancestor would permit the so-called "framesniffing" attack.
1210 RefPtrWillBeRawPtr<LocalFrame> boundaryFrame = url.hasFragmentIdentifier() ? m_frame->document()->findUnsafeParentScrollPropagationBoundary() : 0;
1213 boundaryFrame->view()->setSafeToPropagateScrollToParent(false);
1215 view->scrollToFragment(url);
1218 boundaryFrame->view()->setSafeToPropagateScrollToParent(true);
1221 bool FrameLoader::shouldClose()
1223 Page* page = m_frame->page();
1224 if (!page || !page->chrome().canRunBeforeUnloadConfirmPanel())
1227 // Store all references to each subframe in advance since beforeunload's event handler may modify frame
1228 WillBeHeapVector<RefPtrWillBeMember<LocalFrame> > targetFrames;
1229 targetFrames.append(m_frame);
1230 for (Frame* child = m_frame->tree().firstChild(); child; child = child->tree().traverseNext(m_frame)) {
1231 // FIXME: There is not yet any way to dispatch events to out-of-process frames.
1232 if (child->isLocalFrame())
1233 targetFrames.append(toLocalFrame(child));
1236 bool shouldClose = false;
1238 NavigationDisablerForBeforeUnload navigationDisabler;
1241 bool didAllowNavigation = false;
1242 for (i = 0; i < targetFrames.size(); i++) {
1243 if (!targetFrames[i]->tree().isDescendantOf(m_frame))
1245 if (!targetFrames[i]->document()->dispatchBeforeUnloadEvent(page->chrome(), didAllowNavigation))
1249 if (i == targetFrames.size())
1255 bool FrameLoader::validateTransitionNavigationMode()
1257 if (frame()->document()->inQuirksMode()) {
1258 frame()->document()->addConsoleMessage(ConsoleMessage::create(JSMessageSource, ErrorMessageLevel, "Ignoring transition elements due to quirks mode."));
1262 // FIXME(oysteine): Also check for width=device-width here, to avoid zoom/scaling issues.
1266 bool FrameLoader::dispatchNavigationTransitionData()
1268 Vector<Document::TransitionElementData> elementData;
1269 frame()->document()->getTransitionElementData(elementData);
1270 if (elementData.isEmpty() || !validateTransitionNavigationMode())
1273 Vector<Document::TransitionElementData>::iterator iter = elementData.begin();
1274 for (; iter != elementData.end(); ++iter)
1275 client()->dispatchAddNavigationTransitionData(iter->scope, iter->selector, iter->markup);
1280 void FrameLoader::loadWithNavigationAction(const NavigationAction& action, FrameLoadType type, PassRefPtrWillBeRawPtr<FormState> formState, const SubstituteData& substituteData, ContentSecurityPolicyCheck shouldCheckMainWorldContentSecurityPolicy, ClientRedirectPolicy clientRedirect, const AtomicString& overrideEncoding)
1282 ASSERT(client()->hasWebView());
1283 if (m_frame->document()->pageDismissalEventBeingDispatched() != Document::NoDismissal)
1286 const ResourceRequest& request = action.resourceRequest();
1288 // The current load should replace the history item if it is the first real
1289 // load of the frame.
1290 bool replacesCurrentHistoryItem = false;
1291 if (type == FrameLoadTypeRedirectWithLockedBackForwardList
1292 || !m_stateMachine.committedFirstRealDocumentLoad()) {
1293 replacesCurrentHistoryItem = true;
1296 m_policyDocumentLoader = client()->createDocumentLoader(m_frame, request, substituteData.isValid() ? substituteData : defaultSubstituteDataForURL(request.url()));
1297 m_policyDocumentLoader->setTriggeringAction(action);
1298 m_policyDocumentLoader->setReplacesCurrentHistoryItem(replacesCurrentHistoryItem);
1299 m_policyDocumentLoader->setIsClientRedirect(clientRedirect == ClientRedirect);
1301 Frame* parent = m_frame->tree().parent();
1302 if (parent && parent->isLocalFrame())
1303 m_policyDocumentLoader->setOverrideEncoding(toLocalFrame(parent)->loader().documentLoader()->overrideEncoding());
1304 else if (!overrideEncoding.isEmpty())
1305 m_policyDocumentLoader->setOverrideEncoding(overrideEncoding);
1306 else if (m_documentLoader)
1307 m_policyDocumentLoader->setOverrideEncoding(m_documentLoader->overrideEncoding());
1310 bool isTransitionNavigation = false;
1311 if (RuntimeEnabledFeatures::navigationTransitionsEnabled() && type != FrameLoadTypeReload && type != FrameLoadTypeReloadFromOrigin && type != FrameLoadTypeSame)
1312 isTransitionNavigation = dispatchNavigationTransitionData();
1314 // stopAllLoaders can detach the LocalFrame, so protect it.
1315 RefPtrWillBeRawPtr<LocalFrame> protect(m_frame.get());
1316 if ((!m_policyDocumentLoader->shouldContinueForNavigationPolicy(request, shouldCheckMainWorldContentSecurityPolicy, isTransitionNavigation) || !shouldClose()) && m_policyDocumentLoader) {
1317 m_policyDocumentLoader->detachFromFrame();
1318 m_policyDocumentLoader = nullptr;
1323 if (m_provisionalDocumentLoader) {
1324 m_provisionalDocumentLoader->stopLoading();
1325 if (m_provisionalDocumentLoader)
1326 m_provisionalDocumentLoader->detachFromFrame();
1327 m_provisionalDocumentLoader = nullptr;
1329 m_checkTimer.stop();
1331 // <rdar://problem/6250856> - In certain circumstances on pages with multiple frames, stopAllLoaders()
1332 // might detach the current FrameLoader, in which case we should bail on this newly defunct load.
1333 if (!m_frame->page() || !m_policyDocumentLoader)
1336 if (isLoadingMainFrame())
1337 m_frame->page()->inspectorController().resume();
1338 m_frame->navigationScheduler().cancel();
1340 m_provisionalDocumentLoader = m_policyDocumentLoader.release();
1342 m_state = FrameStateProvisional;
1345 client()->dispatchWillSubmitForm(formState->form());
1347 m_progressTracker->progressStarted();
1348 if (m_provisionalDocumentLoader->isClientRedirect())
1349 m_provisionalDocumentLoader->appendRedirect(m_frame->document()->url());
1350 m_provisionalDocumentLoader->appendRedirect(m_provisionalDocumentLoader->request().url());
1351 client()->dispatchDidStartProvisionalLoad(isTransitionNavigation);
1352 ASSERT(m_provisionalDocumentLoader);
1353 m_provisionalDocumentLoader->startLoadingMainResource();
1356 void FrameLoader::applyUserAgent(ResourceRequest& request)
1358 String userAgent = this->userAgent(request.url());
1359 ASSERT(!userAgent.isNull());
1360 request.setHTTPUserAgent(AtomicString(userAgent));
1363 bool FrameLoader::shouldInterruptLoadForXFrameOptions(const String& content, const KURL& url, unsigned long requestIdentifier)
1365 UseCounter::count(m_frame->domWindow()->document(), UseCounter::XFrameOptions);
1367 Frame* topFrame = m_frame->tree().top();
1368 if (m_frame == topFrame)
1371 XFrameOptionsDisposition disposition = parseXFrameOptionsHeader(content);
1373 switch (disposition) {
1374 case XFrameOptionsSameOrigin: {
1375 UseCounter::count(m_frame->domWindow()->document(), UseCounter::XFrameOptionsSameOrigin);
1376 RefPtr<SecurityOrigin> origin = SecurityOrigin::create(url);
1377 // Out-of-process ancestors are always a different origin.
1378 if (!topFrame->isLocalFrame() || !origin->isSameSchemeHostPort(toLocalFrame(topFrame)->document()->securityOrigin()))
1380 for (Frame* frame = m_frame->tree().parent(); frame; frame = frame->tree().parent()) {
1381 if (!frame->isLocalFrame() || !origin->isSameSchemeHostPort(toLocalFrame(frame)->document()->securityOrigin())) {
1382 UseCounter::count(m_frame->domWindow()->document(), UseCounter::XFrameOptionsSameOriginWithBadAncestorChain);
1388 case XFrameOptionsDeny:
1390 case XFrameOptionsAllowAll:
1392 case XFrameOptionsConflict: {
1393 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'.");
1394 consoleMessage->setRequestIdentifier(requestIdentifier);
1395 m_frame->document()->addConsoleMessage(consoleMessage.release());
1398 case XFrameOptionsInvalid: {
1399 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.");
1400 consoleMessage->setRequestIdentifier(requestIdentifier);
1401 m_frame->document()->addConsoleMessage(consoleMessage.release());
1405 ASSERT_NOT_REACHED();
1410 bool FrameLoader::shouldTreatURLAsSameAsCurrent(const KURL& url) const
1412 return m_currentItem && url == m_currentItem->url();
1415 bool FrameLoader::shouldTreatURLAsSrcdocDocument(const KURL& url) const
1417 if (!equalIgnoringCase(url.string(), "about:srcdoc"))
1419 HTMLFrameOwnerElement* ownerElement = m_frame->deprecatedLocalOwner();
1420 if (!isHTMLIFrameElement(ownerElement))
1422 return ownerElement->fastHasAttribute(srcdocAttr);
1425 LocalFrame* FrameLoader::findFrameForNavigation(const AtomicString& name, Document* activeDocument)
1427 ASSERT(activeDocument);
1428 Frame* frame = m_frame->tree().find(name);
1429 if (!frame || !frame->isLocalFrame() || !activeDocument->canNavigate(toLocalFrame(*frame)))
1431 return toLocalFrame(frame);
1434 void FrameLoader::loadHistoryItem(HistoryItem* item, HistoryLoadType historyLoadType, ResourceRequestCachePolicy cachePolicy)
1436 RefPtrWillBeRawPtr<LocalFrame> protect(m_frame.get());
1437 if (m_frame->page()->defersLoading()) {
1438 m_deferredHistoryLoad = DeferredHistoryLoad(item, historyLoadType, cachePolicy);
1442 m_provisionalItem = item;
1443 if (historyLoadType == HistorySameDocumentLoad) {
1444 loadInSameDocument(item->url(), item->stateObject(), FrameLoadTypeBackForward, NotClientRedirect);
1445 restoreScrollPositionAndViewState();
1449 ResourceRequest request = requestFromHistoryItem(item, cachePolicy);
1450 request.setFrameType(m_frame->isMainFrame() ? WebURLRequest::FrameTypeTopLevel : WebURLRequest::FrameTypeNested);
1451 request.setRequestContext(WebURLRequest::RequestContextInternal);
1452 loadWithNavigationAction(NavigationAction(request, FrameLoadTypeBackForward), FrameLoadTypeBackForward, nullptr, SubstituteData(), CheckContentSecurityPolicy);
1455 void FrameLoader::dispatchDocumentElementAvailable()
1457 client()->documentElementAvailable();
1460 void FrameLoader::dispatchDidClearDocumentOfWindowObject()
1462 if (!m_frame->script().canExecuteScripts(NotAboutToExecuteScript))
1465 if (Page* page = m_frame->page())
1466 page->inspectorController().didClearDocumentOfWindowObject(m_frame);
1467 InspectorInstrumentation::didClearDocumentOfWindowObject(m_frame);
1469 // We just cleared the document, not the entire window object, but for the
1470 // embedder that's close enough.
1471 client()->dispatchDidClearWindowObjectInMainWorld();
1474 void FrameLoader::dispatchDidClearWindowObjectInMainWorld()
1476 if (!m_frame->script().canExecuteScripts(NotAboutToExecuteScript))
1479 client()->dispatchDidClearWindowObjectInMainWorld();
1482 SandboxFlags FrameLoader::effectiveSandboxFlags() const
1484 SandboxFlags flags = m_forcedSandboxFlags;
1485 // FIXME: We need a way to propagate sandbox flags to out-of-process frames.
1486 Frame* parentFrame = m_frame->tree().parent();
1487 if (parentFrame && parentFrame->isLocalFrame())
1488 flags |= toLocalFrame(parentFrame)->document()->sandboxFlags();
1489 if (FrameOwner* frameOwner = m_frame->owner())
1490 flags |= frameOwner->sandboxFlags();
1494 } // namespace blink