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