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