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 "HTMLNames.h"
39 #include "bindings/v8/DOMWrapperWorld.h"
40 #include "bindings/v8/ScriptController.h"
41 #include "bindings/v8/SerializedScriptValue.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/Event.h"
48 #include "core/events/PageTransitionEvent.h"
49 #include "core/fetch/FetchContext.h"
50 #include "core/fetch/ResourceFetcher.h"
51 #include "core/fetch/ResourceLoader.h"
52 #include "core/frame/DOMWindow.h"
53 #include "core/frame/FrameHost.h"
54 #include "core/frame/FrameView.h"
55 #include "core/frame/LocalFrame.h"
56 #include "core/frame/PinchViewport.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/InspectorController.h"
62 #include "core/inspector/InspectorInstrumentation.h"
63 #include "core/loader/DocumentLoadTiming.h"
64 #include "core/loader/DocumentLoader.h"
65 #include "core/loader/FormState.h"
66 #include "core/loader/FormSubmission.h"
67 #include "core/loader/FrameFetchContext.h"
68 #include "core/loader/FrameLoadRequest.h"
69 #include "core/loader/FrameLoaderClient.h"
70 #include "core/loader/ProgressTracker.h"
71 #include "core/loader/UniqueIdentifier.h"
72 #include "core/loader/appcache/ApplicationCacheHost.h"
73 #include "core/page/BackForwardClient.h"
74 #include "core/page/Chrome.h"
75 #include "core/page/ChromeClient.h"
76 #include "core/page/CreateWindow.h"
77 #include "core/page/EventHandler.h"
78 #include "core/page/FrameTree.h"
79 #include "core/page/Page.h"
80 #include "core/frame/Settings.h"
81 #include "core/page/WindowFeatures.h"
82 #include "core/page/scrolling/ScrollingCoordinator.h"
83 #include "core/xml/parser/XMLDocumentParser.h"
84 #include "platform/Logging.h"
85 #include "platform/UserGestureIndicator.h"
86 #include "platform/geometry/FloatRect.h"
87 #include "platform/network/ContentSecurityPolicyResponseHeaders.h"
88 #include "platform/network/HTTPParsers.h"
89 #include "platform/network/ResourceRequest.h"
90 #include "platform/scroll/ScrollAnimator.h"
91 #include "platform/weborigin/SecurityOrigin.h"
92 #include "platform/weborigin/SecurityPolicy.h"
93 #include "wtf/TemporaryChange.h"
94 #include "wtf/text/CString.h"
95 #include "wtf/text/WTFString.h"
99 using namespace HTMLNames;
101 bool isBackForwardLoadType(FrameLoadType type)
103 return type == FrameLoadTypeBackForward;
106 static bool needsHistoryItemRestore(FrameLoadType type)
108 return type == FrameLoadTypeBackForward || type == FrameLoadTypeReload || type == FrameLoadTypeReloadFromOrigin;
111 FrameLoader::FrameLoader(LocalFrame* frame, FrameLoaderClient* client)
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_isComplete(false)
121 , m_checkTimer(this, &FrameLoader::checkTimerFired)
122 , m_shouldCallCheckCompleted(false)
123 , m_didAccessInitialDocument(false)
124 , m_didAccessInitialDocumentTimer(this, &FrameLoader::didAccessInitialDocumentTimerFired)
125 , m_forcedSandboxFlags(SandboxNone)
129 FrameLoader::~FrameLoader()
133 void FrameLoader::init()
135 m_provisionalDocumentLoader = m_client->createDocumentLoader(m_frame, ResourceRequest(KURL(ParsedURLString, emptyString())), SubstituteData());
136 m_provisionalDocumentLoader->startLoadingMainResource();
137 m_frame->document()->cancelParsing();
138 m_stateMachine.advanceTo(FrameLoaderStateMachine::DisplayingInitialEmptyDocument);
141 void FrameLoader::setDefersLoading(bool defers)
143 if (m_documentLoader)
144 m_documentLoader->setDefersLoading(defers);
145 if (m_provisionalDocumentLoader)
146 m_provisionalDocumentLoader->setDefersLoading(defers);
147 if (m_policyDocumentLoader)
148 m_policyDocumentLoader->setDefersLoading(defers);
151 if (m_deferredHistoryLoad.isValid()) {
152 loadHistoryItem(m_deferredHistoryLoad.m_item.get(), m_deferredHistoryLoad.m_type, m_deferredHistoryLoad.m_cachePolicy);
153 m_deferredHistoryLoad = DeferredHistoryLoad();
155 m_frame->navigationScheduler().startTimer();
156 startCheckCompleteTimer();
160 void FrameLoader::stopLoading()
162 m_isComplete = true; // to avoid calling completed() in finishedParsing()
164 if (m_frame->document() && m_frame->document()->parsing()) {
166 m_frame->document()->setParsing(false);
169 if (Document* doc = m_frame->document()) {
170 // FIXME: HTML5 doesn't tell us to set the state to complete when aborting, but we do anyway to match legacy behavior.
171 // http://www.w3.org/Bugs/Public/show_bug.cgi?id=10537
172 doc->setReadyState(Document::Complete);
175 // FIXME: This will cancel redirection timer, which really needs to be restarted when restoring the frame from b/f cache.
176 m_frame->navigationScheduler().cancel();
179 void FrameLoader::saveScrollState()
181 if (!m_currentItem || !m_frame->view())
184 // Shouldn't clobber anything if we might still restore later.
185 if (needsHistoryItemRestore(m_loadType) && !m_frame->view()->wasScrolledByUser())
188 m_currentItem->setScrollPoint(m_frame->view()->scrollPosition());
190 if (m_frame->settings()->pinchVirtualViewportEnabled())
191 m_currentItem->setPinchViewportScrollPoint(m_frame->host()->pinchViewport().visibleRect().location());
193 m_currentItem->setPinchViewportScrollPoint(FloatPoint(-1, -1));
195 if (m_frame->isMainFrame() && !m_frame->page()->inspectorController().deviceEmulationEnabled())
196 m_currentItem->setPageScaleFactor(m_frame->page()->pageScaleFactor());
198 m_client->didUpdateCurrentHistoryItem();
201 void FrameLoader::clearScrollPositionAndViewState()
203 ASSERT(m_frame->isMainFrame());
206 m_currentItem->clearScrollPoint();
207 m_currentItem->setPageScaleFactor(0);
210 bool FrameLoader::closeURL()
214 // Should only send the pagehide event here if the current document exists.
215 if (m_frame->document())
216 m_frame->document()->dispatchUnloadEvents();
219 if (Page* page = m_frame->page())
220 page->undoStack().didUnloadFrame(*m_frame);
224 void FrameLoader::didExplicitOpen()
226 m_isComplete = false;
228 // Calling document.open counts as committing the first real document load.
229 if (!m_stateMachine.committedFirstRealDocumentLoad())
230 m_stateMachine.advanceTo(FrameLoaderStateMachine::CommittedFirstRealLoad);
232 // Prevent window.open(url) -- eg window.open("about:blank") -- from blowing away results
233 // from a subsequent window.document.open / window.document.write call.
234 // Canceling redirection here works for all cases because document.open
235 // implicitly precedes document.write.
236 m_frame->navigationScheduler().cancel();
239 void FrameLoader::clear()
241 if (m_stateMachine.creatingInitialEmptyDocument())
244 m_frame->editor().clear();
245 m_frame->document()->cancelParsing();
246 m_frame->document()->prepareForDestruction();
247 m_frame->document()->removeFocusedElementOfSubtree(m_frame->document());
249 m_frame->selection().prepareForDestruction();
250 m_frame->eventHandler().clear();
252 m_frame->view()->clear();
254 m_frame->script().enableEval();
256 m_frame->navigationScheduler().clear();
259 m_shouldCallCheckCompleted = false;
261 if (m_stateMachine.isDisplayingInitialEmptyDocument())
262 m_stateMachine.advanceTo(FrameLoaderStateMachine::CommittedFirstRealLoad);
265 void FrameLoader::setHistoryItemStateForCommit(HistoryCommitType historyCommitType, bool isPushOrReplaceState, PassRefPtr<SerializedScriptValue> stateObject)
267 if (m_provisionalItem)
268 m_currentItem = m_provisionalItem.release();
270 if (!m_currentItem || historyCommitType == StandardCommit) {
271 m_currentItem = HistoryItem::create();
272 } else if (!isPushOrReplaceState && m_documentLoader->url() != m_currentItem->url()) {
273 m_currentItem->generateNewItemSequenceNumber();
274 if (!equalIgnoringFragmentIdentifier(m_documentLoader->url(), m_currentItem->url()))
275 m_currentItem->generateNewDocumentSequenceNumber();
278 m_currentItem->setURL(m_documentLoader->urlForHistory());
279 m_currentItem->setDocumentState(m_frame->document()->formElementsState());
280 m_currentItem->setTarget(m_frame->tree().uniqueName());
281 if (isPushOrReplaceState)
282 m_currentItem->setStateObject(stateObject);
283 m_currentItem->setReferrer(Referrer(m_documentLoader->request().httpReferrer(), m_documentLoader->request().referrerPolicy()));
284 m_currentItem->setFormInfoFromRequest(isPushOrReplaceState ? ResourceRequest() : m_documentLoader->request());
287 static HistoryCommitType loadTypeToCommitType(FrameLoadType type, bool isValidHistoryURL)
290 case FrameLoadTypeStandard:
291 return isValidHistoryURL ? StandardCommit : HistoryInertCommit;
292 case FrameLoadTypeInitialInChildFrame:
293 return InitialCommitInChildFrame;
294 case FrameLoadTypeBackForward:
295 return BackForwardCommit;
299 return HistoryInertCommit;
302 void FrameLoader::receivedFirstData()
304 if (m_stateMachine.creatingInitialEmptyDocument())
307 bool isValidHistoryURL = !m_documentLoader->urlForHistory().isEmpty() && (!opener() || m_currentItem || !m_documentLoader->originalRequest().url().isEmpty());
308 HistoryCommitType historyCommitType = loadTypeToCommitType(m_loadType, isValidHistoryURL);
309 setHistoryItemStateForCommit(historyCommitType);
311 if (!m_stateMachine.committedMultipleRealLoads() && m_loadType == FrameLoadTypeStandard)
312 m_stateMachine.advanceTo(FrameLoaderStateMachine::CommittedMultipleRealLoads);
314 m_client->dispatchDidCommitLoad(m_frame, m_currentItem.get(), historyCommitType);
316 InspectorInstrumentation::didCommitLoad(m_frame, m_documentLoader.get());
317 m_frame->page()->didCommitLoad(m_frame);
318 dispatchDidClearDocumentOfWindowObject();
321 static void didFailContentSecurityPolicyCheck(FrameLoader* loader)
323 // load event and stopAllLoaders can detach the LocalFrame, so protect it.
324 RefPtr<LocalFrame> frame(loader->frame());
326 // Move the page to a unique origin, and cancel the load.
327 frame->document()->enforceSandboxFlags(SandboxOrigin);
328 loader->stopAllLoaders();
330 // Fire a load event, as timing attacks would otherwise reveal that the
331 // frame was blocked. This way, it looks like every other cross-origin
333 if (HTMLFrameOwnerElement* ownerElement = frame->ownerElement())
334 ownerElement->dispatchEvent(Event::create(EventTypeNames::load));
337 void FrameLoader::didBeginDocument(bool dispatch)
339 m_isComplete = false;
340 m_frame->document()->setReadyState(Document::Loading);
342 if (m_provisionalItem && m_loadType == FrameLoadTypeBackForward)
343 m_frame->domWindow()->statePopped(m_provisionalItem->stateObject());
346 dispatchDidClearDocumentOfWindowObject();
348 m_frame->document()->initContentSecurityPolicy(m_documentLoader ? ContentSecurityPolicyResponseHeaders(m_documentLoader->response()) : ContentSecurityPolicyResponseHeaders());
350 if (!m_frame->document()->contentSecurityPolicy()->allowAncestors(m_frame)) {
351 didFailContentSecurityPolicyCheck(this);
355 Settings* settings = m_frame->document()->settings();
357 m_frame->document()->fetcher()->setImagesEnabled(settings->imagesEnabled());
358 m_frame->document()->fetcher()->setAutoLoadImages(settings->loadsImagesAutomatically());
361 if (m_documentLoader) {
362 const AtomicString& dnsPrefetchControl = m_documentLoader->response().httpHeaderField("X-DNS-Prefetch-Control");
363 if (!dnsPrefetchControl.isEmpty())
364 m_frame->document()->parseDNSPrefetchControlHeader(dnsPrefetchControl);
366 String headerContentLanguage = m_documentLoader->response().httpHeaderField("Content-Language");
367 if (!headerContentLanguage.isEmpty()) {
368 size_t commaIndex = headerContentLanguage.find(',');
369 headerContentLanguage.truncate(commaIndex); // kNotFound == -1 == don't truncate
370 headerContentLanguage = headerContentLanguage.stripWhiteSpace(isHTMLSpace<UChar>);
371 if (!headerContentLanguage.isEmpty())
372 m_frame->document()->setContentLanguage(AtomicString(headerContentLanguage));
376 if (m_provisionalItem && m_loadType == FrameLoadTypeBackForward)
377 m_frame->document()->setStateForNewFormElements(m_provisionalItem->documentState());
380 void FrameLoader::finishedParsing()
382 if (m_stateMachine.creatingInitialEmptyDocument())
385 // This can be called from the LocalFrame's destructor, in which case we shouldn't protect ourselves
386 // because doing so will cause us to re-enter the destructor when protector goes out of scope.
387 // Null-checking the FrameView indicates whether or not we're in the destructor.
388 RefPtr<LocalFrame> protector = m_frame->view() ? m_frame : 0;
391 m_client->dispatchDidFinishDocumentLoad();
395 if (!m_frame->view())
396 return; // We are being destroyed by something checkCompleted called.
398 // Check if the scrollbars are really needed for the content.
399 // If not, remove them, relayout, and repaint.
400 m_frame->view()->restoreScrollbar();
401 scrollToFragmentWithParentBoundary(m_frame->document()->url());
404 void FrameLoader::loadDone()
409 bool FrameLoader::allChildrenAreComplete() const
411 for (LocalFrame* child = m_frame->tree().firstChild(); child; child = child->tree().nextSibling()) {
412 if (!child->loader().m_isComplete)
418 bool FrameLoader::allAncestorsAreComplete() const
420 for (LocalFrame* ancestor = m_frame; ancestor; ancestor = ancestor->tree().parent()) {
421 if (!ancestor->document()->loadEventFinished())
427 void FrameLoader::checkCompleted()
429 RefPtr<LocalFrame> protect(m_frame);
430 m_shouldCallCheckCompleted = false;
433 m_frame->view()->handleLoadCompleted();
435 // Have we completed before?
439 // Are we still parsing?
440 if (m_frame->document()->parsing())
443 // Still waiting imports?
444 if (!m_frame->document()->haveImportsLoaded())
447 // Still waiting for images/scripts?
448 if (m_frame->document()->fetcher()->requestCount())
451 // Still waiting for elements that don't go through a FrameLoader?
452 if (m_frame->document()->isDelayingLoadEvent())
455 // Any frame that hasn't completed yet?
456 if (!allChildrenAreComplete())
461 m_frame->document()->setReadyState(Document::Complete);
462 if (m_frame->document()->loadEventStillNeeded())
463 m_frame->document()->implicitClose();
465 m_frame->navigationScheduler().startTimer();
472 m_frame->view()->handleLoadCompleted();
475 void FrameLoader::checkTimerFired(Timer<FrameLoader>*)
477 RefPtr<LocalFrame> protect(m_frame);
479 if (Page* page = m_frame->page()) {
480 if (page->defersLoading())
483 if (m_shouldCallCheckCompleted)
487 void FrameLoader::startCheckCompleteTimer()
489 if (!m_shouldCallCheckCompleted)
491 if (m_checkTimer.isActive())
493 m_checkTimer.startOneShot(0, FROM_HERE);
496 void FrameLoader::scheduleCheckCompleted()
498 m_shouldCallCheckCompleted = true;
499 startCheckCompleteTimer();
502 LocalFrame* FrameLoader::opener()
504 // FIXME: Temporary hack to stage converting locations that really should be Frame.
505 return m_client ? toLocalFrame(m_client->opener()) : 0;
508 void FrameLoader::setOpener(LocalFrame* opener)
510 // If the frame is already detached, the opener has already been cleared.
512 m_client->setOpener(opener);
515 bool FrameLoader::allowPlugins(ReasonForCallingAllowPlugins reason)
517 Settings* settings = m_frame->settings();
518 bool allowed = m_client->allowPlugins(settings && settings->pluginsEnabled());
519 if (!allowed && reason == AboutToInstantiatePlugin)
520 m_client->didNotAllowPlugins();
524 void FrameLoader::updateForSameDocumentNavigation(const KURL& newURL, SameDocumentNavigationSource sameDocumentNavigationSource, PassRefPtr<SerializedScriptValue> data, UpdateBackForwardListPolicy updateBackForwardList)
526 // Update the data source's request with the new URL to fake the URL change
527 m_frame->document()->setURL(newURL);
528 documentLoader()->updateForSameDocumentNavigation(newURL);
530 // Generate start and stop notifications only when loader is completed so that we
531 // don't fire them for fragment redirection that happens in window.onload handler.
532 // See https://bugs.webkit.org/show_bug.cgi?id=31838
533 if (m_frame->document()->loadEventFinished())
534 m_client->didStartLoading(NavigationWithinSameDocument);
536 HistoryCommitType historyCommitType = updateBackForwardList == UpdateBackForwardList && m_currentItem ? StandardCommit : HistoryInertCommit;
537 setHistoryItemStateForCommit(historyCommitType, sameDocumentNavigationSource == SameDocumentNavigationHistoryApi, data);
538 m_client->dispatchDidNavigateWithinPage(m_currentItem.get(), historyCommitType);
539 m_client->dispatchDidReceiveTitle(m_frame->document()->title());
540 if (m_frame->document()->loadEventFinished())
541 m_client->didStopLoading();
544 void FrameLoader::loadInSameDocument(const KURL& url, PassRefPtr<SerializedScriptValue> stateObject, UpdateBackForwardListPolicy updateBackForwardList, ClientRedirectPolicy clientRedirect)
546 // If we have a state object, we cannot also be a new navigation.
547 ASSERT(!stateObject || updateBackForwardList == DoNotUpdateBackForwardList);
549 // If we have a provisional request for a different document, a fragment scroll should cancel it.
550 if (m_provisionalDocumentLoader) {
551 m_provisionalDocumentLoader->stopLoading();
552 if (m_provisionalDocumentLoader)
553 m_provisionalDocumentLoader->detachFromFrame();
554 m_provisionalDocumentLoader = nullptr;
558 KURL oldURL = m_frame->document()->url();
559 // If we were in the autoscroll/panScroll mode we want to stop it before following the link to the anchor
560 bool hashChange = equalIgnoringFragmentIdentifier(url, oldURL) && url.fragmentIdentifier() != oldURL.fragmentIdentifier();
562 m_frame->eventHandler().stopAutoscroll();
563 m_frame->domWindow()->enqueueHashchangeEvent(oldURL, url);
565 m_documentLoader->setIsClientRedirect(clientRedirect == ClientRedirect);
566 bool replacesCurrentHistoryItem = updateBackForwardList == DoNotUpdateBackForwardList;
567 m_documentLoader->setReplacesCurrentHistoryItem(replacesCurrentHistoryItem);
568 updateForSameDocumentNavigation(url, SameDocumentNavigationDefault, nullptr, updateBackForwardList);
570 m_frame->view()->setWasScrolledByUser(false);
572 // It's important to model this as a load that starts and immediately finishes.
573 // Otherwise, the parent frame may think we never finished loading.
576 // We need to scroll to the fragment whether or not a hash change occurred, since
577 // the user might have scrolled since the previous navigation.
578 scrollToFragmentWithParentBoundary(url);
580 m_isComplete = false;
583 m_frame->domWindow()->statePopped(stateObject ? stateObject : SerializedScriptValue::nullValue());
586 void FrameLoader::completed()
588 RefPtr<LocalFrame> protect(m_frame);
590 for (LocalFrame* descendant = m_frame->tree().traverseNext(m_frame); descendant; descendant = descendant->tree().traverseNext(m_frame))
591 descendant->navigationScheduler().startTimer();
593 if (LocalFrame* parent = m_frame->tree().parent())
594 parent->loader().checkCompleted();
597 m_frame->view()->maintainScrollPositionAtAnchor(0);
600 void FrameLoader::started()
602 for (LocalFrame* frame = m_frame; frame; frame = frame->tree().parent())
603 frame->loader().m_isComplete = false;
606 void FrameLoader::setReferrerForFrameRequest(ResourceRequest& request, ShouldSendReferrer shouldSendReferrer, Document* originDocument)
608 if (shouldSendReferrer == NeverSendReferrer) {
609 request.clearHTTPReferrer();
613 // Always use the initiating document to generate the referrer.
614 // We need to generateReferrerHeader(), because we might not have enforced ReferrerPolicy or https->http
615 // referrer suppression yet.
616 String argsReferrer(request.httpReferrer());
617 if (argsReferrer.isEmpty())
618 argsReferrer = originDocument->outgoingReferrer();
619 String referrer = SecurityPolicy::generateReferrerHeader(originDocument->referrerPolicy(), request.url(), argsReferrer);
621 request.setHTTPReferrer(Referrer(referrer, originDocument->referrerPolicy()));
622 RefPtr<SecurityOrigin> referrerOrigin = SecurityOrigin::createFromString(referrer);
623 addHTTPOriginIfNeeded(request, referrerOrigin->toAtomicString());
626 bool FrameLoader::isScriptTriggeredFormSubmissionInChildFrame(const FrameLoadRequest& request) const
628 // If this is a child frame and the form submission was triggered by a script, lock the back/forward list
629 // to match IE and Opera.
630 // See https://bugs.webkit.org/show_bug.cgi?id=32383 for the original motivation for this.
631 if (!m_frame->tree().parent() || UserGestureIndicator::processingUserGesture())
633 return request.formState() && request.formState()->formSubmissionTrigger() == SubmittedByJavaScript;
636 FrameLoadType FrameLoader::determineFrameLoadType(const FrameLoadRequest& request)
638 if (m_frame->tree().parent() && !m_stateMachine.committedFirstRealDocumentLoad())
639 return FrameLoadTypeInitialInChildFrame;
640 if (!m_frame->tree().parent() && !m_frame->page()->backForward().backForwardListCount())
641 return FrameLoadTypeStandard;
642 if (m_provisionalDocumentLoader && request.substituteData().failingURL() == m_provisionalDocumentLoader->url() && m_loadType == FrameLoadTypeBackForward)
643 return FrameLoadTypeBackForward;
644 if (request.resourceRequest().cachePolicy() == ReloadIgnoringCacheData)
645 return FrameLoadTypeReload;
646 if (request.lockBackForwardList() || isScriptTriggeredFormSubmissionInChildFrame(request))
647 return FrameLoadTypeRedirectWithLockedBackForwardList;
648 if (!request.originDocument() && request.resourceRequest().url() == m_documentLoader->urlForHistory())
649 return FrameLoadTypeSame;
650 if (request.substituteData().failingURL() == m_documentLoader->urlForHistory() && m_loadType == FrameLoadTypeReload)
651 return FrameLoadTypeReload;
652 return FrameLoadTypeStandard;
655 bool FrameLoader::prepareRequestForThisFrame(FrameLoadRequest& request)
657 // If no origin Document* was specified, skip security checks and assume the caller has fully initialized the FrameLoadRequest.
658 if (!request.originDocument())
661 KURL url = request.resourceRequest().url();
662 if (m_frame->script().executeScriptIfJavaScriptURL(url))
665 if (!request.originDocument()->securityOrigin()->canDisplay(url)) {
666 reportLocalLoadFailed(m_frame, url.elidedString());
670 if (!request.formState() && request.frameName().isEmpty())
671 request.setFrameName(m_frame->document()->baseTarget());
673 setReferrerForFrameRequest(request.resourceRequest(), request.shouldSendReferrer(), request.originDocument());
677 static bool shouldOpenInNewWindow(LocalFrame* targetFrame, const FrameLoadRequest& request, const NavigationAction& action)
679 if (!targetFrame && !request.frameName().isEmpty())
681 // FIXME: This case is a workaround for the fact that ctrl+clicking a form submission incorrectly
682 // sends as a GET rather than a POST if it creates a new window in a different process.
683 return request.formState() && action.shouldOpenInNewWindow();
686 void FrameLoader::load(const FrameLoadRequest& passedRequest)
688 ASSERT(m_frame->document());
690 RefPtr<LocalFrame> protect(m_frame);
692 if (m_inStopAllLoaders)
695 FrameLoadRequest request(passedRequest);
696 if (!prepareRequestForThisFrame(request))
699 RefPtr<LocalFrame> targetFrame = request.formState() ? 0 : findFrameForNavigation(AtomicString(request.frameName()), request.formState() ? request.formState()->sourceDocument() : m_frame->document());
700 if (targetFrame && targetFrame != m_frame) {
701 request.setFrameName("_self");
702 targetFrame->loader().load(request);
703 if (Page* page = targetFrame->page())
704 page->chrome().focus();
708 FrameLoadType newLoadType = determineFrameLoadType(request);
709 NavigationAction action(request.resourceRequest(), newLoadType, request.formState(), request.triggeringEvent());
710 if (shouldOpenInNewWindow(targetFrame.get(), request, action)) {
711 if (action.policy() == NavigationPolicyDownload)
712 m_client->loadURLExternally(action.resourceRequest(), NavigationPolicyDownload);
714 createWindowForRequest(request, *m_frame, action.policy(), request.shouldSendReferrer());
718 const KURL& url = request.resourceRequest().url();
719 if (!action.shouldOpenInNewWindow() && shouldPerformFragmentNavigation(request.formState(), request.resourceRequest().httpMethod(), newLoadType, url)) {
720 m_documentLoader->setTriggeringAction(action);
721 loadInSameDocument(url, nullptr, newLoadType == FrameLoadTypeStandard && !shouldTreatURLAsSameAsCurrent(url) ? UpdateBackForwardList : DoNotUpdateBackForwardList, request.clientRedirect());
724 bool sameURL = url == m_documentLoader->urlForHistory();
725 loadWithNavigationAction(action, newLoadType, request.formState(), request.substituteData(), request.clientRedirect());
726 // Example of this case are sites that reload the same URL with a different cookie
727 // driving the generated content, or a master frame with links that drive a target
728 // frame, where the user has clicked on the same link repeatedly.
729 if (sameURL && newLoadType != FrameLoadTypeReload && newLoadType != FrameLoadTypeReloadFromOrigin && request.resourceRequest().httpMethod() != "POST")
730 m_loadType = FrameLoadTypeSame;
733 SubstituteData FrameLoader::defaultSubstituteDataForURL(const KURL& url)
735 if (!shouldTreatURLAsSrcdocDocument(url))
736 return SubstituteData();
737 String srcdoc = m_frame->ownerElement()->fastGetAttribute(srcdocAttr);
738 ASSERT(!srcdoc.isNull());
739 CString encodedSrcdoc = srcdoc.utf8();
740 return SubstituteData(SharedBuffer::create(encodedSrcdoc.data(), encodedSrcdoc.length()), "text/html", "UTF-8", KURL());
743 void FrameLoader::reportLocalLoadFailed(LocalFrame* frame, const String& url)
745 ASSERT(!url.isEmpty());
749 frame->document()->addConsoleMessage(SecurityMessageSource, ErrorMessageLevel, "Not allowed to load local resource: " + url);
752 static ResourceRequest requestFromHistoryItem(HistoryItem* item, ResourceRequestCachePolicy cachePolicy)
754 RefPtr<FormData> formData = item->formData();
755 ResourceRequest request(item->url(), item->referrer());
756 request.setCachePolicy(cachePolicy);
758 request.setHTTPMethod("POST");
759 request.setHTTPBody(formData);
760 request.setHTTPContentType(item->formContentType());
761 RefPtr<SecurityOrigin> securityOrigin = SecurityOrigin::createFromString(item->referrer().referrer);
762 FrameLoader::addHTTPOriginIfNeeded(request, securityOrigin->toAtomicString());
767 void FrameLoader::reload(ReloadPolicy reloadPolicy, const KURL& overrideURL, const AtomicString& overrideEncoding)
772 ResourceRequest request = requestFromHistoryItem(m_currentItem.get(), ReloadIgnoringCacheData);
773 if (!overrideURL.isEmpty()) {
774 request.setURL(overrideURL);
775 request.clearHTTPReferrer();
778 FrameLoadType type = reloadPolicy == EndToEndReload ? FrameLoadTypeReloadFromOrigin : FrameLoadTypeReload;
779 loadWithNavigationAction(NavigationAction(request, type), type, nullptr, SubstituteData(), NotClientRedirect, overrideEncoding);
782 void FrameLoader::stopAllLoaders()
784 if (m_frame->document()->pageDismissalEventBeingDispatched() != Document::NoDismissal)
787 // If this method is called from within this method, infinite recursion can occur (3442218). Avoid this.
788 if (m_inStopAllLoaders)
791 // Calling stopLoading() on the provisional document loader can blow away
792 // the frame from underneath.
793 RefPtr<LocalFrame> protect(m_frame);
795 m_inStopAllLoaders = true;
797 for (RefPtr<LocalFrame> child = m_frame->tree().firstChild(); child; child = child->tree().nextSibling())
798 child->loader().stopAllLoaders();
799 if (m_provisionalDocumentLoader)
800 m_provisionalDocumentLoader->stopLoading();
801 if (m_documentLoader)
802 m_documentLoader->stopLoading();
804 if (m_provisionalDocumentLoader)
805 m_provisionalDocumentLoader->detachFromFrame();
806 m_provisionalDocumentLoader = nullptr;
810 m_inStopAllLoaders = false;
812 // detachFromParent() can be called multiple times on same LocalFrame, which
813 // means we may no longer have a FrameLoaderClient to talk to.
815 m_client->didStopAllLoaders();
818 void FrameLoader::didAccessInitialDocument()
820 // We only need to notify the client once, and only for the main frame.
821 if (isLoadingMainFrame() && !m_didAccessInitialDocument) {
822 m_didAccessInitialDocument = true;
823 // Notify asynchronously, since this is called within a JavaScript security check.
824 m_didAccessInitialDocumentTimer.startOneShot(0, FROM_HERE);
828 void FrameLoader::didAccessInitialDocumentTimerFired(Timer<FrameLoader>*)
830 m_client->didAccessInitialDocument();
833 void FrameLoader::notifyIfInitialDocumentAccessed()
835 if (m_didAccessInitialDocumentTimer.isActive()) {
836 m_didAccessInitialDocumentTimer.stop();
837 didAccessInitialDocumentTimerFired(0);
841 bool FrameLoader::isLoading() const
843 if (m_provisionalDocumentLoader)
845 return m_documentLoader && m_documentLoader->isLoading();
848 void FrameLoader::commitProvisionalLoad()
850 ASSERT(m_client->hasWebView());
851 ASSERT(m_state == FrameStateProvisional);
852 RefPtr<DocumentLoader> pdl = m_provisionalDocumentLoader;
853 RefPtr<LocalFrame> protect(m_frame);
855 // Check if the destination page is allowed to access the previous page's timing information.
856 if (m_frame->document()) {
857 RefPtr<SecurityOrigin> securityOrigin = SecurityOrigin::create(pdl->request().url());
858 pdl->timing()->setHasSameOriginAsPreviousDocument(securityOrigin->canRequest(m_frame->document()->url()));
861 // The call to closeURL() invokes the unload event handler, which can execute arbitrary
862 // JavaScript. If the script initiates a new load, we need to abandon the current load,
863 // or the two will stomp each other.
864 // detachChildren will similarly trigger child frame unload event handlers.
865 if (m_documentLoader) {
866 m_client->dispatchWillClose();
870 if (pdl != m_provisionalDocumentLoader)
872 if (m_documentLoader)
873 m_documentLoader->detachFromFrame();
874 m_documentLoader = m_provisionalDocumentLoader.release();
875 m_state = FrameStateCommittedPage;
877 if (isLoadingMainFrame())
878 m_frame->page()->chrome().client().needTouchEvents(false);
880 m_client->transitionToCommittedForNewPage();
881 m_frame->navigationScheduler().cancel();
882 m_frame->editor().clearLastEditCommand();
884 // If we are still in the process of initializing an empty document then
885 // its frame is not in a consistent state for rendering, so avoid setJSStatusBarText
886 // since it may cause clients to attempt to render the frame.
887 if (!m_stateMachine.creatingInitialEmptyDocument()) {
888 DOMWindow* window = m_frame->domWindow();
889 window->setStatus(String());
890 window->setDefaultStatus(String());
895 bool FrameLoader::isLoadingMainFrame() const
897 return m_frame->isMainFrame();
900 FrameLoadType FrameLoader::loadType() const
905 // This function is an incomprehensible mess and is only used in checkLoadCompleteForThisFrame.
906 // If you're thinking of using it elsewhere, stop right now and reconsider your life.
907 static bool isDocumentDoneLoading(Document* document)
909 if (!document->loader())
911 if (document->loader()->isLoadingMainResource())
913 if (!document->loadEventFinished()) {
914 if (document->loader()->isLoading() || document->isDelayingLoadEvent())
917 if (document->fetcher()->requestCount())
919 if (document->processingLoadEvent())
921 if (document->hasActiveParser())
926 bool FrameLoader::checkLoadCompleteForThisFrame()
928 ASSERT(m_client->hasWebView());
929 RefPtr<LocalFrame> protect(m_frame);
931 if (m_state == FrameStateProvisional && m_provisionalDocumentLoader) {
932 const ResourceError& error = m_provisionalDocumentLoader->mainDocumentError();
935 RefPtr<DocumentLoader> loader = m_provisionalDocumentLoader;
936 m_client->dispatchDidFailProvisionalLoad(error);
937 if (loader != m_provisionalDocumentLoader)
939 m_provisionalDocumentLoader->detachFromFrame();
940 m_provisionalDocumentLoader = nullptr;
941 m_progressTracker->progressCompleted();
942 m_state = FrameStateComplete;
946 bool allChildrenAreDoneLoading = true;
947 for (LocalFrame* child = m_frame->tree().firstChild(); child; child = child->tree().nextSibling())
948 allChildrenAreDoneLoading &= child->loader().checkLoadCompleteForThisFrame();
949 if (!allChildrenAreDoneLoading)
952 if (m_state == FrameStateComplete)
954 if (m_provisionalDocumentLoader || !m_documentLoader)
956 if (!isDocumentDoneLoading(m_frame->document()) && !m_inStopAllLoaders)
959 m_state = FrameStateComplete;
961 // FIXME: Is this subsequent work important if we already navigated away?
962 // Maybe there are bugs because of that, or extra work we can skip because
963 // the new page is ready.
965 // Retry restoring scroll offset since FrameStateComplete disables content
967 restoreScrollPositionAndViewState();
969 if (!m_stateMachine.committedFirstRealDocumentLoad())
972 m_progressTracker->progressCompleted();
973 m_frame->domWindow()->finishedLoading();
975 const ResourceError& error = m_documentLoader->mainDocumentError();
976 if (!error.isNull()) {
977 m_client->dispatchDidFailLoad(error);
979 // Report mobile vs. desktop page statistics. This will only report on Android.
980 if (m_frame->isMainFrame())
981 m_frame->document()->viewportDescription().reportMobilePageStats(m_frame);
983 m_client->dispatchDidFinishLoad();
985 m_loadType = FrameLoadTypeStandard;
989 void FrameLoader::restoreScrollPositionAndViewState()
991 FrameView* view = m_frame->view();
992 if (!m_frame->page() || !view || !m_currentItem || !m_stateMachine.committedFirstRealDocumentLoad())
995 if (!needsHistoryItemRestore(m_loadType))
998 // This tries to balance 1. restoring as soon as possible, 2. detecting
999 // clamping to avoid repeatedly popping the scroll position down as the
1000 // page height increases, 3. ignore clamp detection after load completes
1001 // because that may be because the page will never reach its previous
1003 float mainFrameScale = m_frame->settings()->pinchVirtualViewportEnabled() ? 1 : m_currentItem->pageScaleFactor();
1004 bool canRestoreWithoutClamping = view->clampOffsetAtScale(m_currentItem->scrollPoint(), mainFrameScale) == m_currentItem->scrollPoint();
1005 bool canRestoreWithoutAnnoyingUser = !view->wasScrolledByUser() && (canRestoreWithoutClamping || m_state == FrameStateComplete);
1006 if (!canRestoreWithoutAnnoyingUser)
1009 if (m_frame->isMainFrame() && m_currentItem->pageScaleFactor()) {
1010 FloatPoint pinchViewportOffset(m_currentItem->pinchViewportScrollPoint());
1011 IntPoint frameScrollOffset(m_currentItem->scrollPoint());
1013 m_frame->page()->setPageScaleFactor(m_currentItem->pageScaleFactor(), frameScrollOffset);
1015 if (m_frame->document()->settings()->pinchVirtualViewportEnabled()) {
1016 // If the pinch viewport's offset is (-1, -1) it means the history item
1017 // is an old version of HistoryItem so distribute the scroll between
1018 // the main frame and the pinch viewport as best as we can.
1019 // FIXME(bokan): This legacy distribution can be removed once the virtual viewport
1020 // pinch path is enabled on all platforms for at least one release.
1021 if (pinchViewportOffset.x() == -1 && pinchViewportOffset.y() == -1)
1022 pinchViewportOffset = FloatPoint(frameScrollOffset - view->scrollPosition());
1024 m_frame->host()->pinchViewport().setLocation(pinchViewportOffset);
1027 view->setScrollPositionNonProgrammatically(m_currentItem->scrollPoint());
1030 if (m_frame->isMainFrame()) {
1031 if (ScrollingCoordinator* scrollingCoordinator = m_frame->page()->scrollingCoordinator())
1032 scrollingCoordinator->frameViewRootLayerDidChange(view);
1036 void FrameLoader::detachChildren()
1038 typedef Vector<RefPtr<LocalFrame> > FrameVector;
1039 FrameVector childrenToDetach;
1040 childrenToDetach.reserveCapacity(m_frame->tree().childCount());
1041 for (LocalFrame* child = m_frame->tree().lastChild(); child; child = child->tree().previousSibling())
1042 childrenToDetach.append(child);
1043 FrameVector::iterator end = childrenToDetach.end();
1044 for (FrameVector::iterator it = childrenToDetach.begin(); it != end; ++it)
1045 (*it)->loader().detachFromParent();
1048 void FrameLoader::closeAndRemoveChild(LocalFrame* child)
1050 child->setView(nullptr);
1051 if (child->ownerElement() && child->page())
1052 child->page()->decrementSubframeCount();
1053 child->willDetachFrameHost();
1054 child->loader().detachClient();
1057 // Called every time a resource is completely loaded or an error is received.
1058 void FrameLoader::checkLoadComplete()
1060 ASSERT(m_client->hasWebView());
1061 if (Page* page = m_frame->page())
1062 page->mainFrame()->loader().checkLoadCompleteForThisFrame();
1065 String FrameLoader::userAgent(const KURL& url) const
1067 String userAgent = m_client->userAgent(url);
1068 InspectorInstrumentation::applyUserAgentOverride(m_frame, &userAgent);
1072 void FrameLoader::frameDetached()
1074 // stopAllLoaders can detach the LocalFrame, so protect it.
1075 RefPtr<LocalFrame> protect(m_frame);
1080 void FrameLoader::detachFromParent()
1082 // stopAllLoaders can detach the LocalFrame, so protect it.
1083 RefPtr<LocalFrame> protect(m_frame);
1087 // stopAllLoaders() needs to be called after detachChildren(), because detachedChildren()
1088 // will trigger the unload event handlers of any child frames, and those event
1089 // handlers might start a new subresource load in this frame.
1092 InspectorInstrumentation::frameDetachedFromParent(m_frame);
1094 if (m_documentLoader)
1095 m_documentLoader->detachFromFrame();
1096 m_documentLoader = nullptr;
1101 // FIXME: All this code belongs up in Page.
1102 if (LocalFrame* parent = m_frame->tree().parent()) {
1103 parent->loader().closeAndRemoveChild(m_frame);
1104 parent->loader().scheduleCheckCompleted();
1106 m_frame->setView(nullptr);
1107 m_frame->willDetachFrameHost();
1110 m_frame->detachFromFrameHost();
1114 void FrameLoader::detachClient()
1118 // Finish all cleanup work that might require talking to the embedder.
1119 m_progressTracker.clear();
1121 // Notify ScriptController that the frame is closing, since its cleanup ends up calling
1122 // back to FrameLoaderClient via V8WindowShell.
1123 m_frame->script().clearForClose();
1125 // m_client should never be null because that means we somehow re-entered
1126 // the frame detach code... but it is sometimes.
1127 // FIXME: Understand why this is happening so we can document this insanity.
1129 // After this, we must no longer talk to the client since this clears
1130 // its owning reference back to our owning LocalFrame.
1131 m_client->detachedFromParent();
1136 void FrameLoader::addHTTPOriginIfNeeded(ResourceRequest& request, const AtomicString& origin)
1138 if (!request.httpOrigin().isEmpty())
1139 return; // Request already has an Origin header.
1141 // Don't send an Origin header for GET or HEAD to avoid privacy issues.
1142 // For example, if an intranet page has a hyperlink to an external web
1143 // site, we don't want to include the Origin of the request because it
1144 // will leak the internal host name. Similar privacy concerns have lead
1145 // to the widespread suppression of the Referer header at the network
1147 if (request.httpMethod() == "GET" || request.httpMethod() == "HEAD")
1150 // For non-GET and non-HEAD methods, always send an Origin header so the
1151 // server knows we support this feature.
1153 if (origin.isEmpty()) {
1154 // If we don't know what origin header to attach, we attach the value
1155 // for an empty origin.
1156 request.setHTTPOrigin(SecurityOrigin::createUnique()->toAtomicString());
1160 request.setHTTPOrigin(origin);
1163 void FrameLoader::receivedMainResourceError(const ResourceError& error)
1165 // Retain because the stop may release the last reference to it.
1166 RefPtr<LocalFrame> protect(m_frame);
1168 if (m_frame->document()->parser())
1169 m_frame->document()->parser()->stopParsing();
1171 // FIXME: We really ought to be able to just check for isCancellation() here, but there are some
1172 // ResourceErrors that setIsCancellation() but aren't created by ResourceError::cancelledError().
1173 ResourceError c(ResourceError::cancelledError(KURL()));
1174 if ((error.errorCode() != c.errorCode() || error.domain() != c.domain()) && m_frame->ownerElement())
1175 m_frame->ownerElement()->renderFallbackContent();
1178 if (m_frame->page())
1179 checkLoadComplete();
1182 bool FrameLoader::shouldPerformFragmentNavigation(bool isFormSubmission, const String& httpMethod, FrameLoadType loadType, const KURL& url)
1184 ASSERT(loadType != FrameLoadTypeReloadFromOrigin);
1185 // We don't do this if we are submitting a form with method other than "GET", explicitly reloading,
1186 // currently displaying a frameset, or if the URL does not have a fragment.
1187 return (!isFormSubmission || equalIgnoringCase(httpMethod, "GET"))
1188 && loadType != FrameLoadTypeReload
1189 && loadType != FrameLoadTypeSame
1190 && loadType != FrameLoadTypeBackForward
1191 && url.hasFragmentIdentifier()
1192 && equalIgnoringFragmentIdentifier(m_frame->document()->url(), url)
1193 // We don't want to just scroll if a link from within a
1194 // frameset is trying to reload the frameset into _top.
1195 && !m_frame->document()->isFrameSet();
1198 void FrameLoader::scrollToFragmentWithParentBoundary(const KURL& url)
1200 FrameView* view = m_frame->view();
1204 // Leaking scroll position to a cross-origin ancestor would permit the so-called "framesniffing" attack.
1205 RefPtr<LocalFrame> boundaryFrame(url.hasFragmentIdentifier() ? m_frame->document()->findUnsafeParentScrollPropagationBoundary() : 0);
1208 boundaryFrame->view()->setSafeToPropagateScrollToParent(false);
1210 view->scrollToFragment(url);
1213 boundaryFrame->view()->setSafeToPropagateScrollToParent(true);
1216 bool FrameLoader::shouldClose()
1218 Page* page = m_frame->page();
1219 if (!page || !page->chrome().canRunBeforeUnloadConfirmPanel())
1222 // Store all references to each subframe in advance since beforeunload's event handler may modify frame
1223 Vector<RefPtr<LocalFrame> > targetFrames;
1224 targetFrames.append(m_frame);
1225 for (LocalFrame* child = m_frame->tree().firstChild(); child; child = child->tree().traverseNext(m_frame))
1226 targetFrames.append(child);
1228 bool shouldClose = false;
1230 NavigationDisablerForBeforeUnload navigationDisabler;
1233 bool didAllowNavigation = false;
1234 for (i = 0; i < targetFrames.size(); i++) {
1235 if (!targetFrames[i]->tree().isDescendantOf(m_frame))
1237 if (!targetFrames[i]->document()->dispatchBeforeUnloadEvent(page->chrome(), didAllowNavigation))
1241 if (i == targetFrames.size())
1247 void FrameLoader::loadWithNavigationAction(const NavigationAction& action, FrameLoadType type, PassRefPtrWillBeRawPtr<FormState> formState, const SubstituteData& substituteData, ClientRedirectPolicy clientRedirect, const AtomicString& overrideEncoding)
1249 ASSERT(m_client->hasWebView());
1250 if (m_frame->document()->pageDismissalEventBeingDispatched() != Document::NoDismissal)
1253 const ResourceRequest& request = action.resourceRequest();
1255 // The current load should replace the history item if it is the first real
1256 // load of the frame.
1257 bool replacesCurrentHistoryItem = false;
1258 if (type == FrameLoadTypeRedirectWithLockedBackForwardList
1259 || !m_stateMachine.committedFirstRealDocumentLoad()) {
1260 replacesCurrentHistoryItem = true;
1263 m_policyDocumentLoader = m_client->createDocumentLoader(m_frame, request, substituteData.isValid() ? substituteData : defaultSubstituteDataForURL(request.url()));
1264 m_policyDocumentLoader->setTriggeringAction(action);
1265 m_policyDocumentLoader->setReplacesCurrentHistoryItem(replacesCurrentHistoryItem);
1266 m_policyDocumentLoader->setIsClientRedirect(clientRedirect == ClientRedirect);
1268 if (LocalFrame* parent = m_frame->tree().parent())
1269 m_policyDocumentLoader->setOverrideEncoding(parent->loader().documentLoader()->overrideEncoding());
1270 else if (!overrideEncoding.isEmpty())
1271 m_policyDocumentLoader->setOverrideEncoding(overrideEncoding);
1272 else if (m_documentLoader)
1273 m_policyDocumentLoader->setOverrideEncoding(m_documentLoader->overrideEncoding());
1275 // stopAllLoaders can detach the LocalFrame, so protect it.
1276 RefPtr<LocalFrame> protect(m_frame);
1277 if ((!m_policyDocumentLoader->shouldContinueForNavigationPolicy(request) || !shouldClose()) && m_policyDocumentLoader) {
1278 m_policyDocumentLoader->detachFromFrame();
1279 m_policyDocumentLoader = nullptr;
1283 // A new navigation is in progress, so don't clear the history's provisional item.
1286 // <rdar://problem/6250856> - In certain circumstances on pages with multiple frames, stopAllLoaders()
1287 // might detach the current FrameLoader, in which case we should bail on this newly defunct load.
1288 if (!m_frame->page() || !m_policyDocumentLoader)
1291 if (isLoadingMainFrame())
1292 m_frame->page()->inspectorController().resume();
1293 m_frame->navigationScheduler().cancel();
1295 m_provisionalDocumentLoader = m_policyDocumentLoader.release();
1297 m_state = FrameStateProvisional;
1300 m_client->dispatchWillSubmitForm(formState->form());
1302 m_progressTracker->progressStarted();
1303 if (m_provisionalDocumentLoader->isClientRedirect())
1304 m_provisionalDocumentLoader->appendRedirect(m_frame->document()->url());
1305 m_provisionalDocumentLoader->appendRedirect(m_provisionalDocumentLoader->request().url());
1306 m_client->dispatchDidStartProvisionalLoad();
1307 ASSERT(m_provisionalDocumentLoader);
1308 m_provisionalDocumentLoader->startLoadingMainResource();
1311 void FrameLoader::applyUserAgent(ResourceRequest& request)
1313 String userAgent = this->userAgent(request.url());
1314 ASSERT(!userAgent.isNull());
1315 request.setHTTPUserAgent(AtomicString(userAgent));
1318 bool FrameLoader::shouldInterruptLoadForXFrameOptions(const String& content, const KURL& url, unsigned long requestIdentifier)
1320 UseCounter::count(m_frame->domWindow()->document(), UseCounter::XFrameOptions);
1322 LocalFrame* topFrame = m_frame->tree().top();
1323 if (m_frame == topFrame)
1326 XFrameOptionsDisposition disposition = parseXFrameOptionsHeader(content);
1328 switch (disposition) {
1329 case XFrameOptionsSameOrigin: {
1330 UseCounter::count(m_frame->domWindow()->document(), UseCounter::XFrameOptionsSameOrigin);
1331 RefPtr<SecurityOrigin> origin = SecurityOrigin::create(url);
1332 if (!origin->isSameSchemeHostPort(topFrame->document()->securityOrigin()))
1334 for (LocalFrame* frame = m_frame->tree().parent(); frame; frame = frame->tree().parent()) {
1335 if (!origin->isSameSchemeHostPort(frame->document()->securityOrigin())) {
1336 UseCounter::count(m_frame->domWindow()->document(), UseCounter::XFrameOptionsSameOriginWithBadAncestorChain);
1342 case XFrameOptionsDeny:
1344 case XFrameOptionsAllowAll:
1346 case XFrameOptionsConflict:
1347 m_frame->document()->addConsoleMessageWithRequestIdentifier(JSMessageSource, ErrorMessageLevel, "Multiple 'X-Frame-Options' headers with conflicting values ('" + content + "') encountered when loading '" + url.elidedString() + "'. Falling back to 'DENY'.", requestIdentifier);
1349 case XFrameOptionsInvalid:
1350 m_frame->document()->addConsoleMessageWithRequestIdentifier(JSMessageSource, ErrorMessageLevel, "Invalid 'X-Frame-Options' header encountered when loading '" + url.elidedString() + "': '" + content + "' is not a recognized directive. The header will be ignored.", requestIdentifier);
1353 ASSERT_NOT_REACHED();
1358 bool FrameLoader::shouldTreatURLAsSameAsCurrent(const KURL& url) const
1360 return m_currentItem && url == m_currentItem->url();
1363 bool FrameLoader::shouldTreatURLAsSrcdocDocument(const KURL& url) const
1365 if (!equalIgnoringCase(url.string(), "about:srcdoc"))
1367 HTMLFrameOwnerElement* ownerElement = m_frame->ownerElement();
1368 if (!isHTMLIFrameElement(ownerElement))
1370 return ownerElement->fastHasAttribute(srcdocAttr);
1373 LocalFrame* FrameLoader::findFrameForNavigation(const AtomicString& name, Document* activeDocument)
1375 ASSERT(activeDocument);
1376 LocalFrame* frame = m_frame->tree().find(name);
1377 if (!activeDocument->canNavigate(frame))
1382 void FrameLoader::loadHistoryItem(HistoryItem* item, HistoryLoadType historyLoadType, ResourceRequestCachePolicy cachePolicy)
1384 RefPtr<LocalFrame> protect(m_frame);
1385 if (m_frame->page()->defersLoading()) {
1386 m_deferredHistoryLoad = DeferredHistoryLoad(item, historyLoadType, cachePolicy);
1390 m_provisionalItem = item;
1391 if (historyLoadType == HistorySameDocumentLoad) {
1392 m_loadType = FrameLoadTypeBackForward;
1393 loadInSameDocument(item->url(), item->stateObject(), DoNotUpdateBackForwardList, NotClientRedirect);
1394 restoreScrollPositionAndViewState();
1397 loadWithNavigationAction(NavigationAction(requestFromHistoryItem(item, cachePolicy), FrameLoadTypeBackForward), FrameLoadTypeBackForward, nullptr, SubstituteData());
1400 void FrameLoader::dispatchDocumentElementAvailable()
1402 m_client->documentElementAvailable();
1405 void FrameLoader::dispatchDidClearDocumentOfWindowObject()
1407 if (!m_frame->script().canExecuteScripts(NotAboutToExecuteScript))
1410 if (Page* page = m_frame->page())
1411 page->inspectorController().didClearDocumentOfWindowObject(m_frame);
1412 InspectorInstrumentation::didClearDocumentOfWindowObject(m_frame);
1414 // We just cleared the document, not the entire window object, but for the
1415 // embedder that's close enough.
1416 m_client->dispatchDidClearWindowObjectInMainWorld();
1419 void FrameLoader::dispatchDidClearWindowObjectInMainWorld()
1421 if (!m_frame->script().canExecuteScripts(NotAboutToExecuteScript))
1424 // FIXME: Why isn't the inspector notified of this?
1426 m_client->dispatchDidClearWindowObjectInMainWorld();
1429 SandboxFlags FrameLoader::effectiveSandboxFlags() const
1431 SandboxFlags flags = m_forcedSandboxFlags;
1432 if (LocalFrame* parentFrame = m_frame->tree().parent())
1433 flags |= parentFrame->document()->sandboxFlags();
1434 if (HTMLFrameOwnerElement* ownerElement = m_frame->ownerElement())
1435 flags |= ownerElement->sandboxFlags();
1439 } // namespace WebCore