• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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@atoker.com>
6  * Copyright (C) Research In Motion Limited 2009. All rights reserved.
7  * Copyright (C) 2011 Kris Jordan <krisjordan@gmail.com>
8  * Copyright (C) 2011 Google Inc. All rights reserved.
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 
isBackForwardLoadType(FrameLoadType type)103 bool isBackForwardLoadType(FrameLoadType type)
104 {
105     return type == FrameLoadTypeBackForward;
106 }
107 
needsHistoryItemRestore(FrameLoadType type)108 static bool needsHistoryItemRestore(FrameLoadType type)
109 {
110     return type == FrameLoadTypeBackForward || type == FrameLoadTypeReload || type == FrameLoadTypeReloadFromOrigin;
111 }
112 
FrameLoader(LocalFrame * frame)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 
~FrameLoader()128 FrameLoader::~FrameLoader()
129 {
130     // Verify that this FrameLoader has been detached.
131     ASSERT(!m_progressTracker);
132 }
133 
trace(Visitor * visitor)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 
init()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 
client() const153 FrameLoaderClient* FrameLoader::client() const
154 {
155     return static_cast<FrameLoaderClient*>(m_frame->client());
156 }
157 
setDefersLoading(bool defers)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 
stopLoading()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 
saveScrollState()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 
clearScrollPositionAndViewState()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 
closeURL()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 
didExplicitOpen()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 
clear()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.
replaceDocumentWhileExecutingJavaScriptURL(const String & source,Document * ownerDocument)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 
setHistoryItemStateForCommit(HistoryCommitType historyCommitType,bool isPushOrReplaceState,PassRefPtr<SerializedScriptValue> stateObject)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 
loadTypeToCommitType(FrameLoadType type)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 
receivedFirstData()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 
didBeginDocument(bool dispatch)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 
finishedParsing()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 
loadDone()428 void FrameLoader::loadDone()
429 {
430     checkCompleted();
431 }
432 
allChildrenAreComplete() const433 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 
allAncestorsAreComplete() const445 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 
checkCompleted()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 
checkTimerFired(Timer<FrameLoader> *)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 
scheduleCheckCompleted()508 void FrameLoader::scheduleCheckCompleted()
509 {
510     if (!m_checkTimer.isActive())
511         m_checkTimer.startOneShot(0, FROM_HERE);
512 }
513 
opener()514 Frame* FrameLoader::opener()
515 {
516     return client() ? client()->opener() : 0;
517 }
518 
setOpener(LocalFrame * opener)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 
allowPlugins(ReasonForCallingAllowPlugins reason)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 
updateForSameDocumentNavigation(const KURL & newURL,SameDocumentNavigationSource sameDocumentNavigationSource,PassRefPtr<SerializedScriptValue> data,FrameLoadType type)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 
loadInSameDocument(const KURL & url,PassRefPtr<SerializedScriptValue> stateObject,FrameLoadType type,ClientRedirectPolicy clientRedirect)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 
completed()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 
setReferrerForFrameRequest(ResourceRequest & request,ShouldSendReferrer shouldSendReferrer,Document * originDocument)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 
isScriptTriggeredFormSubmissionInChildFrame(const FrameLoadRequest & request) const638 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 
determineFrameLoadType(const FrameLoadRequest & request)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 
prepareRequestForThisFrame(FrameLoadRequest & request)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 
shouldOpenInNewWindow(LocalFrame * targetFrame,const FrameLoadRequest & request,const NavigationAction & action)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 
determineRequestContextFromNavigationType(const NavigationType navigationType)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 
load(const FrameLoadRequest & passedRequest)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 
defaultSubstituteDataForURL(const KURL & url)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 
reportLocalLoadFailed(LocalFrame * frame,const String & url)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
requestFromHistoryItem(HistoryItem * item,ResourceRequestCachePolicy cachePolicy)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 
reload(ReloadPolicy reloadPolicy,const KURL & overrideURL,const AtomicString & overrideEncoding,ClientRedirectPolicy clientRedirectPolicy)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 
stopAllLoaders()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 
didAccessInitialDocument()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 
didAccessInitialDocumentTimerFired(Timer<FrameLoader> *)886 void FrameLoader::didAccessInitialDocumentTimerFired(Timer<FrameLoader>*)
887 {
888     if (client())
889         client()->didAccessInitialDocument();
890 }
891 
notifyIfInitialDocumentAccessed()892 void FrameLoader::notifyIfInitialDocumentAccessed()
893 {
894     if (m_didAccessInitialDocumentTimer.isActive()) {
895         m_didAccessInitialDocumentTimer.stop();
896         didAccessInitialDocumentTimerFired(0);
897     }
898 }
899 
commitProvisionalLoad()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 
isLoadingMainFrame() const946 bool FrameLoader::isLoadingMainFrame() const
947 {
948     return m_frame->isMainFrame();
949 }
950 
loadType() const951 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.
isDocumentDoneLoading(Document * document)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 
checkLoadCompleteForThisFrame()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 
restoreScrollPositionAndViewState()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.
checkLoadComplete()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 
userAgent(const KURL & url) const1101 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 
detachFromParent()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 
detachClient()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 
receivedMainResourceError(const ResourceError & error)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 
shouldPerformFragmentNavigation(bool isFormSubmission,const String & httpMethod,FrameLoadType loadType,const KURL & url)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 
scrollToFragmentWithParentBoundary(const KURL & url)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 
shouldClose()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 
validateTransitionNavigationMode()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 
dispatchNavigationTransitionData()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 
loadWithNavigationAction(const NavigationAction & action,FrameLoadType type,PassRefPtrWillBeRawPtr<FormState> formState,const SubstituteData & substituteData,ContentSecurityPolicyCheck shouldCheckMainWorldContentSecurityPolicy,ClientRedirectPolicy clientRedirect,const AtomicString & overrideEncoding)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 
applyUserAgent(ResourceRequest & request)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 
shouldInterruptLoadForXFrameOptions(const String & content,const KURL & url,unsigned long requestIdentifier)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 
shouldTreatURLAsSameAsCurrent(const KURL & url) const1410 bool FrameLoader::shouldTreatURLAsSameAsCurrent(const KURL& url) const
1411 {
1412     return m_currentItem && url == m_currentItem->url();
1413 }
1414 
shouldTreatURLAsSrcdocDocument(const KURL & url) const1415 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 
findFrameForNavigation(const AtomicString & name,Document * activeDocument)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 
loadHistoryItem(HistoryItem * item,HistoryLoadType historyLoadType,ResourceRequestCachePolicy cachePolicy)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 
dispatchDocumentElementAvailable()1455 void FrameLoader::dispatchDocumentElementAvailable()
1456 {
1457     client()->documentElementAvailable();
1458 }
1459 
dispatchDidClearDocumentOfWindowObject()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 
dispatchDidClearWindowObjectInMainWorld()1474 void FrameLoader::dispatchDidClearWindowObjectInMainWorld()
1475 {
1476     if (!m_frame->script().canExecuteScripts(NotAboutToExecuteScript))
1477         return;
1478 
1479     client()->dispatchDidClearWindowObjectInMainWorld();
1480 }
1481 
effectiveSandboxFlags() const1482 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