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