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