1/* 2 * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved. 3 * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) 4 * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/) 5 * Copyright (C) 2008 Alp Toker <alp@atoker.com> 6 * Copyright (C) Research In Motion Limited 2009. All rights reserved. 7 * Copyright (C) 2011 Kris Jordan <krisjordan@gmail.com> 8 * Copyright (C) 2011 Google Inc. All rights reserved. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of 20 * its contributors may be used to endorse or promote products derived 21 * from this software without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 24 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 25 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 26 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 27 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 28 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 29 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 30 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 32 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 */ 34 35#include "config.h" 36#include "FrameLoader.h" 37 38#include "AXObjectCache.h" 39#include "ApplicationCacheHost.h" 40#include "BackForwardController.h" 41#include "BeforeUnloadEvent.h" 42#include "CachedPage.h" 43#include "CachedResourceLoader.h" 44#include "Chrome.h" 45#include "ChromeClient.h" 46#include "Console.h" 47#include "ContentSecurityPolicy.h" 48#include "DOMImplementation.h" 49#include "DOMWindow.h" 50#include "DatabaseManager.h" 51#include "Document.h" 52#include "DocumentLoadTiming.h" 53#include "DocumentLoader.h" 54#include "Editor.h" 55#include "EditorClient.h" 56#include "Element.h" 57#include "Event.h" 58#include "EventHandler.h" 59#include "EventNames.h" 60#include "FloatRect.h" 61#include "FormState.h" 62#include "FormSubmission.h" 63#include "Frame.h" 64#include "FrameLoadRequest.h" 65#include "FrameLoaderClient.h" 66#include "FrameNetworkingContext.h" 67#include "FrameTree.h" 68#include "FrameView.h" 69#include "HTMLAnchorElement.h" 70#include "HTMLFormElement.h" 71#include "HTMLInputElement.h" 72#include "HTMLNames.h" 73#include "HTMLObjectElement.h" 74#include "HTMLParserIdioms.h" 75#include "HTTPParsers.h" 76#include "HistoryController.h" 77#include "HistoryItem.h" 78#include "IconController.h" 79#include "InspectorController.h" 80#include "InspectorInstrumentation.h" 81#include "LoaderStrategy.h" 82#include "Logging.h" 83#include "MIMETypeRegistry.h" 84#include "MemoryCache.h" 85#include "Page.h" 86#include "PageActivityAssertionToken.h" 87#include "PageCache.h" 88#include "PageTransitionEvent.h" 89#include "PlatformStrategies.h" 90#include "PluginData.h" 91#include "PluginDatabase.h" 92#include "PluginDocument.h" 93#include "PolicyChecker.h" 94#include "ProgressTracker.h" 95#include "ResourceHandle.h" 96#include "ResourceRequest.h" 97#include "SchemeRegistry.h" 98#include "ScriptCallStack.h" 99#include "ScriptController.h" 100#include "ScriptSourceCode.h" 101#include "ScrollAnimator.h" 102#include "SecurityOrigin.h" 103#include "SecurityPolicy.h" 104#include "SegmentedString.h" 105#include "SerializedScriptValue.h" 106#include "Settings.h" 107#include "TextResourceDecoder.h" 108#include "WindowFeatures.h" 109#include "XMLDocumentParser.h" 110#include <wtf/CurrentTime.h> 111#include <wtf/StdLibExtras.h> 112#include <wtf/text/CString.h> 113#include <wtf/text/WTFString.h> 114 115#if ENABLE(SHARED_WORKERS) 116#include "SharedWorkerRepository.h" 117#endif 118 119#if ENABLE(SVG) 120#include "SVGDocument.h" 121#include "SVGLocatable.h" 122#include "SVGNames.h" 123#include "SVGPreserveAspectRatio.h" 124#include "SVGSVGElement.h" 125#include "SVGViewElement.h" 126#include "SVGViewSpec.h" 127#endif 128 129#if ENABLE(WEB_ARCHIVE) || ENABLE(MHTML) 130#include "Archive.h" 131#endif 132 133 134namespace WebCore { 135 136using namespace HTMLNames; 137 138#if ENABLE(SVG) 139using namespace SVGNames; 140#endif 141 142static const char defaultAcceptHeader[] = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"; 143static double storedTimeOfLastCompletedLoad; 144 145bool isBackForwardLoadType(FrameLoadType type) 146{ 147 switch (type) { 148 case FrameLoadTypeStandard: 149 case FrameLoadTypeReload: 150 case FrameLoadTypeReloadFromOrigin: 151 case FrameLoadTypeSame: 152 case FrameLoadTypeRedirectWithLockedBackForwardList: 153 case FrameLoadTypeReplace: 154 return false; 155 case FrameLoadTypeBack: 156 case FrameLoadTypeForward: 157 case FrameLoadTypeIndexedBackForward: 158 return true; 159 } 160 ASSERT_NOT_REACHED(); 161 return false; 162} 163 164// This is not in the FrameLoader class to emphasize that it does not depend on 165// private FrameLoader data, and to avoid increasing the number of public functions 166// with access to private data. Since only this .cpp file needs it, making it 167// non-member lets us exclude it from the header file, thus keeping FrameLoader.h's 168// API simpler. 169// 170static bool isDocumentSandboxed(Frame* frame, SandboxFlags mask) 171{ 172 return frame->document() && frame->document()->isSandboxed(mask); 173} 174 175class FrameLoader::FrameProgressTracker { 176public: 177 static PassOwnPtr<FrameProgressTracker> create(Frame* frame) { return adoptPtr(new FrameProgressTracker(frame)); } 178 ~FrameProgressTracker() 179 { 180 ASSERT(!m_inProgress || m_frame->page()); 181 if (m_inProgress) 182 m_frame->page()->progress()->progressCompleted(m_frame); 183 } 184 185 void progressStarted() 186 { 187 ASSERT(m_frame->page()); 188 if (!m_inProgress) 189 m_frame->page()->progress()->progressStarted(m_frame); 190 m_inProgress = true; 191 } 192 193 void progressCompleted() 194 { 195 ASSERT(m_inProgress); 196 ASSERT(m_frame->page()); 197 m_inProgress = false; 198 m_frame->page()->progress()->progressCompleted(m_frame); 199 } 200 201private: 202 FrameProgressTracker(Frame* frame) 203 : m_frame(frame) 204 , m_inProgress(false) 205 { 206 } 207 208 Frame* m_frame; 209 bool m_inProgress; 210}; 211 212FrameLoader::FrameLoader(Frame* frame, FrameLoaderClient* client) 213 : m_frame(frame) 214 , m_client(client) 215 , m_policyChecker(adoptPtr(new PolicyChecker(frame))) 216 , m_history(adoptPtr(new HistoryController(frame))) 217 , m_notifer(frame) 218 , m_subframeLoader(frame) 219 , m_icon(adoptPtr(new IconController(frame))) 220 , m_mixedContentChecker(frame) 221 , m_state(FrameStateProvisional) 222 , m_loadType(FrameLoadTypeStandard) 223 , m_delegateIsHandlingProvisionalLoadError(false) 224 , m_quickRedirectComing(false) 225 , m_sentRedirectNotification(false) 226 , m_inStopAllLoaders(false) 227 , m_isExecutingJavaScriptFormAction(false) 228 , m_didCallImplicitClose(true) 229 , m_wasUnloadEventEmitted(false) 230 , m_pageDismissalEventBeingDispatched(NoDismissal) 231 , m_isComplete(false) 232 , m_needsClear(false) 233 , m_checkTimer(this, &FrameLoader::checkTimerFired) 234 , m_shouldCallCheckCompleted(false) 235 , m_shouldCallCheckLoadComplete(false) 236 , m_opener(0) 237 , m_didPerformFirstNavigation(false) 238 , m_loadingFromCachedPage(false) 239 , m_suppressOpenerInNewFrame(false) 240 , m_currentNavigationHasShownBeforeUnloadConfirmPanel(false) 241 , m_forcedSandboxFlags(SandboxNone) 242{ 243} 244 245FrameLoader::~FrameLoader() 246{ 247 setOpener(0); 248 249 HashSet<Frame*>::iterator end = m_openedFrames.end(); 250 for (HashSet<Frame*>::iterator it = m_openedFrames.begin(); it != end; ++it) 251 (*it)->loader()->m_opener = 0; 252 253 m_client->frameLoaderDestroyed(); 254 255 if (m_networkingContext) 256 m_networkingContext->invalidate(); 257} 258 259void FrameLoader::init() 260{ 261 // This somewhat odd set of steps gives the frame an initial empty document. 262 setPolicyDocumentLoader(m_client->createDocumentLoader(ResourceRequest(KURL(ParsedURLString, emptyString())), SubstituteData()).get()); 263 setProvisionalDocumentLoader(m_policyDocumentLoader.get()); 264 m_provisionalDocumentLoader->startLoadingMainResource(); 265 266 RefPtr<Frame> protect(m_frame); 267 m_frame->document()->cancelParsing(); 268 m_stateMachine.advanceTo(FrameLoaderStateMachine::DisplayingInitialEmptyDocument); 269 270 m_networkingContext = m_client->createNetworkingContext(); 271 m_progressTracker = FrameProgressTracker::create(m_frame); 272} 273 274void FrameLoader::setDefersLoading(bool defers) 275{ 276 if (m_documentLoader) 277 m_documentLoader->setDefersLoading(defers); 278 if (m_provisionalDocumentLoader) 279 m_provisionalDocumentLoader->setDefersLoading(defers); 280 if (m_policyDocumentLoader) 281 m_policyDocumentLoader->setDefersLoading(defers); 282 history()->setDefersLoading(defers); 283 284 if (!defers) { 285 m_frame->navigationScheduler()->startTimer(); 286 startCheckCompleteTimer(); 287 } 288} 289 290void FrameLoader::changeLocation(SecurityOrigin* securityOrigin, const KURL& url, const String& referrer, bool lockHistory, bool lockBackForwardList, bool refresh) 291{ 292 urlSelected(FrameLoadRequest(securityOrigin, ResourceRequest(url, referrer, refresh ? ReloadIgnoringCacheData : UseProtocolCachePolicy), "_self"), 293 0, lockHistory, lockBackForwardList, MaybeSendReferrer, ReplaceDocumentIfJavaScriptURL); 294} 295 296void FrameLoader::urlSelected(const KURL& url, const String& passedTarget, PassRefPtr<Event> triggeringEvent, bool lockHistory, bool lockBackForwardList, ShouldSendReferrer shouldSendReferrer) 297{ 298 urlSelected(FrameLoadRequest(m_frame->document()->securityOrigin(), ResourceRequest(url), passedTarget), 299 triggeringEvent, lockHistory, lockBackForwardList, shouldSendReferrer, DoNotReplaceDocumentIfJavaScriptURL); 300} 301 302// The shouldReplaceDocumentIfJavaScriptURL parameter will go away when the FIXME to eliminate the 303// corresponding parameter from ScriptController::executeIfJavaScriptURL() is addressed. 304void FrameLoader::urlSelected(const FrameLoadRequest& passedRequest, PassRefPtr<Event> triggeringEvent, bool lockHistory, bool lockBackForwardList, ShouldSendReferrer shouldSendReferrer, ShouldReplaceDocumentIfJavaScriptURL shouldReplaceDocumentIfJavaScriptURL) 305{ 306 ASSERT(!m_suppressOpenerInNewFrame); 307 308 RefPtr<Frame> protect(m_frame); 309 FrameLoadRequest frameRequest(passedRequest); 310 311 if (m_frame->script()->executeIfJavaScriptURL(frameRequest.resourceRequest().url(), shouldReplaceDocumentIfJavaScriptURL)) 312 return; 313 314 if (frameRequest.frameName().isEmpty()) 315 frameRequest.setFrameName(m_frame->document()->baseTarget()); 316 317 if (shouldSendReferrer == NeverSendReferrer) 318 m_suppressOpenerInNewFrame = true; 319 addHTTPOriginIfNeeded(frameRequest.resourceRequest(), outgoingOrigin()); 320 321 loadFrameRequest(frameRequest, lockHistory, lockBackForwardList, triggeringEvent, 0, shouldSendReferrer); 322 323 m_suppressOpenerInNewFrame = false; 324} 325 326void FrameLoader::submitForm(PassRefPtr<FormSubmission> submission) 327{ 328 ASSERT(submission->method() == FormSubmission::PostMethod || submission->method() == FormSubmission::GetMethod); 329 330 // FIXME: Find a good spot for these. 331 ASSERT(submission->data()); 332 ASSERT(submission->state()); 333 ASSERT(!submission->state()->sourceDocument()->frame() || submission->state()->sourceDocument()->frame() == m_frame); 334 335 if (!m_frame->page()) 336 return; 337 338 if (submission->action().isEmpty()) 339 return; 340 341 if (isDocumentSandboxed(m_frame, SandboxForms)) { 342 // FIXME: This message should be moved off the console once a solution to https://bugs.webkit.org/show_bug.cgi?id=103274 exists. 343 m_frame->document()->addConsoleMessage(SecurityMessageSource, ErrorMessageLevel, "Blocked form submission to '" + submission->action().stringCenterEllipsizedToLength() + "' because the form's frame is sandboxed and the 'allow-forms' permission is not set."); 344 return; 345 } 346 347 if (protocolIsJavaScript(submission->action())) { 348 if (!m_frame->document()->contentSecurityPolicy()->allowFormAction(KURL(submission->action()))) 349 return; 350 m_isExecutingJavaScriptFormAction = true; 351 RefPtr<Frame> protect(m_frame); 352 m_frame->script()->executeIfJavaScriptURL(submission->action(), DoNotReplaceDocumentIfJavaScriptURL); 353 m_isExecutingJavaScriptFormAction = false; 354 return; 355 } 356 357 Frame* targetFrame = findFrameForNavigation(submission->target(), submission->state()->sourceDocument()); 358 if (!targetFrame) { 359 if (!DOMWindow::allowPopUp(m_frame) && !ScriptController::processingUserGesture()) 360 return; 361 362 targetFrame = m_frame; 363 } else 364 submission->clearTarget(); 365 366 if (!targetFrame->page()) 367 return; 368 369 // FIXME: We'd like to remove this altogether and fix the multiple form submission issue another way. 370 371 // We do not want to submit more than one form from the same page, nor do we want to submit a single 372 // form more than once. This flag prevents these from happening; not sure how other browsers prevent this. 373 // The flag is reset in each time we start handle a new mouse or key down event, and 374 // also in setView since this part may get reused for a page from the back/forward cache. 375 // The form multi-submit logic here is only needed when we are submitting a form that affects this frame. 376 377 // FIXME: Frame targeting is only one of the ways the submission could end up doing something other 378 // than replacing this frame's content, so this check is flawed. On the other hand, the check is hardly 379 // needed any more now that we reset m_submittedFormURL on each mouse or key down event. 380 381 if (m_frame->tree()->isDescendantOf(targetFrame)) { 382 if (m_submittedFormURL == submission->requestURL()) 383 return; 384 m_submittedFormURL = submission->requestURL(); 385 } 386 387 submission->data()->generateFiles(m_frame->document()); 388 submission->setReferrer(outgoingReferrer()); 389 submission->setOrigin(outgoingOrigin()); 390 391 targetFrame->navigationScheduler()->scheduleFormSubmission(submission); 392} 393 394void FrameLoader::stopLoading(UnloadEventPolicy unloadEventPolicy) 395{ 396 if (m_frame->document() && m_frame->document()->parser()) 397 m_frame->document()->parser()->stopParsing(); 398 399 if (unloadEventPolicy != UnloadEventPolicyNone) { 400 if (m_frame->document()) { 401 if (m_didCallImplicitClose && !m_wasUnloadEventEmitted) { 402 Element* currentFocusedElement = m_frame->document()->focusedElement(); 403 if (currentFocusedElement && currentFocusedElement->toInputElement()) 404 currentFocusedElement->toInputElement()->endEditing(); 405 if (m_pageDismissalEventBeingDispatched == NoDismissal) { 406 if (unloadEventPolicy == UnloadEventPolicyUnloadAndPageHide) { 407 m_pageDismissalEventBeingDispatched = PageHideDismissal; 408 m_frame->document()->domWindow()->dispatchEvent(PageTransitionEvent::create(eventNames().pagehideEvent, m_frame->document()->inPageCache()), m_frame->document()); 409 } 410 411 // FIXME: update Page Visibility state here. 412 // https://bugs.webkit.org/show_bug.cgi?id=116770 413 414 if (!m_frame->document()->inPageCache()) { 415 RefPtr<Event> unloadEvent(Event::create(eventNames().unloadEvent, false, false)); 416 // The DocumentLoader (and thus its DocumentLoadTiming) might get destroyed 417 // while dispatching the event, so protect it to prevent writing the end 418 // time into freed memory. 419 RefPtr<DocumentLoader> documentLoader = m_provisionalDocumentLoader; 420 m_pageDismissalEventBeingDispatched = UnloadDismissal; 421 if (documentLoader && !documentLoader->timing()->unloadEventStart() && !documentLoader->timing()->unloadEventEnd()) { 422 DocumentLoadTiming* timing = documentLoader->timing(); 423 ASSERT(timing->navigationStart()); 424 timing->markUnloadEventStart(); 425 m_frame->document()->domWindow()->dispatchEvent(unloadEvent, m_frame->document()); 426 timing->markUnloadEventEnd(); 427 } else 428 m_frame->document()->domWindow()->dispatchEvent(unloadEvent, m_frame->document()); 429 } 430 } 431 m_pageDismissalEventBeingDispatched = NoDismissal; 432 if (m_frame->document()) 433 m_frame->document()->updateStyleIfNeeded(); 434 m_wasUnloadEventEmitted = true; 435 } 436 } 437 438 // Dispatching the unload event could have made m_frame->document() null. 439 if (m_frame->document() && !m_frame->document()->inPageCache()) { 440 // Don't remove event listeners from a transitional empty document (see bug 28716 for more information). 441 bool keepEventListeners = m_stateMachine.isDisplayingInitialEmptyDocument() && m_provisionalDocumentLoader 442 && m_frame->document()->isSecureTransitionTo(m_provisionalDocumentLoader->url()); 443 444 if (!keepEventListeners) 445 m_frame->document()->removeAllEventListeners(); 446 } 447 } 448 449 m_isComplete = true; // to avoid calling completed() in finishedParsing() 450 m_didCallImplicitClose = true; // don't want that one either 451 452 if (m_frame->document() && m_frame->document()->parsing()) { 453 finishedParsing(); 454 m_frame->document()->setParsing(false); 455 } 456 457 if (Document* doc = m_frame->document()) { 458 // FIXME: HTML5 doesn't tell us to set the state to complete when aborting, but we do anyway to match legacy behavior. 459 // http://www.w3.org/Bugs/Public/show_bug.cgi?id=10537 460 doc->setReadyState(Document::Complete); 461 462#if ENABLE(SQL_DATABASE) 463 // FIXME: Should the DatabaseManager watch for something like ActiveDOMObject::stop() rather than being special-cased here? 464 DatabaseManager::manager().stopDatabases(doc, 0); 465#endif 466 } 467 468 // FIXME: This will cancel redirection timer, which really needs to be restarted when restoring the frame from b/f cache. 469 m_frame->navigationScheduler()->cancel(); 470} 471 472void FrameLoader::stop() 473{ 474 // http://bugs.webkit.org/show_bug.cgi?id=10854 475 // The frame's last ref may be removed and it will be deleted by checkCompleted(). 476 RefPtr<Frame> protector(m_frame); 477 478 if (DocumentParser* parser = m_frame->document()->parser()) { 479 parser->stopParsing(); 480 parser->finish(); 481 } 482 483 icon()->stopLoader(); 484} 485 486void FrameLoader::willTransitionToCommitted() 487{ 488 // This function is called when a frame is still fully in place (not cached, not detached), but will be replaced. 489 490 if (m_frame->editor().hasComposition()) { 491 // The text was already present in DOM, so it's better to confirm than to cancel the composition. 492 m_frame->editor().confirmComposition(); 493 if (EditorClient* editorClient = m_frame->editor().client()) 494 editorClient->respondToChangedSelection(m_frame); 495 } 496} 497 498bool FrameLoader::closeURL() 499{ 500 history()->saveDocumentState(); 501 502 // Should only send the pagehide event here if the current document exists and has not been placed in the page cache. 503 Document* currentDocument = m_frame->document(); 504 stopLoading(currentDocument && !currentDocument->inPageCache() ? UnloadEventPolicyUnloadAndPageHide : UnloadEventPolicyUnloadOnly); 505 506 m_frame->editor().clearUndoRedoOperations(); 507 return true; 508} 509 510bool FrameLoader::didOpenURL() 511{ 512 if (m_frame->navigationScheduler()->redirectScheduledDuringLoad()) { 513 // A redirect was scheduled before the document was created. 514 // This can happen when one frame changes another frame's location. 515 return false; 516 } 517 518 m_frame->navigationScheduler()->cancel(); 519 m_frame->editor().clearLastEditCommand(); 520 521 m_isComplete = false; 522 m_didCallImplicitClose = false; 523 524 // If we are still in the process of initializing an empty document then 525 // its frame is not in a consistent state for rendering, so avoid setJSStatusBarText 526 // since it may cause clients to attempt to render the frame. 527 if (!m_stateMachine.creatingInitialEmptyDocument()) { 528 DOMWindow* window = m_frame->document()->domWindow(); 529 window->setStatus(String()); 530 window->setDefaultStatus(String()); 531 } 532 533 started(); 534 535 return true; 536} 537 538void FrameLoader::didExplicitOpen() 539{ 540 m_isComplete = false; 541 m_didCallImplicitClose = false; 542 543 // Calling document.open counts as committing the first real document load. 544 if (!m_stateMachine.committedFirstRealDocumentLoad()) 545 m_stateMachine.advanceTo(FrameLoaderStateMachine::DisplayingInitialEmptyDocumentPostCommit); 546 547 // Prevent window.open(url) -- eg window.open("about:blank") -- from blowing away results 548 // from a subsequent window.document.open / window.document.write call. 549 // Canceling redirection here works for all cases because document.open 550 // implicitly precedes document.write. 551 m_frame->navigationScheduler()->cancel(); 552} 553 554 555void FrameLoader::cancelAndClear() 556{ 557 m_frame->navigationScheduler()->cancel(); 558 559 if (!m_isComplete) 560 closeURL(); 561 562 clear(m_frame->document(), false); 563 m_frame->script()->updatePlatformScriptObjects(); 564} 565 566void FrameLoader::clear(Document* newDocument, bool clearWindowProperties, bool clearScriptObjects, bool clearFrameView) 567{ 568 m_frame->editor().clear(); 569 570 if (!m_needsClear) 571 return; 572 m_needsClear = false; 573 574 if (!m_frame->document()->inPageCache()) { 575 m_frame->document()->cancelParsing(); 576 m_frame->document()->stopActiveDOMObjects(); 577 if (m_frame->document()->attached()) { 578 m_frame->document()->prepareForDestruction(); 579 m_frame->document()->removeFocusedNodeOfSubtree(m_frame->document()); 580 } 581 } 582 583 // Do this after detaching the document so that the unload event works. 584 if (clearWindowProperties) { 585 InspectorInstrumentation::frameWindowDiscarded(m_frame, m_frame->document()->domWindow()); 586 m_frame->document()->domWindow()->resetUnlessSuspendedForPageCache(); 587 m_frame->script()->clearWindowShell(newDocument->domWindow(), m_frame->document()->inPageCache()); 588 } 589 590 m_frame->selection()->prepareForDestruction(); 591 m_frame->eventHandler()->clear(); 592 if (clearFrameView && m_frame->view()) 593 m_frame->view()->clear(); 594 595 // Do not drop the document before the ScriptController and view are cleared 596 // as some destructors might still try to access the document. 597 m_frame->setDocument(0); 598 599 m_subframeLoader.clear(); 600 601 if (clearScriptObjects) 602 m_frame->script()->clearScriptObjects(); 603 604 m_frame->script()->enableEval(); 605 606 m_frame->navigationScheduler()->clear(); 607 608 m_checkTimer.stop(); 609 m_shouldCallCheckCompleted = false; 610 m_shouldCallCheckLoadComplete = false; 611 612 if (m_stateMachine.isDisplayingInitialEmptyDocument() && m_stateMachine.committedFirstRealDocumentLoad()) 613 m_stateMachine.advanceTo(FrameLoaderStateMachine::CommittedFirstRealLoad); 614} 615 616void FrameLoader::receivedFirstData() 617{ 618 dispatchDidCommitLoad(); 619 dispatchDidClearWindowObjectsInAllWorlds(); 620 dispatchGlobalObjectAvailableInAllWorlds(); 621 622 if (m_documentLoader) { 623 StringWithDirection ptitle = m_documentLoader->title(); 624 // If we have a title let the WebView know about it. 625 if (!ptitle.isNull()) 626 m_client->dispatchDidReceiveTitle(ptitle); 627 } 628 629 if (!m_documentLoader) 630 return; 631 if (m_frame->document()->isViewSource()) 632 return; 633 634 double delay; 635 String url; 636 if (!parseHTTPRefresh(m_documentLoader->response().httpHeaderField("Refresh"), false, delay, url)) 637 return; 638 if (url.isEmpty()) 639 url = m_frame->document()->url().string(); 640 else 641 url = m_frame->document()->completeURL(url).string(); 642 643 m_frame->navigationScheduler()->scheduleRedirect(delay, url); 644} 645 646void FrameLoader::setOutgoingReferrer(const KURL& url) 647{ 648 m_outgoingReferrer = url.strippedForUseAsReferrer(); 649} 650 651void FrameLoader::didBeginDocument(bool dispatch) 652{ 653 m_needsClear = true; 654 m_isComplete = false; 655 m_didCallImplicitClose = false; 656 m_frame->document()->setReadyState(Document::Loading); 657 658 if (m_pendingStateObject) { 659 m_frame->document()->statePopped(m_pendingStateObject.get()); 660 m_pendingStateObject.clear(); 661 } 662 663 if (dispatch) 664 dispatchDidClearWindowObjectsInAllWorlds(); 665 666 updateFirstPartyForCookies(); 667 m_frame->document()->initContentSecurityPolicy(); 668 669 Settings* settings = m_frame->document()->settings(); 670 if (settings) { 671 m_frame->document()->cachedResourceLoader()->setImagesEnabled(settings->areImagesEnabled()); 672 m_frame->document()->cachedResourceLoader()->setAutoLoadImages(settings->loadsImagesAutomatically()); 673 } 674 675 if (m_documentLoader) { 676 String dnsPrefetchControl = m_documentLoader->response().httpHeaderField("X-DNS-Prefetch-Control"); 677 if (!dnsPrefetchControl.isEmpty()) 678 m_frame->document()->parseDNSPrefetchControlHeader(dnsPrefetchControl); 679 680 String policyValue = m_documentLoader->response().httpHeaderField("Content-Security-Policy"); 681 if (!policyValue.isEmpty()) 682 m_frame->document()->contentSecurityPolicy()->didReceiveHeader(policyValue, ContentSecurityPolicy::Enforce); 683 684 policyValue = m_documentLoader->response().httpHeaderField("Content-Security-Policy-Report-Only"); 685 if (!policyValue.isEmpty()) 686 m_frame->document()->contentSecurityPolicy()->didReceiveHeader(policyValue, ContentSecurityPolicy::Report); 687 688 policyValue = m_documentLoader->response().httpHeaderField("X-WebKit-CSP"); 689 if (!policyValue.isEmpty()) 690 m_frame->document()->contentSecurityPolicy()->didReceiveHeader(policyValue, ContentSecurityPolicy::PrefixedEnforce); 691 692 policyValue = m_documentLoader->response().httpHeaderField("X-WebKit-CSP-Report-Only"); 693 if (!policyValue.isEmpty()) 694 m_frame->document()->contentSecurityPolicy()->didReceiveHeader(policyValue, ContentSecurityPolicy::PrefixedReport); 695 696 String headerContentLanguage = m_documentLoader->response().httpHeaderField("Content-Language"); 697 if (!headerContentLanguage.isEmpty()) { 698 size_t commaIndex = headerContentLanguage.find(','); 699 headerContentLanguage.truncate(commaIndex); // notFound == -1 == don't truncate 700 headerContentLanguage = headerContentLanguage.stripWhiteSpace(isHTMLSpace); 701 if (!headerContentLanguage.isEmpty()) 702 m_frame->document()->setContentLanguage(headerContentLanguage); 703 } 704 } 705 706 history()->restoreDocumentState(); 707} 708 709void FrameLoader::finishedParsing() 710{ 711 m_frame->injectUserScripts(InjectAtDocumentEnd); 712 713 if (m_stateMachine.creatingInitialEmptyDocument()) 714 return; 715 716 // This can be called from the Frame's destructor, in which case we shouldn't protect ourselves 717 // because doing so will cause us to re-enter the destructor when protector goes out of scope. 718 // Null-checking the FrameView indicates whether or not we're in the destructor. 719 RefPtr<Frame> protector = m_frame->view() ? m_frame : 0; 720 721 m_client->dispatchDidFinishDocumentLoad(); 722 723 checkCompleted(); 724 725 if (!m_frame->view()) 726 return; // We are being destroyed by something checkCompleted called. 727 728 // Check if the scrollbars are really needed for the content. 729 // If not, remove them, relayout, and repaint. 730 m_frame->view()->restoreScrollbar(); 731 scrollToFragmentWithParentBoundary(m_frame->document()->url()); 732} 733 734void FrameLoader::loadDone() 735{ 736 checkCompleted(); 737} 738 739bool FrameLoader::allChildrenAreComplete() const 740{ 741 for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling()) { 742 if (!child->loader()->m_isComplete) 743 return false; 744 } 745 return true; 746} 747 748bool FrameLoader::allAncestorsAreComplete() const 749{ 750 for (Frame* ancestor = m_frame; ancestor; ancestor = ancestor->tree()->parent()) { 751 if (!ancestor->loader()->m_isComplete) 752 return false; 753 } 754 return true; 755} 756 757void FrameLoader::checkCompleted() 758{ 759 RefPtr<Frame> protect(m_frame); 760 m_shouldCallCheckCompleted = false; 761 762 if (m_frame->view()) 763 m_frame->view()->handleLoadCompleted(); 764 765 // Have we completed before? 766 if (m_isComplete) 767 return; 768 769 // Are we still parsing? 770 if (m_frame->document()->parsing()) 771 return; 772 773 // Still waiting for images/scripts? 774 if (m_frame->document()->cachedResourceLoader()->requestCount()) 775 return; 776 777 // Still waiting for elements that don't go through a FrameLoader? 778 if (m_frame->document()->isDelayingLoadEvent()) 779 return; 780 781 // Any frame that hasn't completed yet? 782 if (!allChildrenAreComplete()) 783 return; 784 785 // OK, completed. 786 m_isComplete = true; 787 m_requestedHistoryItem = 0; 788 m_frame->document()->setReadyState(Document::Complete); 789 790 checkCallImplicitClose(); // if we didn't do it before 791 792 m_frame->navigationScheduler()->startTimer(); 793 794 completed(); 795 if (m_frame->page()) 796 checkLoadComplete(); 797 798 if (m_frame->view()) 799 m_frame->view()->handleLoadCompleted(); 800} 801 802void FrameLoader::checkTimerFired(Timer<FrameLoader>*) 803{ 804 RefPtr<Frame> protect(m_frame); 805 806 if (Page* page = m_frame->page()) { 807 if (page->defersLoading()) 808 return; 809 } 810 if (m_shouldCallCheckCompleted) 811 checkCompleted(); 812 if (m_shouldCallCheckLoadComplete) 813 checkLoadComplete(); 814} 815 816void FrameLoader::startCheckCompleteTimer() 817{ 818 if (!(m_shouldCallCheckCompleted || m_shouldCallCheckLoadComplete)) 819 return; 820 if (m_checkTimer.isActive()) 821 return; 822 m_checkTimer.startOneShot(0); 823} 824 825void FrameLoader::scheduleCheckCompleted() 826{ 827 m_shouldCallCheckCompleted = true; 828 startCheckCompleteTimer(); 829} 830 831void FrameLoader::scheduleCheckLoadComplete() 832{ 833 m_shouldCallCheckLoadComplete = true; 834 startCheckCompleteTimer(); 835} 836 837void FrameLoader::checkCallImplicitClose() 838{ 839 if (m_didCallImplicitClose || m_frame->document()->parsing() || m_frame->document()->isDelayingLoadEvent()) 840 return; 841 842 if (!allChildrenAreComplete()) 843 return; // still got a frame running -> too early 844 845 m_didCallImplicitClose = true; 846 m_wasUnloadEventEmitted = false; 847 m_frame->document()->implicitClose(); 848} 849 850void FrameLoader::loadURLIntoChildFrame(const KURL& url, const String& referer, Frame* childFrame) 851{ 852 ASSERT(childFrame); 853 854#if ENABLE(WEB_ARCHIVE) || ENABLE(MHTML) 855 RefPtr<Archive> subframeArchive = activeDocumentLoader()->popArchiveForSubframe(childFrame->tree()->uniqueName(), url); 856 if (subframeArchive) { 857 childFrame->loader()->loadArchive(subframeArchive.release()); 858 return; 859 } 860#endif // ENABLE(WEB_ARCHIVE) 861 862 HistoryItem* parentItem = history()->currentItem(); 863 // If we're moving in the back/forward list, we might want to replace the content 864 // of this child frame with whatever was there at that point. 865 if (parentItem && parentItem->children().size() && isBackForwardLoadType(loadType()) 866 && !m_frame->document()->loadEventFinished()) { 867 HistoryItem* childItem = parentItem->childItemWithTarget(childFrame->tree()->uniqueName()); 868 if (childItem) { 869 childFrame->loader()->loadDifferentDocumentItem(childItem, loadType(), MayAttemptCacheOnlyLoadForFormSubmissionItem); 870 return; 871 } 872 } 873 874 childFrame->loader()->loadURL(url, referer, "_self", false, FrameLoadTypeRedirectWithLockedBackForwardList, 0, 0); 875} 876 877#if ENABLE(WEB_ARCHIVE) || ENABLE(MHTML) 878void FrameLoader::loadArchive(PassRefPtr<Archive> archive) 879{ 880 ArchiveResource* mainResource = archive->mainResource(); 881 ASSERT(mainResource); 882 if (!mainResource) 883 return; 884 885 SubstituteData substituteData(mainResource->data(), mainResource->mimeType(), mainResource->textEncoding(), KURL()); 886 887 ResourceRequest request(mainResource->url()); 888#if PLATFORM(MAC) 889 request.applyWebArchiveHackForMail(); 890#endif 891 892 RefPtr<DocumentLoader> documentLoader = m_client->createDocumentLoader(request, substituteData); 893 documentLoader->setArchive(archive.get()); 894 load(documentLoader.get()); 895} 896#endif // ENABLE(WEB_ARCHIVE) || ENABLE(MHTML) 897 898ObjectContentType FrameLoader::defaultObjectContentType(const KURL& url, const String& mimeTypeIn, bool shouldPreferPlugInsForImages) 899{ 900 String mimeType = mimeTypeIn; 901 902 if (mimeType.isEmpty()) 903 mimeType = mimeTypeFromURL(url); 904 905#if !PLATFORM(MAC) && !PLATFORM(EFL) // Mac has no PluginDatabase, nor does Chromium or EFL 906 if (mimeType.isEmpty()) { 907 String decodedPath = decodeURLEscapeSequences(url.path()); 908 mimeType = PluginDatabase::installedPlugins()->MIMETypeForExtension(decodedPath.substring(decodedPath.reverseFind('.') + 1)); 909 } 910#endif 911 912 if (mimeType.isEmpty()) 913 return ObjectContentFrame; // Go ahead and hope that we can display the content. 914 915#if !PLATFORM(MAC) && !PLATFORM(EFL) // Mac has no PluginDatabase, nor does Chromium or EFL 916 bool plugInSupportsMIMEType = PluginDatabase::installedPlugins()->isMIMETypeRegistered(mimeType); 917#else 918 bool plugInSupportsMIMEType = false; 919#endif 920 921 if (MIMETypeRegistry::isSupportedImageMIMEType(mimeType)) 922 return shouldPreferPlugInsForImages && plugInSupportsMIMEType ? WebCore::ObjectContentNetscapePlugin : WebCore::ObjectContentImage; 923 924 if (plugInSupportsMIMEType) 925 return WebCore::ObjectContentNetscapePlugin; 926 927 if (MIMETypeRegistry::isSupportedNonImageMIMEType(mimeType)) 928 return WebCore::ObjectContentFrame; 929 930 return WebCore::ObjectContentNone; 931} 932 933String FrameLoader::outgoingReferrer() const 934{ 935 // See http://www.whatwg.org/specs/web-apps/current-work/#fetching-resources 936 // for why we walk the parent chain for srcdoc documents. 937 Frame* frame = m_frame; 938 while (frame->document()->isSrcdocDocument()) { 939 frame = frame->tree()->parent(); 940 // Srcdoc documents cannot be top-level documents, by definition, 941 // because they need to be contained in iframes with the srcdoc. 942 ASSERT(frame); 943 } 944 return frame->loader()->m_outgoingReferrer; 945} 946 947String FrameLoader::outgoingOrigin() const 948{ 949 return m_frame->document()->securityOrigin()->toString(); 950} 951 952bool FrameLoader::checkIfFormActionAllowedByCSP(const KURL& url) const 953{ 954 if (m_submittedFormURL.isEmpty()) 955 return true; 956 957 return m_frame->document()->contentSecurityPolicy()->allowFormAction(url); 958} 959 960Frame* FrameLoader::opener() 961{ 962 return m_opener; 963} 964 965void FrameLoader::setOpener(Frame* opener) 966{ 967 if (m_opener && !opener) 968 m_client->didDisownOpener(); 969 970 if (m_opener) 971 m_opener->loader()->m_openedFrames.remove(m_frame); 972 if (opener) 973 opener->loader()->m_openedFrames.add(m_frame); 974 m_opener = opener; 975 976 if (m_frame->document()) 977 m_frame->document()->initSecurityContext(); 978} 979 980// FIXME: This does not belong in FrameLoader! 981void FrameLoader::handleFallbackContent() 982{ 983 HTMLFrameOwnerElement* owner = m_frame->ownerElement(); 984 if (!owner || !owner->hasTagName(objectTag)) 985 return; 986 static_cast<HTMLObjectElement*>(owner)->renderFallbackContent(); 987} 988 989void FrameLoader::provisionalLoadStarted() 990{ 991 if (m_stateMachine.firstLayoutDone()) 992 m_stateMachine.advanceTo(FrameLoaderStateMachine::CommittedFirstRealLoad); 993 m_frame->navigationScheduler()->cancel(true); 994 m_client->provisionalLoadStarted(); 995} 996 997void FrameLoader::resetMultipleFormSubmissionProtection() 998{ 999 m_submittedFormURL = KURL(); 1000} 1001 1002void FrameLoader::updateFirstPartyForCookies() 1003{ 1004 if (m_frame->tree()->parent()) 1005 setFirstPartyForCookies(m_frame->tree()->parent()->document()->firstPartyForCookies()); 1006 else 1007 setFirstPartyForCookies(m_frame->document()->url()); 1008} 1009 1010void FrameLoader::setFirstPartyForCookies(const KURL& url) 1011{ 1012 for (Frame* frame = m_frame; frame; frame = frame->tree()->traverseNext(m_frame)) 1013 frame->document()->setFirstPartyForCookies(url); 1014} 1015 1016// This does the same kind of work that didOpenURL does, except it relies on the fact 1017// that a higher level already checked that the URLs match and the scrolling is the right thing to do. 1018void FrameLoader::loadInSameDocument(const KURL& url, PassRefPtr<SerializedScriptValue> stateObject, bool isNewNavigation) 1019{ 1020 // If we have a state object, we cannot also be a new navigation. 1021 ASSERT(!stateObject || (stateObject && !isNewNavigation)); 1022 1023 // Update the data source's request with the new URL to fake the URL change 1024 KURL oldURL = m_frame->document()->url(); 1025 m_frame->document()->setURL(url); 1026 setOutgoingReferrer(url); 1027 documentLoader()->replaceRequestURLForSameDocumentNavigation(url); 1028 if (isNewNavigation && !shouldTreatURLAsSameAsCurrent(url) && !stateObject) { 1029 // NB: must happen after replaceRequestURLForSameDocumentNavigation(), since we add 1030 // based on the current request. Must also happen before we openURL and displace the 1031 // scroll position, since adding the BF item will save away scroll state. 1032 1033 // NB2: If we were loading a long, slow doc, and the user fragment navigated before 1034 // it was done, currItem is now set the that slow doc, and prevItem is whatever was 1035 // before it. Adding the b/f item will bump the slow doc down to prevItem, even 1036 // though its load is not yet done. I think this all works out OK, for one because 1037 // we have already saved away the scroll and doc state for the long slow load, 1038 // but it's not an obvious case. 1039 1040 history()->updateBackForwardListForFragmentScroll(); 1041 } 1042 1043 bool hashChange = equalIgnoringFragmentIdentifier(url, oldURL) && url.fragmentIdentifier() != oldURL.fragmentIdentifier(); 1044 1045 history()->updateForSameDocumentNavigation(); 1046 1047 // If we were in the autoscroll/panScroll mode we want to stop it before following the link to the anchor 1048 if (hashChange) 1049 m_frame->eventHandler()->stopAutoscrollTimer(); 1050 1051 // It's important to model this as a load that starts and immediately finishes. 1052 // Otherwise, the parent frame may think we never finished loading. 1053 started(); 1054 1055 // We need to scroll to the fragment whether or not a hash change occurred, since 1056 // the user might have scrolled since the previous navigation. 1057 scrollToFragmentWithParentBoundary(url); 1058 1059 m_isComplete = false; 1060 checkCompleted(); 1061 1062 if (isNewNavigation) { 1063 // This will clear previousItem from the rest of the frame tree that didn't 1064 // doing any loading. We need to make a pass on this now, since for fragment 1065 // navigation we'll not go through a real load and reach Completed state. 1066 checkLoadComplete(); 1067 } 1068 1069 m_client->dispatchDidNavigateWithinPage(); 1070 1071 m_frame->document()->statePopped(stateObject ? stateObject : SerializedScriptValue::nullValue()); 1072 m_client->dispatchDidPopStateWithinPage(); 1073 1074 if (hashChange) { 1075 m_frame->document()->enqueueHashchangeEvent(oldURL, url); 1076 m_client->dispatchDidChangeLocationWithinPage(); 1077 } 1078 1079 // FrameLoaderClient::didFinishLoad() tells the internal load delegate the load finished with no error 1080 m_client->didFinishLoad(); 1081} 1082 1083bool FrameLoader::isComplete() const 1084{ 1085 return m_isComplete; 1086} 1087 1088void FrameLoader::completed() 1089{ 1090 RefPtr<Frame> protect(m_frame); 1091 1092 for (Frame* descendant = m_frame->tree()->traverseNext(m_frame); descendant; descendant = descendant->tree()->traverseNext(m_frame)) 1093 descendant->navigationScheduler()->startTimer(); 1094 1095 if (Frame* parent = m_frame->tree()->parent()) 1096 parent->loader()->checkCompleted(); 1097 1098 if (m_frame->view()) 1099 m_frame->view()->maintainScrollPositionAtAnchor(0); 1100 m_activityAssertion.clear(); 1101} 1102 1103void FrameLoader::started() 1104{ 1105 if (m_frame && m_frame->page()) 1106 m_activityAssertion = m_frame->page()->createActivityToken(); 1107 for (Frame* frame = m_frame; frame; frame = frame->tree()->parent()) 1108 frame->loader()->m_isComplete = false; 1109} 1110 1111void FrameLoader::prepareForHistoryNavigation() 1112{ 1113 // If there is no currentItem, but we still want to engage in 1114 // history navigation we need to manufacture one, and update 1115 // the state machine of this frame to impersonate having 1116 // loaded it. 1117 RefPtr<HistoryItem> currentItem = history()->currentItem(); 1118 if (!currentItem) { 1119 currentItem = HistoryItem::create(); 1120 currentItem->setLastVisitWasFailure(true); 1121 history()->setCurrentItem(currentItem.get()); 1122 frame()->page()->backForward()->setCurrentItem(currentItem.get()); 1123 1124 ASSERT(stateMachine()->isDisplayingInitialEmptyDocument()); 1125 stateMachine()->advanceTo(FrameLoaderStateMachine::DisplayingInitialEmptyDocumentPostCommit); 1126 stateMachine()->advanceTo(FrameLoaderStateMachine::CommittedFirstRealLoad); 1127 } 1128} 1129 1130void FrameLoader::prepareForLoadStart() 1131{ 1132 m_progressTracker->progressStarted(); 1133 m_client->dispatchDidStartProvisionalLoad(); 1134 1135 // Notify accessibility. 1136 if (AXObjectCache* cache = m_frame->document()->existingAXObjectCache()) { 1137 AXObjectCache::AXLoadingEvent loadingEvent = loadType() == FrameLoadTypeReload ? AXObjectCache::AXLoadingReloaded : AXObjectCache::AXLoadingStarted; 1138 cache->frameLoadingEventNotification(m_frame, loadingEvent); 1139 } 1140} 1141 1142void FrameLoader::setupForReplace() 1143{ 1144 m_client->revertToProvisionalState(m_documentLoader.get()); 1145 setState(FrameStateProvisional); 1146 m_provisionalDocumentLoader = m_documentLoader; 1147 m_documentLoader = 0; 1148 detachChildren(); 1149} 1150 1151void FrameLoader::loadFrameRequest(const FrameLoadRequest& request, bool lockHistory, bool lockBackForwardList, 1152 PassRefPtr<Event> event, PassRefPtr<FormState> formState, ShouldSendReferrer shouldSendReferrer) 1153{ 1154 // Protect frame from getting blown away inside dispatchBeforeLoadEvent in loadWithDocumentLoader. 1155 RefPtr<Frame> protect(m_frame); 1156 1157 KURL url = request.resourceRequest().url(); 1158 1159 ASSERT(m_frame->document()); 1160 if (!request.requester()->canDisplay(url)) { 1161 reportLocalLoadFailed(m_frame, url.stringCenterEllipsizedToLength()); 1162 return; 1163 } 1164 1165 String argsReferrer = request.resourceRequest().httpReferrer(); 1166 if (argsReferrer.isEmpty()) 1167 argsReferrer = outgoingReferrer(); 1168 1169 String referrer = SecurityPolicy::generateReferrerHeader(m_frame->document()->referrerPolicy(), url, argsReferrer); 1170 if (shouldSendReferrer == NeverSendReferrer) 1171 referrer = String(); 1172 1173 FrameLoadType loadType; 1174 if (request.resourceRequest().cachePolicy() == ReloadIgnoringCacheData) 1175 loadType = FrameLoadTypeReload; 1176 else if (lockBackForwardList) 1177 loadType = FrameLoadTypeRedirectWithLockedBackForwardList; 1178 else 1179 loadType = FrameLoadTypeStandard; 1180 1181 if (request.resourceRequest().httpMethod() == "POST") 1182 loadPostRequest(request.resourceRequest(), referrer, request.frameName(), lockHistory, loadType, event, formState.get()); 1183 else 1184 loadURL(request.resourceRequest().url(), referrer, request.frameName(), lockHistory, loadType, event, formState.get()); 1185 1186 // FIXME: It's possible this targetFrame will not be the same frame that was targeted by the actual 1187 // load if frame names have changed. 1188 Frame* sourceFrame = formState ? formState->sourceDocument()->frame() : m_frame; 1189 if (!sourceFrame) 1190 sourceFrame = m_frame; 1191 Frame* targetFrame = sourceFrame->loader()->findFrameForNavigation(request.frameName()); 1192 if (targetFrame && targetFrame != sourceFrame) { 1193 if (Page* page = targetFrame->page()) 1194 page->chrome().focus(); 1195 } 1196} 1197 1198void FrameLoader::loadURL(const KURL& newURL, const String& referrer, const String& frameName, bool lockHistory, FrameLoadType newLoadType, 1199 PassRefPtr<Event> event, PassRefPtr<FormState> prpFormState) 1200{ 1201 if (m_inStopAllLoaders) 1202 return; 1203 1204 RefPtr<Frame> protect(m_frame); 1205 1206 RefPtr<FormState> formState = prpFormState; 1207 bool isFormSubmission = formState; 1208 1209 ResourceRequest request(newURL); 1210 if (!referrer.isEmpty()) { 1211 request.setHTTPReferrer(referrer); 1212 RefPtr<SecurityOrigin> referrerOrigin = SecurityOrigin::createFromString(referrer); 1213 addHTTPOriginIfNeeded(request, referrerOrigin->toString()); 1214 } 1215#if ENABLE(CACHE_PARTITIONING) 1216 if (m_frame->tree()->top() != m_frame) 1217 request.setCachePartition(m_frame->tree()->top()->document()->securityOrigin()->cachePartition()); 1218#endif 1219 addExtraFieldsToRequest(request, newLoadType, true); 1220 if (newLoadType == FrameLoadTypeReload || newLoadType == FrameLoadTypeReloadFromOrigin) 1221 request.setCachePolicy(ReloadIgnoringCacheData); 1222 1223 ASSERT(newLoadType != FrameLoadTypeSame); 1224 1225 // The search for a target frame is done earlier in the case of form submission. 1226 Frame* targetFrame = isFormSubmission ? 0 : findFrameForNavigation(frameName); 1227 if (targetFrame && targetFrame != m_frame) { 1228 targetFrame->loader()->loadURL(newURL, referrer, "_self", lockHistory, newLoadType, event, formState.release()); 1229 return; 1230 } 1231 1232 if (m_pageDismissalEventBeingDispatched != NoDismissal) 1233 return; 1234 1235 NavigationAction action(request, newLoadType, isFormSubmission, event); 1236 1237 if (!targetFrame && !frameName.isEmpty()) { 1238 policyChecker()->checkNewWindowPolicy(action, FrameLoader::callContinueLoadAfterNewWindowPolicy, 1239 request, formState.release(), frameName, this); 1240 return; 1241 } 1242 1243 RefPtr<DocumentLoader> oldDocumentLoader = m_documentLoader; 1244 1245 bool sameURL = shouldTreatURLAsSameAsCurrent(newURL); 1246 const String& httpMethod = request.httpMethod(); 1247 1248 // Make sure to do scroll to fragment processing even if the URL is 1249 // exactly the same so pages with '#' links and DHTML side effects 1250 // work properly. 1251 if (shouldPerformFragmentNavigation(isFormSubmission, httpMethod, newLoadType, newURL)) { 1252 oldDocumentLoader->setTriggeringAction(action); 1253 policyChecker()->stopCheck(); 1254 policyChecker()->setLoadType(newLoadType); 1255 policyChecker()->checkNavigationPolicy(request, oldDocumentLoader.get(), formState.release(), 1256 callContinueFragmentScrollAfterNavigationPolicy, this); 1257 } else { 1258 // must grab this now, since this load may stop the previous load and clear this flag 1259 bool isRedirect = m_quickRedirectComing; 1260 loadWithNavigationAction(request, action, lockHistory, newLoadType, formState.release()); 1261 if (isRedirect) { 1262 m_quickRedirectComing = false; 1263 if (m_provisionalDocumentLoader) 1264 m_provisionalDocumentLoader->setIsClientRedirect(true); 1265 } else if (sameURL && newLoadType != FrameLoadTypeReload && newLoadType != FrameLoadTypeReloadFromOrigin) 1266 // Example of this case are sites that reload the same URL with a different cookie 1267 // driving the generated content, or a master frame with links that drive a target 1268 // frame, where the user has clicked on the same link repeatedly. 1269 m_loadType = FrameLoadTypeSame; 1270 } 1271} 1272 1273SubstituteData FrameLoader::defaultSubstituteDataForURL(const KURL& url) 1274{ 1275 if (!shouldTreatURLAsSrcdocDocument(url)) 1276 return SubstituteData(); 1277 String srcdoc = m_frame->ownerElement()->fastGetAttribute(srcdocAttr); 1278 ASSERT(!srcdoc.isNull()); 1279 CString encodedSrcdoc = srcdoc.utf8(); 1280 return SubstituteData(SharedBuffer::create(encodedSrcdoc.data(), encodedSrcdoc.length()), "text/html", "UTF-8", KURL()); 1281} 1282 1283void FrameLoader::load(const FrameLoadRequest& passedRequest) 1284{ 1285 FrameLoadRequest request(passedRequest); 1286 1287 if (m_inStopAllLoaders) 1288 return; 1289 1290 if (!request.frameName().isEmpty()) { 1291 Frame* frame = findFrameForNavigation(request.frameName()); 1292 if (frame) { 1293 request.setShouldCheckNewWindowPolicy(false); 1294 if (frame->loader() != this) { 1295 frame->loader()->load(request); 1296 return; 1297 } 1298 } 1299 } 1300 1301 if (request.shouldCheckNewWindowPolicy()) { 1302 policyChecker()->checkNewWindowPolicy(NavigationAction(request.resourceRequest(), NavigationTypeOther), FrameLoader::callContinueLoadAfterNewWindowPolicy, request.resourceRequest(), 0, request.frameName(), this); 1303 return; 1304 } 1305 1306 if (!request.hasSubstituteData()) 1307 request.setSubstituteData(defaultSubstituteDataForURL(request.resourceRequest().url())); 1308 1309 RefPtr<DocumentLoader> loader = m_client->createDocumentLoader(request.resourceRequest(), request.substituteData()); 1310 if (request.lockHistory() && m_documentLoader) 1311 loader->setClientRedirectSourceForHistory(m_documentLoader->didCreateGlobalHistoryEntry() ? m_documentLoader->urlForHistory().string() : m_documentLoader->clientRedirectSourceForHistory()); 1312 load(loader.get()); 1313} 1314 1315void FrameLoader::loadWithNavigationAction(const ResourceRequest& request, const NavigationAction& action, bool lockHistory, FrameLoadType type, PassRefPtr<FormState> formState) 1316{ 1317 RefPtr<DocumentLoader> loader = m_client->createDocumentLoader(request, defaultSubstituteDataForURL(request.url())); 1318 if (lockHistory && m_documentLoader) 1319 loader->setClientRedirectSourceForHistory(m_documentLoader->didCreateGlobalHistoryEntry() ? m_documentLoader->urlForHistory().string() : m_documentLoader->clientRedirectSourceForHistory()); 1320 1321 loader->setTriggeringAction(action); 1322 if (m_documentLoader) 1323 loader->setOverrideEncoding(m_documentLoader->overrideEncoding()); 1324 1325 loadWithDocumentLoader(loader.get(), type, formState); 1326} 1327 1328void FrameLoader::load(DocumentLoader* newDocumentLoader) 1329{ 1330 ResourceRequest& r = newDocumentLoader->request(); 1331 addExtraFieldsToMainResourceRequest(r); 1332 FrameLoadType type; 1333 1334 if (shouldTreatURLAsSameAsCurrent(newDocumentLoader->originalRequest().url())) { 1335 r.setCachePolicy(ReloadIgnoringCacheData); 1336 type = FrameLoadTypeSame; 1337 } else if (shouldTreatURLAsSameAsCurrent(newDocumentLoader->unreachableURL()) && m_loadType == FrameLoadTypeReload) 1338 type = FrameLoadTypeReload; 1339 else 1340 type = FrameLoadTypeStandard; 1341 1342 if (m_documentLoader) 1343 newDocumentLoader->setOverrideEncoding(m_documentLoader->overrideEncoding()); 1344 1345 // When we loading alternate content for an unreachable URL that we're 1346 // visiting in the history list, we treat it as a reload so the history list 1347 // is appropriately maintained. 1348 // 1349 // FIXME: This seems like a dangerous overloading of the meaning of "FrameLoadTypeReload" ... 1350 // shouldn't a more explicit type of reload be defined, that means roughly 1351 // "load without affecting history" ? 1352 if (shouldReloadToHandleUnreachableURL(newDocumentLoader)) { 1353 // shouldReloadToHandleUnreachableURL() returns true only when the original load type is back-forward. 1354 // In this case we should save the document state now. Otherwise the state can be lost because load type is 1355 // changed and updateForBackForwardNavigation() will not be called when loading is committed. 1356 history()->saveDocumentAndScrollState(); 1357 1358 ASSERT(type == FrameLoadTypeStandard); 1359 type = FrameLoadTypeReload; 1360 } 1361 1362 loadWithDocumentLoader(newDocumentLoader, type, 0); 1363} 1364 1365void FrameLoader::loadWithDocumentLoader(DocumentLoader* loader, FrameLoadType type, PassRefPtr<FormState> prpFormState) 1366{ 1367 // Retain because dispatchBeforeLoadEvent may release the last reference to it. 1368 RefPtr<Frame> protect(m_frame); 1369 1370 ASSERT(m_client->hasWebView()); 1371 1372 // Unfortunately the view must be non-nil, this is ultimately due 1373 // to parser requiring a FrameView. We should fix this dependency. 1374 1375 ASSERT(m_frame->view()); 1376 1377 if (m_pageDismissalEventBeingDispatched != NoDismissal) 1378 return; 1379 1380 if (m_frame->document()) 1381 m_previousURL = m_frame->document()->url(); 1382 1383 policyChecker()->setLoadType(type); 1384 RefPtr<FormState> formState = prpFormState; 1385 bool isFormSubmission = formState; 1386 1387 const KURL& newURL = loader->request().url(); 1388 const String& httpMethod = loader->request().httpMethod(); 1389 1390 if (shouldPerformFragmentNavigation(isFormSubmission, httpMethod, policyChecker()->loadType(), newURL)) { 1391 RefPtr<DocumentLoader> oldDocumentLoader = m_documentLoader; 1392 NavigationAction action(loader->request(), policyChecker()->loadType(), isFormSubmission); 1393 1394 oldDocumentLoader->setTriggeringAction(action); 1395 policyChecker()->stopCheck(); 1396 policyChecker()->checkNavigationPolicy(loader->request(), oldDocumentLoader.get(), formState, 1397 callContinueFragmentScrollAfterNavigationPolicy, this); 1398 } else { 1399 if (Frame* parent = m_frame->tree()->parent()) 1400 loader->setOverrideEncoding(parent->loader()->documentLoader()->overrideEncoding()); 1401 1402 policyChecker()->stopCheck(); 1403 setPolicyDocumentLoader(loader); 1404 if (loader->triggeringAction().isEmpty()) 1405 loader->setTriggeringAction(NavigationAction(loader->request(), policyChecker()->loadType(), isFormSubmission)); 1406 1407 if (Element* ownerElement = m_frame->ownerElement()) { 1408 // We skip dispatching the beforeload event if we've already 1409 // committed a real document load because the event would leak 1410 // subsequent activity by the frame which the parent frame isn't 1411 // supposed to learn. For example, if the child frame navigated to 1412 // a new URL, the parent frame shouldn't learn the URL. 1413 if (!m_stateMachine.committedFirstRealDocumentLoad() 1414 && !ownerElement->dispatchBeforeLoadEvent(loader->request().url().string())) { 1415 continueLoadAfterNavigationPolicy(loader->request(), formState, false); 1416 return; 1417 } 1418 } 1419 1420 policyChecker()->checkNavigationPolicy(loader->request(), loader, formState, 1421 callContinueLoadAfterNavigationPolicy, this); 1422 } 1423} 1424 1425void FrameLoader::reportLocalLoadFailed(Frame* frame, const String& url) 1426{ 1427 ASSERT(!url.isEmpty()); 1428 if (!frame) 1429 return; 1430 1431 frame->document()->addConsoleMessage(SecurityMessageSource, ErrorMessageLevel, "Not allowed to load local resource: " + url); 1432} 1433 1434const ResourceRequest& FrameLoader::initialRequest() const 1435{ 1436 return activeDocumentLoader()->originalRequest(); 1437} 1438 1439bool FrameLoader::willLoadMediaElementURL(KURL& url) 1440{ 1441 ResourceRequest request(url); 1442 1443 unsigned long identifier; 1444 ResourceError error; 1445 requestFromDelegate(request, identifier, error); 1446 notifier()->sendRemainingDelegateMessages(m_documentLoader.get(), identifier, request, ResourceResponse(url, String(), -1, String(), String()), 0, -1, -1, error); 1447 1448 url = request.url(); 1449 1450 return error.isNull(); 1451} 1452 1453bool FrameLoader::shouldReloadToHandleUnreachableURL(DocumentLoader* docLoader) 1454{ 1455 KURL unreachableURL = docLoader->unreachableURL(); 1456 1457 if (unreachableURL.isEmpty()) 1458 return false; 1459 1460 if (!isBackForwardLoadType(policyChecker()->loadType())) 1461 return false; 1462 1463 // We only treat unreachableURLs specially during the delegate callbacks 1464 // for provisional load errors and navigation policy decisions. The former 1465 // case handles well-formed URLs that can't be loaded, and the latter 1466 // case handles malformed URLs and unknown schemes. Loading alternate content 1467 // at other times behaves like a standard load. 1468 DocumentLoader* compareDocumentLoader = 0; 1469 if (policyChecker()->delegateIsDecidingNavigationPolicy() || policyChecker()->delegateIsHandlingUnimplementablePolicy()) 1470 compareDocumentLoader = m_policyDocumentLoader.get(); 1471 else if (m_delegateIsHandlingProvisionalLoadError) 1472 compareDocumentLoader = m_provisionalDocumentLoader.get(); 1473 1474 return compareDocumentLoader && unreachableURL == compareDocumentLoader->request().url(); 1475} 1476 1477void FrameLoader::reloadWithOverrideEncoding(const String& encoding) 1478{ 1479 if (!m_documentLoader) 1480 return; 1481 1482 ResourceRequest request = m_documentLoader->request(); 1483 KURL unreachableURL = m_documentLoader->unreachableURL(); 1484 if (!unreachableURL.isEmpty()) 1485 request.setURL(unreachableURL); 1486 1487 // FIXME: If the resource is a result of form submission and is not cached, the form will be silently resubmitted. 1488 // We should ask the user for confirmation in this case. 1489 request.setCachePolicy(ReturnCacheDataElseLoad); 1490 1491 RefPtr<DocumentLoader> loader = m_client->createDocumentLoader(request, defaultSubstituteDataForURL(request.url())); 1492 setPolicyDocumentLoader(loader.get()); 1493 1494 loader->setOverrideEncoding(encoding); 1495 1496 loadWithDocumentLoader(loader.get(), FrameLoadTypeReload, 0); 1497} 1498 1499void FrameLoader::reloadWithOverrideURL(const KURL& overrideUrl, bool endToEndReload) 1500{ 1501 if (!m_documentLoader) 1502 return; 1503 1504 if (overrideUrl.isEmpty()) 1505 return; 1506 1507 ResourceRequest request = m_documentLoader->request(); 1508 request.setURL(overrideUrl); 1509 reloadWithRequest(request, endToEndReload); 1510} 1511 1512void FrameLoader::reload(bool endToEndReload) 1513{ 1514 if (!m_documentLoader) 1515 return; 1516 1517 // If a window is created by javascript, its main frame can have an empty but non-nil URL. 1518 // Reloading in this case will lose the current contents (see 4151001). 1519 if (m_documentLoader->request().url().isEmpty()) 1520 return; 1521 1522 // Replace error-page URL with the URL we were trying to reach. 1523 ResourceRequest initialRequest = m_documentLoader->request(); 1524 KURL unreachableURL = m_documentLoader->unreachableURL(); 1525 if (!unreachableURL.isEmpty()) 1526 initialRequest.setURL(unreachableURL); 1527 1528 reloadWithRequest(initialRequest, endToEndReload); 1529} 1530 1531void FrameLoader::reloadWithRequest(const ResourceRequest& initialRequest, bool endToEndReload) 1532{ 1533 ASSERT(m_documentLoader); 1534 1535 // Create a new document loader for the reload, this will become m_documentLoader eventually, 1536 // but first it has to be the "policy" document loader, and then the "provisional" document loader. 1537 RefPtr<DocumentLoader> loader = m_client->createDocumentLoader(initialRequest, defaultSubstituteDataForURL(initialRequest.url())); 1538 1539 ResourceRequest& request = loader->request(); 1540 1541 // FIXME: We don't have a mechanism to revalidate the main resource without reloading at the moment. 1542 request.setCachePolicy(ReloadIgnoringCacheData); 1543 1544 // If we're about to re-post, set up action so the application can warn the user. 1545 if (request.httpMethod() == "POST") 1546 loader->setTriggeringAction(NavigationAction(request, NavigationTypeFormResubmitted)); 1547 1548 loader->setOverrideEncoding(m_documentLoader->overrideEncoding()); 1549 1550 loadWithDocumentLoader(loader.get(), endToEndReload ? FrameLoadTypeReloadFromOrigin : FrameLoadTypeReload, 0); 1551} 1552 1553void FrameLoader::stopAllLoaders(ClearProvisionalItemPolicy clearProvisionalItemPolicy) 1554{ 1555 ASSERT(!m_frame->document() || !m_frame->document()->inPageCache()); 1556 if (m_pageDismissalEventBeingDispatched != NoDismissal) 1557 return; 1558 1559 // If this method is called from within this method, infinite recursion can occur (3442218). Avoid this. 1560 if (m_inStopAllLoaders) 1561 return; 1562 1563 // Calling stopLoading() on the provisional document loader can blow away 1564 // the frame from underneath. 1565 RefPtr<Frame> protect(m_frame); 1566 1567 m_inStopAllLoaders = true; 1568 1569 policyChecker()->stopCheck(); 1570 1571 // If no new load is in progress, we should clear the provisional item from history 1572 // before we call stopLoading. 1573 if (clearProvisionalItemPolicy == ShouldClearProvisionalItem) 1574 history()->setProvisionalItem(0); 1575 1576 for (RefPtr<Frame> child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling()) 1577 child->loader()->stopAllLoaders(clearProvisionalItemPolicy); 1578 if (m_provisionalDocumentLoader) 1579 m_provisionalDocumentLoader->stopLoading(); 1580 if (m_documentLoader) 1581 m_documentLoader->stopLoading(); 1582 1583 setProvisionalDocumentLoader(0); 1584 1585 m_checkTimer.stop(); 1586 1587 m_inStopAllLoaders = false; 1588} 1589 1590void FrameLoader::stopForUserCancel(bool deferCheckLoadComplete) 1591{ 1592 stopAllLoaders(); 1593 1594 if (deferCheckLoadComplete) 1595 scheduleCheckLoadComplete(); 1596 else if (m_frame->page()) 1597 checkLoadComplete(); 1598} 1599 1600DocumentLoader* FrameLoader::activeDocumentLoader() const 1601{ 1602 if (m_state == FrameStateProvisional) 1603 return m_provisionalDocumentLoader.get(); 1604 return m_documentLoader.get(); 1605} 1606 1607bool FrameLoader::isLoading() const 1608{ 1609 DocumentLoader* docLoader = activeDocumentLoader(); 1610 if (!docLoader) 1611 return false; 1612 return docLoader->isLoading(); 1613} 1614 1615bool FrameLoader::frameHasLoaded() const 1616{ 1617 return m_stateMachine.committedFirstRealDocumentLoad() || (m_provisionalDocumentLoader && !m_stateMachine.creatingInitialEmptyDocument()); 1618} 1619 1620void FrameLoader::setDocumentLoader(DocumentLoader* loader) 1621{ 1622 if (!loader && !m_documentLoader) 1623 return; 1624 1625 ASSERT(loader != m_documentLoader); 1626 ASSERT(!loader || loader->frameLoader() == this); 1627 1628 m_client->prepareForDataSourceReplacement(); 1629 detachChildren(); 1630 1631 // detachChildren() can trigger this frame's unload event, and therefore 1632 // script can run and do just about anything. For example, an unload event that calls 1633 // document.write("") on its parent frame can lead to a recursive detachChildren() 1634 // invocation for this frame. In that case, we can end up at this point with a 1635 // loader that hasn't been deleted but has been detached from its frame. Such a 1636 // DocumentLoader has been sufficiently detached that we'll end up in an inconsistent 1637 // state if we try to use it. 1638 if (loader && !loader->frame()) 1639 return; 1640 1641 if (m_documentLoader) 1642 m_documentLoader->detachFromFrame(); 1643 1644 m_documentLoader = loader; 1645} 1646 1647void FrameLoader::setPolicyDocumentLoader(DocumentLoader* loader) 1648{ 1649 if (m_policyDocumentLoader == loader) 1650 return; 1651 1652 ASSERT(m_frame); 1653 if (loader) 1654 loader->setFrame(m_frame); 1655 if (m_policyDocumentLoader 1656 && m_policyDocumentLoader != m_provisionalDocumentLoader 1657 && m_policyDocumentLoader != m_documentLoader) 1658 m_policyDocumentLoader->detachFromFrame(); 1659 1660 m_policyDocumentLoader = loader; 1661} 1662 1663void FrameLoader::setProvisionalDocumentLoader(DocumentLoader* loader) 1664{ 1665 ASSERT(!loader || !m_provisionalDocumentLoader); 1666 ASSERT(!loader || loader->frameLoader() == this); 1667 1668 if (m_provisionalDocumentLoader && m_provisionalDocumentLoader != m_documentLoader) 1669 m_provisionalDocumentLoader->detachFromFrame(); 1670 1671 m_provisionalDocumentLoader = loader; 1672} 1673 1674double FrameLoader::timeOfLastCompletedLoad() 1675{ 1676 return storedTimeOfLastCompletedLoad; 1677} 1678 1679void FrameLoader::setState(FrameState newState) 1680{ 1681 m_state = newState; 1682 1683 if (newState == FrameStateProvisional) 1684 provisionalLoadStarted(); 1685 else if (newState == FrameStateComplete) { 1686 frameLoadCompleted(); 1687 storedTimeOfLastCompletedLoad = currentTime(); 1688 if (m_documentLoader) 1689 m_documentLoader->stopRecordingResponses(); 1690 } 1691} 1692 1693void FrameLoader::clearProvisionalLoad() 1694{ 1695 setProvisionalDocumentLoader(0); 1696 m_progressTracker->progressCompleted(); 1697 setState(FrameStateComplete); 1698} 1699 1700void FrameLoader::commitProvisionalLoad() 1701{ 1702 RefPtr<CachedPage> cachedPage = m_loadingFromCachedPage ? pageCache()->get(history()->provisionalItem()) : 0; 1703 RefPtr<DocumentLoader> pdl = m_provisionalDocumentLoader; 1704 RefPtr<Frame> protect(m_frame); 1705 1706 LOG(PageCache, "WebCoreLoading %s: About to commit provisional load from previous URL '%s' to new URL '%s'", m_frame->tree()->uniqueName().string().utf8().data(), 1707 m_frame->document() ? m_frame->document()->url().stringCenterEllipsizedToLength().utf8().data() : "", 1708 pdl ? pdl->url().stringCenterEllipsizedToLength().utf8().data() : "<no provisional DocumentLoader>"); 1709 1710 willTransitionToCommitted(); 1711 1712 // Check to see if we need to cache the page we are navigating away from into the back/forward cache. 1713 // We are doing this here because we know for sure that a new page is about to be loaded. 1714 HistoryItem* item = history()->currentItem(); 1715 if (!m_frame->tree()->parent() && pageCache()->canCache(m_frame->page()) && !item->isInPageCache()) 1716 pageCache()->add(item, m_frame->page()); 1717 1718 if (m_loadType != FrameLoadTypeReplace) 1719 closeOldDataSources(); 1720 1721 if (!cachedPage && !m_stateMachine.creatingInitialEmptyDocument()) 1722 m_client->makeRepresentation(pdl.get()); 1723 1724 transitionToCommitted(cachedPage); 1725 1726 if (pdl && m_documentLoader) { 1727 // Check if the destination page is allowed to access the previous page's timing information. 1728 RefPtr<SecurityOrigin> securityOrigin = SecurityOrigin::create(pdl->request().url()); 1729 m_documentLoader->timing()->setHasSameOriginAsPreviousDocument(securityOrigin->canRequest(m_previousURL)); 1730 } 1731 1732 // Call clientRedirectCancelledOrFinished() here so that the frame load delegate is notified that the redirect's 1733 // status has changed, if there was a redirect. The frame load delegate may have saved some state about 1734 // the redirect in its -webView:willPerformClientRedirectToURL:delay:fireDate:forFrame:. Since we are 1735 // just about to commit a new page, there cannot possibly be a pending redirect at this point. 1736 if (m_sentRedirectNotification) 1737 clientRedirectCancelledOrFinished(false); 1738 1739 if (cachedPage && cachedPage->document()) { 1740 prepareForCachedPageRestore(); 1741 cachedPage->restore(m_frame->page()); 1742 1743 // The page should be removed from the cache immediately after a restoration in order for the PageCache to be consistent. 1744 pageCache()->remove(history()->currentItem()); 1745 1746 dispatchDidCommitLoad(); 1747 1748 // If we have a title let the WebView know about it. 1749 StringWithDirection title = m_documentLoader->title(); 1750 if (!title.isNull()) 1751 m_client->dispatchDidReceiveTitle(title); 1752 1753 checkCompleted(); 1754 } else { 1755 if (cachedPage) 1756 pageCache()->remove(history()->currentItem()); 1757 didOpenURL(); 1758 } 1759 1760 LOG(Loading, "WebCoreLoading %s: Finished committing provisional load to URL %s", m_frame->tree()->uniqueName().string().utf8().data(), 1761 m_frame->document() ? m_frame->document()->url().stringCenterEllipsizedToLength().utf8().data() : ""); 1762 1763 if (m_loadType == FrameLoadTypeStandard && m_documentLoader->isClientRedirect()) 1764 history()->updateForClientRedirect(); 1765 1766 if (m_loadingFromCachedPage) { 1767 m_frame->document()->documentDidResumeFromPageCache(); 1768 1769 // Force a layout to update view size and thereby update scrollbars. 1770 m_frame->view()->forceLayout(); 1771 1772 const ResponseVector& responses = m_documentLoader->responses(); 1773 size_t count = responses.size(); 1774 for (size_t i = 0; i < count; i++) { 1775 const ResourceResponse& response = responses[i]; 1776 // FIXME: If the WebKit client changes or cancels the request, this is not respected. 1777 ResourceError error; 1778 unsigned long identifier; 1779 ResourceRequest request(response.url()); 1780 requestFromDelegate(request, identifier, error); 1781 // FIXME: If we get a resource with more than 2B bytes, this code won't do the right thing. 1782 // However, with today's computers and networking speeds, this won't happen in practice. 1783 // Could be an issue with a giant local file. 1784 notifier()->sendRemainingDelegateMessages(m_documentLoader.get(), identifier, request, response, 0, static_cast<int>(response.expectedContentLength()), 0, error); 1785 } 1786 1787 // FIXME: Why only this frame and not parent frames? 1788 checkLoadCompleteForThisFrame(); 1789 } 1790} 1791 1792void FrameLoader::transitionToCommitted(PassRefPtr<CachedPage> cachedPage) 1793{ 1794 ASSERT(m_client->hasWebView()); 1795 ASSERT(m_state == FrameStateProvisional); 1796 1797 if (m_state != FrameStateProvisional) 1798 return; 1799 1800 if (FrameView* view = m_frame->view()) { 1801 if (ScrollAnimator* scrollAnimator = view->existingScrollAnimator()) 1802 scrollAnimator->cancelAnimations(); 1803 } 1804 1805 m_client->setCopiesOnScroll(); 1806 history()->updateForCommit(); 1807 1808 // The call to closeURL() invokes the unload event handler, which can execute arbitrary 1809 // JavaScript. If the script initiates a new load, we need to abandon the current load, 1810 // or the two will stomp each other. 1811 DocumentLoader* pdl = m_provisionalDocumentLoader.get(); 1812 if (m_documentLoader) 1813 closeURL(); 1814 if (pdl != m_provisionalDocumentLoader) 1815 return; 1816 1817 // Nothing else can interupt this commit - set the Provisional->Committed transition in stone 1818 if (m_documentLoader) 1819 m_documentLoader->stopLoadingSubresources(); 1820 if (m_documentLoader) 1821 m_documentLoader->stopLoadingPlugIns(); 1822 1823 setDocumentLoader(m_provisionalDocumentLoader.get()); 1824 setProvisionalDocumentLoader(0); 1825 1826 if (pdl != m_documentLoader) { 1827 ASSERT(m_state == FrameStateComplete); 1828 return; 1829 } 1830 1831 setState(FrameStateCommittedPage); 1832 1833#if ENABLE(TOUCH_EVENTS) 1834 if (isLoadingMainFrame()) 1835 m_frame->page()->chrome().client()->needTouchEvents(false); 1836#endif 1837 1838 // Handle adding the URL to the back/forward list. 1839 DocumentLoader* dl = m_documentLoader.get(); 1840 1841 switch (m_loadType) { 1842 case FrameLoadTypeForward: 1843 case FrameLoadTypeBack: 1844 case FrameLoadTypeIndexedBackForward: 1845 if (m_frame->page()) { 1846 // If the first load within a frame is a navigation within a back/forward list that was attached 1847 // without any of the items being loaded then we need to update the history in a similar manner as 1848 // for a standard load with the exception of updating the back/forward list (<rdar://problem/8091103>). 1849 if (!m_stateMachine.committedFirstRealDocumentLoad() && isLoadingMainFrame()) 1850 history()->updateForStandardLoad(HistoryController::UpdateAllExceptBackForwardList); 1851 1852 history()->updateForBackForwardNavigation(); 1853 1854 // For cached pages, CachedFrame::restore will take care of firing the popstate event with the history item's state object 1855 if (history()->currentItem() && !cachedPage) 1856 m_pendingStateObject = history()->currentItem()->stateObject(); 1857 1858 // Create a document view for this document, or used the cached view. 1859 if (cachedPage) { 1860 DocumentLoader* cachedDocumentLoader = cachedPage->documentLoader(); 1861 ASSERT(cachedDocumentLoader); 1862 cachedDocumentLoader->setFrame(m_frame); 1863 m_client->transitionToCommittedFromCachedFrame(cachedPage->cachedMainFrame()); 1864 1865 } else 1866 m_client->transitionToCommittedForNewPage(); 1867 } 1868 break; 1869 1870 case FrameLoadTypeReload: 1871 case FrameLoadTypeReloadFromOrigin: 1872 case FrameLoadTypeSame: 1873 case FrameLoadTypeReplace: 1874 history()->updateForReload(); 1875 m_client->transitionToCommittedForNewPage(); 1876 break; 1877 1878 case FrameLoadTypeStandard: 1879 history()->updateForStandardLoad(); 1880 if (m_frame->view()) 1881 m_frame->view()->setScrollbarsSuppressed(true); 1882 m_client->transitionToCommittedForNewPage(); 1883 break; 1884 1885 case FrameLoadTypeRedirectWithLockedBackForwardList: 1886 history()->updateForRedirectWithLockedBackForwardList(); 1887 m_client->transitionToCommittedForNewPage(); 1888 break; 1889 1890 // FIXME Remove this check when dummy ds is removed (whatever "dummy ds" is). 1891 // An exception should be thrown if we're in the FrameLoadTypeUninitialized state. 1892 default: 1893 ASSERT_NOT_REACHED(); 1894 } 1895 1896 m_documentLoader->writer()->setMIMEType(dl->responseMIMEType()); 1897 1898 // Tell the client we've committed this URL. 1899 ASSERT(m_frame->view()); 1900 1901 if (m_stateMachine.creatingInitialEmptyDocument()) 1902 return; 1903 1904 if (!m_stateMachine.committedFirstRealDocumentLoad()) 1905 m_stateMachine.advanceTo(FrameLoaderStateMachine::DisplayingInitialEmptyDocumentPostCommit); 1906} 1907 1908void FrameLoader::clientRedirectCancelledOrFinished(bool cancelWithLoadInProgress) 1909{ 1910 // Note that -webView:didCancelClientRedirectForFrame: is called on the frame load delegate even if 1911 // the redirect succeeded. We should either rename this API, or add a new method, like 1912 // -webView:didFinishClientRedirectForFrame: 1913 m_client->dispatchDidCancelClientRedirect(); 1914 1915 if (!cancelWithLoadInProgress) 1916 m_quickRedirectComing = false; 1917 1918 m_sentRedirectNotification = false; 1919} 1920 1921void FrameLoader::clientRedirected(const KURL& url, double seconds, double fireDate, bool lockBackForwardList) 1922{ 1923 m_client->dispatchWillPerformClientRedirect(url, seconds, fireDate); 1924 1925 // Remember that we sent a redirect notification to the frame load delegate so that when we commit 1926 // the next provisional load, we can send a corresponding -webView:didCancelClientRedirectForFrame: 1927 m_sentRedirectNotification = true; 1928 1929 // If a "quick" redirect comes in, we set a special mode so we treat the next 1930 // load as part of the original navigation. If we don't have a document loader, we have 1931 // no "original" load on which to base a redirect, so we treat the redirect as a normal load. 1932 // Loads triggered by JavaScript form submissions never count as quick redirects. 1933 m_quickRedirectComing = (lockBackForwardList || history()->currentItemShouldBeReplaced()) && m_documentLoader && !m_isExecutingJavaScriptFormAction; 1934} 1935 1936bool FrameLoader::shouldReload(const KURL& currentURL, const KURL& destinationURL) 1937{ 1938 // This function implements the rule: "Don't reload if navigating by fragment within 1939 // the same URL, but do reload if going to a new URL or to the same URL with no 1940 // fragment identifier at all." 1941 if (!destinationURL.hasFragmentIdentifier()) 1942 return true; 1943 return !equalIgnoringFragmentIdentifier(currentURL, destinationURL); 1944} 1945 1946void FrameLoader::closeOldDataSources() 1947{ 1948 // FIXME: Is it important for this traversal to be postorder instead of preorder? 1949 // If so, add helpers for postorder traversal, and use them. If not, then lets not 1950 // use a recursive algorithm here. 1951 for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling()) 1952 child->loader()->closeOldDataSources(); 1953 1954 if (m_documentLoader) 1955 m_client->dispatchWillClose(); 1956 1957 m_client->setMainFrameDocumentReady(false); // stop giving out the actual DOMDocument to observers 1958} 1959 1960void FrameLoader::prepareForCachedPageRestore() 1961{ 1962 ASSERT(!m_frame->tree()->parent()); 1963 ASSERT(m_frame->page()); 1964 ASSERT(m_frame->page()->mainFrame() == m_frame); 1965 1966 m_frame->navigationScheduler()->cancel(); 1967 1968 // We still have to close the previous part page. 1969 closeURL(); 1970 1971 // Delete old status bar messages (if it _was_ activated on last URL). 1972 if (m_frame->script()->canExecuteScripts(NotAboutToExecuteScript)) { 1973 DOMWindow* window = m_frame->document()->domWindow(); 1974 window->setStatus(String()); 1975 window->setDefaultStatus(String()); 1976 } 1977} 1978 1979void FrameLoader::open(CachedFrameBase& cachedFrame) 1980{ 1981 m_isComplete = false; 1982 1983 // Don't re-emit the load event. 1984 m_didCallImplicitClose = true; 1985 1986 KURL url = cachedFrame.url(); 1987 1988 // FIXME: I suspect this block of code doesn't do anything. 1989 if (url.protocolIsInHTTPFamily() && !url.host().isEmpty() && url.path().isEmpty()) 1990 url.setPath("/"); 1991 1992 started(); 1993 Document* document = cachedFrame.document(); 1994 ASSERT(document); 1995 ASSERT(document->domWindow()); 1996 1997 clear(document, true, true, cachedFrame.isMainFrame()); 1998 1999 document->setInPageCache(false); 2000 2001 m_needsClear = true; 2002 m_isComplete = false; 2003 m_didCallImplicitClose = false; 2004 m_outgoingReferrer = url.string(); 2005 2006 FrameView* view = cachedFrame.view(); 2007 2008 // When navigating to a CachedFrame its FrameView should never be null. If it is we'll crash in creative ways downstream. 2009 ASSERT(view); 2010 view->setWasScrolledByUser(false); 2011 2012 // Use the current ScrollView's frame rect. 2013 if (m_frame->view()) 2014 view->setFrameRect(m_frame->view()->frameRect()); 2015 m_frame->setView(view); 2016 2017 m_frame->setDocument(document); 2018 document->domWindow()->resumeFromPageCache(); 2019 2020 updateFirstPartyForCookies(); 2021 2022 cachedFrame.restore(); 2023} 2024 2025bool FrameLoader::isHostedByObjectElement() const 2026{ 2027 HTMLFrameOwnerElement* owner = m_frame->ownerElement(); 2028 return owner && owner->hasTagName(objectTag); 2029} 2030 2031bool FrameLoader::isLoadingMainFrame() const 2032{ 2033 Page* page = m_frame->page(); 2034 return page && m_frame == page->mainFrame(); 2035} 2036 2037bool FrameLoader::isReplacing() const 2038{ 2039 return m_loadType == FrameLoadTypeReplace; 2040} 2041 2042void FrameLoader::setReplacing() 2043{ 2044 m_loadType = FrameLoadTypeReplace; 2045} 2046 2047bool FrameLoader::subframeIsLoading() const 2048{ 2049 // It's most likely that the last added frame is the last to load so we walk backwards. 2050 for (Frame* child = m_frame->tree()->lastChild(); child; child = child->tree()->previousSibling()) { 2051 FrameLoader* childLoader = child->loader(); 2052 DocumentLoader* documentLoader = childLoader->documentLoader(); 2053 if (documentLoader && documentLoader->isLoadingInAPISense()) 2054 return true; 2055 documentLoader = childLoader->provisionalDocumentLoader(); 2056 if (documentLoader && documentLoader->isLoadingInAPISense()) 2057 return true; 2058 documentLoader = childLoader->policyDocumentLoader(); 2059 if (documentLoader) 2060 return true; 2061 } 2062 return false; 2063} 2064 2065void FrameLoader::willChangeTitle(DocumentLoader* loader) 2066{ 2067 m_client->willChangeTitle(loader); 2068} 2069 2070FrameLoadType FrameLoader::loadType() const 2071{ 2072 return m_loadType; 2073} 2074 2075CachePolicy FrameLoader::subresourceCachePolicy() const 2076{ 2077 if (m_isComplete) 2078 return CachePolicyVerify; 2079 2080 if (m_loadType == FrameLoadTypeReloadFromOrigin) 2081 return CachePolicyReload; 2082 2083 if (Frame* parentFrame = m_frame->tree()->parent()) { 2084 CachePolicy parentCachePolicy = parentFrame->loader()->subresourceCachePolicy(); 2085 if (parentCachePolicy != CachePolicyVerify) 2086 return parentCachePolicy; 2087 } 2088 2089 if (m_loadType == FrameLoadTypeReload) 2090 return CachePolicyRevalidate; 2091 2092 const ResourceRequest& request(documentLoader()->request()); 2093#if PLATFORM(MAC) 2094 if (request.cachePolicy() == ReloadIgnoringCacheData && !equalIgnoringCase(request.httpMethod(), "post") && ResourceRequest::useQuickLookResourceCachingQuirks()) 2095 return CachePolicyRevalidate; 2096#endif 2097 2098 if (request.cachePolicy() == ReturnCacheDataElseLoad) 2099 return CachePolicyHistoryBuffer; 2100 2101 return CachePolicyVerify; 2102} 2103 2104void FrameLoader::checkLoadCompleteForThisFrame() 2105{ 2106 ASSERT(m_client->hasWebView()); 2107 2108 Settings* settings = m_frame->settings(); 2109 2110 switch (m_state) { 2111 case FrameStateProvisional: { 2112 if (m_delegateIsHandlingProvisionalLoadError) 2113 return; 2114 2115 RefPtr<DocumentLoader> pdl = m_provisionalDocumentLoader; 2116 if (!pdl) 2117 return; 2118 2119 // If we've received any errors we may be stuck in the provisional state and actually complete. 2120 const ResourceError& error = pdl->mainDocumentError(); 2121 if (error.isNull()) 2122 return; 2123 2124 // Check all children first. 2125 RefPtr<HistoryItem> item; 2126 if (Page* page = m_frame->page()) 2127 if (isBackForwardLoadType(loadType())) 2128 // Reset the back forward list to the last committed history item at the top level. 2129 item = page->mainFrame()->loader()->history()->currentItem(); 2130 2131 // Only reset if we aren't already going to a new provisional item. 2132 bool shouldReset = !history()->provisionalItem(); 2133 if (!pdl->isLoadingInAPISense() || pdl->isStopping()) { 2134 m_delegateIsHandlingProvisionalLoadError = true; 2135 m_client->dispatchDidFailProvisionalLoad(error); 2136 m_delegateIsHandlingProvisionalLoadError = false; 2137 2138 ASSERT(!pdl->isLoading()); 2139 2140 // If we're in the middle of loading multipart data, we need to restore the document loader. 2141 if (isReplacing() && !m_documentLoader.get()) 2142 setDocumentLoader(m_provisionalDocumentLoader.get()); 2143 2144 // Finish resetting the load state, but only if another load hasn't been started by the 2145 // delegate callback. 2146 if (pdl == m_provisionalDocumentLoader) 2147 clearProvisionalLoad(); 2148 else if (activeDocumentLoader()) { 2149 KURL unreachableURL = activeDocumentLoader()->unreachableURL(); 2150 if (!unreachableURL.isEmpty() && unreachableURL == pdl->request().url()) 2151 shouldReset = false; 2152 } 2153 } 2154 if (shouldReset && item) 2155 if (Page* page = m_frame->page()) { 2156 page->backForward()->setCurrentItem(item.get()); 2157 m_frame->loader()->client()->updateGlobalHistoryItemForPage(); 2158 } 2159 return; 2160 } 2161 2162 case FrameStateCommittedPage: { 2163 DocumentLoader* dl = m_documentLoader.get(); 2164 if (!dl || (dl->isLoadingInAPISense() && !dl->isStopping())) 2165 return; 2166 2167 setState(FrameStateComplete); 2168 2169 // FIXME: Is this subsequent work important if we already navigated away? 2170 // Maybe there are bugs because of that, or extra work we can skip because 2171 // the new page is ready. 2172 2173 m_client->forceLayoutForNonHTML(); 2174 2175 // If the user had a scroll point, scroll to it, overriding the anchor point if any. 2176 if (m_frame->page()) { 2177 if (isBackForwardLoadType(m_loadType) || m_loadType == FrameLoadTypeReload || m_loadType == FrameLoadTypeReloadFromOrigin) 2178 history()->restoreScrollPositionAndViewState(); 2179 } 2180 2181 if (m_stateMachine.creatingInitialEmptyDocument() || !m_stateMachine.committedFirstRealDocumentLoad()) 2182 return; 2183 2184 if (!settings->needsDidFinishLoadOrderQuirk()) { 2185 m_progressTracker->progressCompleted(); 2186 if (Page* page = m_frame->page()) { 2187 if (m_frame == page->mainFrame()) 2188 page->resetRelevantPaintedObjectCounter(); 2189 } 2190 } 2191 2192 const ResourceError& error = dl->mainDocumentError(); 2193 2194 AXObjectCache::AXLoadingEvent loadingEvent; 2195 if (!error.isNull()) { 2196 m_client->dispatchDidFailLoad(error); 2197 loadingEvent = AXObjectCache::AXLoadingFailed; 2198 } else { 2199 m_client->dispatchDidFinishLoad(); 2200 loadingEvent = AXObjectCache::AXLoadingFinished; 2201 } 2202 2203 if (settings->needsDidFinishLoadOrderQuirk()) { 2204 m_progressTracker->progressCompleted(); 2205 if (Page* page = m_frame->page()) { 2206 if (m_frame == page->mainFrame()) 2207 page->resetRelevantPaintedObjectCounter(); 2208 } 2209 } 2210 2211 // Notify accessibility. 2212 if (AXObjectCache* cache = m_frame->document()->existingAXObjectCache()) 2213 cache->frameLoadingEventNotification(m_frame, loadingEvent); 2214 2215 return; 2216 } 2217 2218 case FrameStateComplete: 2219 m_loadType = FrameLoadTypeStandard; 2220 frameLoadCompleted(); 2221 return; 2222 } 2223 2224 ASSERT_NOT_REACHED(); 2225} 2226 2227void FrameLoader::continueLoadAfterWillSubmitForm() 2228{ 2229 if (!m_provisionalDocumentLoader) 2230 return; 2231 2232 prepareForLoadStart(); 2233 2234 // The load might be cancelled inside of prepareForLoadStart(), nulling out the m_provisionalDocumentLoader, 2235 // so we need to null check it again. 2236 if (!m_provisionalDocumentLoader) 2237 return; 2238 2239 DocumentLoader* activeDocLoader = activeDocumentLoader(); 2240 if (activeDocLoader && activeDocLoader->isLoadingMainResource()) 2241 return; 2242 2243 m_loadingFromCachedPage = false; 2244 m_provisionalDocumentLoader->startLoadingMainResource(); 2245} 2246 2247static KURL originatingURLFromBackForwardList(Page* page) 2248{ 2249 // FIXME: Can this logic be replaced with m_frame->document()->firstPartyForCookies()? 2250 // It has the same meaning of "page a user thinks is the current one". 2251 2252 KURL originalURL; 2253 int backCount = page->backForward()->backCount(); 2254 for (int backIndex = 0; backIndex <= backCount; backIndex++) { 2255 // FIXME: At one point we had code here to check a "was user gesture" flag. 2256 // Do we need to restore that logic? 2257 HistoryItem* historyItem = page->backForward()->itemAtIndex(-backIndex); 2258 if (!historyItem) 2259 continue; 2260 2261 originalURL = historyItem->originalURL(); 2262 if (!originalURL.isNull()) 2263 return originalURL; 2264 } 2265 2266 return KURL(); 2267} 2268 2269void FrameLoader::setOriginalURLForDownloadRequest(ResourceRequest& request) 2270{ 2271 KURL originalURL; 2272 2273 // If there is no referrer, assume that the download was initiated directly, so current document is 2274 // completely unrelated to it. See <rdar://problem/5294691>. 2275 // FIXME: Referrer is not sent in many other cases, so we will often miss this important information. 2276 // Find a better way to decide whether the download was unrelated to current document. 2277 if (!request.httpReferrer().isNull()) { 2278 // find the first item in the history that was originated by the user 2279 originalURL = originatingURLFromBackForwardList(m_frame->page()); 2280 } 2281 2282 if (originalURL.isNull()) 2283 originalURL = request.url(); 2284 2285 if (!originalURL.protocol().isEmpty() && !originalURL.host().isEmpty()) { 2286 unsigned port = originalURL.port(); 2287 2288 // Original URL is needed to show the user where a file was downloaded from. We should make a URL that won't result in downloading the file again. 2289 // FIXME: Using host-only URL is a very heavy-handed approach. We should attempt to provide the actual page where the download was initiated from, as a reminder to the user. 2290 String hostOnlyURLString; 2291 if (port) 2292 hostOnlyURLString = makeString(originalURL.protocol(), "://", originalURL.host(), ":", String::number(port)); 2293 else 2294 hostOnlyURLString = makeString(originalURL.protocol(), "://", originalURL.host()); 2295 2296 // FIXME: Rename firstPartyForCookies back to mainDocumentURL. It was a mistake to think that it was only used for cookies. 2297 request.setFirstPartyForCookies(KURL(KURL(), hostOnlyURLString)); 2298 } 2299} 2300 2301void FrameLoader::didLayout(LayoutMilestones milestones) 2302{ 2303 m_client->dispatchDidLayout(milestones); 2304} 2305 2306void FrameLoader::didFirstLayout() 2307{ 2308 if (m_frame->page() && isBackForwardLoadType(m_loadType)) 2309 history()->restoreScrollPositionAndViewState(); 2310 2311 if (m_stateMachine.committedFirstRealDocumentLoad() && !m_stateMachine.isDisplayingInitialEmptyDocument() && !m_stateMachine.firstLayoutDone()) 2312 m_stateMachine.advanceTo(FrameLoaderStateMachine::FirstLayoutDone); 2313} 2314 2315void FrameLoader::frameLoadCompleted() 2316{ 2317 // Note: Can be called multiple times. 2318 2319 m_client->frameLoadCompleted(); 2320 2321 history()->updateForFrameLoadCompleted(); 2322 2323 // After a canceled provisional load, firstLayoutDone is false. 2324 // Reset it to true if we're displaying a page. 2325 if (m_documentLoader && m_stateMachine.committedFirstRealDocumentLoad() && !m_stateMachine.isDisplayingInitialEmptyDocument() && !m_stateMachine.firstLayoutDone()) 2326 m_stateMachine.advanceTo(FrameLoaderStateMachine::FirstLayoutDone); 2327} 2328 2329void FrameLoader::detachChildren() 2330{ 2331 typedef Vector<RefPtr<Frame> > FrameVector; 2332 FrameVector childrenToDetach; 2333 childrenToDetach.reserveCapacity(m_frame->tree()->childCount()); 2334 for (Frame* child = m_frame->tree()->lastChild(); child; child = child->tree()->previousSibling()) 2335 childrenToDetach.append(child); 2336 FrameVector::iterator end = childrenToDetach.end(); 2337 for (FrameVector::iterator it = childrenToDetach.begin(); it != end; ++it) 2338 (*it)->loader()->detachFromParent(); 2339} 2340 2341void FrameLoader::closeAndRemoveChild(Frame* child) 2342{ 2343 child->tree()->detachFromParent(); 2344 2345 child->setView(0); 2346 if (child->ownerElement() && child->page()) 2347 child->page()->decrementSubframeCount(); 2348 child->willDetachPage(); 2349 child->detachFromPage(); 2350 2351 m_frame->tree()->removeChild(child); 2352} 2353 2354// Called every time a resource is completely loaded or an error is received. 2355void FrameLoader::checkLoadComplete() 2356{ 2357 ASSERT(m_client->hasWebView()); 2358 2359 m_shouldCallCheckLoadComplete = false; 2360 2361 // FIXME: Always traversing the entire frame tree is a bit inefficient, but 2362 // is currently needed in order to null out the previous history item for all frames. 2363 if (Page* page = m_frame->page()) { 2364 Vector<RefPtr<Frame>, 10> frames; 2365 for (RefPtr<Frame> frame = page->mainFrame(); frame; frame = frame->tree()->traverseNext()) 2366 frames.append(frame); 2367 // To process children before their parents, iterate the vector backwards. 2368 for (size_t i = frames.size(); i; --i) 2369 frames[i - 1]->loader()->checkLoadCompleteForThisFrame(); 2370 } 2371} 2372 2373int FrameLoader::numPendingOrLoadingRequests(bool recurse) const 2374{ 2375 if (!recurse) 2376 return m_frame->document()->cachedResourceLoader()->requestCount(); 2377 2378 int count = 0; 2379 for (Frame* frame = m_frame; frame; frame = frame->tree()->traverseNext(m_frame)) 2380 count += frame->document()->cachedResourceLoader()->requestCount(); 2381 return count; 2382} 2383 2384String FrameLoader::userAgent(const KURL& url) const 2385{ 2386 String userAgent = m_client->userAgent(url); 2387 InspectorInstrumentation::applyUserAgentOverride(m_frame, &userAgent); 2388 return userAgent; 2389} 2390 2391void FrameLoader::handledOnloadEvents() 2392{ 2393 m_client->dispatchDidHandleOnloadEvents(); 2394 2395 if (documentLoader()) 2396 documentLoader()->handledOnloadEvents(); 2397} 2398 2399void FrameLoader::frameDetached() 2400{ 2401 stopAllLoaders(); 2402 m_frame->document()->stopActiveDOMObjects(); 2403 detachFromParent(); 2404} 2405 2406void FrameLoader::detachFromParent() 2407{ 2408 RefPtr<Frame> protect(m_frame); 2409 2410 closeURL(); 2411 history()->saveScrollPositionAndViewStateToItem(history()->currentItem()); 2412 detachChildren(); 2413 // stopAllLoaders() needs to be called after detachChildren(), because detachedChildren() 2414 // will trigger the unload event handlers of any child frames, and those event 2415 // handlers might start a new subresource load in this frame. 2416 stopAllLoaders(); 2417 2418 InspectorInstrumentation::frameDetachedFromParent(m_frame); 2419 2420 detachViewsAndDocumentLoader(); 2421 2422 m_progressTracker.clear(); 2423 2424 if (Frame* parent = m_frame->tree()->parent()) { 2425 parent->loader()->closeAndRemoveChild(m_frame); 2426 parent->loader()->scheduleCheckCompleted(); 2427 } else { 2428 m_frame->setView(0); 2429 m_frame->willDetachPage(); 2430 m_frame->detachFromPage(); 2431 } 2432} 2433 2434void FrameLoader::detachViewsAndDocumentLoader() 2435{ 2436 m_client->detachedFromParent2(); 2437 setDocumentLoader(0); 2438 m_client->detachedFromParent3(); 2439} 2440 2441void FrameLoader::addExtraFieldsToSubresourceRequest(ResourceRequest& request) 2442{ 2443 addExtraFieldsToRequest(request, m_loadType, false); 2444} 2445 2446void FrameLoader::addExtraFieldsToMainResourceRequest(ResourceRequest& request) 2447{ 2448 // FIXME: Using m_loadType seems wrong for some callers. 2449 // If we are only preparing to load the main resource, that is previous load's load type! 2450 addExtraFieldsToRequest(request, m_loadType, true); 2451} 2452 2453void FrameLoader::addExtraFieldsToRequest(ResourceRequest& request, FrameLoadType loadType, bool mainResource) 2454{ 2455 // Don't set the cookie policy URL if it's already been set. 2456 // But make sure to set it on all requests regardless of protocol, as it has significance beyond the cookie policy (<rdar://problem/6616664>). 2457 if (request.firstPartyForCookies().isEmpty()) { 2458 if (mainResource && isLoadingMainFrame()) 2459 request.setFirstPartyForCookies(request.url()); 2460 else if (Document* document = m_frame->document()) 2461 request.setFirstPartyForCookies(document->firstPartyForCookies()); 2462 } 2463 2464 // The remaining modifications are only necessary for HTTP and HTTPS. 2465 if (!request.url().isEmpty() && !request.url().protocolIsInHTTPFamily()) 2466 return; 2467 2468 applyUserAgent(request); 2469 2470 if (!mainResource) { 2471 if (request.isConditional()) 2472 request.setCachePolicy(ReloadIgnoringCacheData); 2473 else if (documentLoader()->isLoadingInAPISense()) { 2474 // If we inherit cache policy from a main resource, we use the DocumentLoader's 2475 // original request cache policy for two reasons: 2476 // 1. For POST requests, we mutate the cache policy for the main resource, 2477 // but we do not want this to apply to subresources 2478 // 2. Delegates that modify the cache policy using willSendRequest: should 2479 // not affect any other resources. Such changes need to be done 2480 // per request. 2481 ResourceRequestCachePolicy mainDocumentOriginalCachePolicy = documentLoader()->originalRequest().cachePolicy(); 2482 // Back-forward navigations try to load main resource from cache only to avoid re-submitting form data, and start over (with a warning dialog) if that fails. 2483 // This policy is set on initial request too, but should not be inherited. 2484 ResourceRequestCachePolicy subresourceCachePolicy = (mainDocumentOriginalCachePolicy == ReturnCacheDataDontLoad) ? ReturnCacheDataElseLoad : mainDocumentOriginalCachePolicy; 2485 request.setCachePolicy(subresourceCachePolicy); 2486 } else 2487 request.setCachePolicy(UseProtocolCachePolicy); 2488 2489 // FIXME: Other FrameLoader functions have duplicated code for setting cache policy of main request when reloading. 2490 // It seems better to manage it explicitly than to hide the logic inside addExtraFieldsToRequest(). 2491 } else if (loadType == FrameLoadTypeReload || loadType == FrameLoadTypeReloadFromOrigin || request.isConditional()) 2492 request.setCachePolicy(ReloadIgnoringCacheData); 2493 2494 if (request.cachePolicy() == ReloadIgnoringCacheData) { 2495 if (loadType == FrameLoadTypeReload) 2496 request.setHTTPHeaderField("Cache-Control", "max-age=0"); 2497 else if (loadType == FrameLoadTypeReloadFromOrigin) { 2498 request.setHTTPHeaderField("Cache-Control", "no-cache"); 2499 request.setHTTPHeaderField("Pragma", "no-cache"); 2500 } 2501 } 2502 2503 if (mainResource) 2504 request.setHTTPAccept(defaultAcceptHeader); 2505 2506 // Make sure we send the Origin header. 2507 addHTTPOriginIfNeeded(request, String()); 2508 2509 // Only set fallback array if it's still empty (later attempts may be incorrect, see bug 117818). 2510 if (request.responseContentDispositionEncodingFallbackArray().isEmpty()) { 2511 // Always try UTF-8. If that fails, try frame encoding (if any) and then the default. 2512 Settings* settings = m_frame->settings(); 2513 request.setResponseContentDispositionEncodingFallbackArray("UTF-8", m_frame->document()->encoding(), settings ? settings->defaultTextEncodingName() : String()); 2514 } 2515} 2516 2517void FrameLoader::addHTTPOriginIfNeeded(ResourceRequest& request, const String& origin) 2518{ 2519 if (!request.httpOrigin().isEmpty()) 2520 return; // Request already has an Origin header. 2521 2522 // Don't send an Origin header for GET or HEAD to avoid privacy issues. 2523 // For example, if an intranet page has a hyperlink to an external web 2524 // site, we don't want to include the Origin of the request because it 2525 // will leak the internal host name. Similar privacy concerns have lead 2526 // to the widespread suppression of the Referer header at the network 2527 // layer. 2528 if (request.httpMethod() == "GET" || request.httpMethod() == "HEAD") 2529 return; 2530 2531 // For non-GET and non-HEAD methods, always send an Origin header so the 2532 // server knows we support this feature. 2533 2534 if (origin.isEmpty()) { 2535 // If we don't know what origin header to attach, we attach the value 2536 // for an empty origin. 2537 request.setHTTPOrigin(SecurityOrigin::createUnique()->toString()); 2538 return; 2539 } 2540 2541 request.setHTTPOrigin(origin); 2542} 2543 2544void FrameLoader::loadPostRequest(const ResourceRequest& inRequest, const String& referrer, const String& frameName, bool lockHistory, FrameLoadType loadType, PassRefPtr<Event> event, PassRefPtr<FormState> prpFormState) 2545{ 2546 RefPtr<FormState> formState = prpFormState; 2547 2548 // Previously when this method was reached, the original FrameLoadRequest had been deconstructed to build a 2549 // bunch of parameters that would come in here and then be built back up to a ResourceRequest. In case 2550 // any caller depends on the immutability of the original ResourceRequest, I'm rebuilding a ResourceRequest 2551 // from scratch as it did all along. 2552 const KURL& url = inRequest.url(); 2553 RefPtr<FormData> formData = inRequest.httpBody(); 2554 const String& contentType = inRequest.httpContentType(); 2555 String origin = inRequest.httpOrigin(); 2556 2557 ResourceRequest workingResourceRequest(url); 2558 2559 if (!referrer.isEmpty()) 2560 workingResourceRequest.setHTTPReferrer(referrer); 2561 workingResourceRequest.setHTTPOrigin(origin); 2562 workingResourceRequest.setHTTPMethod("POST"); 2563 workingResourceRequest.setHTTPBody(formData); 2564 workingResourceRequest.setHTTPContentType(contentType); 2565 addExtraFieldsToRequest(workingResourceRequest, loadType, true); 2566 2567 NavigationAction action(workingResourceRequest, loadType, true, event); 2568 2569 if (!frameName.isEmpty()) { 2570 // The search for a target frame is done earlier in the case of form submission. 2571 if (Frame* targetFrame = formState ? 0 : findFrameForNavigation(frameName)) 2572 targetFrame->loader()->loadWithNavigationAction(workingResourceRequest, action, lockHistory, loadType, formState.release()); 2573 else 2574 policyChecker()->checkNewWindowPolicy(action, FrameLoader::callContinueLoadAfterNewWindowPolicy, workingResourceRequest, formState.release(), frameName, this); 2575 } else { 2576 // must grab this now, since this load may stop the previous load and clear this flag 2577 bool isRedirect = m_quickRedirectComing; 2578 loadWithNavigationAction(workingResourceRequest, action, lockHistory, loadType, formState.release()); 2579 if (isRedirect) { 2580 m_quickRedirectComing = false; 2581 if (m_provisionalDocumentLoader) 2582 m_provisionalDocumentLoader->setIsClientRedirect(true); 2583 } 2584 } 2585} 2586 2587unsigned long FrameLoader::loadResourceSynchronously(const ResourceRequest& request, StoredCredentials storedCredentials, ClientCredentialPolicy clientCredentialPolicy, ResourceError& error, ResourceResponse& response, Vector<char>& data) 2588{ 2589 ASSERT(m_frame->document()); 2590 String referrer = SecurityPolicy::generateReferrerHeader(m_frame->document()->referrerPolicy(), request.url(), outgoingReferrer()); 2591 2592 ResourceRequest initialRequest = request; 2593 initialRequest.setTimeoutInterval(10); 2594 2595 if (!referrer.isEmpty()) 2596 initialRequest.setHTTPReferrer(referrer); 2597 addHTTPOriginIfNeeded(initialRequest, outgoingOrigin()); 2598 2599 if (Page* page = m_frame->page()) 2600 initialRequest.setFirstPartyForCookies(page->mainFrame()->loader()->documentLoader()->request().url()); 2601 2602 addExtraFieldsToSubresourceRequest(initialRequest); 2603 2604 unsigned long identifier = 0; 2605 ResourceRequest newRequest(initialRequest); 2606 requestFromDelegate(newRequest, identifier, error); 2607 2608 if (error.isNull()) { 2609 ASSERT(!newRequest.isNull()); 2610 2611 if (!documentLoader()->applicationCacheHost()->maybeLoadSynchronously(newRequest, error, response, data)) { 2612 platformStrategies()->loaderStrategy()->loadResourceSynchronously(networkingContext(), identifier, newRequest, storedCredentials, clientCredentialPolicy, error, response, data); 2613 documentLoader()->applicationCacheHost()->maybeLoadFallbackSynchronously(newRequest, error, response, data); 2614 } 2615 } 2616 notifier()->sendRemainingDelegateMessages(m_documentLoader.get(), identifier, request, response, data.data(), data.size(), -1, error); 2617 return identifier; 2618} 2619 2620const ResourceRequest& FrameLoader::originalRequest() const 2621{ 2622 return activeDocumentLoader()->originalRequestCopy(); 2623} 2624 2625void FrameLoader::receivedMainResourceError(const ResourceError& error) 2626{ 2627 // Retain because the stop may release the last reference to it. 2628 RefPtr<Frame> protect(m_frame); 2629 2630 RefPtr<DocumentLoader> loader = activeDocumentLoader(); 2631 // FIXME: Don't want to do this if an entirely new load is going, so should check 2632 // that both data sources on the frame are either this or nil. 2633 stop(); 2634 if (m_client->shouldFallBack(error)) 2635 handleFallbackContent(); 2636 2637 if (m_state == FrameStateProvisional && m_provisionalDocumentLoader) { 2638 if (m_submittedFormURL == m_provisionalDocumentLoader->originalRequestCopy().url()) 2639 m_submittedFormURL = KURL(); 2640 2641 // We might have made a page cache item, but now we're bailing out due to an error before we ever 2642 // transitioned to the new page (before WebFrameState == commit). The goal here is to restore any state 2643 // so that the existing view (that wenever got far enough to replace) can continue being used. 2644 history()->invalidateCurrentItemCachedPage(); 2645 2646 // Call clientRedirectCancelledOrFinished here so that the frame load delegate is notified that the redirect's 2647 // status has changed, if there was a redirect. The frame load delegate may have saved some state about 2648 // the redirect in its -webView:willPerformClientRedirectToURL:delay:fireDate:forFrame:. Since we are definitely 2649 // not going to use this provisional resource, as it was cancelled, notify the frame load delegate that the redirect 2650 // has ended. 2651 if (m_sentRedirectNotification) 2652 clientRedirectCancelledOrFinished(false); 2653 } 2654 2655 checkCompleted(); 2656 if (m_frame->page()) 2657 checkLoadComplete(); 2658} 2659 2660void FrameLoader::callContinueFragmentScrollAfterNavigationPolicy(void* argument, 2661 const ResourceRequest& request, PassRefPtr<FormState>, bool shouldContinue) 2662{ 2663 FrameLoader* loader = static_cast<FrameLoader*>(argument); 2664 loader->continueFragmentScrollAfterNavigationPolicy(request, shouldContinue); 2665} 2666 2667void FrameLoader::continueFragmentScrollAfterNavigationPolicy(const ResourceRequest& request, bool shouldContinue) 2668{ 2669 m_quickRedirectComing = false; 2670 2671 if (!shouldContinue) 2672 return; 2673 2674 // If we have a provisional request for a different document, a fragment scroll should cancel it. 2675 if (m_provisionalDocumentLoader && !equalIgnoringFragmentIdentifier(m_provisionalDocumentLoader->request().url(), request.url())) { 2676 m_provisionalDocumentLoader->stopLoading(); 2677 setProvisionalDocumentLoader(0); 2678 } 2679 2680 bool isRedirect = m_quickRedirectComing || policyChecker()->loadType() == FrameLoadTypeRedirectWithLockedBackForwardList; 2681 loadInSameDocument(request.url(), 0, !isRedirect); 2682} 2683 2684bool FrameLoader::shouldPerformFragmentNavigation(bool isFormSubmission, const String& httpMethod, FrameLoadType loadType, const KURL& url) 2685{ 2686 // We don't do this if we are submitting a form with method other than "GET", explicitly reloading, 2687 // currently displaying a frameset, or if the URL does not have a fragment. 2688 // These rules were originally based on what KHTML was doing in KHTMLPart::openURL. 2689 2690 // FIXME: What about load types other than Standard and Reload? 2691 2692 return (!isFormSubmission || equalIgnoringCase(httpMethod, "GET")) 2693 && loadType != FrameLoadTypeReload 2694 && loadType != FrameLoadTypeReloadFromOrigin 2695 && loadType != FrameLoadTypeSame 2696 && !shouldReload(m_frame->document()->url(), url) 2697 // We don't want to just scroll if a link from within a 2698 // frameset is trying to reload the frameset into _top. 2699 && !m_frame->document()->isFrameSet(); 2700} 2701 2702void FrameLoader::scrollToFragmentWithParentBoundary(const KURL& url) 2703{ 2704 FrameView* view = m_frame->view(); 2705 if (!view) 2706 return; 2707 2708 // Leaking scroll position to a cross-origin ancestor would permit the so-called "framesniffing" attack. 2709 RefPtr<Frame> boundaryFrame(url.hasFragmentIdentifier() ? m_frame->document()->findUnsafeParentScrollPropagationBoundary() : 0); 2710 2711 if (boundaryFrame) 2712 boundaryFrame->view()->setSafeToPropagateScrollToParent(false); 2713 2714 view->scrollToFragment(url); 2715 2716 if (boundaryFrame) 2717 boundaryFrame->view()->setSafeToPropagateScrollToParent(true); 2718} 2719 2720void FrameLoader::callContinueLoadAfterNavigationPolicy(void* argument, 2721 const ResourceRequest& request, PassRefPtr<FormState> formState, bool shouldContinue) 2722{ 2723 FrameLoader* loader = static_cast<FrameLoader*>(argument); 2724 loader->continueLoadAfterNavigationPolicy(request, formState, shouldContinue); 2725} 2726 2727bool FrameLoader::shouldClose() 2728{ 2729 Page* page = m_frame->page(); 2730 if (!page) 2731 return true; 2732 if (!page->chrome().canRunBeforeUnloadConfirmPanel()) 2733 return true; 2734 2735 // Store all references to each subframe in advance since beforeunload's event handler may modify frame 2736 Vector<RefPtr<Frame> > targetFrames; 2737 targetFrames.append(m_frame); 2738 for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->traverseNext(m_frame)) 2739 targetFrames.append(child); 2740 2741 bool shouldClose = false; 2742 { 2743 NavigationDisablerForBeforeUnload navigationDisabler; 2744 size_t i; 2745 2746 for (i = 0; i < targetFrames.size(); i++) { 2747 if (!targetFrames[i]->tree()->isDescendantOf(m_frame)) 2748 continue; 2749 if (!targetFrames[i]->loader()->handleBeforeUnloadEvent(page->chrome(), this)) 2750 break; 2751 } 2752 2753 if (i == targetFrames.size()) 2754 shouldClose = true; 2755 } 2756 2757 if (!shouldClose) 2758 m_submittedFormURL = KURL(); 2759 2760 m_currentNavigationHasShownBeforeUnloadConfirmPanel = false; 2761 return shouldClose; 2762} 2763 2764bool FrameLoader::handleBeforeUnloadEvent(Chrome& chrome, FrameLoader* frameLoaderBeingNavigated) 2765{ 2766 DOMWindow* domWindow = m_frame->document()->domWindow(); 2767 if (!domWindow) 2768 return true; 2769 2770 RefPtr<Document> document = m_frame->document(); 2771 if (!document->body()) 2772 return true; 2773 2774 RefPtr<BeforeUnloadEvent> beforeUnloadEvent = BeforeUnloadEvent::create(); 2775 m_pageDismissalEventBeingDispatched = BeforeUnloadDismissal; 2776 2777 // We store the frame's page in a local variable because the frame might get detached inside dispatchEvent. 2778 Page* page = m_frame->page(); 2779 page->incrementFrameHandlingBeforeUnloadEventCount(); 2780 domWindow->dispatchEvent(beforeUnloadEvent.get(), domWindow->document()); 2781 page->decrementFrameHandlingBeforeUnloadEventCount(); 2782 2783 m_pageDismissalEventBeingDispatched = NoDismissal; 2784 2785 if (!beforeUnloadEvent->defaultPrevented()) 2786 document->defaultEventHandler(beforeUnloadEvent.get()); 2787 if (beforeUnloadEvent->result().isNull()) 2788 return true; 2789 2790 // If the navigating FrameLoader has already shown a beforeunload confirmation panel for the current navigation attempt, 2791 // this frame is not allowed to cause another one to be shown. 2792 if (frameLoaderBeingNavigated->m_currentNavigationHasShownBeforeUnloadConfirmPanel) { 2793 document->addConsoleMessage(JSMessageSource, ErrorMessageLevel, "Blocked attempt to show multiple beforeunload confirmation dialogs for the same navigation."); 2794 return true; 2795 } 2796 2797 // We should only display the beforeunload dialog for an iframe if its SecurityOrigin matches all 2798 // ancestor frame SecurityOrigins up through the navigating FrameLoader. 2799 if (frameLoaderBeingNavigated != this) { 2800 Frame* parentFrame = m_frame->tree()->parent(); 2801 while (parentFrame) { 2802 Document* parentDocument = parentFrame->document(); 2803 if (!parentDocument) 2804 return true; 2805 if (!m_frame->document() || !m_frame->document()->securityOrigin()->canAccess(parentDocument->securityOrigin())) { 2806 document->addConsoleMessage(JSMessageSource, ErrorMessageLevel, "Blocked attempt to show beforeunload confirmation dialog on behalf of a frame with different security origin. Protocols, domains, and ports must match."); 2807 return true; 2808 } 2809 2810 if (parentFrame->loader() == frameLoaderBeingNavigated) 2811 break; 2812 2813 parentFrame = parentFrame->tree()->parent(); 2814 } 2815 2816 // The navigatingFrameLoader should always be in our ancestory. 2817 ASSERT(parentFrame); 2818 ASSERT(parentFrame->loader() == frameLoaderBeingNavigated); 2819 } 2820 2821 frameLoaderBeingNavigated->m_currentNavigationHasShownBeforeUnloadConfirmPanel = true; 2822 2823 String text = document->displayStringModifiedByEncoding(beforeUnloadEvent->result()); 2824 return chrome.runBeforeUnloadConfirmPanel(text, m_frame); 2825} 2826 2827void FrameLoader::continueLoadAfterNavigationPolicy(const ResourceRequest&, PassRefPtr<FormState> formState, bool shouldContinue) 2828{ 2829 // If we loaded an alternate page to replace an unreachableURL, we'll get in here with a 2830 // nil policyDataSource because loading the alternate page will have passed 2831 // through this method already, nested; otherwise, policyDataSource should still be set. 2832 ASSERT(m_policyDocumentLoader || !m_provisionalDocumentLoader->unreachableURL().isEmpty()); 2833 2834 bool isTargetItem = history()->provisionalItem() ? history()->provisionalItem()->isTargetItem() : false; 2835 2836 // Two reasons we can't continue: 2837 // 1) Navigation policy delegate said we can't so request is nil. A primary case of this 2838 // is the user responding Cancel to the form repost nag sheet. 2839 // 2) User responded Cancel to an alert popped up by the before unload event handler. 2840 bool canContinue = shouldContinue && shouldClose(); 2841 2842 if (!canContinue) { 2843 // If we were waiting for a quick redirect, but the policy delegate decided to ignore it, then we 2844 // need to report that the client redirect was cancelled. 2845 if (m_quickRedirectComing) 2846 clientRedirectCancelledOrFinished(false); 2847 2848 setPolicyDocumentLoader(0); 2849 2850 // If the navigation request came from the back/forward menu, and we punt on it, we have the 2851 // problem that we have optimistically moved the b/f cursor already, so move it back. For sanity, 2852 // we only do this when punting a navigation for the target frame or top-level frame. 2853 if ((isTargetItem || isLoadingMainFrame()) && isBackForwardLoadType(policyChecker()->loadType())) { 2854 if (Page* page = m_frame->page()) { 2855 Frame* mainFrame = page->mainFrame(); 2856 if (HistoryItem* resetItem = mainFrame->loader()->history()->currentItem()) { 2857 page->backForward()->setCurrentItem(resetItem); 2858 m_frame->loader()->client()->updateGlobalHistoryItemForPage(); 2859 } 2860 } 2861 } 2862 return; 2863 } 2864 2865 FrameLoadType type = policyChecker()->loadType(); 2866 // A new navigation is in progress, so don't clear the history's provisional item. 2867 stopAllLoaders(ShouldNotClearProvisionalItem); 2868 2869 // <rdar://problem/6250856> - In certain circumstances on pages with multiple frames, stopAllLoaders() 2870 // might detach the current FrameLoader, in which case we should bail on this newly defunct load. 2871 if (!m_frame->page()) 2872 return; 2873 2874#if ENABLE(JAVASCRIPT_DEBUGGER) && ENABLE(INSPECTOR) 2875 if (Page* page = m_frame->page()) { 2876 if (page->mainFrame() == m_frame) 2877 m_frame->page()->inspectorController()->resume(); 2878 } 2879#endif 2880 2881 setProvisionalDocumentLoader(m_policyDocumentLoader.get()); 2882 m_loadType = type; 2883 setState(FrameStateProvisional); 2884 2885 setPolicyDocumentLoader(0); 2886 2887 if (isBackForwardLoadType(type) && history()->provisionalItem()->isInPageCache()) { 2888 loadProvisionalItemFromCachedPage(); 2889 return; 2890 } 2891 2892 if (formState) 2893 m_client->dispatchWillSubmitForm(&PolicyChecker::continueLoadAfterWillSubmitForm, formState); 2894 else 2895 continueLoadAfterWillSubmitForm(); 2896} 2897 2898void FrameLoader::callContinueLoadAfterNewWindowPolicy(void* argument, 2899 const ResourceRequest& request, PassRefPtr<FormState> formState, const String& frameName, const NavigationAction& action, bool shouldContinue) 2900{ 2901 FrameLoader* loader = static_cast<FrameLoader*>(argument); 2902 loader->continueLoadAfterNewWindowPolicy(request, formState, frameName, action, shouldContinue); 2903} 2904 2905void FrameLoader::continueLoadAfterNewWindowPolicy(const ResourceRequest& request, 2906 PassRefPtr<FormState> formState, const String& frameName, const NavigationAction& action, bool shouldContinue) 2907{ 2908 if (!shouldContinue) 2909 return; 2910 2911 RefPtr<Frame> frame = m_frame; 2912 RefPtr<Frame> mainFrame = m_client->dispatchCreatePage(action); 2913 if (!mainFrame) 2914 return; 2915 2916 if (frameName != "_blank") 2917 mainFrame->tree()->setName(frameName); 2918 2919 mainFrame->page()->setOpenedByDOM(); 2920 mainFrame->loader()->m_client->dispatchShow(); 2921 if (!m_suppressOpenerInNewFrame) { 2922 mainFrame->loader()->setOpener(frame.get()); 2923 mainFrame->document()->setReferrerPolicy(frame->document()->referrerPolicy()); 2924 } 2925 mainFrame->loader()->loadWithNavigationAction(request, NavigationAction(request), false, FrameLoadTypeStandard, formState); 2926} 2927 2928void FrameLoader::requestFromDelegate(ResourceRequest& request, unsigned long& identifier, ResourceError& error) 2929{ 2930 ASSERT(!request.isNull()); 2931 2932 identifier = 0; 2933 if (Page* page = m_frame->page()) { 2934 identifier = page->progress()->createUniqueIdentifier(); 2935 notifier()->assignIdentifierToInitialRequest(identifier, m_documentLoader.get(), request); 2936 } 2937 2938 ResourceRequest newRequest(request); 2939 notifier()->dispatchWillSendRequest(m_documentLoader.get(), identifier, newRequest, ResourceResponse()); 2940 2941 if (newRequest.isNull()) 2942 error = cancelledError(request); 2943 else 2944 error = ResourceError(); 2945 2946 request = newRequest; 2947} 2948 2949void FrameLoader::loadedResourceFromMemoryCache(CachedResource* resource, ResourceRequest& newRequest) 2950{ 2951 Page* page = m_frame->page(); 2952 if (!page) 2953 return; 2954 2955 if (!resource->shouldSendResourceLoadCallbacks() || m_documentLoader->haveToldClientAboutLoad(resource->url())) 2956 return; 2957 2958 // Main resource delegate messages are synthesized in MainResourceLoader, so we must not send them here. 2959 if (resource->type() == CachedResource::MainResource) 2960 return; 2961 2962 if (!page->areMemoryCacheClientCallsEnabled()) { 2963 InspectorInstrumentation::didLoadResourceFromMemoryCache(page, m_documentLoader.get(), resource); 2964 m_documentLoader->recordMemoryCacheLoadForFutureClientNotification(resource->resourceRequest()); 2965 m_documentLoader->didTellClientAboutLoad(resource->url()); 2966 return; 2967 } 2968 2969 if (m_client->dispatchDidLoadResourceFromMemoryCache(m_documentLoader.get(), newRequest, resource->response(), resource->encodedSize())) { 2970 InspectorInstrumentation::didLoadResourceFromMemoryCache(page, m_documentLoader.get(), resource); 2971 m_documentLoader->didTellClientAboutLoad(resource->url()); 2972 return; 2973 } 2974 2975 unsigned long identifier; 2976 ResourceError error; 2977 requestFromDelegate(newRequest, identifier, error); 2978 InspectorInstrumentation::markResourceAsCached(page, identifier); 2979 notifier()->sendRemainingDelegateMessages(m_documentLoader.get(), identifier, newRequest, resource->response(), 0, resource->encodedSize(), 0, error); 2980} 2981 2982void FrameLoader::applyUserAgent(ResourceRequest& request) 2983{ 2984 String userAgent = this->userAgent(request.url()); 2985 ASSERT(!userAgent.isNull()); 2986 request.setHTTPUserAgent(userAgent); 2987} 2988 2989bool FrameLoader::shouldInterruptLoadForXFrameOptions(const String& content, const KURL& url, unsigned long requestIdentifier) 2990{ 2991 FeatureObserver::observe(m_frame->document(), FeatureObserver::XFrameOptions); 2992 2993 Frame* topFrame = m_frame->tree()->top(); 2994 if (m_frame == topFrame) 2995 return false; 2996 2997 XFrameOptionsDisposition disposition = parseXFrameOptionsHeader(content); 2998 2999 switch (disposition) { 3000 case XFrameOptionsSameOrigin: { 3001 FeatureObserver::observe(m_frame->document(), FeatureObserver::XFrameOptionsSameOrigin); 3002 RefPtr<SecurityOrigin> origin = SecurityOrigin::create(url); 3003 if (!origin->isSameSchemeHostPort(topFrame->document()->securityOrigin())) 3004 return true; 3005 for (Frame* frame = m_frame->tree()->parent(); frame; frame = frame->tree()->parent()) { 3006 if (!origin->isSameSchemeHostPort(frame->document()->securityOrigin())) { 3007 FeatureObserver::observe(m_frame->document(), FeatureObserver::XFrameOptionsSameOriginWithBadAncestorChain); 3008 break; 3009 } 3010 } 3011 return false; 3012 } 3013 case XFrameOptionsDeny: 3014 return true; 3015 case XFrameOptionsAllowAll: 3016 return false; 3017 case XFrameOptionsConflict: 3018 m_frame->document()->addConsoleMessage(JSMessageSource, ErrorMessageLevel, "Multiple 'X-Frame-Options' headers with conflicting values ('" + content + "') encountered when loading '" + url.stringCenterEllipsizedToLength() + "'. Falling back to 'DENY'.", requestIdentifier); 3019 return true; 3020 case XFrameOptionsInvalid: 3021 m_frame->document()->addConsoleMessage(JSMessageSource, ErrorMessageLevel, "Invalid 'X-Frame-Options' header encountered when loading '" + url.stringCenterEllipsizedToLength() + "': '" + content + "' is not a recognized directive. The header will be ignored.", requestIdentifier); 3022 return false; 3023 default: 3024 ASSERT_NOT_REACHED(); 3025 return false; 3026 } 3027} 3028 3029void FrameLoader::loadProvisionalItemFromCachedPage() 3030{ 3031 DocumentLoader* provisionalLoader = provisionalDocumentLoader(); 3032 LOG(PageCache, "WebCorePageCache: Loading provisional DocumentLoader %p with URL '%s' from CachedPage", provisionalDocumentLoader(), provisionalDocumentLoader()->url().stringCenterEllipsizedToLength().utf8().data()); 3033 3034 prepareForLoadStart(); 3035 3036 m_loadingFromCachedPage = true; 3037 3038 // Should have timing data from previous time(s) the page was shown. 3039 ASSERT(provisionalLoader->timing()->navigationStart()); 3040 provisionalLoader->resetTiming(); 3041 provisionalLoader->timing()->markNavigationStart(); 3042 3043 provisionalLoader->setCommitted(true); 3044 commitProvisionalLoad(); 3045} 3046 3047bool FrameLoader::shouldTreatURLAsSameAsCurrent(const KURL& url) const 3048{ 3049 if (!history()->currentItem()) 3050 return false; 3051 return url == history()->currentItem()->url() || url == history()->currentItem()->originalURL(); 3052} 3053 3054bool FrameLoader::shouldTreatURLAsSrcdocDocument(const KURL& url) const 3055{ 3056 if (!equalIgnoringCase(url.string(), "about:srcdoc")) 3057 return false; 3058 HTMLFrameOwnerElement* ownerElement = m_frame->ownerElement(); 3059 if (!ownerElement) 3060 return false; 3061 if (!ownerElement->hasTagName(iframeTag)) 3062 return false; 3063 return ownerElement->fastHasAttribute(srcdocAttr); 3064} 3065 3066void FrameLoader::checkDidPerformFirstNavigation() 3067{ 3068 Page* page = m_frame->page(); 3069 if (!page) 3070 return; 3071 3072 if (!m_didPerformFirstNavigation && page->backForward()->currentItem() && !page->backForward()->backItem() && !page->backForward()->forwardItem()) { 3073 m_didPerformFirstNavigation = true; 3074 m_client->didPerformFirstNavigation(); 3075 } 3076} 3077 3078Frame* FrameLoader::findFrameForNavigation(const AtomicString& name, Document* activeDocument) 3079{ 3080 Frame* frame = m_frame->tree()->find(name); 3081 3082 // From http://www.whatwg.org/specs/web-apps/current-work/#seamlessLinks: 3083 // 3084 // If the source browsing context is the same as the browsing context 3085 // being navigated, and this browsing context has its seamless browsing 3086 // context flag set, and the browsing context being navigated was not 3087 // chosen using an explicit self-navigation override, then find the 3088 // nearest ancestor browsing context that does not have its seamless 3089 // browsing context flag set, and continue these steps as if that 3090 // browsing context was the one that was going to be navigated instead. 3091 if (frame == m_frame && name != "_self" && m_frame->document()->shouldDisplaySeamlesslyWithParent()) { 3092 for (Frame* ancestor = m_frame; ancestor; ancestor = ancestor->tree()->parent()) { 3093 if (!ancestor->document()->shouldDisplaySeamlesslyWithParent()) { 3094 frame = ancestor; 3095 break; 3096 } 3097 } 3098 ASSERT(frame != m_frame); 3099 } 3100 3101 if (activeDocument) { 3102 if (!activeDocument->canNavigate(frame)) 3103 return 0; 3104 } else { 3105 // FIXME: Eventually all callers should supply the actual activeDocument 3106 // so we can call canNavigate with the right document. 3107 if (!m_frame->document()->canNavigate(frame)) 3108 return 0; 3109 } 3110 3111 return frame; 3112} 3113 3114void FrameLoader::loadSameDocumentItem(HistoryItem* item) 3115{ 3116 ASSERT(item->documentSequenceNumber() == history()->currentItem()->documentSequenceNumber()); 3117 3118 // Save user view state to the current history item here since we don't do a normal load. 3119 // FIXME: Does form state need to be saved here too? 3120 history()->saveScrollPositionAndViewStateToItem(history()->currentItem()); 3121 if (FrameView* view = m_frame->view()) 3122 view->setWasScrolledByUser(false); 3123 3124 history()->setCurrentItem(item); 3125 3126 // loadInSameDocument() actually changes the URL and notifies load delegates of a "fake" load 3127 loadInSameDocument(item->url(), item->stateObject(), false); 3128 3129 // Restore user view state from the current history item here since we don't do a normal load. 3130 history()->restoreScrollPositionAndViewState(); 3131} 3132 3133// FIXME: This function should really be split into a couple pieces, some of 3134// which should be methods of HistoryController and some of which should be 3135// methods of FrameLoader. 3136void FrameLoader::loadDifferentDocumentItem(HistoryItem* item, FrameLoadType loadType, FormSubmissionCacheLoadPolicy cacheLoadPolicy) 3137{ 3138 // Remember this item so we can traverse any child items as child frames load 3139 history()->setProvisionalItem(item); 3140 3141 if (CachedPage* cachedPage = pageCache()->get(item)) { 3142 loadWithDocumentLoader(cachedPage->documentLoader(), loadType, 0); 3143 return; 3144 } 3145 3146 KURL itemURL = item->url(); 3147 KURL itemOriginalURL = item->originalURL(); 3148 KURL currentURL; 3149 if (documentLoader()) 3150 currentURL = documentLoader()->url(); 3151 RefPtr<FormData> formData = item->formData(); 3152 3153 ResourceRequest request(itemURL); 3154 3155 if (!item->referrer().isNull()) 3156 request.setHTTPReferrer(item->referrer()); 3157 3158 // If this was a repost that failed the page cache, we might try to repost the form. 3159 NavigationAction action; 3160 if (formData) { 3161 formData->generateFiles(m_frame->document()); 3162 3163 request.setHTTPMethod("POST"); 3164 request.setHTTPBody(formData); 3165 request.setHTTPContentType(item->formContentType()); 3166 RefPtr<SecurityOrigin> securityOrigin = SecurityOrigin::createFromString(item->referrer()); 3167 addHTTPOriginIfNeeded(request, securityOrigin->toString()); 3168 3169 // Make sure to add extra fields to the request after the Origin header is added for the FormData case. 3170 // See https://bugs.webkit.org/show_bug.cgi?id=22194 for more discussion. 3171 addExtraFieldsToRequest(request, loadType, true); 3172 3173 // FIXME: Slight hack to test if the NSURL cache contains the page we're going to. 3174 // We want to know this before talking to the policy delegate, since it affects whether 3175 // we show the DoYouReallyWantToRepost nag. 3176 // 3177 // This trick has a small bug (3123893) where we might find a cache hit, but then 3178 // have the item vanish when we try to use it in the ensuing nav. This should be 3179 // extremely rare, but in that case the user will get an error on the navigation. 3180 3181 if (cacheLoadPolicy == MayAttemptCacheOnlyLoadForFormSubmissionItem) { 3182 request.setCachePolicy(ReturnCacheDataDontLoad); 3183 action = NavigationAction(request, loadType, false); 3184 } else { 3185 request.setCachePolicy(ReturnCacheDataElseLoad); 3186 action = NavigationAction(request, NavigationTypeFormResubmitted); 3187 } 3188 } else { 3189 switch (loadType) { 3190 case FrameLoadTypeReload: 3191 case FrameLoadTypeReloadFromOrigin: 3192 request.setCachePolicy(ReloadIgnoringCacheData); 3193 break; 3194 case FrameLoadTypeBack: 3195 case FrameLoadTypeForward: 3196 case FrameLoadTypeIndexedBackForward: 3197 // If the first load within a frame is a navigation within a back/forward list that was attached 3198 // without any of the items being loaded then we should use the default caching policy (<rdar://problem/8131355>). 3199 if (m_stateMachine.committedFirstRealDocumentLoad()) 3200 request.setCachePolicy(ReturnCacheDataElseLoad); 3201 break; 3202 case FrameLoadTypeStandard: 3203 case FrameLoadTypeRedirectWithLockedBackForwardList: 3204 break; 3205 case FrameLoadTypeSame: 3206 default: 3207 ASSERT_NOT_REACHED(); 3208 } 3209 3210 addExtraFieldsToRequest(request, loadType, true); 3211 3212 ResourceRequest requestForOriginalURL(request); 3213 requestForOriginalURL.setURL(itemOriginalURL); 3214 action = NavigationAction(requestForOriginalURL, loadType, false); 3215 } 3216 3217 loadWithNavigationAction(request, action, false, loadType, 0); 3218} 3219 3220// Loads content into this frame, as specified by history item 3221void FrameLoader::loadItem(HistoryItem* item, FrameLoadType loadType) 3222{ 3223 m_requestedHistoryItem = item; 3224 HistoryItem* currentItem = history()->currentItem(); 3225 bool sameDocumentNavigation = currentItem && item->shouldDoSameDocumentNavigationTo(currentItem); 3226 3227 if (sameDocumentNavigation) 3228 loadSameDocumentItem(item); 3229 else 3230 loadDifferentDocumentItem(item, loadType, MayAttemptCacheOnlyLoadForFormSubmissionItem); 3231} 3232 3233void FrameLoader::retryAfterFailedCacheOnlyMainResourceLoad() 3234{ 3235 ASSERT(m_state == FrameStateProvisional); 3236 ASSERT(!m_loadingFromCachedPage); 3237 // We only use cache-only loads to avoid resubmitting forms. 3238 ASSERT(isBackForwardLoadType(m_loadType)); 3239 ASSERT(m_history->provisionalItem()->formData()); 3240 ASSERT(m_history->provisionalItem() == m_requestedHistoryItem.get()); 3241 3242 FrameLoadType loadType = m_loadType; 3243 HistoryItem* item = m_history->provisionalItem(); 3244 3245 stopAllLoaders(ShouldNotClearProvisionalItem); 3246 loadDifferentDocumentItem(item, loadType, MayNotAttemptCacheOnlyLoadForFormSubmissionItem); 3247} 3248 3249ResourceError FrameLoader::cancelledError(const ResourceRequest& request) const 3250{ 3251 ResourceError error = m_client->cancelledError(request); 3252 error.setIsCancellation(true); 3253 return error; 3254} 3255 3256void FrameLoader::setTitle(const StringWithDirection& title) 3257{ 3258 documentLoader()->setTitle(title); 3259} 3260 3261String FrameLoader::referrer() const 3262{ 3263 return m_documentLoader ? m_documentLoader->request().httpReferrer() : ""; 3264} 3265 3266void FrameLoader::dispatchDocumentElementAvailable() 3267{ 3268 m_frame->injectUserScripts(InjectAtDocumentStart); 3269 m_client->documentElementAvailable(); 3270} 3271 3272void FrameLoader::dispatchDidClearWindowObjectsInAllWorlds() 3273{ 3274 if (!m_frame->script()->canExecuteScripts(NotAboutToExecuteScript)) 3275 return; 3276 3277 Vector<RefPtr<DOMWrapperWorld> > worlds; 3278 ScriptController::getAllWorlds(worlds); 3279 for (size_t i = 0; i < worlds.size(); ++i) 3280 dispatchDidClearWindowObjectInWorld(worlds[i].get()); 3281} 3282 3283void FrameLoader::dispatchDidClearWindowObjectInWorld(DOMWrapperWorld* world) 3284{ 3285 if (!m_frame->script()->canExecuteScripts(NotAboutToExecuteScript) || !m_frame->script()->existingWindowShell(world)) 3286 return; 3287 3288 m_client->dispatchDidClearWindowObjectInWorld(world); 3289 3290#if ENABLE(INSPECTOR) 3291 if (Page* page = m_frame->page()) 3292 page->inspectorController()->didClearWindowObjectInWorld(m_frame, world); 3293#endif 3294 3295 InspectorInstrumentation::didClearWindowObjectInWorld(m_frame, world); 3296} 3297 3298void FrameLoader::dispatchGlobalObjectAvailableInAllWorlds() 3299{ 3300 Vector<RefPtr<DOMWrapperWorld> > worlds; 3301 ScriptController::getAllWorlds(worlds); 3302 for (size_t i = 0; i < worlds.size(); ++i) 3303 m_client->dispatchGlobalObjectAvailable(worlds[i].get()); 3304} 3305 3306SandboxFlags FrameLoader::effectiveSandboxFlags() const 3307{ 3308 SandboxFlags flags = m_forcedSandboxFlags; 3309 if (Frame* parentFrame = m_frame->tree()->parent()) 3310 flags |= parentFrame->document()->sandboxFlags(); 3311 if (HTMLFrameOwnerElement* ownerElement = m_frame->ownerElement()) 3312 flags |= ownerElement->sandboxFlags(); 3313 return flags; 3314} 3315 3316void FrameLoader::didChangeTitle(DocumentLoader* loader) 3317{ 3318 m_client->didChangeTitle(loader); 3319 3320 if (loader == m_documentLoader) { 3321 // Must update the entries in the back-forward list too. 3322 history()->setCurrentItemTitle(loader->title()); 3323 // This must go through the WebFrame because it has the right notion of the current b/f item. 3324 m_client->setTitle(loader->title(), loader->urlForHistory()); 3325 m_client->setMainFrameDocumentReady(true); // update observers with new DOMDocument 3326 m_client->dispatchDidReceiveTitle(loader->title()); 3327 } 3328} 3329 3330void FrameLoader::didChangeIcons(IconType type) 3331{ 3332 m_client->dispatchDidChangeIcons(type); 3333} 3334 3335void FrameLoader::dispatchDidCommitLoad() 3336{ 3337 if (m_stateMachine.creatingInitialEmptyDocument()) 3338 return; 3339 3340 m_client->dispatchDidCommitLoad(); 3341 3342 if (isLoadingMainFrame()) { 3343 m_frame->page()->resetSeenPlugins(); 3344 m_frame->page()->resetSeenMediaEngines(); 3345 } 3346 3347 InspectorInstrumentation::didCommitLoad(m_frame, m_documentLoader.get()); 3348 3349 if (m_frame->page()->mainFrame() == m_frame) 3350 m_frame->page()->featureObserver()->didCommitLoad(); 3351 3352} 3353 3354void FrameLoader::tellClientAboutPastMemoryCacheLoads() 3355{ 3356 ASSERT(m_frame->page()); 3357 ASSERT(m_frame->page()->areMemoryCacheClientCallsEnabled()); 3358 3359 if (!m_documentLoader) 3360 return; 3361 3362 Vector<ResourceRequest> pastLoads; 3363 m_documentLoader->takeMemoryCacheLoadsForClientNotification(pastLoads); 3364 3365 size_t size = pastLoads.size(); 3366 for (size_t i = 0; i < size; ++i) { 3367 CachedResource* resource = memoryCache()->resourceForRequest(pastLoads[i]); 3368 3369 // FIXME: These loads, loaded from cache, but now gone from the cache by the time 3370 // Page::setMemoryCacheClientCallsEnabled(true) is called, will not be seen by the client. 3371 // Consider if there's some efficient way of remembering enough to deliver this client call. 3372 // We have the URL, but not the rest of the response or the length. 3373 if (!resource) 3374 continue; 3375 3376 ResourceRequest request(resource->url()); 3377 m_client->dispatchDidLoadResourceFromMemoryCache(m_documentLoader.get(), request, resource->response(), resource->encodedSize()); 3378 } 3379} 3380 3381NetworkingContext* FrameLoader::networkingContext() const 3382{ 3383 return m_networkingContext.get(); 3384} 3385 3386void FrameLoader::loadProgressingStatusChanged() 3387{ 3388 FrameView* view = m_frame->page()->mainFrame()->view(); 3389 if (!view) 3390 return; 3391 3392 view->updateLayerFlushThrottlingInAllFrames(); 3393 view->adjustTiledBackingCoverage(); 3394} 3395 3396void FrameLoader::forcePageTransitionIfNeeded() 3397{ 3398 m_client->forcePageTransitionIfNeeded(); 3399} 3400 3401bool FrameLoaderClient::hasHTMLView() const 3402{ 3403 return true; 3404} 3405 3406PassRefPtr<Frame> createWindow(Frame* openerFrame, Frame* lookupFrame, const FrameLoadRequest& request, const WindowFeatures& features, bool& created) 3407{ 3408 ASSERT(!features.dialog || request.frameName().isEmpty()); 3409 3410 created = false; 3411 3412 if (!request.frameName().isEmpty() && request.frameName() != "_blank") { 3413 if (RefPtr<Frame> frame = lookupFrame->loader()->findFrameForNavigation(request.frameName(), openerFrame->document())) { 3414 if (request.frameName() != "_self") { 3415 if (Page* page = frame->page()) 3416 page->chrome().focus(); 3417 } 3418 return frame.release(); 3419 } 3420 } 3421 3422 // Sandboxed frames cannot open new auxiliary browsing contexts. 3423 if (isDocumentSandboxed(openerFrame, SandboxPopups)) { 3424 // FIXME: This message should be moved off the console once a solution to https://bugs.webkit.org/show_bug.cgi?id=103274 exists. 3425 openerFrame->document()->addConsoleMessage(SecurityMessageSource, ErrorMessageLevel, "Blocked opening '" + request.resourceRequest().url().stringCenterEllipsizedToLength() + "' in a new window because the request was made in a sandboxed frame whose 'allow-popups' permission is not set."); 3426 return nullptr; 3427 } 3428 3429 // FIXME: Setting the referrer should be the caller's responsibility. 3430 FrameLoadRequest requestWithReferrer = request; 3431 String referrer = SecurityPolicy::generateReferrerHeader(openerFrame->document()->referrerPolicy(), request.resourceRequest().url(), openerFrame->loader()->outgoingReferrer()); 3432 if (!referrer.isEmpty()) 3433 requestWithReferrer.resourceRequest().setHTTPReferrer(referrer); 3434 FrameLoader::addHTTPOriginIfNeeded(requestWithReferrer.resourceRequest(), openerFrame->loader()->outgoingOrigin()); 3435 3436 if (openerFrame->settings() && !openerFrame->settings()->supportsMultipleWindows()) { 3437 created = false; 3438 return openerFrame; 3439 } 3440 3441 Page* oldPage = openerFrame->page(); 3442 if (!oldPage) 3443 return nullptr; 3444 3445 Page* page = oldPage->chrome().createWindow(openerFrame, requestWithReferrer, features, NavigationAction(requestWithReferrer.resourceRequest())); 3446 if (!page) 3447 return nullptr; 3448 3449 RefPtr<Frame> frame = page->mainFrame(); 3450 3451 frame->loader()->forceSandboxFlags(openerFrame->document()->sandboxFlags()); 3452 3453 if (request.frameName() != "_blank") 3454 frame->tree()->setName(request.frameName()); 3455 3456 page->chrome().setToolbarsVisible(features.toolBarVisible || features.locationBarVisible); 3457 3458 if (!frame->page()) 3459 return nullptr; 3460 page->chrome().setStatusbarVisible(features.statusBarVisible); 3461 3462 if (!frame->page()) 3463 return nullptr; 3464 page->chrome().setScrollbarsVisible(features.scrollbarsVisible); 3465 3466 if (!frame->page()) 3467 return nullptr; 3468 page->chrome().setMenubarVisible(features.menuBarVisible); 3469 3470 if (!frame->page()) 3471 return nullptr; 3472 page->chrome().setResizable(features.resizable); 3473 3474 // 'x' and 'y' specify the location of the window, while 'width' and 'height' 3475 // specify the size of the viewport. We can only resize the window, so adjust 3476 // for the difference between the window size and the viewport size. 3477 3478 FloatRect windowRect = page->chrome().windowRect(); 3479 FloatSize viewportSize = page->chrome().pageRect().size(); 3480 3481 if (features.xSet) 3482 windowRect.setX(features.x); 3483 if (features.ySet) 3484 windowRect.setY(features.y); 3485 // Zero width and height mean using default size, not minumum one. 3486 if (features.widthSet && features.width) 3487 windowRect.setWidth(features.width + (windowRect.width() - viewportSize.width())); 3488 if (features.heightSet && features.height) 3489 windowRect.setHeight(features.height + (windowRect.height() - viewportSize.height())); 3490 3491 // Ensure non-NaN values, minimum size as well as being within valid screen area. 3492 FloatRect newWindowRect = DOMWindow::adjustWindowRect(page, windowRect); 3493 3494 if (!frame->page()) 3495 return nullptr; 3496 page->chrome().setWindowRect(newWindowRect); 3497 3498 if (!frame->page()) 3499 return nullptr; 3500 page->chrome().show(); 3501 3502 created = true; 3503 return frame; 3504} 3505 3506} // namespace WebCore 3507