Home | History | Annotate | Download | only in loader
      1 /*
      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 (at) atoker.com>
      6  * Copyright (C) Research In Motion Limited 2009. All rights reserved.
      7  * Copyright (C) 2011 Kris Jordan <krisjordan (at) gmail.com>
      8  * Copyright (C) 2011 Google Inc. All rights reserved.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  *
     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.
     22  *
     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.
     33  */
     34 
     35 #include "config.h"
     36 #include "core/loader/FrameLoader.h"
     37 
     38 #include "bindings/core/v8/DOMWrapperWorld.h"
     39 #include "bindings/core/v8/ScriptController.h"
     40 #include "bindings/core/v8/SerializedScriptValue.h"
     41 #include "core/HTMLNames.h"
     42 #include "core/dom/Document.h"
     43 #include "core/dom/Element.h"
     44 #include "core/dom/ViewportDescription.h"
     45 #include "core/editing/Editor.h"
     46 #include "core/editing/UndoStack.h"
     47 #include "core/events/PageTransitionEvent.h"
     48 #include "core/fetch/FetchContext.h"
     49 #include "core/fetch/ResourceFetcher.h"
     50 #include "core/fetch/ResourceLoader.h"
     51 #include "core/frame/LocalDOMWindow.h"
     52 #include "core/frame/FrameHost.h"
     53 #include "core/frame/FrameView.h"
     54 #include "core/frame/LocalFrame.h"
     55 #include "core/frame/PinchViewport.h"
     56 #include "core/frame/Settings.h"
     57 #include "core/frame/csp/ContentSecurityPolicy.h"
     58 #include "core/html/HTMLFormElement.h"
     59 #include "core/html/HTMLFrameOwnerElement.h"
     60 #include "core/html/parser/HTMLParserIdioms.h"
     61 #include "core/inspector/ConsoleMessage.h"
     62 #include "core/inspector/InspectorController.h"
     63 #include "core/inspector/InspectorInstrumentation.h"
     64 #include "core/loader/DocumentLoadTiming.h"
     65 #include "core/loader/DocumentLoader.h"
     66 #include "core/loader/FormState.h"
     67 #include "core/loader/FormSubmission.h"
     68 #include "core/loader/FrameFetchContext.h"
     69 #include "core/loader/FrameLoadRequest.h"
     70 #include "core/loader/FrameLoaderClient.h"
     71 #include "core/loader/ProgressTracker.h"
     72 #include "core/loader/UniqueIdentifier.h"
     73 #include "core/loader/appcache/ApplicationCacheHost.h"
     74 #include "core/page/BackForwardClient.h"
     75 #include "core/page/Chrome.h"
     76 #include "core/page/ChromeClient.h"
     77 #include "core/page/CreateWindow.h"
     78 #include "core/page/EventHandler.h"
     79 #include "core/page/FrameTree.h"
     80 #include "core/page/Page.h"
     81 #include "core/page/WindowFeatures.h"
     82 #include "core/page/scrolling/ScrollingCoordinator.h"
     83 #include "core/xml/parser/XMLDocumentParser.h"
     84 #include "platform/Logging.h"
     85 #include "platform/UserGestureIndicator.h"
     86 #include "platform/geometry/FloatRect.h"
     87 #include "platform/network/HTTPParsers.h"
     88 #include "platform/network/ResourceRequest.h"
     89 #include "platform/scroll/ScrollAnimator.h"
     90 #include "platform/weborigin/SecurityOrigin.h"
     91 #include "platform/weborigin/SecurityPolicy.h"
     92 #include "public/platform/WebURLRequest.h"
     93 #include "wtf/TemporaryChange.h"
     94 #include "wtf/text/CString.h"
     95 #include "wtf/text/WTFString.h"
     96 
     97 using blink::WebURLRequest;
     98 
     99 namespace blink {
    100 
    101 using namespace HTMLNames;
    102 
    103 bool isBackForwardLoadType(FrameLoadType type)
    104 {
    105     return type == FrameLoadTypeBackForward;
    106 }
    107 
    108 static bool needsHistoryItemRestore(FrameLoadType type)
    109 {
    110     return type == FrameLoadTypeBackForward || type == FrameLoadTypeReload || type == FrameLoadTypeReloadFromOrigin;
    111 }
    112 
    113 FrameLoader::FrameLoader(LocalFrame* frame)
    114     : m_frame(frame)
    115     , m_mixedContentChecker(frame)
    116     , m_progressTracker(ProgressTracker::create(frame))
    117     , m_state(FrameStateProvisional)
    118     , m_loadType(FrameLoadTypeStandard)
    119     , m_fetchContext(FrameFetchContext::create(frame))
    120     , m_inStopAllLoaders(false)
    121     , m_checkTimer(this, &FrameLoader::checkTimerFired)
    122     , m_didAccessInitialDocument(false)
    123     , m_didAccessInitialDocumentTimer(this, &FrameLoader::didAccessInitialDocumentTimerFired)
    124     , m_forcedSandboxFlags(SandboxNone)
    125 {
    126 }
    127 
    128 FrameLoader::~FrameLoader()
    129 {
    130     // Verify that this FrameLoader has been detached.
    131     ASSERT(!m_progressTracker);
    132 }
    133 
    134 void FrameLoader::trace(Visitor* visitor)
    135 {
    136     visitor->trace(m_frame);
    137     visitor->trace(m_mixedContentChecker);
    138     visitor->trace(m_progressTracker);
    139     visitor->trace(m_fetchContext);
    140 }
    141 
    142 void FrameLoader::init()
    143 {
    144     ResourceRequest initialRequest(KURL(ParsedURLString, emptyString()));
    145     initialRequest.setRequestContext(WebURLRequest::RequestContextInternal);
    146     initialRequest.setFrameType(m_frame->isMainFrame() ? WebURLRequest::FrameTypeTopLevel : WebURLRequest::FrameTypeNested);
    147     m_provisionalDocumentLoader = client()->createDocumentLoader(m_frame, initialRequest, SubstituteData());
    148     m_provisionalDocumentLoader->startLoadingMainResource();
    149     m_frame->document()->cancelParsing();
    150     m_stateMachine.advanceTo(FrameLoaderStateMachine::DisplayingInitialEmptyDocument);
    151 }
    152 
    153 FrameLoaderClient* FrameLoader::client() const
    154 {
    155     return static_cast<FrameLoaderClient*>(m_frame->client());
    156 }
    157 
    158 void FrameLoader::setDefersLoading(bool defers)
    159 {
    160     if (m_documentLoader)
    161         m_documentLoader->setDefersLoading(defers);
    162     if (m_provisionalDocumentLoader)
    163         m_provisionalDocumentLoader->setDefersLoading(defers);
    164     if (m_policyDocumentLoader)
    165         m_policyDocumentLoader->setDefersLoading(defers);
    166 
    167     if (!defers) {
    168         if (m_deferredHistoryLoad.isValid()) {
    169             loadHistoryItem(m_deferredHistoryLoad.m_item.get(), m_deferredHistoryLoad.m_type, m_deferredHistoryLoad.m_cachePolicy);
    170             m_deferredHistoryLoad = DeferredHistoryLoad();
    171         }
    172         m_frame->navigationScheduler().startTimer();
    173         scheduleCheckCompleted();
    174     }
    175 }
    176 
    177 void FrameLoader::stopLoading()
    178 {
    179     if (m_frame->document() && m_frame->document()->parsing()) {
    180         finishedParsing();
    181         m_frame->document()->setParsing(false);
    182     }
    183 
    184     if (Document* doc = m_frame->document()) {
    185         // FIXME: HTML5 doesn't tell us to set the state to complete when aborting, but we do anyway to match legacy behavior.
    186         // http://www.w3.org/Bugs/Public/show_bug.cgi?id=10537
    187         doc->setReadyState(Document::Complete);
    188     }
    189 
    190     // FIXME: This will cancel redirection timer, which really needs to be restarted when restoring the frame from b/f cache.
    191     m_frame->navigationScheduler().cancel();
    192 }
    193 
    194 void FrameLoader::saveScrollState()
    195 {
    196     if (!m_currentItem || !m_frame->view())
    197         return;
    198 
    199     // Shouldn't clobber anything if we might still restore later.
    200     if (needsHistoryItemRestore(m_loadType) && !m_frame->view()->wasScrolledByUser())
    201         return;
    202 
    203     m_currentItem->setScrollPoint(m_frame->view()->scrollPosition());
    204 
    205     if (m_frame->settings()->pinchVirtualViewportEnabled())
    206         m_currentItem->setPinchViewportScrollPoint(m_frame->host()->pinchViewport().visibleRect().location());
    207     else
    208         m_currentItem->setPinchViewportScrollPoint(FloatPoint(-1, -1));
    209 
    210     if (m_frame->isMainFrame())
    211         m_currentItem->setPageScaleFactor(m_frame->page()->pageScaleFactor());
    212 
    213     client()->didUpdateCurrentHistoryItem();
    214 }
    215 
    216 void FrameLoader::clearScrollPositionAndViewState()
    217 {
    218     ASSERT(m_frame->isMainFrame());
    219     if (!m_currentItem)
    220         return;
    221     m_currentItem->clearScrollPoint();
    222     m_currentItem->setPageScaleFactor(0);
    223 }
    224 
    225 bool FrameLoader::closeURL()
    226 {
    227     saveScrollState();
    228 
    229     // Should only send the pagehide event here if the current document exists.
    230     if (m_frame->document())
    231         m_frame->document()->dispatchUnloadEvents();
    232     stopLoading();
    233 
    234     if (Page* page = m_frame->page())
    235         page->undoStack().didUnloadFrame(*m_frame);
    236     return true;
    237 }
    238 
    239 void FrameLoader::didExplicitOpen()
    240 {
    241     // Calling document.open counts as committing the first real document load.
    242     if (!m_stateMachine.committedFirstRealDocumentLoad())
    243         m_stateMachine.advanceTo(FrameLoaderStateMachine::CommittedFirstRealLoad);
    244 
    245     // Prevent window.open(url) -- eg window.open("about:blank") -- from blowing away results
    246     // from a subsequent window.document.open / window.document.write call.
    247     // Canceling redirection here works for all cases because document.open
    248     // implicitly precedes document.write.
    249     m_frame->navigationScheduler().cancel();
    250 }
    251 
    252 void FrameLoader::clear()
    253 {
    254     // clear() is called during (Local)Frame finalization and when creating
    255     // a new Document within it (DocumentLoader::createWriterFor().)
    256     if (m_stateMachine.creatingInitialEmptyDocument())
    257         return;
    258 
    259     m_frame->editor().clear();
    260     m_frame->document()->cancelParsing();
    261     m_frame->document()->prepareForDestruction();
    262     m_frame->document()->removeFocusedElementOfSubtree(m_frame->document());
    263     m_frame->selection().prepareForDestruction();
    264     m_frame->eventHandler().clear();
    265     if (m_frame->view())
    266         m_frame->view()->clear();
    267 
    268     m_frame->script().enableEval();
    269 
    270     m_frame->navigationScheduler().cancel();
    271 
    272     m_checkTimer.stop();
    273 
    274     if (m_stateMachine.isDisplayingInitialEmptyDocument())
    275         m_stateMachine.advanceTo(FrameLoaderStateMachine::CommittedFirstRealLoad);
    276 }
    277 
    278 // This is only called by ScriptController::executeScriptIfJavaScriptURL
    279 // and always contains the result of evaluating a javascript: url.
    280 // This is the <iframe src="javascript:'html'"> case.
    281 void FrameLoader::replaceDocumentWhileExecutingJavaScriptURL(const String& source, Document* ownerDocument)
    282 {
    283     if (!m_frame->document()->loader())
    284         return;
    285 
    286     // DocumentWriter::replaceDocumentWhileExecutingJavaScriptURL can cause the DocumentLoader to get deref'ed and possible destroyed,
    287     // so protect it with a RefPtr.
    288     RefPtr<DocumentLoader> documentLoader(m_frame->document()->loader());
    289 
    290     UseCounter::count(*m_frame->document(), UseCounter::ReplaceDocumentViaJavaScriptURL);
    291 
    292     // Prepare a DocumentInit before clearing the frame, because it may need to
    293     // inherit an aliased security context.
    294     DocumentInit init(m_frame->document()->url(), m_frame);
    295     init.withNewRegistrationContext();
    296 
    297     stopAllLoaders();
    298     clear();
    299 
    300     // clear() potentially detaches the frame from the document. The
    301     // loading cannot continue in that case.
    302     if (!m_frame->page())
    303         return;
    304 
    305     documentLoader->replaceDocumentWhileExecutingJavaScriptURL(init, source, ownerDocument);
    306 }
    307 
    308 void FrameLoader::setHistoryItemStateForCommit(HistoryCommitType historyCommitType, bool isPushOrReplaceState, PassRefPtr<SerializedScriptValue> stateObject)
    309 {
    310     if (m_provisionalItem)
    311         m_currentItem = m_provisionalItem.release();
    312 
    313     if (!m_currentItem || historyCommitType == StandardCommit) {
    314         m_currentItem = HistoryItem::create();
    315     } else if (!isPushOrReplaceState && m_documentLoader->url() != m_currentItem->url()) {
    316         m_currentItem->generateNewItemSequenceNumber();
    317         if (!equalIgnoringFragmentIdentifier(m_documentLoader->url(), m_currentItem->url()))
    318             m_currentItem->generateNewDocumentSequenceNumber();
    319     }
    320 
    321     m_currentItem->setURL(m_documentLoader->urlForHistory());
    322     m_currentItem->setDocumentState(m_frame->document()->formElementsState());
    323     m_currentItem->setTarget(m_frame->tree().uniqueName());
    324     if (isPushOrReplaceState)
    325         m_currentItem->setStateObject(stateObject);
    326     m_currentItem->setReferrer(Referrer(m_documentLoader->request().httpReferrer(), m_documentLoader->request().referrerPolicy()));
    327     m_currentItem->setFormInfoFromRequest(m_documentLoader->request());
    328 }
    329 
    330 static HistoryCommitType loadTypeToCommitType(FrameLoadType type)
    331 {
    332     switch (type) {
    333     case FrameLoadTypeStandard:
    334         return StandardCommit;
    335     case FrameLoadTypeInitialInChildFrame:
    336         return InitialCommitInChildFrame;
    337     case FrameLoadTypeBackForward:
    338         return BackForwardCommit;
    339     default:
    340         break;
    341     }
    342     return HistoryInertCommit;
    343 }
    344 
    345 void FrameLoader::receivedFirstData()
    346 {
    347     if (m_stateMachine.creatingInitialEmptyDocument())
    348         return;
    349 
    350     HistoryCommitType historyCommitType = loadTypeToCommitType(m_loadType);
    351     if (historyCommitType == StandardCommit && (m_documentLoader->urlForHistory().isEmpty() || (opener() && !m_currentItem && m_documentLoader->originalRequest().url().isEmpty())))
    352         historyCommitType = HistoryInertCommit;
    353     else if (historyCommitType == InitialCommitInChildFrame && (!m_frame->tree().top()->isLocalFrame() || MixedContentChecker::isMixedContent(toLocalFrame(m_frame->tree().top())->document()->securityOrigin(), m_documentLoader->url())))
    354         historyCommitType = HistoryInertCommit;
    355     setHistoryItemStateForCommit(historyCommitType);
    356 
    357     if (!m_stateMachine.committedMultipleRealLoads() && m_loadType == FrameLoadTypeStandard)
    358         m_stateMachine.advanceTo(FrameLoaderStateMachine::CommittedMultipleRealLoads);
    359 
    360     client()->dispatchDidCommitLoad(m_frame, m_currentItem.get(), historyCommitType);
    361 
    362     InspectorInstrumentation::didCommitLoad(m_frame, m_documentLoader.get());
    363     m_frame->page()->didCommitLoad(m_frame);
    364     dispatchDidClearDocumentOfWindowObject();
    365 }
    366 
    367 void FrameLoader::didBeginDocument(bool dispatch)
    368 {
    369     m_frame->document()->setReadyState(Document::Loading);
    370 
    371     if (m_provisionalItem && m_loadType == FrameLoadTypeBackForward)
    372         m_frame->domWindow()->statePopped(m_provisionalItem->stateObject());
    373 
    374     if (dispatch)
    375         dispatchDidClearDocumentOfWindowObject();
    376 
    377     m_frame->document()->initContentSecurityPolicy(m_documentLoader ? m_documentLoader->releaseContentSecurityPolicy() : ContentSecurityPolicy::create());
    378 
    379     Settings* settings = m_frame->document()->settings();
    380     if (settings) {
    381         m_frame->document()->fetcher()->setImagesEnabled(settings->imagesEnabled());
    382         m_frame->document()->fetcher()->setAutoLoadImages(settings->loadsImagesAutomatically());
    383     }
    384 
    385     if (m_documentLoader) {
    386         const AtomicString& dnsPrefetchControl = m_documentLoader->response().httpHeaderField("X-DNS-Prefetch-Control");
    387         if (!dnsPrefetchControl.isEmpty())
    388             m_frame->document()->parseDNSPrefetchControlHeader(dnsPrefetchControl);
    389 
    390         String headerContentLanguage = m_documentLoader->response().httpHeaderField("Content-Language");
    391         if (!headerContentLanguage.isEmpty()) {
    392             size_t commaIndex = headerContentLanguage.find(',');
    393             headerContentLanguage.truncate(commaIndex); // kNotFound == -1 == don't truncate
    394             headerContentLanguage = headerContentLanguage.stripWhiteSpace(isHTMLSpace<UChar>);
    395             if (!headerContentLanguage.isEmpty())
    396                 m_frame->document()->setContentLanguage(AtomicString(headerContentLanguage));
    397         }
    398     }
    399 
    400     if (m_provisionalItem && m_loadType == FrameLoadTypeBackForward)
    401         m_frame->document()->setStateForNewFormElements(m_provisionalItem->documentState());
    402 }
    403 
    404 void FrameLoader::finishedParsing()
    405 {
    406     if (m_stateMachine.creatingInitialEmptyDocument())
    407         return;
    408 
    409     // This can be called from the LocalFrame's destructor, in which case we shouldn't protect ourselves
    410     // because doing so will cause us to re-enter the destructor when protector goes out of scope.
    411     // Null-checking the FrameView indicates whether or not we're in the destructor.
    412     RefPtrWillBeRawPtr<LocalFrame> protect(m_frame->view() ? m_frame.get() : nullptr);
    413 
    414     if (client())
    415         client()->dispatchDidFinishDocumentLoad();
    416 
    417     checkCompleted();
    418 
    419     if (!m_frame->view())
    420         return; // We are being destroyed by something checkCompleted called.
    421 
    422     // Check if the scrollbars are really needed for the content.
    423     // If not, remove them, relayout, and repaint.
    424     m_frame->view()->restoreScrollbar();
    425     scrollToFragmentWithParentBoundary(m_frame->document()->url());
    426 }
    427 
    428 void FrameLoader::loadDone()
    429 {
    430     checkCompleted();
    431 }
    432 
    433 bool FrameLoader::allChildrenAreComplete() const
    434 {
    435     for (Frame* child = m_frame->tree().firstChild(); child; child = child->tree().nextSibling()) {
    436         if (!child->isLocalFrame())
    437             continue;
    438         LocalFrame* frame = toLocalFrame(child);
    439         if (!frame->document()->isLoadCompleted() || frame->loader().m_provisionalDocumentLoader)
    440             return false;
    441     }
    442     return true;
    443 }
    444 
    445 bool FrameLoader::allAncestorsAreComplete() const
    446 {
    447     for (Frame* ancestor = m_frame; ancestor; ancestor = ancestor->tree().parent()) {
    448         if (ancestor->isLocalFrame() && !toLocalFrame(ancestor)->document()->loadEventFinished())
    449             return false;
    450     }
    451     return true;
    452 }
    453 
    454 void FrameLoader::checkCompleted()
    455 {
    456     RefPtrWillBeRawPtr<LocalFrame> protect(m_frame.get());
    457 
    458     if (m_frame->view())
    459         m_frame->view()->handleLoadCompleted();
    460 
    461     if (m_frame->document()->isLoadCompleted() && m_stateMachine.committedFirstRealDocumentLoad())
    462         return;
    463 
    464     // Are we still parsing?
    465     if (m_frame->document()->parsing())
    466         return;
    467 
    468     // Still waiting imports?
    469     if (!m_frame->document()->haveImportsLoaded())
    470         return;
    471 
    472     // Still waiting for images/scripts?
    473     if (m_frame->document()->fetcher()->requestCount())
    474         return;
    475 
    476     // Still waiting for elements that don't go through a FrameLoader?
    477     if (m_frame->document()->isDelayingLoadEvent())
    478         return;
    479 
    480     // Any frame that hasn't completed yet?
    481     if (!allChildrenAreComplete())
    482         return;
    483 
    484     // OK, completed.
    485     m_frame->document()->setReadyState(Document::Complete);
    486     if (m_frame->document()->loadEventStillNeeded())
    487         m_frame->document()->implicitClose();
    488 
    489     m_frame->navigationScheduler().startTimer();
    490 
    491     completed();
    492     if (m_frame->page())
    493         checkLoadComplete();
    494 
    495     if (m_frame->view())
    496         m_frame->view()->handleLoadCompleted();
    497 }
    498 
    499 void FrameLoader::checkTimerFired(Timer<FrameLoader>*)
    500 {
    501     if (Page* page = m_frame->page()) {
    502         if (page->defersLoading())
    503             return;
    504     }
    505     checkCompleted();
    506 }
    507 
    508 void FrameLoader::scheduleCheckCompleted()
    509 {
    510     if (!m_checkTimer.isActive())
    511         m_checkTimer.startOneShot(0, FROM_HERE);
    512 }
    513 
    514 Frame* FrameLoader::opener()
    515 {
    516     return client() ? client()->opener() : 0;
    517 }
    518 
    519 void FrameLoader::setOpener(LocalFrame* opener)
    520 {
    521     // If the frame is already detached, the opener has already been cleared.
    522     if (client())
    523         client()->setOpener(opener);
    524 }
    525 
    526 bool FrameLoader::allowPlugins(ReasonForCallingAllowPlugins reason)
    527 {
    528     // With Oilpan, a FrameLoader might be accessed after the
    529     // FrameHost has been detached. FrameClient will not be
    530     // accessible, so bail early.
    531     if (!client())
    532         return false;
    533     Settings* settings = m_frame->settings();
    534     bool allowed = client()->allowPlugins(settings && settings->pluginsEnabled());
    535     if (!allowed && reason == AboutToInstantiatePlugin)
    536         client()->didNotAllowPlugins();
    537     return allowed;
    538 }
    539 
    540 void FrameLoader::updateForSameDocumentNavigation(const KURL& newURL, SameDocumentNavigationSource sameDocumentNavigationSource, PassRefPtr<SerializedScriptValue> data, FrameLoadType type)
    541 {
    542     // Update the data source's request with the new URL to fake the URL change
    543     m_frame->document()->setURL(newURL);
    544     documentLoader()->updateForSameDocumentNavigation(newURL, sameDocumentNavigationSource);
    545 
    546     // Generate start and stop notifications only when loader is completed so that we
    547     // don't fire them for fragment redirection that happens in window.onload handler.
    548     // See https://bugs.webkit.org/show_bug.cgi?id=31838
    549     if (m_frame->document()->loadEventFinished())
    550         client()->didStartLoading(NavigationWithinSameDocument);
    551 
    552     HistoryCommitType historyCommitType = loadTypeToCommitType(type);
    553     if (!m_currentItem)
    554         historyCommitType = HistoryInertCommit;
    555 
    556     setHistoryItemStateForCommit(historyCommitType, sameDocumentNavigationSource == SameDocumentNavigationHistoryApi, data);
    557     client()->dispatchDidNavigateWithinPage(m_currentItem.get(), historyCommitType);
    558     client()->dispatchDidReceiveTitle(m_frame->document()->title());
    559     if (m_frame->document()->loadEventFinished())
    560         client()->didStopLoading();
    561 }
    562 
    563 void FrameLoader::loadInSameDocument(const KURL& url, PassRefPtr<SerializedScriptValue> stateObject, FrameLoadType type, ClientRedirectPolicy clientRedirect)
    564 {
    565     // If we have a state object, we cannot also be a new navigation.
    566     ASSERT(!stateObject || type == FrameLoadTypeBackForward);
    567 
    568     // If we have a provisional request for a different document, a fragment scroll should cancel it.
    569     if (m_provisionalDocumentLoader) {
    570         m_provisionalDocumentLoader->stopLoading();
    571         if (m_provisionalDocumentLoader)
    572             m_provisionalDocumentLoader->detachFromFrame();
    573         m_provisionalDocumentLoader = nullptr;
    574         if (!m_frame->host())
    575             return;
    576     }
    577     m_loadType = type;
    578     saveScrollState();
    579 
    580     KURL oldURL = m_frame->document()->url();
    581     // If we were in the autoscroll/panScroll mode we want to stop it before following the link to the anchor
    582     bool hashChange = equalIgnoringFragmentIdentifier(url, oldURL) && url.fragmentIdentifier() != oldURL.fragmentIdentifier();
    583     if (hashChange) {
    584         m_frame->eventHandler().stopAutoscroll();
    585         m_frame->domWindow()->enqueueHashchangeEvent(oldURL, url);
    586     }
    587     m_documentLoader->setIsClientRedirect(clientRedirect == ClientRedirect);
    588     m_documentLoader->setReplacesCurrentHistoryItem(m_loadType == FrameLoadTypeStandard);
    589     updateForSameDocumentNavigation(url, SameDocumentNavigationDefault, nullptr, type);
    590 
    591     m_frame->view()->setWasScrolledByUser(false);
    592 
    593     // We need to scroll to the fragment whether or not a hash change occurred, since
    594     // the user might have scrolled since the previous navigation.
    595     scrollToFragmentWithParentBoundary(url);
    596     checkCompleted();
    597 
    598     m_frame->domWindow()->statePopped(stateObject ? stateObject : SerializedScriptValue::nullValue());
    599 }
    600 
    601 void FrameLoader::completed()
    602 {
    603     RefPtrWillBeRawPtr<LocalFrame> protect(m_frame.get());
    604 
    605     for (Frame* descendant = m_frame->tree().traverseNext(m_frame); descendant; descendant = descendant->tree().traverseNext(m_frame)) {
    606         if (descendant->isLocalFrame())
    607             toLocalFrame(descendant)->navigationScheduler().startTimer();
    608     }
    609 
    610     Frame* parent = m_frame->tree().parent();
    611     if (parent && parent->isLocalFrame())
    612         toLocalFrame(parent)->loader().checkCompleted();
    613 
    614     if (m_frame->view())
    615         m_frame->view()->maintainScrollPositionAtAnchor(0);
    616 }
    617 
    618 void FrameLoader::setReferrerForFrameRequest(ResourceRequest& request, ShouldSendReferrer shouldSendReferrer, Document* originDocument)
    619 {
    620     if (shouldSendReferrer == NeverSendReferrer) {
    621         request.clearHTTPReferrer();
    622         return;
    623     }
    624 
    625     // Always use the initiating document to generate the referrer.
    626     // We need to generateReferrerHeader(), because we might not have enforced ReferrerPolicy or https->http
    627     // referrer suppression yet.
    628     String argsReferrer(request.httpReferrer());
    629     if (argsReferrer.isEmpty())
    630         argsReferrer = originDocument->outgoingReferrer();
    631     String referrer = SecurityPolicy::generateReferrerHeader(originDocument->referrerPolicy(), request.url(), argsReferrer);
    632 
    633     request.setHTTPReferrer(Referrer(referrer, originDocument->referrerPolicy()));
    634     RefPtr<SecurityOrigin> referrerOrigin = SecurityOrigin::createFromString(referrer);
    635     request.addHTTPOriginIfNeeded(referrerOrigin->toAtomicString());
    636 }
    637 
    638 bool FrameLoader::isScriptTriggeredFormSubmissionInChildFrame(const FrameLoadRequest& request) const
    639 {
    640     // If this is a child frame and the form submission was triggered by a script, lock the back/forward list
    641     // to match IE and Opera.
    642     // See https://bugs.webkit.org/show_bug.cgi?id=32383 for the original motivation for this.
    643     if (!m_frame->tree().parent() || UserGestureIndicator::processingUserGesture())
    644         return false;
    645     return request.formState() && request.formState()->formSubmissionTrigger() == SubmittedByJavaScript;
    646 }
    647 
    648 FrameLoadType FrameLoader::determineFrameLoadType(const FrameLoadRequest& request)
    649 {
    650     if (m_frame->tree().parent() && !m_stateMachine.committedFirstRealDocumentLoad())
    651         return FrameLoadTypeInitialInChildFrame;
    652     if (!m_frame->tree().parent() && !m_frame->page()->backForward().backForwardListCount())
    653         return FrameLoadTypeStandard;
    654     if (m_provisionalDocumentLoader && request.substituteData().failingURL() == m_provisionalDocumentLoader->url() && m_loadType == FrameLoadTypeBackForward)
    655         return FrameLoadTypeBackForward;
    656     if (request.resourceRequest().cachePolicy() == ReloadIgnoringCacheData)
    657         return FrameLoadTypeReload;
    658     if (request.resourceRequest().cachePolicy() == ReloadBypassingCache)
    659         return FrameLoadTypeReloadFromOrigin;
    660     if (request.lockBackForwardList() || isScriptTriggeredFormSubmissionInChildFrame(request))
    661         return FrameLoadTypeRedirectWithLockedBackForwardList;
    662     if (!request.originDocument() && request.resourceRequest().url() == m_documentLoader->urlForHistory())
    663         return FrameLoadTypeSame;
    664     if (request.substituteData().failingURL() == m_documentLoader->urlForHistory() && m_loadType == FrameLoadTypeReload)
    665         return FrameLoadTypeReload;
    666     return FrameLoadTypeStandard;
    667 }
    668 
    669 bool FrameLoader::prepareRequestForThisFrame(FrameLoadRequest& request)
    670 {
    671     request.resourceRequest().setFrameType(m_frame->isMainFrame() ? WebURLRequest::FrameTypeTopLevel : WebURLRequest::FrameTypeNested);
    672 
    673     // If no origin Document* was specified, skip remaining security checks and assume the caller has fully initialized the FrameLoadRequest.
    674     if (!request.originDocument())
    675         return true;
    676 
    677     KURL url = request.resourceRequest().url();
    678     if (m_frame->script().executeScriptIfJavaScriptURL(url))
    679         return false;
    680 
    681     if (!request.originDocument()->securityOrigin()->canDisplay(url)) {
    682         reportLocalLoadFailed(m_frame, url.elidedString());
    683         return false;
    684     }
    685 
    686     if (!request.formState() && request.frameName().isEmpty())
    687         request.setFrameName(m_frame->document()->baseTarget());
    688 
    689     setReferrerForFrameRequest(request.resourceRequest(), request.shouldSendReferrer(), request.originDocument());
    690     return true;
    691 }
    692 
    693 static bool shouldOpenInNewWindow(LocalFrame* targetFrame, const FrameLoadRequest& request, const NavigationAction& action)
    694 {
    695     if (!targetFrame && !request.frameName().isEmpty())
    696         return true;
    697     // FIXME: This case is a workaround for the fact that ctrl+clicking a form submission incorrectly
    698     // sends as a GET rather than a POST if it creates a new window in a different process.
    699     return request.formState() && action.shouldOpenInNewWindow();
    700 }
    701 
    702 static WebURLRequest::RequestContext determineRequestContextFromNavigationType(const NavigationType navigationType)
    703 {
    704     switch (navigationType) {
    705     case NavigationTypeLinkClicked:
    706         return WebURLRequest::RequestContextHyperlink;
    707 
    708     case NavigationTypeOther:
    709         return WebURLRequest::RequestContextLocation;
    710 
    711     case NavigationTypeFormResubmitted:
    712     case NavigationTypeFormSubmitted:
    713         return WebURLRequest::RequestContextForm;
    714 
    715     case NavigationTypeBackForward:
    716     case NavigationTypeReload:
    717         return WebURLRequest::RequestContextInternal;
    718     }
    719     ASSERT_NOT_REACHED();
    720     return WebURLRequest::RequestContextHyperlink;
    721 }
    722 
    723 void FrameLoader::load(const FrameLoadRequest& passedRequest)
    724 {
    725     ASSERT(m_frame->document());
    726 
    727     RefPtrWillBeRawPtr<LocalFrame> protect(m_frame.get());
    728 
    729     if (m_inStopAllLoaders)
    730         return;
    731 
    732     FrameLoadRequest request(passedRequest);
    733     if (!prepareRequestForThisFrame(request))
    734         return;
    735 
    736     RefPtrWillBeRawPtr<LocalFrame> targetFrame = request.formState() ? 0 : findFrameForNavigation(AtomicString(request.frameName()), request.formState() ? request.formState()->sourceDocument() : m_frame->document());
    737     if (targetFrame && targetFrame.get() != m_frame) {
    738         request.setFrameName("_self");
    739         targetFrame->loader().load(request);
    740         if (Page* page = targetFrame->page())
    741             page->chrome().focus();
    742         return;
    743     }
    744 
    745     FrameLoadType newLoadType = determineFrameLoadType(request);
    746     NavigationAction action(request.resourceRequest(), newLoadType, request.formState(), request.triggeringEvent());
    747     if (action.resourceRequest().requestContext() == WebURLRequest::RequestContextUnspecified)
    748         action.mutableResourceRequest().setRequestContext(determineRequestContextFromNavigationType(action.type()));
    749     if (shouldOpenInNewWindow(targetFrame.get(), request, action)) {
    750         if (action.policy() == NavigationPolicyDownload)
    751             client()->loadURLExternally(action.resourceRequest(), NavigationPolicyDownload);
    752         else
    753             createWindowForRequest(request, *m_frame, action.policy(), request.shouldSendReferrer());
    754         return;
    755     }
    756 
    757     const KURL& url = request.resourceRequest().url();
    758     if (!action.shouldOpenInNewWindow() && shouldPerformFragmentNavigation(request.formState(), request.resourceRequest().httpMethod(), newLoadType, url)) {
    759         m_documentLoader->setTriggeringAction(action);
    760         if (shouldTreatURLAsSameAsCurrent(url))
    761             newLoadType = FrameLoadTypeRedirectWithLockedBackForwardList;
    762         loadInSameDocument(url, nullptr, newLoadType, request.clientRedirect());
    763         return;
    764     }
    765     bool sameURL = url == m_documentLoader->urlForHistory();
    766     loadWithNavigationAction(action, newLoadType, request.formState(), request.substituteData(), request.shouldCheckMainWorldContentSecurityPolicy(), request.clientRedirect());
    767     // Example of this case are sites that reload the same URL with a different cookie
    768     // driving the generated content, or a master frame with links that drive a target
    769     // frame, where the user has clicked on the same link repeatedly.
    770     if (sameURL && newLoadType != FrameLoadTypeReload && newLoadType != FrameLoadTypeReloadFromOrigin && request.resourceRequest().httpMethod() != "POST")
    771         m_loadType = FrameLoadTypeSame;
    772 }
    773 
    774 SubstituteData FrameLoader::defaultSubstituteDataForURL(const KURL& url)
    775 {
    776     if (!shouldTreatURLAsSrcdocDocument(url))
    777         return SubstituteData();
    778     String srcdoc = m_frame->deprecatedLocalOwner()->fastGetAttribute(srcdocAttr);
    779     ASSERT(!srcdoc.isNull());
    780     CString encodedSrcdoc = srcdoc.utf8();
    781     return SubstituteData(SharedBuffer::create(encodedSrcdoc.data(), encodedSrcdoc.length()), "text/html", "UTF-8", KURL());
    782 }
    783 
    784 void FrameLoader::reportLocalLoadFailed(LocalFrame* frame, const String& url)
    785 {
    786     ASSERT(!url.isEmpty());
    787     if (!frame)
    788         return;
    789 
    790     frame->document()->addConsoleMessage(ConsoleMessage::create(SecurityMessageSource, ErrorMessageLevel, "Not allowed to load local resource: " + url));
    791 }
    792 
    793 // static
    794 ResourceRequest FrameLoader::requestFromHistoryItem(HistoryItem* item, ResourceRequestCachePolicy cachePolicy)
    795 {
    796     RefPtr<FormData> formData = item->formData();
    797     ResourceRequest request(item->url(), item->referrer());
    798     request.setCachePolicy(cachePolicy);
    799     if (formData) {
    800         request.setHTTPMethod("POST");
    801         request.setHTTPBody(formData);
    802         request.setHTTPContentType(item->formContentType());
    803         RefPtr<SecurityOrigin> securityOrigin = SecurityOrigin::createFromString(item->referrer().referrer);
    804         request.addHTTPOriginIfNeeded(securityOrigin->toAtomicString());
    805     }
    806     return request;
    807 }
    808 
    809 void FrameLoader::reload(ReloadPolicy reloadPolicy, const KURL& overrideURL, const AtomicString& overrideEncoding, ClientRedirectPolicy clientRedirectPolicy)
    810 {
    811     if (!m_currentItem)
    812         return;
    813 
    814     ResourceRequestCachePolicy cachePolicy = reloadPolicy == EndToEndReload ? ReloadBypassingCache : ReloadIgnoringCacheData;
    815     ResourceRequest request = requestFromHistoryItem(m_currentItem.get(), cachePolicy);
    816     request.setFrameType(m_frame->isMainFrame() ? WebURLRequest::FrameTypeTopLevel : WebURLRequest::FrameTypeNested);
    817     request.setRequestContext(WebURLRequest::RequestContextInternal);
    818 
    819     // ClientRedirectPolicy is an indication that this load was triggered by
    820     // some direct interaction with the page. If this reload is not a client
    821     // redirect, we should reuse the referrer from the original load of the
    822     // current document. If this reload is a client redirect (e.g., location.reload()),
    823     // it was initiated by something in the current document and should
    824     // therefore show the current document's url as the referrer.
    825     if (clientRedirectPolicy == ClientRedirect)
    826         request.setHTTPReferrer(Referrer(m_frame->document()->outgoingReferrer(), m_frame->document()->referrerPolicy()));
    827 
    828     if (!overrideURL.isEmpty()) {
    829         request.setURL(overrideURL);
    830         request.clearHTTPReferrer();
    831     }
    832     request.setSkipServiceWorker(reloadPolicy == EndToEndReload);
    833 
    834     FrameLoadType type = reloadPolicy == EndToEndReload ? FrameLoadTypeReloadFromOrigin : FrameLoadTypeReload;
    835     loadWithNavigationAction(NavigationAction(request, type), type, nullptr, SubstituteData(), CheckContentSecurityPolicy, clientRedirectPolicy, overrideEncoding);
    836 }
    837 
    838 void FrameLoader::stopAllLoaders()
    839 {
    840     if (m_frame->document()->pageDismissalEventBeingDispatched() != Document::NoDismissal)
    841         return;
    842 
    843     // If this method is called from within this method, infinite recursion can occur (3442218). Avoid this.
    844     if (m_inStopAllLoaders)
    845         return;
    846 
    847     // Calling stopLoading() on the provisional document loader can blow away
    848     // the frame from underneath.
    849     RefPtrWillBeRawPtr<LocalFrame> protect(m_frame.get());
    850 
    851     m_inStopAllLoaders = true;
    852 
    853     for (RefPtrWillBeRawPtr<Frame> child = m_frame->tree().firstChild(); child; child = child->tree().nextSibling()) {
    854         if (child->isLocalFrame())
    855             toLocalFrame(child.get())->loader().stopAllLoaders();
    856     }
    857     if (m_provisionalDocumentLoader)
    858         m_provisionalDocumentLoader->stopLoading();
    859     if (m_documentLoader)
    860         m_documentLoader->stopLoading();
    861 
    862     if (m_provisionalDocumentLoader)
    863         m_provisionalDocumentLoader->detachFromFrame();
    864     m_provisionalDocumentLoader = nullptr;
    865 
    866     m_checkTimer.stop();
    867 
    868     m_inStopAllLoaders = false;
    869 
    870     // detachFromParent() can be called multiple times on same LocalFrame, which
    871     // means we may no longer have a FrameLoaderClient to talk to.
    872     if (client())
    873         client()->didStopAllLoaders();
    874 }
    875 
    876 void FrameLoader::didAccessInitialDocument()
    877 {
    878     // We only need to notify the client once, and only for the main frame.
    879     if (isLoadingMainFrame() && !m_didAccessInitialDocument) {
    880         m_didAccessInitialDocument = true;
    881         // Notify asynchronously, since this is called within a JavaScript security check.
    882         m_didAccessInitialDocumentTimer.startOneShot(0, FROM_HERE);
    883     }
    884 }
    885 
    886 void FrameLoader::didAccessInitialDocumentTimerFired(Timer<FrameLoader>*)
    887 {
    888     if (client())
    889         client()->didAccessInitialDocument();
    890 }
    891 
    892 void FrameLoader::notifyIfInitialDocumentAccessed()
    893 {
    894     if (m_didAccessInitialDocumentTimer.isActive()) {
    895         m_didAccessInitialDocumentTimer.stop();
    896         didAccessInitialDocumentTimerFired(0);
    897     }
    898 }
    899 
    900 void FrameLoader::commitProvisionalLoad()
    901 {
    902     ASSERT(client()->hasWebView());
    903     ASSERT(m_state == FrameStateProvisional);
    904     RefPtr<DocumentLoader> pdl = m_provisionalDocumentLoader;
    905     RefPtrWillBeRawPtr<LocalFrame> protect(m_frame.get());
    906 
    907     // Check if the destination page is allowed to access the previous page's timing information.
    908     if (m_frame->document()) {
    909         RefPtr<SecurityOrigin> securityOrigin = SecurityOrigin::create(pdl->request().url());
    910         pdl->timing()->setHasSameOriginAsPreviousDocument(securityOrigin->canRequest(m_frame->document()->url()));
    911     }
    912 
    913     // The call to closeURL() invokes the unload event handler, which can execute arbitrary
    914     // JavaScript. If the script initiates a new load, we need to abandon the current load,
    915     // or the two will stomp each other.
    916     // detachChildren will similarly trigger child frame unload event handlers.
    917     if (m_documentLoader) {
    918         client()->dispatchWillClose();
    919         closeURL();
    920     }
    921     m_frame->detachChildren();
    922     if (pdl != m_provisionalDocumentLoader)
    923         return;
    924     if (m_documentLoader)
    925         m_documentLoader->detachFromFrame();
    926     m_documentLoader = m_provisionalDocumentLoader.release();
    927     m_state = FrameStateCommittedPage;
    928 
    929     if (isLoadingMainFrame())
    930         m_frame->page()->chrome().client().needTouchEvents(false);
    931 
    932     client()->transitionToCommittedForNewPage();
    933     m_frame->navigationScheduler().cancel();
    934     m_frame->editor().clearLastEditCommand();
    935 
    936     // If we are still in the process of initializing an empty document then
    937     // its frame is not in a consistent state for rendering, so avoid setJSStatusBarText
    938     // since it may cause clients to attempt to render the frame.
    939     if (!m_stateMachine.creatingInitialEmptyDocument()) {
    940         LocalDOMWindow* window = m_frame->domWindow();
    941         window->setStatus(String());
    942         window->setDefaultStatus(String());
    943     }
    944 }
    945 
    946 bool FrameLoader::isLoadingMainFrame() const
    947 {
    948     return m_frame->isMainFrame();
    949 }
    950 
    951 FrameLoadType FrameLoader::loadType() const
    952 {
    953     return m_loadType;
    954 }
    955 
    956 // This function is an incomprehensible mess and is only used in checkLoadCompleteForThisFrame.
    957 // If you're thinking of using it elsewhere, stop right now and reconsider your life.
    958 static bool isDocumentDoneLoading(Document* document)
    959 {
    960     if (!document->loader())
    961         return true;
    962     if (document->loader()->isLoadingMainResource())
    963         return false;
    964     if (!document->loadEventFinished()) {
    965         if (document->loader()->isLoading() || document->isDelayingLoadEvent())
    966             return false;
    967     }
    968     if (document->fetcher()->requestCount())
    969         return false;
    970     if (document->processingLoadEvent())
    971         return false;
    972     if (document->hasActiveParser())
    973         return false;
    974     return true;
    975 }
    976 
    977 bool FrameLoader::checkLoadCompleteForThisFrame()
    978 {
    979     ASSERT(client()->hasWebView());
    980     RefPtrWillBeRawPtr<LocalFrame> protect(m_frame.get());
    981 
    982     bool allChildrenAreDoneLoading = true;
    983     for (RefPtrWillBeRawPtr<Frame> child = m_frame->tree().firstChild(); child; child = child->tree().nextSibling()) {
    984         if (child->isLocalFrame())
    985             allChildrenAreDoneLoading &= toLocalFrame(child.get())->loader().checkLoadCompleteForThisFrame();
    986     }
    987 
    988     if (m_state == FrameStateProvisional && m_provisionalDocumentLoader) {
    989         const ResourceError& error = m_provisionalDocumentLoader->mainDocumentError();
    990         if (error.isNull())
    991             return false;
    992         RefPtr<DocumentLoader> loader = m_provisionalDocumentLoader;
    993         client()->dispatchDidFailProvisionalLoad(error);
    994         if (loader != m_provisionalDocumentLoader)
    995             return false;
    996         m_provisionalDocumentLoader->detachFromFrame();
    997         m_provisionalDocumentLoader = nullptr;
    998         m_progressTracker->progressCompleted();
    999         m_state = FrameStateComplete;
   1000         checkCompleted();
   1001         return true;
   1002     }
   1003 
   1004     if (!allChildrenAreDoneLoading)
   1005         return false;
   1006 
   1007     if (m_state == FrameStateComplete)
   1008         return true;
   1009     if (m_provisionalDocumentLoader || !m_documentLoader)
   1010         return false;
   1011     if (!isDocumentDoneLoading(m_frame->document()) && !m_inStopAllLoaders)
   1012         return false;
   1013 
   1014     m_state = FrameStateComplete;
   1015 
   1016     // FIXME: Is this subsequent work important if we already navigated away?
   1017     // Maybe there are bugs because of that, or extra work we can skip because
   1018     // the new page is ready.
   1019 
   1020     // Retry restoring scroll offset since FrameStateComplete disables content
   1021     // size clamping.
   1022     restoreScrollPositionAndViewState();
   1023 
   1024     if (!m_stateMachine.committedFirstRealDocumentLoad())
   1025         return true;
   1026 
   1027     m_progressTracker->progressCompleted();
   1028     m_frame->domWindow()->finishedLoading();
   1029 
   1030     const ResourceError& error = m_documentLoader->mainDocumentError();
   1031     if (!error.isNull()) {
   1032         client()->dispatchDidFailLoad(error);
   1033     } else {
   1034         // Report mobile vs. desktop page statistics. This will only report on Android.
   1035         if (m_frame->isMainFrame())
   1036             m_frame->document()->viewportDescription().reportMobilePageStats(m_frame);
   1037 
   1038         client()->dispatchDidFinishLoad();
   1039     }
   1040     m_loadType = FrameLoadTypeStandard;
   1041     return true;
   1042 }
   1043 
   1044 void FrameLoader::restoreScrollPositionAndViewState()
   1045 {
   1046     FrameView* view = m_frame->view();
   1047     if (!m_frame->page() || !view || !m_currentItem || !m_stateMachine.committedFirstRealDocumentLoad())
   1048         return;
   1049 
   1050     if (!needsHistoryItemRestore(m_loadType))
   1051         return;
   1052 
   1053     // This tries to balance 1. restoring as soon as possible, 2. detecting
   1054     // clamping to avoid repeatedly popping the scroll position down as the
   1055     // page height increases, 3. ignore clamp detection after load completes
   1056     // because that may be because the page will never reach its previous
   1057     // height.
   1058     float mainFrameScale = m_frame->settings()->pinchVirtualViewportEnabled() ? 1 : m_currentItem->pageScaleFactor();
   1059     bool canRestoreWithoutClamping = view->clampOffsetAtScale(m_currentItem->scrollPoint(), mainFrameScale) == m_currentItem->scrollPoint();
   1060     bool canRestoreWithoutAnnoyingUser = !view->wasScrolledByUser() && (canRestoreWithoutClamping || m_state == FrameStateComplete);
   1061     if (!canRestoreWithoutAnnoyingUser)
   1062         return;
   1063 
   1064     if (m_frame->isMainFrame() && m_currentItem->pageScaleFactor()) {
   1065         FloatPoint pinchViewportOffset(m_currentItem->pinchViewportScrollPoint());
   1066         IntPoint frameScrollOffset(m_currentItem->scrollPoint());
   1067 
   1068         m_frame->page()->setPageScaleFactor(m_currentItem->pageScaleFactor(), frameScrollOffset);
   1069 
   1070         if (m_frame->settings()->pinchVirtualViewportEnabled()) {
   1071             // If the pinch viewport's offset is (-1, -1) it means the history item
   1072             // is an old version of HistoryItem so distribute the scroll between
   1073             // the main frame and the pinch viewport as best as we can.
   1074             // FIXME(bokan): This legacy distribution can be removed once the virtual viewport
   1075             // pinch path is enabled on all platforms for at least one release.
   1076             if (pinchViewportOffset.x() == -1 && pinchViewportOffset.y() == -1)
   1077                 pinchViewportOffset = FloatPoint(frameScrollOffset - view->scrollPosition());
   1078 
   1079             m_frame->host()->pinchViewport().setLocation(pinchViewportOffset);
   1080         }
   1081     } else {
   1082         view->setScrollPositionNonProgrammatically(m_currentItem->scrollPoint());
   1083     }
   1084 
   1085     if (m_frame->isMainFrame()) {
   1086         if (ScrollingCoordinator* scrollingCoordinator = m_frame->page()->scrollingCoordinator())
   1087             scrollingCoordinator->frameViewRootLayerDidChange(view);
   1088     }
   1089 }
   1090 
   1091 // Called every time a resource is completely loaded or an error is received.
   1092 void FrameLoader::checkLoadComplete()
   1093 {
   1094     ASSERT(client()->hasWebView());
   1095     if (Page* page = m_frame->page()) {
   1096         if (page->mainFrame()->isLocalFrame())
   1097             page->deprecatedLocalMainFrame()->loader().checkLoadCompleteForThisFrame();
   1098     }
   1099 }
   1100 
   1101 String FrameLoader::userAgent(const KURL& url) const
   1102 {
   1103     String userAgent = client()->userAgent(url);
   1104     InspectorInstrumentation::applyUserAgentOverride(m_frame, &userAgent);
   1105     return userAgent;
   1106 }
   1107 
   1108 void FrameLoader::detachFromParent()
   1109 {
   1110 #if !ENABLE(OILPAN)
   1111     // The caller must protect a reference to m_frame.
   1112     ASSERT(m_frame->refCount() > 1);
   1113 #endif
   1114 
   1115     InspectorInstrumentation::frameDetachedFromParent(m_frame);
   1116 
   1117     if (m_documentLoader)
   1118         m_documentLoader->detachFromFrame();
   1119     m_documentLoader = nullptr;
   1120 
   1121     if (!client())
   1122         return;
   1123 
   1124     // FIXME: All this code belongs up in Page.
   1125     Frame* parent = m_frame->tree().parent();
   1126     if (parent && parent->isLocalFrame()) {
   1127         m_frame->setView(nullptr);
   1128         // FIXME: Shouldn't need to check if page() is null here.
   1129         if (m_frame->owner() && m_frame->page())
   1130             m_frame->page()->decrementSubframeCount();
   1131         m_frame->willDetachFrameHost();
   1132         detachClient();
   1133         toLocalFrame(parent)->loader().scheduleCheckCompleted();
   1134     } else {
   1135         m_frame->setView(nullptr);
   1136         m_frame->willDetachFrameHost();
   1137         detachClient();
   1138     }
   1139     m_frame->detachFromFrameHost();
   1140 }
   1141 
   1142 void FrameLoader::detachClient()
   1143 {
   1144     ASSERT(client());
   1145 
   1146     // Finish all cleanup work that might require talking to the embedder.
   1147     m_progressTracker->dispose();
   1148     m_progressTracker.clear();
   1149     setOpener(0);
   1150     // Notify ScriptController that the frame is closing, since its cleanup ends up calling
   1151     // back to FrameLoaderClient via WindowProxy.
   1152     m_frame->script().clearForClose();
   1153 
   1154     // client() should never be null because that means we somehow re-entered
   1155     // the frame detach code... but it is sometimes.
   1156     // FIXME: Understand why this is happening so we can document this insanity.
   1157     if (client()) {
   1158         // After this, we must no longer talk to the client since this clears
   1159         // its owning reference back to our owning LocalFrame.
   1160         client()->detachedFromParent();
   1161         m_frame->clearClient();
   1162     }
   1163 }
   1164 
   1165 void FrameLoader::receivedMainResourceError(const ResourceError& error)
   1166 {
   1167     // Retain because the stop may release the last reference to it.
   1168     RefPtrWillBeRawPtr<LocalFrame> protect(m_frame.get());
   1169 
   1170     if (m_frame->document()->parser())
   1171         m_frame->document()->parser()->stopParsing();
   1172 
   1173     // FIXME: We really ought to be able to just check for isCancellation() here, but there are some
   1174     // ResourceErrors that setIsCancellation() but aren't created by ResourceError::cancelledError().
   1175     ResourceError c(ResourceError::cancelledError(KURL()));
   1176     if ((error.errorCode() != c.errorCode() || error.domain() != c.domain()) && m_frame->owner()) {
   1177         // FIXME: For now, fallback content doesn't work cross process.
   1178         ASSERT(m_frame->owner()->isLocal());
   1179         m_frame->deprecatedLocalOwner()->renderFallbackContent();
   1180     }
   1181 
   1182     checkCompleted();
   1183     if (m_frame->page())
   1184         checkLoadComplete();
   1185 }
   1186 
   1187 bool FrameLoader::shouldPerformFragmentNavigation(bool isFormSubmission, const String& httpMethod, FrameLoadType loadType, const KURL& url)
   1188 {
   1189     ASSERT(loadType != FrameLoadTypeReloadFromOrigin);
   1190     // We don't do this if we are submitting a form with method other than "GET", explicitly reloading,
   1191     // currently displaying a frameset, or if the URL does not have a fragment.
   1192     return (!isFormSubmission || equalIgnoringCase(httpMethod, "GET"))
   1193         && loadType != FrameLoadTypeReload
   1194         && loadType != FrameLoadTypeSame
   1195         && loadType != FrameLoadTypeBackForward
   1196         && url.hasFragmentIdentifier()
   1197         && equalIgnoringFragmentIdentifier(m_frame->document()->url(), url)
   1198         // We don't want to just scroll if a link from within a
   1199         // frameset is trying to reload the frameset into _top.
   1200         && !m_frame->document()->isFrameSet();
   1201 }
   1202 
   1203 void FrameLoader::scrollToFragmentWithParentBoundary(const KURL& url)
   1204 {
   1205     FrameView* view = m_frame->view();
   1206     if (!view)
   1207         return;
   1208 
   1209     // Leaking scroll position to a cross-origin ancestor would permit the so-called "framesniffing" attack.
   1210     RefPtrWillBeRawPtr<LocalFrame> boundaryFrame = url.hasFragmentIdentifier() ? m_frame->document()->findUnsafeParentScrollPropagationBoundary() : 0;
   1211 
   1212     if (boundaryFrame)
   1213         boundaryFrame->view()->setSafeToPropagateScrollToParent(false);
   1214 
   1215     view->scrollToFragment(url);
   1216 
   1217     if (boundaryFrame)
   1218         boundaryFrame->view()->setSafeToPropagateScrollToParent(true);
   1219 }
   1220 
   1221 bool FrameLoader::shouldClose()
   1222 {
   1223     Page* page = m_frame->page();
   1224     if (!page || !page->chrome().canRunBeforeUnloadConfirmPanel())
   1225         return true;
   1226 
   1227     // Store all references to each subframe in advance since beforeunload's event handler may modify frame
   1228     WillBeHeapVector<RefPtrWillBeMember<LocalFrame> > targetFrames;
   1229     targetFrames.append(m_frame);
   1230     for (Frame* child = m_frame->tree().firstChild(); child; child = child->tree().traverseNext(m_frame)) {
   1231         // FIXME: There is not yet any way to dispatch events to out-of-process frames.
   1232         if (child->isLocalFrame())
   1233             targetFrames.append(toLocalFrame(child));
   1234     }
   1235 
   1236     bool shouldClose = false;
   1237     {
   1238         NavigationDisablerForBeforeUnload navigationDisabler;
   1239         size_t i;
   1240 
   1241         bool didAllowNavigation = false;
   1242         for (i = 0; i < targetFrames.size(); i++) {
   1243             if (!targetFrames[i]->tree().isDescendantOf(m_frame))
   1244                 continue;
   1245             if (!targetFrames[i]->document()->dispatchBeforeUnloadEvent(page->chrome(), didAllowNavigation))
   1246                 break;
   1247         }
   1248 
   1249         if (i == targetFrames.size())
   1250             shouldClose = true;
   1251     }
   1252     return shouldClose;
   1253 }
   1254 
   1255 bool FrameLoader::validateTransitionNavigationMode()
   1256 {
   1257     if (frame()->document()->inQuirksMode()) {
   1258         frame()->document()->addConsoleMessage(ConsoleMessage::create(JSMessageSource, ErrorMessageLevel, "Ignoring transition elements due to quirks mode."));
   1259         return false;
   1260     }
   1261 
   1262     // FIXME(oysteine): Also check for width=device-width here, to avoid zoom/scaling issues.
   1263     return true;
   1264 }
   1265 
   1266 bool FrameLoader::dispatchNavigationTransitionData()
   1267 {
   1268     Vector<Document::TransitionElementData> elementData;
   1269     frame()->document()->getTransitionElementData(elementData);
   1270     if (elementData.isEmpty() || !validateTransitionNavigationMode())
   1271         return false;
   1272 
   1273     Vector<Document::TransitionElementData>::iterator iter = elementData.begin();
   1274     for (; iter != elementData.end(); ++iter)
   1275         client()->dispatchAddNavigationTransitionData(iter->scope, iter->selector, iter->markup);
   1276 
   1277     return true;
   1278 }
   1279 
   1280 void FrameLoader::loadWithNavigationAction(const NavigationAction& action, FrameLoadType type, PassRefPtrWillBeRawPtr<FormState> formState, const SubstituteData& substituteData, ContentSecurityPolicyCheck shouldCheckMainWorldContentSecurityPolicy, ClientRedirectPolicy clientRedirect, const AtomicString& overrideEncoding)
   1281 {
   1282     ASSERT(client()->hasWebView());
   1283     if (m_frame->document()->pageDismissalEventBeingDispatched() != Document::NoDismissal)
   1284         return;
   1285 
   1286     const ResourceRequest& request = action.resourceRequest();
   1287 
   1288     // The current load should replace the history item if it is the first real
   1289     // load of the frame.
   1290     bool replacesCurrentHistoryItem = false;
   1291     if (type == FrameLoadTypeRedirectWithLockedBackForwardList
   1292         || !m_stateMachine.committedFirstRealDocumentLoad()) {
   1293         replacesCurrentHistoryItem = true;
   1294     }
   1295 
   1296     m_policyDocumentLoader = client()->createDocumentLoader(m_frame, request, substituteData.isValid() ? substituteData : defaultSubstituteDataForURL(request.url()));
   1297     m_policyDocumentLoader->setTriggeringAction(action);
   1298     m_policyDocumentLoader->setReplacesCurrentHistoryItem(replacesCurrentHistoryItem);
   1299     m_policyDocumentLoader->setIsClientRedirect(clientRedirect == ClientRedirect);
   1300 
   1301     Frame* parent = m_frame->tree().parent();
   1302     if (parent && parent->isLocalFrame())
   1303         m_policyDocumentLoader->setOverrideEncoding(toLocalFrame(parent)->loader().documentLoader()->overrideEncoding());
   1304     else if (!overrideEncoding.isEmpty())
   1305         m_policyDocumentLoader->setOverrideEncoding(overrideEncoding);
   1306     else if (m_documentLoader)
   1307         m_policyDocumentLoader->setOverrideEncoding(m_documentLoader->overrideEncoding());
   1308 
   1309 
   1310     bool isTransitionNavigation = false;
   1311     if (RuntimeEnabledFeatures::navigationTransitionsEnabled() && type != FrameLoadTypeReload && type != FrameLoadTypeReloadFromOrigin && type != FrameLoadTypeSame)
   1312         isTransitionNavigation = dispatchNavigationTransitionData();
   1313 
   1314     // stopAllLoaders can detach the LocalFrame, so protect it.
   1315     RefPtrWillBeRawPtr<LocalFrame> protect(m_frame.get());
   1316     if ((!m_policyDocumentLoader->shouldContinueForNavigationPolicy(request, shouldCheckMainWorldContentSecurityPolicy, isTransitionNavigation) || !shouldClose()) && m_policyDocumentLoader) {
   1317         m_policyDocumentLoader->detachFromFrame();
   1318         m_policyDocumentLoader = nullptr;
   1319         checkCompleted();
   1320         return;
   1321     }
   1322 
   1323     if (m_provisionalDocumentLoader) {
   1324         m_provisionalDocumentLoader->stopLoading();
   1325         if (m_provisionalDocumentLoader)
   1326             m_provisionalDocumentLoader->detachFromFrame();
   1327         m_provisionalDocumentLoader = nullptr;
   1328     }
   1329     m_checkTimer.stop();
   1330 
   1331     // <rdar://problem/6250856> - In certain circumstances on pages with multiple frames, stopAllLoaders()
   1332     // might detach the current FrameLoader, in which case we should bail on this newly defunct load.
   1333     if (!m_frame->page() || !m_policyDocumentLoader)
   1334         return;
   1335 
   1336     if (isLoadingMainFrame())
   1337         m_frame->page()->inspectorController().resume();
   1338     m_frame->navigationScheduler().cancel();
   1339 
   1340     m_provisionalDocumentLoader = m_policyDocumentLoader.release();
   1341     m_loadType = type;
   1342     m_state = FrameStateProvisional;
   1343 
   1344     if (formState)
   1345         client()->dispatchWillSubmitForm(formState->form());
   1346 
   1347     m_progressTracker->progressStarted();
   1348     if (m_provisionalDocumentLoader->isClientRedirect())
   1349         m_provisionalDocumentLoader->appendRedirect(m_frame->document()->url());
   1350     m_provisionalDocumentLoader->appendRedirect(m_provisionalDocumentLoader->request().url());
   1351     client()->dispatchDidStartProvisionalLoad(isTransitionNavigation);
   1352     ASSERT(m_provisionalDocumentLoader);
   1353     m_provisionalDocumentLoader->startLoadingMainResource();
   1354 }
   1355 
   1356 void FrameLoader::applyUserAgent(ResourceRequest& request)
   1357 {
   1358     String userAgent = this->userAgent(request.url());
   1359     ASSERT(!userAgent.isNull());
   1360     request.setHTTPUserAgent(AtomicString(userAgent));
   1361 }
   1362 
   1363 bool FrameLoader::shouldInterruptLoadForXFrameOptions(const String& content, const KURL& url, unsigned long requestIdentifier)
   1364 {
   1365     UseCounter::count(m_frame->domWindow()->document(), UseCounter::XFrameOptions);
   1366 
   1367     Frame* topFrame = m_frame->tree().top();
   1368     if (m_frame == topFrame)
   1369         return false;
   1370 
   1371     XFrameOptionsDisposition disposition = parseXFrameOptionsHeader(content);
   1372 
   1373     switch (disposition) {
   1374     case XFrameOptionsSameOrigin: {
   1375         UseCounter::count(m_frame->domWindow()->document(), UseCounter::XFrameOptionsSameOrigin);
   1376         RefPtr<SecurityOrigin> origin = SecurityOrigin::create(url);
   1377         // Out-of-process ancestors are always a different origin.
   1378         if (!topFrame->isLocalFrame() || !origin->isSameSchemeHostPort(toLocalFrame(topFrame)->document()->securityOrigin()))
   1379             return true;
   1380         for (Frame* frame = m_frame->tree().parent(); frame; frame = frame->tree().parent()) {
   1381             if (!frame->isLocalFrame() || !origin->isSameSchemeHostPort(toLocalFrame(frame)->document()->securityOrigin())) {
   1382                 UseCounter::count(m_frame->domWindow()->document(), UseCounter::XFrameOptionsSameOriginWithBadAncestorChain);
   1383                 break;
   1384             }
   1385         }
   1386         return false;
   1387     }
   1388     case XFrameOptionsDeny:
   1389         return true;
   1390     case XFrameOptionsAllowAll:
   1391         return false;
   1392     case XFrameOptionsConflict: {
   1393         RefPtrWillBeRawPtr<ConsoleMessage> consoleMessage = ConsoleMessage::create(JSMessageSource, ErrorMessageLevel, "Multiple 'X-Frame-Options' headers with conflicting values ('" + content + "') encountered when loading '" + url.elidedString() + "'. Falling back to 'DENY'.");
   1394         consoleMessage->setRequestIdentifier(requestIdentifier);
   1395         m_frame->document()->addConsoleMessage(consoleMessage.release());
   1396         return true;
   1397     }
   1398     case XFrameOptionsInvalid: {
   1399         RefPtrWillBeRawPtr<ConsoleMessage> consoleMessage = ConsoleMessage::create(JSMessageSource, ErrorMessageLevel, "Invalid 'X-Frame-Options' header encountered when loading '" + url.elidedString() + "': '" + content + "' is not a recognized directive. The header will be ignored.");
   1400         consoleMessage->setRequestIdentifier(requestIdentifier);
   1401         m_frame->document()->addConsoleMessage(consoleMessage.release());
   1402         return false;
   1403     }
   1404     default:
   1405         ASSERT_NOT_REACHED();
   1406         return false;
   1407     }
   1408 }
   1409 
   1410 bool FrameLoader::shouldTreatURLAsSameAsCurrent(const KURL& url) const
   1411 {
   1412     return m_currentItem && url == m_currentItem->url();
   1413 }
   1414 
   1415 bool FrameLoader::shouldTreatURLAsSrcdocDocument(const KURL& url) const
   1416 {
   1417     if (!equalIgnoringCase(url.string(), "about:srcdoc"))
   1418         return false;
   1419     HTMLFrameOwnerElement* ownerElement = m_frame->deprecatedLocalOwner();
   1420     if (!isHTMLIFrameElement(ownerElement))
   1421         return false;
   1422     return ownerElement->fastHasAttribute(srcdocAttr);
   1423 }
   1424 
   1425 LocalFrame* FrameLoader::findFrameForNavigation(const AtomicString& name, Document* activeDocument)
   1426 {
   1427     ASSERT(activeDocument);
   1428     Frame* frame = m_frame->tree().find(name);
   1429     if (!frame || !frame->isLocalFrame() || !activeDocument->canNavigate(toLocalFrame(*frame)))
   1430         return 0;
   1431     return toLocalFrame(frame);
   1432 }
   1433 
   1434 void FrameLoader::loadHistoryItem(HistoryItem* item, HistoryLoadType historyLoadType, ResourceRequestCachePolicy cachePolicy)
   1435 {
   1436     RefPtrWillBeRawPtr<LocalFrame> protect(m_frame.get());
   1437     if (m_frame->page()->defersLoading()) {
   1438         m_deferredHistoryLoad = DeferredHistoryLoad(item, historyLoadType, cachePolicy);
   1439         return;
   1440     }
   1441 
   1442     m_provisionalItem = item;
   1443     if (historyLoadType == HistorySameDocumentLoad) {
   1444         loadInSameDocument(item->url(), item->stateObject(), FrameLoadTypeBackForward, NotClientRedirect);
   1445         restoreScrollPositionAndViewState();
   1446         return;
   1447     }
   1448 
   1449     ResourceRequest request = requestFromHistoryItem(item, cachePolicy);
   1450     request.setFrameType(m_frame->isMainFrame() ? WebURLRequest::FrameTypeTopLevel : WebURLRequest::FrameTypeNested);
   1451     request.setRequestContext(WebURLRequest::RequestContextInternal);
   1452     loadWithNavigationAction(NavigationAction(request, FrameLoadTypeBackForward), FrameLoadTypeBackForward, nullptr, SubstituteData(), CheckContentSecurityPolicy);
   1453 }
   1454 
   1455 void FrameLoader::dispatchDocumentElementAvailable()
   1456 {
   1457     client()->documentElementAvailable();
   1458 }
   1459 
   1460 void FrameLoader::dispatchDidClearDocumentOfWindowObject()
   1461 {
   1462     if (!m_frame->script().canExecuteScripts(NotAboutToExecuteScript))
   1463         return;
   1464 
   1465     if (Page* page = m_frame->page())
   1466         page->inspectorController().didClearDocumentOfWindowObject(m_frame);
   1467     InspectorInstrumentation::didClearDocumentOfWindowObject(m_frame);
   1468 
   1469     // We just cleared the document, not the entire window object, but for the
   1470     // embedder that's close enough.
   1471     client()->dispatchDidClearWindowObjectInMainWorld();
   1472 }
   1473 
   1474 void FrameLoader::dispatchDidClearWindowObjectInMainWorld()
   1475 {
   1476     if (!m_frame->script().canExecuteScripts(NotAboutToExecuteScript))
   1477         return;
   1478 
   1479     client()->dispatchDidClearWindowObjectInMainWorld();
   1480 }
   1481 
   1482 SandboxFlags FrameLoader::effectiveSandboxFlags() const
   1483 {
   1484     SandboxFlags flags = m_forcedSandboxFlags;
   1485     // FIXME: We need a way to propagate sandbox flags to out-of-process frames.
   1486     Frame* parentFrame = m_frame->tree().parent();
   1487     if (parentFrame && parentFrame->isLocalFrame())
   1488         flags |= toLocalFrame(parentFrame)->document()->sandboxFlags();
   1489     if (FrameOwner* frameOwner = m_frame->owner())
   1490         flags |= frameOwner->sandboxFlags();
   1491     return flags;
   1492 }
   1493 
   1494 } // namespace blink
   1495