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