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