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