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