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