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