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/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/page/WindowFeatures.h"
81 #include "core/page/scrolling/ScrollingCoordinator.h"
82 #include "core/xml/parser/XMLDocumentParser.h"
83 #include "platform/Logging.h"
84 #include "platform/UserGestureIndicator.h"
85 #include "platform/geometry/FloatRect.h"
86 #include "platform/network/HTTPParsers.h"
87 #include "platform/network/ResourceRequest.h"
88 #include "platform/scroll/ScrollAnimator.h"
89 #include "platform/weborigin/SecurityOrigin.h"
90 #include "platform/weborigin/SecurityPolicy.h"
91 #include "public/platform/WebURLRequest.h"
92 #include "wtf/TemporaryChange.h"
93 #include "wtf/text/CString.h"
94 #include "wtf/text/WTFString.h"
96 using blink::WebURLRequest;
100 using namespace HTMLNames;
102 bool isBackForwardLoadType(FrameLoadType type)
104 return type == FrameLoadTypeBackForward || type == FrameLoadTypeInitialHistoryLoad;
107 static bool needsHistoryItemRestore(FrameLoadType type)
109 return type == FrameLoadTypeBackForward || type == FrameLoadTypeReload || type == FrameLoadTypeReloadFromOrigin;
112 FrameLoader::FrameLoader(LocalFrame* frame)
114 , m_mixedContentChecker(frame)
115 , m_progressTracker(ProgressTracker::create(frame))
116 , m_state(FrameStateProvisional)
117 , m_loadType(FrameLoadTypeStandard)
118 , m_fetchContext(FrameFetchContext::create(frame))
119 , m_inStopAllLoaders(false)
120 , m_checkTimer(this, &FrameLoader::checkTimerFired)
121 , m_didAccessInitialDocument(false)
122 , m_didAccessInitialDocumentTimer(this, &FrameLoader::didAccessInitialDocumentTimerFired)
123 , m_forcedSandboxFlags(SandboxNone)
127 FrameLoader::~FrameLoader()
129 // Verify that this FrameLoader has been detached.
130 ASSERT(!m_progressTracker);
133 void FrameLoader::trace(Visitor* visitor)
135 visitor->trace(m_frame);
136 visitor->trace(m_mixedContentChecker);
137 visitor->trace(m_progressTracker);
138 visitor->trace(m_fetchContext);
139 visitor->trace(m_currentItem);
140 visitor->trace(m_provisionalItem);
141 visitor->trace(m_deferredHistoryLoad);
144 void FrameLoader::init()
146 ResourceRequest initialRequest(KURL(ParsedURLString, emptyString()));
147 initialRequest.setRequestContext(WebURLRequest::RequestContextInternal);
148 initialRequest.setFrameType(m_frame->isMainFrame() ? WebURLRequest::FrameTypeTopLevel : WebURLRequest::FrameTypeNested);
149 m_provisionalDocumentLoader = client()->createDocumentLoader(m_frame, initialRequest, SubstituteData());
150 m_provisionalDocumentLoader->startLoadingMainResource();
151 m_frame->document()->cancelParsing();
152 m_stateMachine.advanceTo(FrameLoaderStateMachine::DisplayingInitialEmptyDocument);
155 FrameLoaderClient* FrameLoader::client() const
157 return static_cast<FrameLoaderClient*>(m_frame->client());
160 void FrameLoader::setDefersLoading(bool defers)
162 if (m_documentLoader)
163 m_documentLoader->setDefersLoading(defers);
164 if (m_provisionalDocumentLoader)
165 m_provisionalDocumentLoader->setDefersLoading(defers);
166 if (m_policyDocumentLoader)
167 m_policyDocumentLoader->setDefersLoading(defers);
170 if (m_deferredHistoryLoad.isValid()) {
171 loadHistoryItem(m_deferredHistoryLoad.m_item.get(), FrameLoadTypeBackForward,
172 m_deferredHistoryLoad.m_type, m_deferredHistoryLoad.m_cachePolicy);
173 m_deferredHistoryLoad = DeferredHistoryLoad();
175 m_frame->navigationScheduler().startTimer();
176 scheduleCheckCompleted();
180 void FrameLoader::stopLoading()
182 if (m_frame->document() && m_frame->document()->parsing()) {
184 m_frame->document()->setParsing(false);
187 if (Document* doc = m_frame->document()) {
188 // FIXME: HTML5 doesn't tell us to set the state to complete when aborting, but we do anyway to match legacy behavior.
189 // http://www.w3.org/Bugs/Public/show_bug.cgi?id=10537
190 doc->setReadyState(Document::Complete);
193 // FIXME: This will cancel redirection timer, which really needs to be restarted when restoring the frame from b/f cache.
194 m_frame->navigationScheduler().cancel();
197 void FrameLoader::saveScrollState()
199 if (!m_currentItem || !m_frame->view())
202 // Shouldn't clobber anything if we might still restore later.
203 if (needsHistoryItemRestore(m_loadType) && !m_frame->view()->wasScrolledByUser())
206 m_currentItem->setScrollPoint(m_frame->view()->scrollPosition());
208 if (m_frame->settings()->pinchVirtualViewportEnabled())
209 m_currentItem->setPinchViewportScrollPoint(m_frame->host()->pinchViewport().visibleRect().location());
211 m_currentItem->setPinchViewportScrollPoint(FloatPoint(-1, -1));
213 if (m_frame->isMainFrame())
214 m_currentItem->setPageScaleFactor(m_frame->page()->pageScaleFactor());
216 client()->didUpdateCurrentHistoryItem();
219 void FrameLoader::clearScrollPositionAndViewState()
221 ASSERT(m_frame->isMainFrame());
224 m_currentItem->clearScrollPoint();
225 m_currentItem->setPageScaleFactor(0);
228 bool FrameLoader::closeURL()
232 // Should only send the pagehide event here if the current document exists.
233 if (m_frame->document())
234 m_frame->document()->dispatchUnloadEvents();
237 if (Page* page = m_frame->page())
238 page->undoStack().didUnloadFrame(*m_frame);
242 void FrameLoader::didExplicitOpen()
244 // Calling document.open counts as committing the first real document load.
245 if (!m_stateMachine.committedFirstRealDocumentLoad()) {
246 m_stateMachine.advanceTo(FrameLoaderStateMachine::CommittedFirstRealLoad);
247 m_progressTracker->progressStarted();
250 // Prevent window.open(url) -- eg window.open("about:blank") -- from blowing away results
251 // from a subsequent window.document.open / window.document.write call.
252 // Canceling redirection here works for all cases because document.open
253 // implicitly precedes document.write.
254 m_frame->navigationScheduler().cancel();
257 void FrameLoader::clear()
259 // clear() is called during (Local)Frame detachment or when
260 // reusing a FrameLoader by putting a new Document within it
261 // (DocumentLoader::ensureWriter().)
262 if (m_stateMachine.creatingInitialEmptyDocument())
265 m_frame->editor().clear();
266 m_frame->document()->cancelParsing();
267 m_frame->document()->prepareForDestruction();
268 m_frame->document()->removeFocusedElementOfSubtree(m_frame->document());
269 m_frame->selection().prepareForDestruction();
270 m_frame->eventHandler().clear();
272 m_frame->view()->clear();
274 m_frame->script().enableEval();
276 m_frame->navigationScheduler().cancel();
280 if (m_stateMachine.isDisplayingInitialEmptyDocument())
281 m_stateMachine.advanceTo(FrameLoaderStateMachine::CommittedFirstRealLoad);
284 // This is only called by ScriptController::executeScriptIfJavaScriptURL
285 // and always contains the result of evaluating a javascript: url.
286 // This is the <iframe src="javascript:'html'"> case.
287 void FrameLoader::replaceDocumentWhileExecutingJavaScriptURL(const String& source, Document* ownerDocument)
289 if (!m_frame->document()->loader())
292 // DocumentLoader::replaceDocumentWhileExecutingJavaScriptURL can cause the DocumentLoader to get deref'ed and possible destroyed,
293 // so protect it with a RefPtr.
294 RefPtr<DocumentLoader> documentLoader(m_frame->document()->loader());
296 UseCounter::count(*m_frame->document(), UseCounter::ReplaceDocumentViaJavaScriptURL);
298 // Prepare a DocumentInit before clearing the frame, because it may need to
299 // inherit an aliased security context.
300 DocumentInit init(m_frame->document()->url(), m_frame);
301 init.withNewRegistrationContext();
306 // clear() potentially detaches the frame from the document. The
307 // loading cannot continue in that case.
308 if (!m_frame->page())
311 documentLoader->replaceDocumentWhileExecutingJavaScriptURL(init, source, ownerDocument);
314 void FrameLoader::setHistoryItemStateForCommit(HistoryCommitType historyCommitType, bool isPushOrReplaceState, PassRefPtr<SerializedScriptValue> stateObject)
316 if (m_provisionalItem)
317 m_currentItem = m_provisionalItem.release();
319 if (!m_currentItem || historyCommitType == StandardCommit) {
320 m_currentItem = HistoryItem::create();
321 } else if (!isPushOrReplaceState && m_documentLoader->url() != m_currentItem->url()) {
322 m_currentItem->generateNewItemSequenceNumber();
323 if (!equalIgnoringFragmentIdentifier(m_documentLoader->url(), m_currentItem->url()))
324 m_currentItem->generateNewDocumentSequenceNumber();
327 m_currentItem->setURL(m_documentLoader->urlForHistory());
328 m_currentItem->setDocumentState(m_frame->document()->formElementsState());
329 m_currentItem->setTarget(m_frame->tree().uniqueName());
330 if (isPushOrReplaceState)
331 m_currentItem->setStateObject(stateObject);
332 m_currentItem->setReferrer(Referrer(m_documentLoader->request().httpReferrer(), m_documentLoader->request().referrerPolicy()));
333 m_currentItem->setFormInfoFromRequest(m_documentLoader->request());
336 static HistoryCommitType loadTypeToCommitType(FrameLoadType type)
339 case FrameLoadTypeStandard:
340 return StandardCommit;
341 case FrameLoadTypeInitialInChildFrame:
342 case FrameLoadTypeInitialHistoryLoad:
343 return InitialCommitInChildFrame;
344 case FrameLoadTypeBackForward:
345 return BackForwardCommit;
349 return HistoryInertCommit;
352 void FrameLoader::receivedFirstData()
354 if (m_stateMachine.creatingInitialEmptyDocument())
357 HistoryCommitType historyCommitType = loadTypeToCommitType(m_loadType);
358 if (historyCommitType == StandardCommit && (m_documentLoader->urlForHistory().isEmpty() || (opener() && !m_currentItem && m_documentLoader->originalRequest().url().isEmpty())))
359 historyCommitType = HistoryInertCommit;
360 else if (historyCommitType == InitialCommitInChildFrame && (!m_frame->tree().top()->isLocalFrame() || MixedContentChecker::isMixedContent(toLocalFrame(m_frame->tree().top())->document()->securityOrigin(), m_documentLoader->url())))
361 historyCommitType = HistoryInertCommit;
362 setHistoryItemStateForCommit(historyCommitType);
364 if (!m_stateMachine.committedMultipleRealLoads() && m_loadType == FrameLoadTypeStandard)
365 m_stateMachine.advanceTo(FrameLoaderStateMachine::CommittedMultipleRealLoads);
367 client()->dispatchDidCommitLoad(m_frame, m_currentItem.get(), historyCommitType);
369 InspectorInstrumentation::didCommitLoad(m_frame, m_documentLoader.get());
370 m_frame->page()->didCommitLoad(m_frame);
371 dispatchDidClearDocumentOfWindowObject();
374 void FrameLoader::didBeginDocument(bool dispatch)
376 m_frame->document()->setReadyState(Document::Loading);
379 dispatchDidClearDocumentOfWindowObject();
381 m_frame->document()->initContentSecurityPolicy(m_documentLoader ? m_documentLoader->releaseContentSecurityPolicy() : ContentSecurityPolicy::create());
383 Settings* settings = m_frame->document()->settings();
385 m_frame->document()->fetcher()->setImagesEnabled(settings->imagesEnabled());
386 m_frame->document()->fetcher()->setAutoLoadImages(settings->loadsImagesAutomatically());
389 if (m_documentLoader) {
390 const AtomicString& dnsPrefetchControl = m_documentLoader->response().httpHeaderField("X-DNS-Prefetch-Control");
391 if (!dnsPrefetchControl.isEmpty())
392 m_frame->document()->parseDNSPrefetchControlHeader(dnsPrefetchControl);
394 String headerContentLanguage = m_documentLoader->response().httpHeaderField("Content-Language");
395 if (!headerContentLanguage.isEmpty()) {
396 size_t commaIndex = headerContentLanguage.find(',');
397 headerContentLanguage.truncate(commaIndex); // kNotFound == -1 == don't truncate
398 headerContentLanguage = headerContentLanguage.stripWhiteSpace(isHTMLSpace<UChar>);
399 if (!headerContentLanguage.isEmpty())
400 m_frame->document()->setContentLanguage(AtomicString(headerContentLanguage));
404 if (m_provisionalItem && (m_loadType == FrameLoadTypeBackForward || m_loadType == FrameLoadTypeInitialHistoryLoad))
405 m_frame->document()->setStateForNewFormElements(m_provisionalItem->documentState());
408 void FrameLoader::finishedParsing()
410 if (m_stateMachine.creatingInitialEmptyDocument())
413 // This can be called from the LocalFrame's destructor, in which case we shouldn't protect ourselves
414 // because doing so will cause us to re-enter the destructor when protector goes out of scope.
415 // Null-checking the FrameView indicates whether or not we're in the destructor.
416 RefPtrWillBeRawPtr<LocalFrame> protect(m_frame->view() ? m_frame.get() : nullptr);
419 client()->dispatchDidFinishDocumentLoad();
423 if (!m_frame->view())
424 return; // We are being destroyed by something checkCompleted called.
426 // Check if the scrollbars are really needed for the content.
427 // If not, remove them, relayout, and repaint.
428 m_frame->view()->restoreScrollbar();
429 scrollToFragmentWithParentBoundary(m_frame->document()->url());
432 void FrameLoader::loadDone()
437 bool FrameLoader::allChildrenAreComplete() const
439 for (Frame* child = m_frame->tree().firstChild(); child; child = child->tree().nextSibling()) {
440 if (!child->isLocalFrame())
442 LocalFrame* frame = toLocalFrame(child);
443 if (!frame->document()->isLoadCompleted() || frame->loader().m_provisionalDocumentLoader)
449 bool FrameLoader::allAncestorsAreComplete() const
451 for (Frame* ancestor = m_frame; ancestor; ancestor = ancestor->tree().parent()) {
452 if (ancestor->isLocalFrame() && !toLocalFrame(ancestor)->document()->loadEventFinished())
458 void FrameLoader::checkCompleted()
460 RefPtrWillBeRawPtr<LocalFrame> protect(m_frame.get());
463 m_frame->view()->handleLoadCompleted();
465 if (m_frame->document()->isLoadCompleted() && m_stateMachine.committedFirstRealDocumentLoad())
468 // Are we still parsing?
469 if (m_frame->document()->parsing())
472 // Still waiting imports?
473 if (!m_frame->document()->haveImportsLoaded())
476 // Still waiting for images/scripts?
477 if (m_frame->document()->fetcher()->requestCount())
480 // Still waiting for elements that don't go through a FrameLoader?
481 if (m_frame->document()->isDelayingLoadEvent())
484 // Any frame that hasn't completed yet?
485 if (!allChildrenAreComplete())
489 m_frame->document()->setReadyState(Document::Complete);
490 if (m_frame->document()->loadEventStillNeeded())
491 m_frame->document()->implicitClose();
493 m_frame->navigationScheduler().startTimer();
500 m_frame->view()->handleLoadCompleted();
503 void FrameLoader::checkTimerFired(Timer<FrameLoader>*)
505 if (Page* page = m_frame->page()) {
506 if (page->defersLoading())
512 void FrameLoader::scheduleCheckCompleted()
514 if (!m_checkTimer.isActive())
515 m_checkTimer.startOneShot(0, FROM_HERE);
518 Frame* FrameLoader::opener()
520 return client() ? client()->opener() : 0;
523 void FrameLoader::setOpener(LocalFrame* opener)
525 // If the frame is already detached, the opener has already been cleared.
527 client()->setOpener(opener);
530 bool FrameLoader::allowPlugins(ReasonForCallingAllowPlugins reason)
532 // With Oilpan, a FrameLoader might be accessed after the
533 // FrameHost has been detached. FrameClient will not be
534 // accessible, so bail early.
537 Settings* settings = m_frame->settings();
538 bool allowed = client()->allowPlugins(settings && settings->pluginsEnabled());
539 if (!allowed && reason == AboutToInstantiatePlugin)
540 client()->didNotAllowPlugins();
544 void FrameLoader::updateForSameDocumentNavigation(const KURL& newURL, SameDocumentNavigationSource sameDocumentNavigationSource, PassRefPtr<SerializedScriptValue> data, FrameLoadType type)
546 // Update the data source's request with the new URL to fake the URL change
547 m_frame->document()->setURL(newURL);
548 documentLoader()->updateForSameDocumentNavigation(newURL, sameDocumentNavigationSource);
550 // Generate start and stop notifications only when loader is completed so that we
551 // don't fire them for fragment redirection that happens in window.onload handler.
552 // See https://bugs.webkit.org/show_bug.cgi?id=31838
553 if (m_frame->document()->loadEventFinished())
554 client()->didStartLoading(NavigationWithinSameDocument);
556 HistoryCommitType historyCommitType = loadTypeToCommitType(type);
558 historyCommitType = HistoryInertCommit;
560 setHistoryItemStateForCommit(historyCommitType, sameDocumentNavigationSource == SameDocumentNavigationHistoryApi, data);
561 client()->dispatchDidNavigateWithinPage(m_currentItem.get(), historyCommitType);
562 client()->dispatchDidReceiveTitle(m_frame->document()->title());
563 if (m_frame->document()->loadEventFinished())
564 client()->didStopLoading();
567 void FrameLoader::loadInSameDocument(const KURL& url, PassRefPtr<SerializedScriptValue> stateObject, FrameLoadType type, ClientRedirectPolicy clientRedirect)
569 // If we have a state object, we cannot also be a new navigation.
570 ASSERT(!stateObject || type == FrameLoadTypeBackForward);
572 // If we have a provisional request for a different document, a fragment scroll should cancel it.
573 if (m_provisionalDocumentLoader) {
574 m_provisionalDocumentLoader->stopLoading();
575 if (m_provisionalDocumentLoader)
576 m_provisionalDocumentLoader->detachFromFrame();
577 m_provisionalDocumentLoader = nullptr;
578 if (!m_frame->host())
584 KURL oldURL = m_frame->document()->url();
585 // If we were in the autoscroll/panScroll mode we want to stop it before following the link to the anchor
586 bool hashChange = equalIgnoringFragmentIdentifier(url, oldURL) && url.fragmentIdentifier() != oldURL.fragmentIdentifier();
588 m_frame->eventHandler().stopAutoscroll();
589 m_frame->domWindow()->enqueueHashchangeEvent(oldURL, url);
591 m_documentLoader->setIsClientRedirect(clientRedirect == ClientRedirect);
592 m_documentLoader->setReplacesCurrentHistoryItem(m_loadType == FrameLoadTypeStandard);
593 updateForSameDocumentNavigation(url, SameDocumentNavigationDefault, nullptr, type);
595 m_frame->view()->setWasScrolledByUser(false);
597 // We need to scroll to the fragment whether or not a hash change occurred, since
598 // the user might have scrolled since the previous navigation.
599 scrollToFragmentWithParentBoundary(url);
602 m_frame->domWindow()->statePopped(stateObject ? stateObject : SerializedScriptValue::nullValue());
605 void FrameLoader::completed()
607 RefPtrWillBeRawPtr<LocalFrame> protect(m_frame.get());
609 for (Frame* descendant = m_frame->tree().traverseNext(m_frame); descendant; descendant = descendant->tree().traverseNext(m_frame)) {
610 if (descendant->isLocalFrame())
611 toLocalFrame(descendant)->navigationScheduler().startTimer();
614 Frame* parent = m_frame->tree().parent();
615 if (parent && parent->isLocalFrame())
616 toLocalFrame(parent)->loader().checkCompleted();
619 m_frame->view()->maintainScrollPositionAtAnchor(0);
622 void FrameLoader::setReferrerForFrameRequest(ResourceRequest& request, ShouldSendReferrer shouldSendReferrer, Document* originDocument)
626 // FIXME: This should be an assertion, but there's some plugin code in the chromium repo
627 // that both determines its own referrer and expects to be associated with an originDocument.
628 if (!request.httpReferrer().isEmpty())
630 if (shouldSendReferrer == NeverSendReferrer)
633 // Always use the initiating document to generate the referrer.
634 // We need to generateReferrer(), because we haven't enforced ReferrerPolicy or https->http
635 // referrer suppression yet.
636 Referrer referrer = SecurityPolicy::generateReferrer(originDocument->referrerPolicy(), request.url(), originDocument->outgoingReferrer());
638 request.setHTTPReferrer(referrer);
639 RefPtr<SecurityOrigin> referrerOrigin = SecurityOrigin::createFromString(referrer.referrer);
640 request.addHTTPOriginIfNeeded(referrerOrigin->toAtomicString());
643 bool FrameLoader::isScriptTriggeredFormSubmissionInChildFrame(const FrameLoadRequest& request) const
645 // If this is a child frame and the form submission was triggered by a script, lock the back/forward list
646 // to match IE and Opera.
647 // See https://bugs.webkit.org/show_bug.cgi?id=32383 for the original motivation for this.
648 if (!m_frame->tree().parent() || UserGestureIndicator::processingUserGesture())
650 return request.formState() && request.formState()->formSubmissionTrigger() == SubmittedByJavaScript;
653 FrameLoadType FrameLoader::determineFrameLoadType(const FrameLoadRequest& request)
655 if (m_frame->tree().parent() && !m_stateMachine.committedFirstRealDocumentLoad())
656 return FrameLoadTypeInitialInChildFrame;
657 if (!m_frame->tree().parent() && !client()->backForwardLength())
658 return FrameLoadTypeStandard;
659 if (m_provisionalDocumentLoader && request.substituteData().failingURL() == m_provisionalDocumentLoader->url() && m_loadType == FrameLoadTypeBackForward)
660 return FrameLoadTypeBackForward;
661 if (request.resourceRequest().cachePolicy() == ReloadIgnoringCacheData)
662 return FrameLoadTypeReload;
663 if (request.resourceRequest().cachePolicy() == ReloadBypassingCache)
664 return FrameLoadTypeReloadFromOrigin;
665 if (request.lockBackForwardList() || isScriptTriggeredFormSubmissionInChildFrame(request))
666 return FrameLoadTypeRedirectWithLockedBackForwardList;
667 if (!request.originDocument() && request.resourceRequest().url() == m_documentLoader->urlForHistory())
668 return FrameLoadTypeSame;
669 if (request.substituteData().failingURL() == m_documentLoader->urlForHistory() && m_loadType == FrameLoadTypeReload)
670 return FrameLoadTypeReload;
671 return FrameLoadTypeStandard;
674 bool FrameLoader::prepareRequestForThisFrame(FrameLoadRequest& request)
676 request.resourceRequest().setFrameType(m_frame->isMainFrame() ? WebURLRequest::FrameTypeTopLevel : WebURLRequest::FrameTypeNested);
678 // If no origin Document* was specified, skip remaining security checks and assume the caller has fully initialized the FrameLoadRequest.
679 if (!request.originDocument())
682 KURL url = request.resourceRequest().url();
683 if (m_frame->script().executeScriptIfJavaScriptURL(url))
686 if (!request.originDocument()->securityOrigin()->canDisplay(url)) {
687 reportLocalLoadFailed(m_frame, url.elidedString());
691 if (!request.formState() && request.frameName().isEmpty())
692 request.setFrameName(m_frame->document()->baseTarget());
696 static bool shouldOpenInNewWindow(LocalFrame* targetFrame, const FrameLoadRequest& request, const NavigationAction& action)
698 if (!targetFrame && !request.frameName().isEmpty())
700 // FIXME: This case is a workaround for the fact that ctrl+clicking a form submission incorrectly
701 // sends as a GET rather than a POST if it creates a new window in a different process.
702 return request.formState() && action.shouldOpenInNewWindow();
705 static WebURLRequest::RequestContext determineRequestContextFromNavigationType(const NavigationType navigationType)
707 switch (navigationType) {
708 case NavigationTypeLinkClicked:
709 return WebURLRequest::RequestContextHyperlink;
711 case NavigationTypeOther:
712 return WebURLRequest::RequestContextLocation;
714 case NavigationTypeFormResubmitted:
715 case NavigationTypeFormSubmitted:
716 return WebURLRequest::RequestContextForm;
718 case NavigationTypeBackForward:
719 case NavigationTypeReload:
720 return WebURLRequest::RequestContextInternal;
722 ASSERT_NOT_REACHED();
723 return WebURLRequest::RequestContextHyperlink;
726 void FrameLoader::load(const FrameLoadRequest& passedRequest)
728 ASSERT(m_frame->document());
730 RefPtrWillBeRawPtr<LocalFrame> protect(m_frame.get());
732 if (m_inStopAllLoaders)
735 FrameLoadRequest request(passedRequest);
736 if (!prepareRequestForThisFrame(request))
739 RefPtrWillBeRawPtr<LocalFrame> targetFrame = request.formState() ? 0 : findFrameForNavigation(AtomicString(request.frameName()), request.formState() ? request.formState()->sourceDocument() : m_frame->document());
740 if (targetFrame && targetFrame.get() != m_frame) {
741 request.setFrameName("_self");
742 targetFrame->loader().load(request);
743 if (Page* page = targetFrame->page())
744 page->chrome().focus();
748 setReferrerForFrameRequest(request.resourceRequest(), request.shouldSendReferrer(), request.originDocument());
750 FrameLoadType newLoadType = determineFrameLoadType(request);
751 NavigationAction action(request.resourceRequest(), newLoadType, request.formState(), request.triggeringEvent());
752 if (action.resourceRequest().requestContext() == WebURLRequest::RequestContextUnspecified)
753 action.mutableResourceRequest().setRequestContext(determineRequestContextFromNavigationType(action.type()));
754 if (shouldOpenInNewWindow(targetFrame.get(), request, action)) {
755 if (action.policy() == NavigationPolicyDownload)
756 client()->loadURLExternally(action.resourceRequest(), NavigationPolicyDownload);
758 createWindowForRequest(request, *m_frame, action.policy(), request.shouldSendReferrer());
762 const KURL& url = request.resourceRequest().url();
763 if (!action.shouldOpenInNewWindow() && shouldPerformFragmentNavigation(request.formState(), request.resourceRequest().httpMethod(), newLoadType, url)) {
764 m_documentLoader->setTriggeringAction(action);
765 if (shouldTreatURLAsSameAsCurrent(url))
766 newLoadType = FrameLoadTypeRedirectWithLockedBackForwardList;
767 loadInSameDocument(url, nullptr, newLoadType, request.clientRedirect());
770 bool sameURL = url == m_documentLoader->urlForHistory();
771 loadWithNavigationAction(action, newLoadType, request.formState(), request.substituteData(), request.shouldCheckMainWorldContentSecurityPolicy(), request.clientRedirect());
772 // Example of this case are sites that reload the same URL with a different cookie
773 // driving the generated content, or a master frame with links that drive a target
774 // frame, where the user has clicked on the same link repeatedly.
775 if (sameURL && newLoadType != FrameLoadTypeReload && newLoadType != FrameLoadTypeReloadFromOrigin && request.resourceRequest().httpMethod() != "POST")
776 m_loadType = FrameLoadTypeSame;
779 SubstituteData FrameLoader::defaultSubstituteDataForURL(const KURL& url)
781 if (!shouldTreatURLAsSrcdocDocument(url))
782 return SubstituteData();
783 String srcdoc = m_frame->deprecatedLocalOwner()->fastGetAttribute(srcdocAttr);
784 ASSERT(!srcdoc.isNull());
785 CString encodedSrcdoc = srcdoc.utf8();
786 return SubstituteData(SharedBuffer::create(encodedSrcdoc.data(), encodedSrcdoc.length()), "text/html", "UTF-8", KURL());
789 void FrameLoader::reportLocalLoadFailed(LocalFrame* frame, const String& url)
791 ASSERT(!url.isEmpty());
795 frame->document()->addConsoleMessage(ConsoleMessage::create(SecurityMessageSource, ErrorMessageLevel, "Not allowed to load local resource: " + url));
799 ResourceRequest FrameLoader::requestFromHistoryItem(HistoryItem* item, ResourceRequestCachePolicy cachePolicy)
801 RefPtr<FormData> formData = item->formData();
802 ResourceRequest request(item->url());
803 request.setHTTPReferrer(item->referrer());
804 request.setCachePolicy(cachePolicy);
806 request.setHTTPMethod("POST");
807 request.setHTTPBody(formData);
808 request.setHTTPContentType(item->formContentType());
809 RefPtr<SecurityOrigin> securityOrigin = SecurityOrigin::createFromString(item->referrer().referrer);
810 request.addHTTPOriginIfNeeded(securityOrigin->toAtomicString());
815 void FrameLoader::reload(ReloadPolicy reloadPolicy, const KURL& overrideURL, ClientRedirectPolicy clientRedirectPolicy)
820 ResourceRequestCachePolicy cachePolicy = reloadPolicy == EndToEndReload ? ReloadBypassingCache : ReloadIgnoringCacheData;
821 ResourceRequest request = requestFromHistoryItem(m_currentItem.get(), cachePolicy);
822 request.setFrameType(m_frame->isMainFrame() ? WebURLRequest::FrameTypeTopLevel : WebURLRequest::FrameTypeNested);
823 request.setRequestContext(WebURLRequest::RequestContextInternal);
825 // ClientRedirectPolicy is an indication that this load was triggered by
826 // some direct interaction with the page. If this reload is not a client
827 // redirect, we should reuse the referrer from the original load of the
828 // current document. If this reload is a client redirect (e.g., location.reload()),
829 // it was initiated by something in the current document and should
830 // therefore show the current document's url as the referrer.
831 if (clientRedirectPolicy == ClientRedirect)
832 request.setHTTPReferrer(Referrer(m_frame->document()->outgoingReferrer(), m_frame->document()->referrerPolicy()));
834 if (!overrideURL.isEmpty()) {
835 request.setURL(overrideURL);
836 request.clearHTTPReferrer();
838 request.setSkipServiceWorker(reloadPolicy == EndToEndReload);
840 FrameLoadType type = reloadPolicy == EndToEndReload ? FrameLoadTypeReloadFromOrigin : FrameLoadTypeReload;
841 loadWithNavigationAction(NavigationAction(request, type), type, nullptr, SubstituteData(), CheckContentSecurityPolicy, clientRedirectPolicy);
844 void FrameLoader::stopAllLoaders()
846 if (m_frame->document()->pageDismissalEventBeingDispatched() != Document::NoDismissal)
849 // If this method is called from within this method, infinite recursion can occur (3442218). Avoid this.
850 if (m_inStopAllLoaders)
853 // Calling stopLoading() on the provisional document loader can blow away
854 // the frame from underneath.
855 RefPtrWillBeRawPtr<LocalFrame> protect(m_frame.get());
857 m_inStopAllLoaders = true;
859 for (RefPtrWillBeRawPtr<Frame> child = m_frame->tree().firstChild(); child; child = child->tree().nextSibling()) {
860 if (child->isLocalFrame())
861 toLocalFrame(child.get())->loader().stopAllLoaders();
863 if (m_provisionalDocumentLoader)
864 m_provisionalDocumentLoader->stopLoading();
865 if (m_documentLoader)
866 m_documentLoader->stopLoading();
868 if (m_provisionalDocumentLoader)
869 m_provisionalDocumentLoader->detachFromFrame();
870 m_provisionalDocumentLoader = nullptr;
874 m_inStopAllLoaders = false;
876 // detachFromParent() can be called multiple times on same LocalFrame, which
877 // means we may no longer have a FrameLoaderClient to talk to.
879 client()->didStopAllLoaders();
882 void FrameLoader::didAccessInitialDocument()
884 // We only need to notify the client once, and only for the main frame.
885 if (isLoadingMainFrame() && !m_didAccessInitialDocument) {
886 m_didAccessInitialDocument = true;
887 // Notify asynchronously, since this is called within a JavaScript security check.
888 m_didAccessInitialDocumentTimer.startOneShot(0, FROM_HERE);
892 void FrameLoader::didAccessInitialDocumentTimerFired(Timer<FrameLoader>*)
895 client()->didAccessInitialDocument();
898 void FrameLoader::notifyIfInitialDocumentAccessed()
900 if (m_didAccessInitialDocumentTimer.isActive()) {
901 m_didAccessInitialDocumentTimer.stop();
902 didAccessInitialDocumentTimerFired(0);
906 void FrameLoader::commitProvisionalLoad()
908 ASSERT(client()->hasWebView());
909 ASSERT(m_state == FrameStateProvisional);
910 RefPtr<DocumentLoader> pdl = m_provisionalDocumentLoader;
911 RefPtrWillBeRawPtr<LocalFrame> protect(m_frame.get());
913 // Check if the destination page is allowed to access the previous page's timing information.
914 if (m_frame->document()) {
915 RefPtr<SecurityOrigin> securityOrigin = SecurityOrigin::create(pdl->request().url());
916 pdl->timing()->setHasSameOriginAsPreviousDocument(securityOrigin->canRequest(m_frame->document()->url()));
919 // The call to closeURL() invokes the unload event handler, which can execute arbitrary
920 // JavaScript. If the script initiates a new load, we need to abandon the current load,
921 // or the two will stomp each other.
922 // detachChildren will similarly trigger child frame unload event handlers.
923 if (m_documentLoader) {
924 client()->dispatchWillClose();
927 m_frame->detachChildren();
928 if (pdl != m_provisionalDocumentLoader)
930 if (m_documentLoader)
931 m_documentLoader->detachFromFrame();
932 m_documentLoader = m_provisionalDocumentLoader.release();
933 m_state = FrameStateCommittedPage;
935 if (isLoadingMainFrame())
936 m_frame->page()->chrome().client().needTouchEvents(false);
938 client()->transitionToCommittedForNewPage();
939 m_frame->navigationScheduler().cancel();
940 m_frame->editor().clearLastEditCommand();
942 // If we are still in the process of initializing an empty document then
943 // its frame is not in a consistent state for rendering, so avoid setJSStatusBarText
944 // since it may cause clients to attempt to render the frame.
945 if (!m_stateMachine.creatingInitialEmptyDocument()) {
946 LocalDOMWindow* window = m_frame->domWindow();
947 window->setStatus(String());
948 window->setDefaultStatus(String());
952 bool FrameLoader::isLoadingMainFrame() const
954 return m_frame->isMainFrame();
957 FrameLoadType FrameLoader::loadType() const
962 #if defined(ENABLE_LOAD_COMPLETION_HACKS)
963 // This function is an incomprehensible mess and is only used in checkLoadCompleteForThisFrame.
964 // If you're thinking of using it elsewhere, stop right now and reconsider your life.
965 static bool isDocumentDoneLoading(Document* document)
967 if (!document->loader())
969 if (document->loader()->isLoadingMainResource())
971 if (!document->loadEventFinished())
973 if (document->fetcher()->requestCount())
975 if (document->processingLoadEvent())
977 if (document->hasActiveParser())
983 bool FrameLoader::checkLoadCompleteForThisFrame()
985 ASSERT(client()->hasWebView());
986 RefPtrWillBeRawPtr<LocalFrame> protect(m_frame.get());
988 bool allChildrenAreDoneLoading = true;
989 for (RefPtrWillBeRawPtr<Frame> child = m_frame->tree().firstChild(); child; child = child->tree().nextSibling()) {
990 if (child->isLocalFrame())
991 allChildrenAreDoneLoading &= toLocalFrame(child.get())->loader().checkLoadCompleteForThisFrame();
994 if (m_state == FrameStateProvisional && m_provisionalDocumentLoader) {
995 const ResourceError& error = m_provisionalDocumentLoader->mainDocumentError();
998 RefPtr<DocumentLoader> loader = m_provisionalDocumentLoader;
999 client()->dispatchDidFailProvisionalLoad(error);
1000 if (loader != m_provisionalDocumentLoader)
1002 m_provisionalDocumentLoader->detachFromFrame();
1003 m_provisionalDocumentLoader = nullptr;
1004 m_progressTracker->progressCompleted();
1005 m_state = FrameStateComplete;
1010 if (!allChildrenAreDoneLoading)
1013 if (m_state == FrameStateComplete)
1015 if (m_provisionalDocumentLoader || !m_documentLoader)
1018 #if defined(ENABLE_LOAD_COMPLETION_HACKS)
1019 if (!isDocumentDoneLoading(m_frame->document()) && !m_inStopAllLoaders)
1022 if (m_inStopAllLoaders)
1023 m_frame->document()->suppressLoadEvent();
1024 if (!m_frame->document()->loadEventFinished())
1028 m_state = FrameStateComplete;
1030 // FIXME: Is this subsequent work important if we already navigated away?
1031 // Maybe there are bugs because of that, or extra work we can skip because
1032 // the new page is ready.
1034 // Retry restoring scroll offset since FrameStateComplete disables content
1036 restoreScrollPositionAndViewState();
1038 if (!m_stateMachine.committedFirstRealDocumentLoad())
1041 m_progressTracker->progressCompleted();
1042 m_frame->domWindow()->finishedLoading();
1044 const ResourceError& error = m_documentLoader->mainDocumentError();
1045 if (!error.isNull()) {
1046 client()->dispatchDidFailLoad(error);
1048 // Report mobile vs. desktop page statistics. This will only report on Android.
1049 if (m_frame->isMainFrame())
1050 m_frame->document()->viewportDescription().reportMobilePageStats(m_frame);
1052 client()->dispatchDidFinishLoad();
1054 m_loadType = FrameLoadTypeStandard;
1058 void FrameLoader::restoreScrollPositionAndViewState()
1060 FrameView* view = m_frame->view();
1061 if (!m_frame->page() || !view || !m_currentItem || !m_stateMachine.committedFirstRealDocumentLoad())
1064 if (!needsHistoryItemRestore(m_loadType))
1067 // This tries to balance 1. restoring as soon as possible, 2. detecting
1068 // clamping to avoid repeatedly popping the scroll position down as the
1069 // page height increases, 3. ignore clamp detection after load completes
1070 // because that may be because the page will never reach its previous
1072 float mainFrameScale = m_frame->settings()->pinchVirtualViewportEnabled() ? 1 : m_currentItem->pageScaleFactor();
1073 bool canRestoreWithoutClamping = view->clampOffsetAtScale(m_currentItem->scrollPoint(), mainFrameScale) == m_currentItem->scrollPoint();
1074 bool canRestoreWithoutAnnoyingUser = !view->wasScrolledByUser() && (canRestoreWithoutClamping || m_state == FrameStateComplete);
1075 if (!canRestoreWithoutAnnoyingUser)
1078 if (m_frame->isMainFrame() && m_currentItem->pageScaleFactor()) {
1079 FloatPoint pinchViewportOffset(m_currentItem->pinchViewportScrollPoint());
1080 IntPoint frameScrollOffset(m_currentItem->scrollPoint());
1082 m_frame->page()->setPageScaleFactor(m_currentItem->pageScaleFactor(), frameScrollOffset);
1084 if (m_frame->settings()->pinchVirtualViewportEnabled()) {
1085 // If the pinch viewport's offset is (-1, -1) it means the history item
1086 // is an old version of HistoryItem so distribute the scroll between
1087 // the main frame and the pinch viewport as best as we can.
1088 // FIXME(bokan): This legacy distribution can be removed once the virtual viewport
1089 // pinch path is enabled on all platforms for at least one release.
1090 if (pinchViewportOffset.x() == -1 && pinchViewportOffset.y() == -1)
1091 pinchViewportOffset = FloatPoint(frameScrollOffset - view->scrollPosition());
1093 m_frame->host()->pinchViewport().setLocation(pinchViewportOffset);
1096 view->setScrollPositionNonProgrammatically(m_currentItem->scrollPoint());
1099 if (m_frame->isMainFrame()) {
1100 if (ScrollingCoordinator* scrollingCoordinator = m_frame->page()->scrollingCoordinator())
1101 scrollingCoordinator->frameViewRootLayerDidChange(view);
1105 // Called every time a resource is completely loaded or an error is received.
1106 void FrameLoader::checkLoadComplete()
1108 ASSERT(client()->hasWebView());
1109 if (Page* page = m_frame->page()) {
1110 if (page->mainFrame()->isLocalFrame())
1111 page->deprecatedLocalMainFrame()->loader().checkLoadCompleteForThisFrame();
1115 String FrameLoader::userAgent(const KURL& url) const
1117 String userAgent = client()->userAgent(url);
1118 InspectorInstrumentation::applyUserAgentOverride(m_frame, &userAgent);
1122 void FrameLoader::detach()
1125 // The caller must protect a reference to m_frame.
1126 ASSERT(m_frame->refCount() > 1);
1128 if (m_documentLoader)
1129 m_documentLoader->detachFromFrame();
1130 m_documentLoader = nullptr;
1132 Frame* parent = m_frame->tree().parent();
1133 if (parent && parent->isLocalFrame())
1134 toLocalFrame(parent)->loader().scheduleCheckCompleted();
1135 m_progressTracker->dispose();
1136 m_progressTracker.clear();
1140 void FrameLoader::receivedMainResourceError(const ResourceError& error)
1142 // Retain because the stop may release the last reference to it.
1143 RefPtrWillBeRawPtr<LocalFrame> protect(m_frame.get());
1145 if (m_frame->document()->parser())
1146 m_frame->document()->parser()->stopParsing();
1148 // FIXME: We really ought to be able to just check for isCancellation() here, but there are some
1149 // ResourceErrors that setIsCancellation() but aren't created by ResourceError::cancelledError().
1150 ResourceError c(ResourceError::cancelledError(KURL()));
1151 if ((error.errorCode() != c.errorCode() || error.domain() != c.domain()) && m_frame->owner()) {
1152 // FIXME: For now, fallback content doesn't work cross process.
1153 ASSERT(m_frame->owner()->isLocal());
1154 m_frame->deprecatedLocalOwner()->renderFallbackContent();
1158 if (m_frame->page())
1159 checkLoadComplete();
1162 bool FrameLoader::shouldPerformFragmentNavigation(bool isFormSubmission, const String& httpMethod, FrameLoadType loadType, const KURL& url)
1164 ASSERT(loadType != FrameLoadTypeReloadFromOrigin);
1165 // We don't do this if we are submitting a form with method other than "GET", explicitly reloading,
1166 // currently displaying a frameset, or if the URL does not have a fragment.
1167 return (!isFormSubmission || equalIgnoringCase(httpMethod, "GET"))
1168 && loadType != FrameLoadTypeReload
1169 && loadType != FrameLoadTypeSame
1170 && loadType != FrameLoadTypeBackForward
1171 && url.hasFragmentIdentifier()
1172 && equalIgnoringFragmentIdentifier(m_frame->document()->url(), url)
1173 // We don't want to just scroll if a link from within a
1174 // frameset is trying to reload the frameset into _top.
1175 && !m_frame->document()->isFrameSet();
1178 void FrameLoader::scrollToFragmentWithParentBoundary(const KURL& url)
1180 FrameView* view = m_frame->view();
1184 // Leaking scroll position to a cross-origin ancestor would permit the so-called "framesniffing" attack.
1185 RefPtrWillBeRawPtr<LocalFrame> boundaryFrame = url.hasFragmentIdentifier() ? m_frame->document()->findUnsafeParentScrollPropagationBoundary() : 0;
1188 boundaryFrame->view()->setSafeToPropagateScrollToParent(false);
1190 view->scrollToFragment(url);
1193 boundaryFrame->view()->setSafeToPropagateScrollToParent(true);
1196 bool FrameLoader::shouldClose()
1198 Page* page = m_frame->page();
1199 if (!page || !page->chrome().canRunBeforeUnloadConfirmPanel())
1202 // Store all references to each subframe in advance since beforeunload's event handler may modify frame
1203 WillBeHeapVector<RefPtrWillBeMember<LocalFrame> > targetFrames;
1204 targetFrames.append(m_frame);
1205 for (Frame* child = m_frame->tree().firstChild(); child; child = child->tree().traverseNext(m_frame)) {
1206 // FIXME: There is not yet any way to dispatch events to out-of-process frames.
1207 if (child->isLocalFrame())
1208 targetFrames.append(toLocalFrame(child));
1211 bool shouldClose = false;
1213 NavigationDisablerForBeforeUnload navigationDisabler;
1216 bool didAllowNavigation = false;
1217 for (i = 0; i < targetFrames.size(); i++) {
1218 if (!targetFrames[i]->tree().isDescendantOf(m_frame))
1220 if (!targetFrames[i]->document()->dispatchBeforeUnloadEvent(page->chrome(), didAllowNavigation))
1224 if (i == targetFrames.size())
1230 bool FrameLoader::validateTransitionNavigationMode()
1232 if (m_frame->document()->inQuirksMode()) {
1233 m_frame->document()->addConsoleMessage(ConsoleMessage::create(JSMessageSource, ErrorMessageLevel, "Ignoring transition elements due to quirks mode."));
1237 // FIXME(oysteine): Also check for width=device-width here, to avoid zoom/scaling issues.
1241 bool FrameLoader::dispatchNavigationTransitionData()
1243 Vector<Document::TransitionElementData> elementData;
1244 m_frame->document()->getTransitionElementData(elementData);
1245 if (elementData.isEmpty() || !validateTransitionNavigationMode())
1248 Vector<Document::TransitionElementData>::iterator iter = elementData.begin();
1249 for (; iter != elementData.end(); ++iter)
1250 client()->dispatchAddNavigationTransitionData(iter->scope, iter->selector, iter->markup);
1255 void FrameLoader::loadWithNavigationAction(const NavigationAction& action, FrameLoadType type, PassRefPtrWillBeRawPtr<FormState> formState, const SubstituteData& substituteData, ContentSecurityPolicyCheck shouldCheckMainWorldContentSecurityPolicy, ClientRedirectPolicy clientRedirect)
1257 ASSERT(client()->hasWebView());
1258 if (m_frame->document()->pageDismissalEventBeingDispatched() != Document::NoDismissal)
1261 const ResourceRequest& request = action.resourceRequest();
1263 // The current load should replace the history item if it is the first real
1264 // load of the frame.
1265 bool replacesCurrentHistoryItem = false;
1266 if (type == FrameLoadTypeRedirectWithLockedBackForwardList
1267 || !m_stateMachine.committedFirstRealDocumentLoad()) {
1268 replacesCurrentHistoryItem = true;
1271 m_policyDocumentLoader = client()->createDocumentLoader(m_frame, request, substituteData.isValid() ? substituteData : defaultSubstituteDataForURL(request.url()));
1272 m_policyDocumentLoader->setTriggeringAction(action);
1273 m_policyDocumentLoader->setReplacesCurrentHistoryItem(replacesCurrentHistoryItem);
1274 m_policyDocumentLoader->setIsClientRedirect(clientRedirect == ClientRedirect);
1276 bool isTransitionNavigation = false;
1277 if (RuntimeEnabledFeatures::navigationTransitionsEnabled() && type != FrameLoadTypeReload && type != FrameLoadTypeReloadFromOrigin && type != FrameLoadTypeSame)
1278 isTransitionNavigation = dispatchNavigationTransitionData();
1280 // stopAllLoaders can detach the LocalFrame, so protect it.
1281 RefPtrWillBeRawPtr<LocalFrame> protect(m_frame.get());
1282 if ((!m_policyDocumentLoader->shouldContinueForNavigationPolicy(request, shouldCheckMainWorldContentSecurityPolicy, isTransitionNavigation) || !shouldClose()) && m_policyDocumentLoader) {
1283 m_policyDocumentLoader->detachFromFrame();
1284 m_policyDocumentLoader = nullptr;
1285 if (!m_stateMachine.committedFirstRealDocumentLoad())
1286 m_state = FrameStateComplete;
1291 if (m_provisionalDocumentLoader) {
1292 m_provisionalDocumentLoader->stopLoading();
1293 if (m_provisionalDocumentLoader)
1294 m_provisionalDocumentLoader->detachFromFrame();
1295 m_provisionalDocumentLoader = nullptr;
1297 m_checkTimer.stop();
1299 // <rdar://problem/6250856> - In certain circumstances on pages with multiple frames, stopAllLoaders()
1300 // might detach the current FrameLoader, in which case we should bail on this newly defunct load.
1301 if (!m_frame->page() || !m_policyDocumentLoader)
1304 if (isLoadingMainFrame())
1305 m_frame->page()->inspectorController().resume();
1306 m_frame->navigationScheduler().cancel();
1308 m_provisionalDocumentLoader = m_policyDocumentLoader.release();
1310 m_state = FrameStateProvisional;
1313 client()->dispatchWillSubmitForm(formState->form());
1315 m_progressTracker->progressStarted();
1316 if (m_provisionalDocumentLoader->isClientRedirect())
1317 m_provisionalDocumentLoader->appendRedirect(m_frame->document()->url());
1318 m_provisionalDocumentLoader->appendRedirect(m_provisionalDocumentLoader->request().url());
1319 client()->dispatchDidStartProvisionalLoad(isTransitionNavigation);
1320 ASSERT(m_provisionalDocumentLoader);
1321 m_provisionalDocumentLoader->startLoadingMainResource();
1324 void FrameLoader::applyUserAgent(ResourceRequest& request)
1326 String userAgent = this->userAgent(request.url());
1327 ASSERT(!userAgent.isNull());
1328 request.setHTTPUserAgent(AtomicString(userAgent));
1331 bool FrameLoader::shouldInterruptLoadForXFrameOptions(const String& content, const KURL& url, unsigned long requestIdentifier)
1333 UseCounter::count(m_frame->domWindow()->document(), UseCounter::XFrameOptions);
1335 Frame* topFrame = m_frame->tree().top();
1336 if (m_frame == topFrame)
1339 XFrameOptionsDisposition disposition = parseXFrameOptionsHeader(content);
1341 switch (disposition) {
1342 case XFrameOptionsSameOrigin: {
1343 UseCounter::count(m_frame->domWindow()->document(), UseCounter::XFrameOptionsSameOrigin);
1344 RefPtr<SecurityOrigin> origin = SecurityOrigin::create(url);
1345 // Out-of-process ancestors are always a different origin.
1346 if (!topFrame->isLocalFrame() || !origin->isSameSchemeHostPort(toLocalFrame(topFrame)->document()->securityOrigin()))
1348 for (Frame* frame = m_frame->tree().parent(); frame; frame = frame->tree().parent()) {
1349 if (!frame->isLocalFrame() || !origin->isSameSchemeHostPort(toLocalFrame(frame)->document()->securityOrigin())) {
1350 UseCounter::count(m_frame->domWindow()->document(), UseCounter::XFrameOptionsSameOriginWithBadAncestorChain);
1356 case XFrameOptionsDeny:
1358 case XFrameOptionsAllowAll:
1360 case XFrameOptionsConflict: {
1361 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'.");
1362 consoleMessage->setRequestIdentifier(requestIdentifier);
1363 m_frame->document()->addConsoleMessage(consoleMessage.release());
1366 case XFrameOptionsInvalid: {
1367 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.");
1368 consoleMessage->setRequestIdentifier(requestIdentifier);
1369 m_frame->document()->addConsoleMessage(consoleMessage.release());
1373 ASSERT_NOT_REACHED();
1378 bool FrameLoader::shouldTreatURLAsSameAsCurrent(const KURL& url) const
1380 return m_currentItem && url == m_currentItem->url();
1383 bool FrameLoader::shouldTreatURLAsSrcdocDocument(const KURL& url) const
1385 if (!equalIgnoringCase(url.string(), "about:srcdoc"))
1387 HTMLFrameOwnerElement* ownerElement = m_frame->deprecatedLocalOwner();
1388 if (!isHTMLIFrameElement(ownerElement))
1390 return ownerElement->fastHasAttribute(srcdocAttr);
1393 LocalFrame* FrameLoader::findFrameForNavigation(const AtomicString& name, Document* activeDocument)
1395 ASSERT(activeDocument);
1396 Frame* frame = m_frame->tree().find(name);
1397 if (!frame || !frame->isLocalFrame() || !activeDocument->canNavigate(toLocalFrame(*frame)))
1399 return toLocalFrame(frame);
1402 void FrameLoader::loadHistoryItem(HistoryItem* item, FrameLoadType frameLoadType, HistoryLoadType historyLoadType, ResourceRequestCachePolicy cachePolicy)
1404 RefPtrWillBeRawPtr<LocalFrame> protect(m_frame.get());
1405 if (m_frame->page()->defersLoading()) {
1406 m_deferredHistoryLoad = DeferredHistoryLoad(item, historyLoadType, cachePolicy);
1410 m_provisionalItem = item;
1411 if (historyLoadType == HistorySameDocumentLoad) {
1412 loadInSameDocument(item->url(), item->stateObject(), frameLoadType, NotClientRedirect);
1413 restoreScrollPositionAndViewState();
1417 ResourceRequest request = requestFromHistoryItem(item, cachePolicy);
1418 request.setFrameType(m_frame->isMainFrame() ? WebURLRequest::FrameTypeTopLevel : WebURLRequest::FrameTypeNested);
1419 request.setRequestContext(WebURLRequest::RequestContextInternal);
1420 loadWithNavigationAction(NavigationAction(request, frameLoadType), frameLoadType, nullptr, SubstituteData(), CheckContentSecurityPolicy);
1423 void FrameLoader::dispatchDocumentElementAvailable()
1425 client()->documentElementAvailable();
1428 void FrameLoader::dispatchDidClearDocumentOfWindowObject()
1430 if (!m_frame->script().canExecuteScripts(NotAboutToExecuteScript))
1433 if (Page* page = m_frame->page())
1434 page->inspectorController().didClearDocumentOfWindowObject(m_frame);
1435 InspectorInstrumentation::didClearDocumentOfWindowObject(m_frame);
1437 // We just cleared the document, not the entire window object, but for the
1438 // embedder that's close enough.
1439 client()->dispatchDidClearWindowObjectInMainWorld();
1442 void FrameLoader::dispatchDidClearWindowObjectInMainWorld()
1444 if (!m_frame->script().canExecuteScripts(NotAboutToExecuteScript))
1447 client()->dispatchDidClearWindowObjectInMainWorld();
1450 SandboxFlags FrameLoader::effectiveSandboxFlags() const
1452 SandboxFlags flags = m_forcedSandboxFlags;
1453 // FIXME: We need a way to propagate sandbox flags to out-of-process frames.
1454 Frame* parentFrame = m_frame->tree().parent();
1455 if (parentFrame && parentFrame->isLocalFrame())
1456 flags |= toLocalFrame(parentFrame)->document()->sandboxFlags();
1457 if (FrameOwner* frameOwner = m_frame->owner())
1458 flags |= frameOwner->sandboxFlags();
1462 } // namespace blink