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