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