1 /* 2 * Copyright (C) 2009 Google Inc. All rights reserved. 3 * Copyright (C) 2011 Apple Inc. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: 8 * 9 * * Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * * Redistributions in binary form must reproduce the above 12 * copyright notice, this list of conditions and the following disclaimer 13 * in the documentation and/or other materials provided with the 14 * distribution. 15 * * Neither the name of Google Inc. nor the names of its 16 * contributors may be used to endorse or promote products derived from 17 * this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include "config.h" 33 #include "FrameLoaderClientImpl.h" 34 35 #include "BackForwardListChromium.h" 36 #include "Chrome.h" 37 #include "Document.h" 38 #include "DocumentLoader.h" 39 #include "FormState.h" 40 #include "FrameLoader.h" 41 #include "FrameLoadRequest.h" 42 #include "FrameNetworkingContextImpl.h" 43 #include "FrameView.h" 44 #include "HTTPParsers.h" 45 #include "HistoryItem.h" 46 #include "HitTestResult.h" 47 #include "HTMLAppletElement.h" 48 #include "HTMLFormElement.h" // needed by FormState.h 49 #include "HTMLNames.h" 50 #include "MIMETypeRegistry.h" 51 #include "MouseEvent.h" 52 #include "Page.h" 53 #include "PlatformString.h" 54 #include "PluginData.h" 55 #include "PluginDataChromium.h" 56 #include "ProgressTracker.h" 57 #include "Settings.h" 58 #include "StringExtras.h" 59 #include "WebDataSourceImpl.h" 60 #include "WebDevToolsAgentPrivate.h" 61 #include "WebFormElement.h" 62 #include "WebFrameClient.h" 63 #include "WebFrameImpl.h" 64 #include "WebKit.h" 65 #include "WebKitClient.h" 66 #include "WebMimeRegistry.h" 67 #include "WebNode.h" 68 #include "WebPlugin.h" 69 #include "WebPluginContainerImpl.h" 70 #include "WebPluginLoadObserver.h" 71 #include "WebPluginParams.h" 72 #include "WebSecurityOrigin.h" 73 #include "WebURL.h" 74 #include "WebURLError.h" 75 #include "WebVector.h" 76 #include "WebViewClient.h" 77 #include "WebViewImpl.h" 78 #include "WindowFeatures.h" 79 #include "WrappedResourceRequest.h" 80 #include "WrappedResourceResponse.h" 81 #include <wtf/text/CString.h> 82 83 using namespace WebCore; 84 85 namespace WebKit { 86 87 // Domain for internal error codes. 88 static const char internalErrorDomain[] = "WebKit"; 89 90 // An internal error code. Used to note a policy change error resulting from 91 // dispatchDecidePolicyForMIMEType not passing the PolicyUse option. 92 enum { 93 PolicyChangeError = -10000, 94 }; 95 96 FrameLoaderClientImpl::FrameLoaderClientImpl(WebFrameImpl* frame) 97 : m_webFrame(frame) 98 , m_hasRepresentation(false) 99 , m_sentInitialResponseToPlugin(false) 100 , m_nextNavigationPolicy(WebNavigationPolicyIgnore) 101 { 102 } 103 104 FrameLoaderClientImpl::~FrameLoaderClientImpl() 105 { 106 } 107 108 void FrameLoaderClientImpl::frameLoaderDestroyed() 109 { 110 // When the WebFrame was created, it had an extra reference given to it on 111 // behalf of the Frame. Since the WebFrame owns us, this extra ref also 112 // serves to keep us alive until the FrameLoader is done with us. The 113 // FrameLoader calls this method when it's going away. Therefore, we balance 114 // out that extra reference, which may cause 'this' to be deleted. 115 m_webFrame->closing(); 116 m_webFrame->deref(); 117 } 118 119 void FrameLoaderClientImpl::dispatchDidClearWindowObjectInWorld(DOMWrapperWorld*) 120 { 121 if (m_webFrame->client()) 122 m_webFrame->client()->didClearWindowObject(m_webFrame); 123 124 WebViewImpl* webview = m_webFrame->viewImpl(); 125 if (webview->devToolsAgentPrivate()) 126 webview->devToolsAgentPrivate()->didClearWindowObject(m_webFrame); 127 } 128 129 void FrameLoaderClientImpl::documentElementAvailable() 130 { 131 if (m_webFrame->client()) 132 m_webFrame->client()->didCreateDocumentElement(m_webFrame); 133 } 134 135 void FrameLoaderClientImpl::didCreateScriptContextForFrame() 136 { 137 if (m_webFrame->client()) 138 m_webFrame->client()->didCreateScriptContext(m_webFrame); 139 } 140 141 void FrameLoaderClientImpl::didDestroyScriptContextForFrame() 142 { 143 if (m_webFrame->client()) 144 m_webFrame->client()->didDestroyScriptContext(m_webFrame); 145 } 146 147 void FrameLoaderClientImpl::didCreateIsolatedScriptContext() 148 { 149 if (m_webFrame->client()) 150 m_webFrame->client()->didCreateIsolatedScriptContext(m_webFrame); 151 } 152 153 bool FrameLoaderClientImpl::allowScriptExtension(const String& extensionName, 154 int extensionGroup) 155 { 156 if (m_webFrame->client()) 157 return m_webFrame->client()->allowScriptExtension(m_webFrame, extensionName, extensionGroup); 158 return false; 159 } 160 161 void FrameLoaderClientImpl::didPerformFirstNavigation() const 162 { 163 } 164 165 void FrameLoaderClientImpl::registerForIconNotification(bool) 166 { 167 } 168 169 void FrameLoaderClientImpl::didChangeScrollOffset() 170 { 171 if (m_webFrame->client()) 172 m_webFrame->client()->didChangeScrollOffset(m_webFrame); 173 } 174 175 bool FrameLoaderClientImpl::allowJavaScript(bool enabledPerSettings) 176 { 177 if (m_webFrame->client()) 178 return m_webFrame->client()->allowScript(m_webFrame, enabledPerSettings); 179 180 return enabledPerSettings; 181 } 182 183 bool FrameLoaderClientImpl::allowPlugins(bool enabledPerSettings) 184 { 185 if (m_webFrame->client()) 186 return m_webFrame->client()->allowPlugins(m_webFrame, enabledPerSettings); 187 188 return enabledPerSettings; 189 } 190 191 bool FrameLoaderClientImpl::allowImages(bool enabledPerSettings) 192 { 193 if (m_webFrame->client()) 194 return m_webFrame->client()->allowImages(m_webFrame, enabledPerSettings); 195 196 return enabledPerSettings; 197 } 198 199 void FrameLoaderClientImpl::didNotAllowScript() 200 { 201 if (m_webFrame->client()) 202 m_webFrame->client()->didNotAllowScript(m_webFrame); 203 } 204 205 void FrameLoaderClientImpl::didNotAllowPlugins() 206 { 207 if (m_webFrame->client()) 208 m_webFrame->client()->didNotAllowPlugins(m_webFrame); 209 } 210 211 bool FrameLoaderClientImpl::hasWebView() const 212 { 213 return m_webFrame->viewImpl(); 214 } 215 216 bool FrameLoaderClientImpl::hasFrameView() const 217 { 218 // The Mac port has this notion of a WebFrameView, which seems to be 219 // some wrapper around an NSView. Since our equivalent is HWND, I guess 220 // we have a "frameview" whenever we have the toplevel HWND. 221 return m_webFrame->viewImpl(); 222 } 223 224 void FrameLoaderClientImpl::makeDocumentView() 225 { 226 m_webFrame->createFrameView(); 227 } 228 229 void FrameLoaderClientImpl::makeRepresentation(DocumentLoader*) 230 { 231 m_hasRepresentation = true; 232 } 233 234 void FrameLoaderClientImpl::forceLayout() 235 { 236 // FIXME 237 } 238 239 void FrameLoaderClientImpl::forceLayoutForNonHTML() 240 { 241 // FIXME 242 } 243 244 void FrameLoaderClientImpl::setCopiesOnScroll() 245 { 246 // FIXME 247 } 248 249 void FrameLoaderClientImpl::detachedFromParent2() 250 { 251 // Nothing to do here. 252 } 253 254 void FrameLoaderClientImpl::detachedFromParent3() 255 { 256 // Close down the proxy. The purpose of this change is to make the 257 // call to ScriptController::clearWindowShell a no-op when called from 258 // Frame::pageDestroyed. Without this change, this call to clearWindowShell 259 // will cause a crash. If you remove/modify this, just ensure that you can 260 // go to a page and then navigate to a new page without getting any asserts 261 // or crashes. 262 m_webFrame->frame()->script()->proxy()->clearForClose(); 263 264 // Alert the client that the frame is being detached. This is the last 265 // chance we have to communicate with the client. 266 if (m_webFrame->client()) 267 m_webFrame->client()->frameDetached(m_webFrame); 268 269 // Stop communicating with the WebFrameClient at this point since we are no 270 // longer associated with the Page. 271 m_webFrame->setClient(0); 272 } 273 274 // This function is responsible for associating the |identifier| with a given 275 // subresource load. The following functions that accept an |identifier| are 276 // called for each subresource, so they should not be dispatched to the 277 // WebFrame. 278 void FrameLoaderClientImpl::assignIdentifierToInitialRequest( 279 unsigned long identifier, DocumentLoader* loader, 280 const ResourceRequest& request) 281 { 282 if (m_webFrame->client()) { 283 WrappedResourceRequest webreq(request); 284 m_webFrame->client()->assignIdentifierToRequest( 285 m_webFrame, identifier, webreq); 286 } 287 } 288 289 // If the request being loaded by |loader| is a frame, update the ResourceType. 290 // A subresource in this context is anything other than a frame -- 291 // this includes images and xmlhttp requests. It is important to note that a 292 // subresource is NOT limited to stuff loaded through the frame's subresource 293 // loader. Synchronous xmlhttp requests for example, do not go through the 294 // subresource loader, but we still label them as TargetIsSubresource. 295 // 296 // The important edge cases to consider when modifying this function are 297 // how synchronous resource loads are treated during load/unload threshold. 298 static void setTargetTypeFromLoader(ResourceRequest& request, DocumentLoader* loader) 299 { 300 if (loader == loader->frameLoader()->provisionalDocumentLoader()) { 301 ResourceRequest::TargetType type; 302 if (loader->frameLoader()->isLoadingMainFrame()) 303 type = ResourceRequest::TargetIsMainFrame; 304 else 305 type = ResourceRequest::TargetIsSubframe; 306 request.setTargetType(type); 307 } 308 } 309 310 void FrameLoaderClientImpl::dispatchWillSendRequest( 311 DocumentLoader* loader, unsigned long identifier, ResourceRequest& request, 312 const ResourceResponse& redirectResponse) 313 { 314 if (loader) { 315 // We want to distinguish between a request for a document to be loaded into 316 // the main frame, a sub-frame, or the sub-objects in that document. 317 setTargetTypeFromLoader(request, loader); 318 319 // Avoid repeating a form submission when navigating back or forward. 320 if (loader == loader->frameLoader()->provisionalDocumentLoader() 321 && request.httpMethod() == "POST" 322 && isBackForwardLoadType(loader->frameLoader()->loadType())) 323 request.setCachePolicy(ReturnCacheDataDontLoad); 324 } 325 326 // FrameLoader::loadEmptyDocumentSynchronously() creates an empty document 327 // with no URL. We don't like that, so we'll rename it to about:blank. 328 if (request.url().isEmpty()) 329 request.setURL(KURL(ParsedURLString, "about:blank")); 330 if (request.firstPartyForCookies().isEmpty()) 331 request.setFirstPartyForCookies(KURL(ParsedURLString, "about:blank")); 332 333 // Give the WebFrameClient a crack at the request. 334 if (m_webFrame->client()) { 335 WrappedResourceRequest webreq(request); 336 WrappedResourceResponse webresp(redirectResponse); 337 m_webFrame->client()->willSendRequest( 338 m_webFrame, identifier, webreq, webresp); 339 } 340 } 341 342 bool FrameLoaderClientImpl::shouldUseCredentialStorage( 343 DocumentLoader*, unsigned long identifier) 344 { 345 // FIXME 346 // Intended to pass through to a method on the resource load delegate. 347 // If implemented, that method controls whether the browser should ask the 348 // networking layer for a stored default credential for the page (say from 349 // the Mac OS keychain). If the method returns false, the user should be 350 // presented with an authentication challenge whether or not the networking 351 // layer has a credential stored. 352 // This returns true for backward compatibility: the ability to override the 353 // system credential store is new. (Actually, not yet fully implemented in 354 // WebKit, as of this writing.) 355 return true; 356 } 357 358 void FrameLoaderClientImpl::dispatchDidReceiveAuthenticationChallenge( 359 DocumentLoader*, unsigned long identifier, const AuthenticationChallenge&) 360 { 361 // FIXME 362 } 363 364 void FrameLoaderClientImpl::dispatchDidCancelAuthenticationChallenge( 365 DocumentLoader*, unsigned long identifier, const AuthenticationChallenge&) 366 { 367 // FIXME 368 } 369 370 void FrameLoaderClientImpl::dispatchDidReceiveResponse(DocumentLoader* loader, 371 unsigned long identifier, 372 const ResourceResponse& response) 373 { 374 if (m_webFrame->client()) { 375 WrappedResourceResponse webresp(response); 376 m_webFrame->client()->didReceiveResponse(m_webFrame, identifier, webresp); 377 } 378 } 379 380 void FrameLoaderClientImpl::dispatchDidReceiveContentLength( 381 DocumentLoader* loader, 382 unsigned long identifier, 383 int dataLength) 384 { 385 } 386 387 // Called when a particular resource load completes 388 void FrameLoaderClientImpl::dispatchDidFinishLoading(DocumentLoader* loader, 389 unsigned long identifier) 390 { 391 if (m_webFrame->client()) 392 m_webFrame->client()->didFinishResourceLoad(m_webFrame, identifier); 393 } 394 395 void FrameLoaderClientImpl::dispatchDidFailLoading(DocumentLoader* loader, 396 unsigned long identifier, 397 const ResourceError& error) 398 { 399 if (m_webFrame->client()) 400 m_webFrame->client()->didFailResourceLoad(m_webFrame, identifier, error); 401 } 402 403 void FrameLoaderClientImpl::dispatchDidFinishDocumentLoad() 404 { 405 // A frame may be reused. This call ensures we don't hold on to our password 406 // listeners and their associated HTMLInputElements. 407 m_webFrame->clearPasswordListeners(); 408 409 if (m_webFrame->client()) 410 m_webFrame->client()->didFinishDocumentLoad(m_webFrame); 411 } 412 413 bool FrameLoaderClientImpl::dispatchDidLoadResourceFromMemoryCache( 414 DocumentLoader* loader, 415 const ResourceRequest& request, 416 const ResourceResponse& response, 417 int length) 418 { 419 if (m_webFrame->client()) { 420 WrappedResourceRequest webreq(request); 421 WrappedResourceResponse webresp(response); 422 m_webFrame->client()->didLoadResourceFromMemoryCache( 423 m_webFrame, webreq, webresp); 424 } 425 return false; // Do not suppress remaining notifications 426 } 427 428 void FrameLoaderClientImpl::dispatchDidHandleOnloadEvents() 429 { 430 if (m_webFrame->client()) 431 m_webFrame->client()->didHandleOnloadEvents(m_webFrame); 432 } 433 434 // Redirect Tracking 435 // ================= 436 // We want to keep track of the chain of redirects that occur during page 437 // loading. There are two types of redirects, server redirects which are HTTP 438 // response codes, and client redirects which are document.location= and meta 439 // refreshes. 440 // 441 // This outlines the callbacks that we get in different redirect situations, 442 // and how each call modifies the redirect chain. 443 // 444 // Normal page load 445 // ---------------- 446 // dispatchDidStartProvisionalLoad() -> adds URL to the redirect list 447 // dispatchDidCommitLoad() -> DISPATCHES & clears list 448 // 449 // Server redirect (success) 450 // ------------------------- 451 // dispatchDidStartProvisionalLoad() -> adds source URL 452 // dispatchDidReceiveServerRedirectForProvisionalLoad() -> adds dest URL 453 // dispatchDidCommitLoad() -> DISPATCHES 454 // 455 // Client redirect (success) 456 // ------------------------- 457 // (on page) 458 // dispatchWillPerformClientRedirect() -> saves expected redirect 459 // dispatchDidStartProvisionalLoad() -> appends redirect source (since 460 // it matches the expected redirect) 461 // and the current page as the dest) 462 // dispatchDidCancelClientRedirect() -> clears expected redirect 463 // dispatchDidCommitLoad() -> DISPATCHES 464 // 465 // Client redirect (cancelled) 466 // (e.g meta-refresh trumped by manual doc.location change, or just cancelled 467 // because a link was clicked that requires the meta refresh to be rescheduled 468 // (the SOURCE URL may have changed). 469 // --------------------------- 470 // dispatchDidCancelClientRedirect() -> clears expected redirect 471 // dispatchDidStartProvisionalLoad() -> adds only URL to redirect list 472 // dispatchDidCommitLoad() -> DISPATCHES & clears list 473 // rescheduled ? dispatchWillPerformClientRedirect() -> saves expected redirect 474 // : nothing 475 476 // Client redirect (failure) 477 // ------------------------- 478 // (on page) 479 // dispatchWillPerformClientRedirect() -> saves expected redirect 480 // dispatchDidStartProvisionalLoad() -> appends redirect source (since 481 // it matches the expected redirect) 482 // and the current page as the dest) 483 // dispatchDidCancelClientRedirect() 484 // dispatchDidFailProvisionalLoad() 485 // 486 // Load 1 -> Server redirect to 2 -> client redirect to 3 -> server redirect to 4 487 // ------------------------------------------------------------------------------ 488 // dispatchDidStartProvisionalLoad() -> adds source URL 1 489 // dispatchDidReceiveServerRedirectForProvisionalLoad() -> adds dest URL 2 490 // dispatchDidCommitLoad() -> DISPATCHES 1+2 491 // -- begin client redirect and NEW DATA SOURCE 492 // dispatchWillPerformClientRedirect() -> saves expected redirect 493 // dispatchDidStartProvisionalLoad() -> appends URL 2 and URL 3 494 // dispatchDidReceiveServerRedirectForProvisionalLoad() -> appends destination URL 4 495 // dispatchDidCancelClientRedirect() -> clears expected redirect 496 // dispatchDidCommitLoad() -> DISPATCHES 497 // 498 // Interesting case with multiple location changes involving anchors. 499 // Load page 1 containing future client-redirect (back to 1, e.g meta refresh) > Click 500 // on a link back to the same page (i.e an anchor href) > 501 // client-redirect finally fires (with new source, set to 1#anchor) 502 // ----------------------------------------------------------------------------- 503 // dispatchWillPerformClientRedirect(non-zero 'interval' param) -> saves expected redirect 504 // -- click on anchor href 505 // dispatchDidCancelClientRedirect() -> clears expected redirect 506 // dispatchDidStartProvisionalLoad() -> adds 1#anchor source 507 // dispatchDidCommitLoad() -> DISPATCHES 1#anchor 508 // dispatchWillPerformClientRedirect() -> saves exp. source (1#anchor) 509 // -- redirect timer fires 510 // dispatchDidStartProvisionalLoad() -> appends 1#anchor (src) and 1 (dest) 511 // dispatchDidCancelClientRedirect() -> clears expected redirect 512 // dispatchDidCommitLoad() -> DISPATCHES 1#anchor + 1 513 // 514 void FrameLoaderClientImpl::dispatchDidReceiveServerRedirectForProvisionalLoad() 515 { 516 WebDataSourceImpl* ds = m_webFrame->provisionalDataSourceImpl(); 517 if (!ds) { 518 // Got a server redirect when there is no provisional DS! 519 ASSERT_NOT_REACHED(); 520 return; 521 } 522 523 // The server redirect may have been blocked. 524 if (ds->request().isNull()) 525 return; 526 527 // A provisional load should have started already, which should have put an 528 // entry in our redirect chain. 529 ASSERT(ds->hasRedirectChain()); 530 531 // The URL of the destination is on the provisional data source. We also need 532 // to update the redirect chain to account for this addition (we do this 533 // before the callback so the callback can look at the redirect chain to see 534 // what happened). 535 ds->appendRedirect(ds->request().url()); 536 537 if (m_webFrame->client()) 538 m_webFrame->client()->didReceiveServerRedirectForProvisionalLoad(m_webFrame); 539 } 540 541 // Called on both success and failure of a client redirect. 542 void FrameLoaderClientImpl::dispatchDidCancelClientRedirect() 543 { 544 // No longer expecting a client redirect. 545 if (m_webFrame->client()) { 546 m_expectedClientRedirectSrc = KURL(); 547 m_expectedClientRedirectDest = KURL(); 548 m_webFrame->client()->didCancelClientRedirect(m_webFrame); 549 } 550 551 // No need to clear the redirect chain, since that data source has already 552 // been deleted by the time this function is called. 553 } 554 555 void FrameLoaderClientImpl::dispatchWillPerformClientRedirect( 556 const KURL& url, 557 double interval, 558 double fireDate) 559 { 560 // Tells dispatchDidStartProvisionalLoad that if it sees this item it is a 561 // redirect and the source item should be added as the start of the chain. 562 m_expectedClientRedirectSrc = m_webFrame->url(); 563 m_expectedClientRedirectDest = url; 564 565 // FIXME: bug 1135512. Webkit does not properly notify us of cancelling 566 // http > file client redirects. Since the FrameLoader's policy is to never 567 // carry out such a navigation anyway, the best thing we can do for now to 568 // not get confused is ignore this notification. 569 if (m_expectedClientRedirectDest.isLocalFile() 570 && m_expectedClientRedirectSrc.protocolInHTTPFamily()) { 571 m_expectedClientRedirectSrc = KURL(); 572 m_expectedClientRedirectDest = KURL(); 573 return; 574 } 575 576 if (m_webFrame->client()) { 577 m_webFrame->client()->willPerformClientRedirect( 578 m_webFrame, 579 m_expectedClientRedirectSrc, 580 m_expectedClientRedirectDest, 581 static_cast<unsigned int>(interval), 582 static_cast<unsigned int>(fireDate)); 583 } 584 } 585 586 void FrameLoaderClientImpl::dispatchDidNavigateWithinPage() 587 { 588 // Anchor fragment navigations are not normal loads, so we need to synthesize 589 // some events for our delegate. 590 WebViewImpl* webView = m_webFrame->viewImpl(); 591 592 // Flag of whether frame loader is completed. Generate didStartLoading and 593 // didStopLoading only when loader is completed so that we don't fire 594 // them for fragment redirection that happens in window.onload handler. 595 // See https://bugs.webkit.org/show_bug.cgi?id=31838 596 bool loaderCompleted = 597 !webView->page()->mainFrame()->loader()->activeDocumentLoader()->isLoadingInAPISense(); 598 599 // Generate didStartLoading if loader is completed. 600 if (webView->client() && loaderCompleted) 601 webView->client()->didStartLoading(); 602 603 // We need to classify some hash changes as client redirects. 604 // FIXME: It seems wrong that the currentItem can sometimes be null. 605 HistoryItem* currentItem = m_webFrame->frame()->loader()->history()->currentItem(); 606 bool isHashChange = !currentItem || !currentItem->stateObject(); 607 608 WebDataSourceImpl* ds = m_webFrame->dataSourceImpl(); 609 ASSERT(ds); // Should not be null when navigating to a reference fragment! 610 if (ds) { 611 KURL url = ds->request().url(); 612 KURL chainEnd; 613 if (ds->hasRedirectChain()) { 614 chainEnd = ds->endOfRedirectChain(); 615 ds->clearRedirectChain(); 616 } 617 618 if (isHashChange) { 619 // Figure out if this location change is because of a JS-initiated 620 // client redirect (e.g onload/setTimeout document.location.href=). 621 // FIXME: (b/1085325, b/1046841) We don't get proper redirect 622 // performed/cancelled notifications across anchor navigations, so the 623 // other redirect-tracking code in this class (see 624 // dispatch*ClientRedirect() and dispatchDidStartProvisionalLoad) is 625 // insufficient to catch and properly flag these transitions. Once a 626 // proper fix for this bug is identified and applied the following 627 // block may no longer be required. 628 bool wasClientRedirect = 629 (url == m_expectedClientRedirectDest && chainEnd == m_expectedClientRedirectSrc) 630 || !m_webFrame->isProcessingUserGesture(); 631 632 if (wasClientRedirect) { 633 if (m_webFrame->client()) 634 m_webFrame->client()->didCompleteClientRedirect(m_webFrame, chainEnd); 635 ds->appendRedirect(chainEnd); 636 // Make sure we clear the expected redirect since we just effectively 637 // completed it. 638 m_expectedClientRedirectSrc = KURL(); 639 m_expectedClientRedirectDest = KURL(); 640 } 641 } 642 643 // Regardless of how we got here, we are navigating to a URL so we need to 644 // add it to the redirect chain. 645 ds->appendRedirect(url); 646 } 647 648 bool isNewNavigation; 649 webView->didCommitLoad(&isNewNavigation); 650 if (m_webFrame->client()) 651 m_webFrame->client()->didNavigateWithinPage(m_webFrame, isNewNavigation); 652 653 // Generate didStopLoading if loader is completed. 654 if (webView->client() && loaderCompleted) 655 webView->client()->didStopLoading(); 656 } 657 658 void FrameLoaderClientImpl::dispatchDidChangeLocationWithinPage() 659 { 660 if (m_webFrame) 661 m_webFrame->client()->didChangeLocationWithinPage(m_webFrame); 662 } 663 664 void FrameLoaderClientImpl::dispatchDidPushStateWithinPage() 665 { 666 dispatchDidNavigateWithinPage(); 667 } 668 669 void FrameLoaderClientImpl::dispatchDidReplaceStateWithinPage() 670 { 671 dispatchDidNavigateWithinPage(); 672 } 673 674 void FrameLoaderClientImpl::dispatchDidPopStateWithinPage() 675 { 676 // Ignored since dispatchDidNavigateWithinPage was already called. 677 } 678 679 void FrameLoaderClientImpl::dispatchWillClose() 680 { 681 if (m_webFrame->client()) 682 m_webFrame->client()->willClose(m_webFrame); 683 } 684 685 void FrameLoaderClientImpl::dispatchDidReceiveIcon() 686 { 687 // The icon database is disabled, so this should never be called. 688 ASSERT_NOT_REACHED(); 689 } 690 691 void FrameLoaderClientImpl::dispatchDidStartProvisionalLoad() 692 { 693 // In case a redirect occurs, we need this to be set so that the redirect 694 // handling code can tell where the redirect came from. Server redirects 695 // will occur on the provisional load, so we need to keep track of the most 696 // recent provisional load URL. 697 // See dispatchDidReceiveServerRedirectForProvisionalLoad. 698 WebDataSourceImpl* ds = m_webFrame->provisionalDataSourceImpl(); 699 if (!ds) { 700 ASSERT_NOT_REACHED(); 701 return; 702 } 703 KURL url = ds->request().url(); 704 705 // Since the provisional load just started, we should have not gotten 706 // any redirects yet. 707 ASSERT(!ds->hasRedirectChain()); 708 709 // If this load is what we expected from a client redirect, treat it as a 710 // redirect from that original page. The expected redirect urls will be 711 // cleared by DidCancelClientRedirect. 712 bool completingClientRedirect = false; 713 if (m_expectedClientRedirectSrc.isValid()) { 714 // m_expectedClientRedirectDest could be something like 715 // "javascript:history.go(-1)" thus we need to exclude url starts with 716 // "javascript:". See bug: 1080873 717 if (m_expectedClientRedirectDest.protocolIs("javascript") 718 || m_expectedClientRedirectDest == url) { 719 ds->appendRedirect(m_expectedClientRedirectSrc); 720 completingClientRedirect = true; 721 } else { 722 // Any pending redirect is no longer in progress. This can happen 723 // if the navigation was canceled with PolicyIgnore, or if the 724 // redirect was scheduled on the wrong frame (e.g., due to a form 725 // submission targeted to _blank, as in http://webkit.org/b/44079). 726 m_expectedClientRedirectSrc = KURL(); 727 m_expectedClientRedirectDest = KURL(); 728 } 729 } 730 ds->appendRedirect(url); 731 732 if (m_webFrame->client()) { 733 // Whatever information didCompleteClientRedirect contains should only 734 // be considered relevant until the next provisional load has started. 735 // So we first tell the client that the load started, and then tell it 736 // about the client redirect the load is responsible for completing. 737 m_webFrame->client()->didStartProvisionalLoad(m_webFrame); 738 if (completingClientRedirect) { 739 m_webFrame->client()->didCompleteClientRedirect( 740 m_webFrame, m_expectedClientRedirectSrc); 741 } 742 } 743 } 744 745 void FrameLoaderClientImpl::dispatchDidReceiveTitle(const StringWithDirection& title) 746 { 747 if (m_webFrame->client()) 748 m_webFrame->client()->didReceiveTitle(m_webFrame, title.string(), title.direction() == LTR ? WebTextDirectionLeftToRight : WebTextDirectionRightToLeft); 749 } 750 751 void FrameLoaderClientImpl::dispatchDidChangeIcons() 752 { 753 if (m_webFrame->client()) 754 m_webFrame->client()->didChangeIcons(m_webFrame); 755 } 756 757 void FrameLoaderClientImpl::dispatchDidCommitLoad() 758 { 759 WebViewImpl* webview = m_webFrame->viewImpl(); 760 bool isNewNavigation; 761 webview->didCommitLoad(&isNewNavigation); 762 763 if (m_webFrame->client()) 764 m_webFrame->client()->didCommitProvisionalLoad(m_webFrame, isNewNavigation); 765 } 766 767 void FrameLoaderClientImpl::dispatchDidFailProvisionalLoad( 768 const ResourceError& error) 769 { 770 771 // If a policy change occured, then we do not want to inform the plugin 772 // delegate. See http://b/907789 for details. FIXME: This means the 773 // plugin won't receive NPP_URLNotify, which seems like it could result in 774 // a memory leak in the plugin!! 775 if (error.domain() == internalErrorDomain 776 && error.errorCode() == PolicyChangeError) { 777 m_webFrame->didFail(cancelledError(error.failingURL()), true); 778 return; 779 } 780 781 OwnPtr<WebPluginLoadObserver> observer = pluginLoadObserver(); 782 m_webFrame->didFail(error, true); 783 if (observer) 784 observer->didFailLoading(error); 785 } 786 787 void FrameLoaderClientImpl::dispatchDidFailLoad(const ResourceError& error) 788 { 789 OwnPtr<WebPluginLoadObserver> observer = pluginLoadObserver(); 790 m_webFrame->didFail(error, false); 791 if (observer) 792 observer->didFailLoading(error); 793 794 // Don't clear the redirect chain, this will happen in the middle of client 795 // redirects, and we need the context. The chain will be cleared when the 796 // provisional load succeeds or fails, not the "real" one. 797 } 798 799 void FrameLoaderClientImpl::dispatchDidFinishLoad() 800 { 801 OwnPtr<WebPluginLoadObserver> observer = pluginLoadObserver(); 802 803 if (m_webFrame->client()) 804 m_webFrame->client()->didFinishLoad(m_webFrame); 805 806 if (observer) 807 observer->didFinishLoading(); 808 809 // Don't clear the redirect chain, this will happen in the middle of client 810 // redirects, and we need the context. The chain will be cleared when the 811 // provisional load succeeds or fails, not the "real" one. 812 } 813 814 void FrameLoaderClientImpl::dispatchDidFirstLayout() 815 { 816 if (m_webFrame->client()) 817 m_webFrame->client()->didFirstLayout(m_webFrame); 818 } 819 820 void FrameLoaderClientImpl::dispatchDidFirstVisuallyNonEmptyLayout() 821 { 822 if (m_webFrame->client()) 823 m_webFrame->client()->didFirstVisuallyNonEmptyLayout(m_webFrame); 824 } 825 826 Frame* FrameLoaderClientImpl::dispatchCreatePage(const NavigationAction& action) 827 { 828 struct WindowFeatures features; 829 Page* newPage = m_webFrame->frame()->page()->chrome()->createWindow( 830 m_webFrame->frame(), FrameLoadRequest(m_webFrame->frame()->document()->securityOrigin()), 831 features, action); 832 833 // Make sure that we have a valid disposition. This should have been set in 834 // the preceeding call to dispatchDecidePolicyForNewWindowAction. 835 ASSERT(m_nextNavigationPolicy != WebNavigationPolicyIgnore); 836 WebNavigationPolicy policy = m_nextNavigationPolicy; 837 m_nextNavigationPolicy = WebNavigationPolicyIgnore; 838 839 // createWindow can return null (e.g., popup blocker denies the window). 840 if (!newPage) 841 return 0; 842 843 WebViewImpl::fromPage(newPage)->setInitialNavigationPolicy(policy); 844 return newPage->mainFrame(); 845 } 846 847 void FrameLoaderClientImpl::dispatchShow() 848 { 849 WebViewImpl* webView = m_webFrame->viewImpl(); 850 if (webView && webView->client()) 851 webView->client()->show(webView->initialNavigationPolicy()); 852 } 853 854 void FrameLoaderClientImpl::dispatchDecidePolicyForResponse( 855 FramePolicyFunction function, 856 const ResourceResponse& response, 857 const ResourceRequest&) 858 { 859 PolicyAction action; 860 861 int statusCode = response.httpStatusCode(); 862 if (statusCode == 204 || statusCode == 205) { 863 // The server does not want us to replace the page contents. 864 action = PolicyIgnore; 865 } else if (WebCore::contentDispositionType(response.httpHeaderField("Content-Disposition")) == WebCore::ContentDispositionAttachment) { 866 // The server wants us to download instead of replacing the page contents. 867 // Downloading is handled by the embedder, but we still get the initial 868 // response so that we can ignore it and clean up properly. 869 action = PolicyIgnore; 870 } else if (!canShowMIMEType(response.mimeType())) { 871 // Make sure that we can actually handle this type internally. 872 action = PolicyIgnore; 873 } else { 874 // OK, we will render this page. 875 action = PolicyUse; 876 } 877 878 // NOTE: PolicyChangeError will be generated when action is not PolicyUse. 879 (m_webFrame->frame()->loader()->policyChecker()->*function)(action); 880 } 881 882 void FrameLoaderClientImpl::dispatchDecidePolicyForNewWindowAction( 883 FramePolicyFunction function, 884 const NavigationAction& action, 885 const ResourceRequest& request, 886 PassRefPtr<FormState> formState, 887 const String& frameName) 888 { 889 WebNavigationPolicy navigationPolicy; 890 if (!actionSpecifiesNavigationPolicy(action, &navigationPolicy)) 891 navigationPolicy = WebNavigationPolicyNewForegroundTab; 892 893 PolicyAction policyAction; 894 if (navigationPolicy == WebNavigationPolicyDownload) 895 policyAction = PolicyDownload; 896 else { 897 policyAction = PolicyUse; 898 899 // Remember the disposition for when dispatchCreatePage is called. It is 900 // unfortunate that WebCore does not provide us with any context when 901 // creating or showing the new window that would allow us to avoid having 902 // to keep this state. 903 m_nextNavigationPolicy = navigationPolicy; 904 } 905 (m_webFrame->frame()->loader()->policyChecker()->*function)(policyAction); 906 } 907 908 void FrameLoaderClientImpl::dispatchDecidePolicyForNavigationAction( 909 FramePolicyFunction function, 910 const NavigationAction& action, 911 const ResourceRequest& request, 912 PassRefPtr<FormState> formState) { 913 PolicyAction policyAction = PolicyIgnore; 914 915 // It is valid for this function to be invoked in code paths where the 916 // the webview is closed. 917 // The null check here is to fix a crash that seems strange 918 // (see - https://bugs.webkit.org/show_bug.cgi?id=23554). 919 if (m_webFrame->client() && !request.url().isNull()) { 920 WebNavigationPolicy navigationPolicy = WebNavigationPolicyCurrentTab; 921 actionSpecifiesNavigationPolicy(action, &navigationPolicy); 922 923 // Give the delegate a chance to change the navigation policy. 924 const WebDataSourceImpl* ds = m_webFrame->provisionalDataSourceImpl(); 925 if (ds) { 926 KURL url = ds->request().url(); 927 ASSERT(!url.protocolIs(backForwardNavigationScheme)); 928 929 bool isRedirect = ds->hasRedirectChain(); 930 931 WebNavigationType webnavType = 932 WebDataSourceImpl::toWebNavigationType(action.type()); 933 934 RefPtr<Node> node; 935 for (const Event* event = action.event(); event; event = event->underlyingEvent()) { 936 if (event->isMouseEvent()) { 937 const MouseEvent* mouseEvent = 938 static_cast<const MouseEvent*>(event); 939 node = m_webFrame->frame()->eventHandler()->hitTestResultAtPoint( 940 mouseEvent->absoluteLocation(), false).innerNonSharedNode(); 941 break; 942 } 943 } 944 WebNode originatingNode(node); 945 946 navigationPolicy = m_webFrame->client()->decidePolicyForNavigation( 947 m_webFrame, ds->request(), webnavType, originatingNode, 948 navigationPolicy, isRedirect); 949 } 950 951 if (navigationPolicy == WebNavigationPolicyCurrentTab) 952 policyAction = PolicyUse; 953 else if (navigationPolicy == WebNavigationPolicyDownload) 954 policyAction = PolicyDownload; 955 else { 956 if (navigationPolicy != WebNavigationPolicyIgnore) { 957 WrappedResourceRequest webreq(request); 958 m_webFrame->client()->loadURLExternally(m_webFrame, webreq, navigationPolicy); 959 } 960 policyAction = PolicyIgnore; 961 } 962 } 963 964 (m_webFrame->frame()->loader()->policyChecker()->*function)(policyAction); 965 } 966 967 void FrameLoaderClientImpl::cancelPolicyCheck() 968 { 969 // FIXME 970 } 971 972 void FrameLoaderClientImpl::dispatchUnableToImplementPolicy(const ResourceError& error) 973 { 974 m_webFrame->client()->unableToImplementPolicyWithError(m_webFrame, error); 975 } 976 977 void FrameLoaderClientImpl::dispatchWillSendSubmitEvent(HTMLFormElement* form) 978 { 979 if (m_webFrame->client()) 980 m_webFrame->client()->willSendSubmitEvent(m_webFrame, WebFormElement(form)); 981 } 982 983 void FrameLoaderClientImpl::dispatchWillSubmitForm(FramePolicyFunction function, 984 PassRefPtr<FormState> formState) 985 { 986 if (m_webFrame->client()) 987 m_webFrame->client()->willSubmitForm(m_webFrame, WebFormElement(formState->form())); 988 (m_webFrame->frame()->loader()->policyChecker()->*function)(PolicyUse); 989 } 990 991 void FrameLoaderClientImpl::dispatchDidLoadMainResource(DocumentLoader*) 992 { 993 // FIXME 994 } 995 996 void FrameLoaderClientImpl::revertToProvisionalState(DocumentLoader*) 997 { 998 m_hasRepresentation = true; 999 } 1000 1001 void FrameLoaderClientImpl::setMainDocumentError(DocumentLoader*, 1002 const ResourceError& error) 1003 { 1004 if (m_pluginWidget.get()) { 1005 if (m_sentInitialResponseToPlugin) { 1006 m_pluginWidget->didFailLoading(error); 1007 m_sentInitialResponseToPlugin = false; 1008 } 1009 m_pluginWidget = 0; 1010 } 1011 } 1012 1013 void FrameLoaderClientImpl::postProgressStartedNotification() 1014 { 1015 WebViewImpl* webview = m_webFrame->viewImpl(); 1016 if (webview && webview->client()) 1017 webview->client()->didStartLoading(); 1018 } 1019 1020 void FrameLoaderClientImpl::postProgressEstimateChangedNotification() 1021 { 1022 WebViewImpl* webview = m_webFrame->viewImpl(); 1023 if (webview && webview->client()) { 1024 webview->client()->didChangeLoadProgress( 1025 m_webFrame, m_webFrame->frame()->page()->progress()->estimatedProgress()); 1026 } 1027 1028 } 1029 1030 void FrameLoaderClientImpl::postProgressFinishedNotification() 1031 { 1032 // FIXME: why might the webview be null? http://b/1234461 1033 WebViewImpl* webview = m_webFrame->viewImpl(); 1034 if (webview && webview->client()) 1035 webview->client()->didStopLoading(); 1036 } 1037 1038 void FrameLoaderClientImpl::setMainFrameDocumentReady(bool ready) 1039 { 1040 // FIXME 1041 } 1042 1043 // Creates a new connection and begins downloading from that (contrast this 1044 // with |download|). 1045 void FrameLoaderClientImpl::startDownload(const ResourceRequest& request) 1046 { 1047 if (m_webFrame->client()) { 1048 WrappedResourceRequest webreq(request); 1049 m_webFrame->client()->loadURLExternally( 1050 m_webFrame, webreq, WebNavigationPolicyDownload); 1051 } 1052 } 1053 1054 void FrameLoaderClientImpl::willChangeTitle(DocumentLoader*) 1055 { 1056 // FIXME 1057 } 1058 1059 void FrameLoaderClientImpl::didChangeTitle(DocumentLoader*) 1060 { 1061 // FIXME 1062 } 1063 1064 // Called whenever data is received. 1065 void FrameLoaderClientImpl::committedLoad(DocumentLoader* loader, const char* data, int length) 1066 { 1067 if (!m_pluginWidget.get()) { 1068 if (m_webFrame->client()) { 1069 bool preventDefault = false; 1070 m_webFrame->client()->didReceiveDocumentData(m_webFrame, data, length, preventDefault); 1071 if (!preventDefault) 1072 m_webFrame->commitDocumentData(data, length); 1073 } 1074 } 1075 1076 // If we are sending data to MediaDocument, we should stop here 1077 // and cancel the request. 1078 if (m_webFrame->frame()->document()->isMediaDocument()) 1079 loader->cancelMainResourceLoad(pluginWillHandleLoadError(loader->response())); 1080 1081 // The plugin widget could have been created in the m_webFrame->DidReceiveData 1082 // function. 1083 if (m_pluginWidget.get()) { 1084 if (!m_sentInitialResponseToPlugin) { 1085 m_sentInitialResponseToPlugin = true; 1086 m_pluginWidget->didReceiveResponse( 1087 m_webFrame->frame()->loader()->activeDocumentLoader()->response()); 1088 } 1089 1090 // It's possible that the above call removed the pointer to the plugin, so 1091 // check before calling it. 1092 if (m_pluginWidget.get()) 1093 m_pluginWidget->didReceiveData(data, length); 1094 } 1095 } 1096 1097 void FrameLoaderClientImpl::finishedLoading(DocumentLoader* dl) 1098 { 1099 if (m_pluginWidget.get()) { 1100 m_pluginWidget->didFinishLoading(); 1101 m_pluginWidget = 0; 1102 m_sentInitialResponseToPlugin = false; 1103 } else { 1104 // This is necessary to create an empty document. See bug 634004. 1105 // However, we only want to do this if makeRepresentation has been called, to 1106 // match the behavior on the Mac. 1107 if (m_hasRepresentation) 1108 dl->writer()->setEncoding("", false); 1109 } 1110 } 1111 1112 void FrameLoaderClientImpl::updateGlobalHistory() 1113 { 1114 } 1115 1116 void FrameLoaderClientImpl::updateGlobalHistoryRedirectLinks() 1117 { 1118 } 1119 1120 bool FrameLoaderClientImpl::shouldGoToHistoryItem(HistoryItem* item) const 1121 { 1122 const KURL& url = item->url(); 1123 if (!url.protocolIs(backForwardNavigationScheme)) 1124 return true; 1125 1126 // Else, we'll punt this history navigation to the embedder. It is 1127 // necessary that we intercept this here, well before the FrameLoader 1128 // has made any state changes for this history traversal. 1129 1130 bool ok; 1131 int offset = url.lastPathComponent().toIntStrict(&ok); 1132 if (!ok) { 1133 ASSERT_NOT_REACHED(); 1134 return false; 1135 } 1136 1137 WebViewImpl* webview = m_webFrame->viewImpl(); 1138 if (webview->client()) 1139 webview->client()->navigateBackForwardSoon(offset); 1140 1141 return false; 1142 } 1143 1144 bool FrameLoaderClientImpl::shouldStopLoadingForHistoryItem(HistoryItem* targetItem) const 1145 { 1146 // Don't stop loading for pseudo-back-forward URLs, since they will get 1147 // translated and then pass through again. 1148 const KURL& url = targetItem->url(); 1149 return !url.protocolIs(backForwardNavigationScheme); 1150 } 1151 1152 void FrameLoaderClientImpl::dispatchDidAddBackForwardItem(HistoryItem*) const 1153 { 1154 } 1155 1156 void FrameLoaderClientImpl::dispatchDidRemoveBackForwardItem(HistoryItem*) const 1157 { 1158 } 1159 1160 void FrameLoaderClientImpl::dispatchDidChangeBackForwardIndex() const 1161 { 1162 } 1163 1164 void FrameLoaderClientImpl::didDisplayInsecureContent() 1165 { 1166 if (m_webFrame->client()) 1167 m_webFrame->client()->didDisplayInsecureContent(m_webFrame); 1168 } 1169 1170 void FrameLoaderClientImpl::didRunInsecureContent(SecurityOrigin* origin, const KURL& insecureURL) 1171 { 1172 if (m_webFrame->client()) 1173 m_webFrame->client()->didRunInsecureContent(m_webFrame, WebSecurityOrigin(origin), insecureURL); 1174 } 1175 1176 ResourceError FrameLoaderClientImpl::blockedError(const ResourceRequest&) 1177 { 1178 // FIXME 1179 return ResourceError(); 1180 } 1181 1182 ResourceError FrameLoaderClientImpl::cancelledError(const ResourceRequest& request) 1183 { 1184 if (!m_webFrame->client()) 1185 return ResourceError(); 1186 1187 return m_webFrame->client()->cancelledError( 1188 m_webFrame, WrappedResourceRequest(request)); 1189 } 1190 1191 ResourceError FrameLoaderClientImpl::cannotShowURLError(const ResourceRequest& request) 1192 { 1193 if (!m_webFrame->client()) 1194 return ResourceError(); 1195 1196 return m_webFrame->client()->cannotHandleRequestError( 1197 m_webFrame, WrappedResourceRequest(request)); 1198 } 1199 1200 ResourceError FrameLoaderClientImpl::interruptForPolicyChangeError( 1201 const ResourceRequest& request) 1202 { 1203 return ResourceError(internalErrorDomain, PolicyChangeError, 1204 request.url().string(), String()); 1205 } 1206 1207 ResourceError FrameLoaderClientImpl::cannotShowMIMETypeError(const ResourceResponse&) 1208 { 1209 // FIXME 1210 return ResourceError(); 1211 } 1212 1213 ResourceError FrameLoaderClientImpl::fileDoesNotExistError(const ResourceResponse&) 1214 { 1215 // FIXME 1216 return ResourceError(); 1217 } 1218 1219 ResourceError FrameLoaderClientImpl::pluginWillHandleLoadError(const ResourceResponse&) 1220 { 1221 // FIXME 1222 return ResourceError(); 1223 } 1224 1225 bool FrameLoaderClientImpl::shouldFallBack(const ResourceError& error) 1226 { 1227 // This method is called when we fail to load the URL for an <object> tag 1228 // that has fallback content (child elements) and is being loaded as a frame. 1229 // The error parameter indicates the reason for the load failure. 1230 // We should let the fallback content load only if this wasn't a cancelled 1231 // request. 1232 // Note: The mac version also has a case for "WebKitErrorPluginWillHandleLoad" 1233 ResourceError c = cancelledError(ResourceRequest()); 1234 return error.errorCode() != c.errorCode() || error.domain() != c.domain(); 1235 } 1236 1237 bool FrameLoaderClientImpl::canHandleRequest(const ResourceRequest& request) const 1238 { 1239 return m_webFrame->client()->canHandleRequest( 1240 m_webFrame, WrappedResourceRequest(request)); 1241 } 1242 1243 bool FrameLoaderClientImpl::canShowMIMETypeAsHTML(const String& MIMEType) const 1244 { 1245 notImplemented(); 1246 return false; 1247 } 1248 1249 bool FrameLoaderClientImpl::canShowMIMEType(const String& mimeType) const 1250 { 1251 // This method is called to determine if the media type can be shown 1252 // "internally" (i.e. inside the browser) regardless of whether or not the 1253 // browser or a plugin is doing the rendering. 1254 1255 // mimeType strings are supposed to be ASCII, but if they are not for some 1256 // reason, then it just means that the mime type will fail all of these "is 1257 // supported" checks and go down the path of an unhandled mime type. 1258 if (webKitClient()->mimeRegistry()->supportsMIMEType(mimeType) == WebMimeRegistry::IsSupported) 1259 return true; 1260 1261 // If Chrome is started with the --disable-plugins switch, pluginData is null. 1262 PluginData* pluginData = m_webFrame->frame()->page()->pluginData(); 1263 1264 // See if the type is handled by an installed plugin, if so, we can show it. 1265 // FIXME: (http://b/1085524) This is the place to stick a preference to 1266 // disable full page plugins (optionally for certain types!) 1267 return !mimeType.isEmpty() && pluginData && pluginData->supportsMimeType(mimeType); 1268 } 1269 1270 bool FrameLoaderClientImpl::representationExistsForURLScheme(const String&) const 1271 { 1272 // FIXME 1273 return false; 1274 } 1275 1276 String FrameLoaderClientImpl::generatedMIMETypeForURLScheme(const String& scheme) const 1277 { 1278 // This appears to generate MIME types for protocol handlers that are handled 1279 // internally. The only place I can find in the WebKit code that uses this 1280 // function is WebView::registerViewClass, where it is used as part of the 1281 // process by which custom view classes for certain document representations 1282 // are registered. 1283 String mimeType("x-apple-web-kit/"); 1284 mimeType.append(scheme.lower()); 1285 return mimeType; 1286 } 1287 1288 void FrameLoaderClientImpl::frameLoadCompleted() 1289 { 1290 // FIXME: the mac port also conditionally calls setDrawsBackground:YES on 1291 // it's ScrollView here. 1292 1293 // This comment from the Mac port: 1294 // Note: Can be called multiple times. 1295 // Even if already complete, we might have set a previous item on a frame that 1296 // didn't do any data loading on the past transaction. Make sure to clear these out. 1297 1298 // FIXME: setPreviousHistoryItem() no longer exists. http://crbug.com/8566 1299 // m_webFrame->frame()->loader()->setPreviousHistoryItem(0); 1300 } 1301 1302 void FrameLoaderClientImpl::saveViewStateToItem(HistoryItem*) 1303 { 1304 // FIXME 1305 } 1306 1307 void FrameLoaderClientImpl::restoreViewState() 1308 { 1309 // FIXME: probably scrolls to last position when you go back or forward 1310 } 1311 1312 void FrameLoaderClientImpl::provisionalLoadStarted() 1313 { 1314 // FIXME: On mac, this does various caching stuff 1315 } 1316 1317 void FrameLoaderClientImpl::didFinishLoad() 1318 { 1319 OwnPtr<WebPluginLoadObserver> observer = pluginLoadObserver(); 1320 if (observer) 1321 observer->didFinishLoading(); 1322 } 1323 1324 void FrameLoaderClientImpl::prepareForDataSourceReplacement() 1325 { 1326 // FIXME 1327 } 1328 1329 PassRefPtr<DocumentLoader> FrameLoaderClientImpl::createDocumentLoader( 1330 const ResourceRequest& request, 1331 const SubstituteData& data) 1332 { 1333 RefPtr<WebDataSourceImpl> ds = WebDataSourceImpl::create(request, data); 1334 if (m_webFrame->client()) 1335 m_webFrame->client()->didCreateDataSource(m_webFrame, ds.get()); 1336 return ds.release(); 1337 } 1338 1339 void FrameLoaderClientImpl::setTitle(const StringWithDirection& title, const KURL& url) 1340 { 1341 // FIXME: inform consumer of changes to the title. 1342 } 1343 1344 String FrameLoaderClientImpl::userAgent(const KURL& url) 1345 { 1346 return webKitClient()->userAgent(url); 1347 } 1348 1349 void FrameLoaderClientImpl::savePlatformDataToCachedFrame(CachedFrame*) 1350 { 1351 // The page cache should be disabled. 1352 ASSERT_NOT_REACHED(); 1353 } 1354 1355 void FrameLoaderClientImpl::transitionToCommittedFromCachedFrame(CachedFrame*) 1356 { 1357 ASSERT_NOT_REACHED(); 1358 } 1359 1360 // Called when the FrameLoader goes into a state in which a new page load 1361 // will occur. 1362 void FrameLoaderClientImpl::transitionToCommittedForNewPage() 1363 { 1364 makeDocumentView(); 1365 } 1366 1367 void FrameLoaderClientImpl::didSaveToPageCache() 1368 { 1369 } 1370 1371 void FrameLoaderClientImpl::didRestoreFromPageCache() 1372 { 1373 } 1374 1375 void FrameLoaderClientImpl::dispatchDidBecomeFrameset(bool) 1376 { 1377 } 1378 1379 bool FrameLoaderClientImpl::canCachePage() const 1380 { 1381 // Since we manage the cache, always report this page as non-cacheable to 1382 // FrameLoader. 1383 return false; 1384 } 1385 1386 // Downloading is handled in the browser process, not WebKit. If we get to this 1387 // point, our download detection code in the ResourceDispatcherHost is broken! 1388 void FrameLoaderClientImpl::download(ResourceHandle* handle, 1389 const ResourceRequest& request, 1390 const ResourceRequest& initialRequest, 1391 const ResourceResponse& response) 1392 { 1393 ASSERT_NOT_REACHED(); 1394 } 1395 1396 PassRefPtr<Frame> FrameLoaderClientImpl::createFrame( 1397 const KURL& url, 1398 const String& name, 1399 HTMLFrameOwnerElement* ownerElement, 1400 const String& referrer, 1401 bool allowsScrolling, 1402 int marginWidth, 1403 int marginHeight) 1404 { 1405 FrameLoadRequest frameRequest(m_webFrame->frame()->document()->securityOrigin(), 1406 ResourceRequest(url, referrer), name); 1407 return m_webFrame->createChildFrame(frameRequest, ownerElement); 1408 } 1409 1410 void FrameLoaderClientImpl::didTransferChildFrameToNewDocument(Page*) 1411 { 1412 ASSERT(m_webFrame->frame()->ownerElement()); 1413 1414 WebFrameImpl* newParent = static_cast<WebFrameImpl*>(m_webFrame->parent()); 1415 if (!newParent || !newParent->client()) 1416 return; 1417 1418 // Replace the client since the old client may be destroyed when the 1419 // previous page is closed. 1420 m_webFrame->setClient(newParent->client()); 1421 } 1422 1423 void FrameLoaderClientImpl::transferLoadingResourceFromPage(unsigned long identifier, DocumentLoader* loader, const ResourceRequest& request, Page* oldPage) 1424 { 1425 assignIdentifierToInitialRequest(identifier, loader, request); 1426 1427 WebFrameImpl* oldWebFrame = WebFrameImpl::fromFrame(oldPage->mainFrame()); 1428 if (oldWebFrame && oldWebFrame->client()) 1429 oldWebFrame->client()->removeIdentifierForRequest(identifier); 1430 } 1431 1432 PassRefPtr<Widget> FrameLoaderClientImpl::createPlugin( 1433 const IntSize& size, // FIXME: how do we use this? 1434 HTMLPlugInElement* element, 1435 const KURL& url, 1436 const Vector<String>& paramNames, 1437 const Vector<String>& paramValues, 1438 const String& mimeType, 1439 bool loadManually) 1440 { 1441 if (!m_webFrame->client()) 1442 return 0; 1443 1444 WebPluginParams params; 1445 params.url = url; 1446 params.mimeType = mimeType; 1447 params.attributeNames = paramNames; 1448 params.attributeValues = paramValues; 1449 params.loadManually = loadManually; 1450 1451 WebPlugin* webPlugin = m_webFrame->client()->createPlugin(m_webFrame, params); 1452 if (!webPlugin) 1453 return 0; 1454 1455 // The container takes ownership of the WebPlugin. 1456 RefPtr<WebPluginContainerImpl> container = 1457 WebPluginContainerImpl::create(element, webPlugin); 1458 1459 if (!webPlugin->initialize(container.get())) 1460 return 0; 1461 1462 // The element might have been removed during plugin initialization! 1463 if (!element->renderer()) 1464 return 0; 1465 1466 return container; 1467 } 1468 1469 // This method gets called when a plugin is put in place of html content 1470 // (e.g., acrobat reader). 1471 void FrameLoaderClientImpl::redirectDataToPlugin(Widget* pluginWidget) 1472 { 1473 if (pluginWidget->isPluginContainer()) 1474 m_pluginWidget = static_cast<WebPluginContainerImpl*>(pluginWidget); 1475 ASSERT(m_pluginWidget.get()); 1476 } 1477 1478 PassRefPtr<Widget> FrameLoaderClientImpl::createJavaAppletWidget( 1479 const IntSize& size, 1480 HTMLAppletElement* element, 1481 const KURL& /* baseURL */, 1482 const Vector<String>& paramNames, 1483 const Vector<String>& paramValues) 1484 { 1485 return createPlugin(size, element, KURL(), paramNames, paramValues, 1486 "application/x-java-applet", false); 1487 } 1488 1489 ObjectContentType FrameLoaderClientImpl::objectContentType( 1490 const KURL& url, 1491 const String& explicitMimeType, 1492 bool shouldPreferPlugInsForImages) 1493 { 1494 // This code is based on Apple's implementation from 1495 // WebCoreSupport/WebFrameBridge.mm. 1496 1497 String mimeType = explicitMimeType; 1498 if (mimeType.isEmpty()) { 1499 // Try to guess the MIME type based off the extension. 1500 String filename = url.lastPathComponent(); 1501 int extensionPos = filename.reverseFind('.'); 1502 if (extensionPos >= 0) { 1503 String extension = filename.substring(extensionPos + 1); 1504 mimeType = MIMETypeRegistry::getMIMETypeForExtension(extension); 1505 if (mimeType.isEmpty()) { 1506 // If there's no mimetype registered for the extension, check to see 1507 // if a plugin can handle the extension. 1508 mimeType = getPluginMimeTypeFromExtension(extension); 1509 } 1510 } 1511 1512 if (mimeType.isEmpty()) 1513 return ObjectContentFrame; 1514 } 1515 1516 // If Chrome is started with the --disable-plugins switch, pluginData is 0. 1517 PluginData* pluginData = m_webFrame->frame()->page()->pluginData(); 1518 bool plugInSupportsMIMEType = pluginData && pluginData->supportsMimeType(mimeType); 1519 1520 if (MIMETypeRegistry::isSupportedImageMIMEType(mimeType)) 1521 return shouldPreferPlugInsForImages && plugInSupportsMIMEType ? ObjectContentNetscapePlugin : ObjectContentImage; 1522 1523 if (plugInSupportsMIMEType) 1524 return ObjectContentNetscapePlugin; 1525 1526 if (MIMETypeRegistry::isSupportedNonImageMIMEType(mimeType)) 1527 return ObjectContentFrame; 1528 1529 return ObjectContentNone; 1530 } 1531 1532 String FrameLoaderClientImpl::overrideMediaType() const 1533 { 1534 // FIXME 1535 return String(); 1536 } 1537 1538 bool FrameLoaderClientImpl::actionSpecifiesNavigationPolicy( 1539 const NavigationAction& action, 1540 WebNavigationPolicy* policy) 1541 { 1542 const MouseEvent* event = 0; 1543 if (action.type() == NavigationTypeLinkClicked 1544 && action.event()->isMouseEvent()) 1545 event = static_cast<const MouseEvent*>(action.event()); 1546 else if (action.type() == NavigationTypeFormSubmitted 1547 && action.event() 1548 && action.event()->underlyingEvent() 1549 && action.event()->underlyingEvent()->isMouseEvent()) 1550 event = static_cast<const MouseEvent*>(action.event()->underlyingEvent()); 1551 1552 if (!event) 1553 return false; 1554 1555 return WebViewImpl::navigationPolicyFromMouseEvent( 1556 event->button(), event->ctrlKey(), event->shiftKey(), event->altKey(), 1557 event->metaKey(), policy); 1558 } 1559 1560 PassOwnPtr<WebPluginLoadObserver> FrameLoaderClientImpl::pluginLoadObserver() 1561 { 1562 WebDataSourceImpl* ds = WebDataSourceImpl::fromDocumentLoader( 1563 m_webFrame->frame()->loader()->activeDocumentLoader()); 1564 if (!ds) { 1565 // We can arrive here if a popstate event handler detaches this frame. 1566 // FIXME: Remove this code once http://webkit.org/b/36202 is fixed. 1567 ASSERT(!m_webFrame->frame()->page()); 1568 return 0; 1569 } 1570 return ds->releasePluginLoadObserver(); 1571 } 1572 1573 PassRefPtr<FrameNetworkingContext> FrameLoaderClientImpl::createNetworkingContext() 1574 { 1575 return FrameNetworkingContextImpl::create(m_webFrame->frame()); 1576 } 1577 1578 } // namespace WebKit 1579