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