• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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