OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/browser/web_contents/render_view_host_manager.h" | 5 #include "content/browser/web_contents/render_view_host_manager.h" |
6 | 6 |
7 #include <utility> | 7 #include <utility> |
8 | 8 |
9 #include "base/command_line.h" | 9 #include "base/command_line.h" |
10 #include "base/debug/trace_event.h" | 10 #include "base/debug/trace_event.h" |
(...skipping 15 matching lines...) Expand all Loading... |
26 #include "content/public/browser/notification_types.h" | 26 #include "content/public/browser/notification_types.h" |
27 #include "content/public/browser/render_widget_host_iterator.h" | 27 #include "content/public/browser/render_widget_host_iterator.h" |
28 #include "content/public/browser/user_metrics.h" | 28 #include "content/public/browser/user_metrics.h" |
29 #include "content/public/browser/web_contents_view.h" | 29 #include "content/public/browser/web_contents_view.h" |
30 #include "content/public/browser/web_ui_controller.h" | 30 #include "content/public/browser/web_ui_controller.h" |
31 #include "content/public/common/content_switches.h" | 31 #include "content/public/common/content_switches.h" |
32 #include "content/public/common/url_constants.h" | 32 #include "content/public/common/url_constants.h" |
33 | 33 |
34 namespace content { | 34 namespace content { |
35 | 35 |
36 RenderViewHostManager::PendingNavigationParams::PendingNavigationParams() { | 36 RenderViewHostManager::PendingNavigationParams::PendingNavigationParams() |
| 37 : is_transfer(false), frame_id(-1) { |
37 } | 38 } |
38 | 39 |
39 RenderViewHostManager::PendingNavigationParams::PendingNavigationParams( | 40 RenderViewHostManager::PendingNavigationParams::PendingNavigationParams( |
40 const GlobalRequestID& global_request_id) | 41 const GlobalRequestID& global_request_id, |
41 : global_request_id(global_request_id) { | 42 bool is_transfer, |
| 43 const GURL& transfer_url, |
| 44 Referrer referrer, |
| 45 int64 frame_id) |
| 46 : global_request_id(global_request_id), |
| 47 is_transfer(is_transfer), |
| 48 transfer_url(transfer_url), |
| 49 referrer(referrer), |
| 50 frame_id(frame_id) { |
42 } | 51 } |
43 | 52 |
44 RenderViewHostManager::RenderViewHostManager( | 53 RenderViewHostManager::RenderViewHostManager( |
45 RenderViewHostDelegate* render_view_delegate, | 54 RenderViewHostDelegate* render_view_delegate, |
46 RenderWidgetHostDelegate* render_widget_delegate, | 55 RenderWidgetHostDelegate* render_widget_delegate, |
47 Delegate* delegate) | 56 Delegate* delegate) |
48 : delegate_(delegate), | 57 : delegate_(delegate), |
49 cross_navigation_pending_(false), | 58 cross_navigation_pending_(false), |
50 render_view_delegate_(render_view_delegate), | 59 render_view_delegate_(render_view_delegate), |
51 render_widget_delegate_(render_widget_delegate), | 60 render_widget_delegate_(render_widget_delegate), |
(...skipping 180 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
232 void RenderViewHostManager::SwappedOut(RenderViewHost* render_view_host) { | 241 void RenderViewHostManager::SwappedOut(RenderViewHost* render_view_host) { |
233 // Make sure this is from our current RVH, and that we have a pending | 242 // Make sure this is from our current RVH, and that we have a pending |
234 // navigation from OnCrossSiteResponse. (There may be no pending navigation | 243 // navigation from OnCrossSiteResponse. (There may be no pending navigation |
235 // for data URLs that don't make network requests, for example.) If not, | 244 // for data URLs that don't make network requests, for example.) If not, |
236 // just return early and ignore. | 245 // just return early and ignore. |
237 if (render_view_host != render_view_host_ || !pending_nav_params_.get()) { | 246 if (render_view_host != render_view_host_ || !pending_nav_params_.get()) { |
238 pending_nav_params_.reset(); | 247 pending_nav_params_.reset(); |
239 return; | 248 return; |
240 } | 249 } |
241 | 250 |
242 // Now that the unload handler has run, we need to resume the paused response. | 251 // Now that the unload handler has run, we need to either initiate the |
243 if (pending_render_view_host_) { | 252 // pending transfer (if there is one) or resume the paused response (if not). |
| 253 // TODO(creis): The blank swapped out page is visible during this time, but |
| 254 // we can shorten this by delivering the response directly, rather than |
| 255 // forcing an identical request to be made. |
| 256 if (pending_nav_params_->is_transfer) { |
| 257 // We don't know whether the original request had |user_action| set to true. |
| 258 // However, since we force the navigation to be in the current tab, it |
| 259 // doesn't matter. |
| 260 render_view_host->GetDelegate()->RequestTransferURL( |
| 261 pending_nav_params_->transfer_url, |
| 262 pending_nav_params_->referrer, |
| 263 CURRENT_TAB, |
| 264 pending_nav_params_->frame_id, |
| 265 pending_nav_params_->global_request_id, |
| 266 false, |
| 267 true); |
| 268 } else if (pending_render_view_host_) { |
244 RenderProcessHostImpl* pending_process = | 269 RenderProcessHostImpl* pending_process = |
245 static_cast<RenderProcessHostImpl*>( | 270 static_cast<RenderProcessHostImpl*>( |
246 pending_render_view_host_->GetProcess()); | 271 pending_render_view_host_->GetProcess()); |
247 pending_process->ResumeDeferredNavigation( | 272 pending_process->ResumeDeferredNavigation( |
248 pending_nav_params_->global_request_id); | 273 pending_nav_params_->global_request_id); |
249 } | 274 } |
250 pending_nav_params_.reset(); | 275 pending_nav_params_.reset(); |
251 } | 276 } |
252 | 277 |
253 void RenderViewHostManager::DidNavigateMainFrame( | 278 void RenderViewHostManager::DidNavigateMainFrame( |
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
363 | 388 |
364 if (proceed_to_fire_unload) { | 389 if (proceed_to_fire_unload) { |
365 // This is not a cross-site navigation, the tab is being closed. | 390 // This is not a cross-site navigation, the tab is being closed. |
366 render_view_host_->ClosePage(); | 391 render_view_host_->ClosePage(); |
367 } | 392 } |
368 } | 393 } |
369 } | 394 } |
370 | 395 |
371 void RenderViewHostManager::OnCrossSiteResponse( | 396 void RenderViewHostManager::OnCrossSiteResponse( |
372 RenderViewHost* pending_render_view_host, | 397 RenderViewHost* pending_render_view_host, |
373 const GlobalRequestID& global_request_id) { | 398 const GlobalRequestID& global_request_id, |
374 // This should be called when the pending RVH is ready to commit. | 399 bool is_transfer, |
375 DCHECK_EQ(pending_render_view_host_, pending_render_view_host); | 400 const GURL& transfer_url, |
| 401 const Referrer& referrer, |
| 402 int64 frame_id) { |
| 403 // This should be called either when the pending RVH is ready to commit or |
| 404 // when we realize that the current RVH's request requires a transfer. |
| 405 DCHECK( |
| 406 pending_render_view_host == pending_render_view_host_ || |
| 407 pending_render_view_host == render_view_host_); |
376 | 408 |
377 // Remember the request ID until the unload handler has run. | 409 // TODO(creis): Eventually we will want to check all navigation responses |
378 pending_nav_params_.reset(new PendingNavigationParams(global_request_id)); | 410 // here, but currently we pass information for a transfer if |
| 411 // ShouldSwapProcessesForRedirect returned true in the network stack. |
| 412 // In that case, we should set up a transfer after the unload handler runs. |
| 413 // If is_transfer is false, we will just run the unload handler and resume. |
| 414 pending_nav_params_.reset(new PendingNavigationParams( |
| 415 global_request_id, is_transfer, transfer_url, referrer, frame_id)); |
379 | 416 |
380 // Run the unload handler of the current page. | 417 // Run the unload handler of the current page. |
381 SwapOutOldPage(); | 418 SwapOutOldPage(); |
382 } | 419 } |
383 | 420 |
384 void RenderViewHostManager::SwapOutOldPage() { | 421 void RenderViewHostManager::SwapOutOldPage() { |
385 // Should only see this while we have a pending renderer. | 422 // Should only see this while we have a pending renderer or transfer. |
386 if (!cross_navigation_pending_) | 423 CHECK(cross_navigation_pending_ || pending_nav_params_.get()); |
387 return; | |
388 DCHECK(pending_render_view_host_); | |
389 | 424 |
390 // Tell the old renderer it is being swapped out. This will fire the unload | 425 // Tell the old renderer it is being swapped out. This will fire the unload |
391 // handler (without firing the beforeunload handler a second time). When the | 426 // handler (without firing the beforeunload handler a second time). When the |
392 // unload handler finishes and the navigation completes, we will send a | 427 // unload handler finishes and the navigation completes, we will send a |
393 // message to the ResourceDispatcherHost, allowing the pending RVH's response | 428 // message to the ResourceDispatcherHost, allowing the pending RVH's response |
394 // to resume. | 429 // to resume. |
395 render_view_host_->SwapOut(); | 430 render_view_host_->SwapOut(); |
396 | 431 |
397 // ResourceDispatcherHost has told us to run the onunload handler, which | 432 // ResourceDispatcherHost has told us to run the onunload handler, which |
398 // means it is not a download or unsafe page, and we are going to perform the | 433 // means it is not a download or unsafe page, and we are going to perform the |
399 // navigation. Thus, we no longer need to remember that the RenderViewHost | 434 // navigation. Thus, we no longer need to remember that the RenderViewHost |
400 // is part of a pending cross-site request. | 435 // is part of a pending cross-site request. |
401 pending_render_view_host_->SetHasPendingCrossSiteRequest(false); | 436 if (pending_render_view_host_) |
| 437 pending_render_view_host_->SetHasPendingCrossSiteRequest(false); |
402 } | 438 } |
403 | 439 |
404 void RenderViewHostManager::Observe( | 440 void RenderViewHostManager::Observe( |
405 int type, | 441 int type, |
406 const NotificationSource& source, | 442 const NotificationSource& source, |
407 const NotificationDetails& details) { | 443 const NotificationDetails& details) { |
408 switch (type) { | 444 switch (type) { |
409 case NOTIFICATION_RENDERER_PROCESS_CLOSED: | 445 case NOTIFICATION_RENDERER_PROCESS_CLOSED: |
410 case NOTIFICATION_RENDERER_PROCESS_CLOSING: | 446 case NOTIFICATION_RENDERER_PROCESS_CLOSING: |
411 RendererProcessClosing( | 447 RendererProcessClosing( |
(...skipping 497 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
909 | 945 |
910 // We need to wait until the beforeunload handler has run, unless we are | 946 // We need to wait until the beforeunload handler has run, unless we are |
911 // transferring an existing request (in which case it has already run). | 947 // transferring an existing request (in which case it has already run). |
912 // Suspend the new render view (i.e., don't let it send the cross-site | 948 // Suspend the new render view (i.e., don't let it send the cross-site |
913 // Navigate message) until we hear back from the old renderer's | 949 // Navigate message) until we hear back from the old renderer's |
914 // beforeunload handler. If the handler returns false, we'll have to | 950 // beforeunload handler. If the handler returns false, we'll have to |
915 // cancel the request. | 951 // cancel the request. |
916 DCHECK(!pending_render_view_host_->are_navigations_suspended()); | 952 DCHECK(!pending_render_view_host_->are_navigations_suspended()); |
917 bool is_transfer = | 953 bool is_transfer = |
918 entry.transferred_global_request_id() != GlobalRequestID(); | 954 entry.transferred_global_request_id() != GlobalRequestID(); |
919 if (!is_transfer) { | 955 if (is_transfer) { |
| 956 // We don't need to stop the old renderer or run beforeunload/unload |
| 957 // handlers, because those have already been done. |
| 958 DCHECK(pending_nav_params_->global_request_id == |
| 959 entry.transferred_global_request_id()); |
| 960 } else { |
920 // Also make sure the old render view stops, in case a load is in | 961 // Also make sure the old render view stops, in case a load is in |
921 // progress. (We don't want to do this for transfers, since it will | 962 // progress. (We don't want to do this for transfers, since it will |
922 // interrupt the transfer with an unexpected DidStopLoading.) | 963 // interrupt the transfer with an unexpected DidStopLoading.) |
923 render_view_host_->Send( | 964 render_view_host_->Send( |
924 new ViewMsg_Stop(render_view_host_->GetRoutingID())); | 965 new ViewMsg_Stop(render_view_host_->GetRoutingID())); |
925 | 966 |
926 pending_render_view_host_->SetNavigationsSuspended(true, | 967 pending_render_view_host_->SetNavigationsSuspended(true, |
927 base::TimeTicks()); | 968 base::TimeTicks()); |
| 969 |
| 970 // Tell the CrossSiteRequestManager that this RVH has a pending cross-site |
| 971 // request, so that ResourceDispatcherHost will know to tell us to run the |
| 972 // old page's unload handler before it sends the response. |
| 973 pending_render_view_host_->SetHasPendingCrossSiteRequest(true); |
928 } | 974 } |
929 | 975 |
930 // Tell the CrossSiteRequestManager that this RVH has a pending cross-site | |
931 // request, so that ResourceDispatcherHost will know to tell us to run the | |
932 // old page's unload handler before it sends the response. | |
933 pending_render_view_host_->SetHasPendingCrossSiteRequest(true); | |
934 | |
935 // We now have a pending RVH. | 976 // We now have a pending RVH. |
936 DCHECK(!cross_navigation_pending_); | 977 DCHECK(!cross_navigation_pending_); |
937 cross_navigation_pending_ = true; | 978 cross_navigation_pending_ = true; |
938 | 979 |
939 // Unless we are transferring an existing request, we should now | 980 // Unless we are transferring an existing request, we should now |
940 // tell the old render view to run its beforeunload handler, since it | 981 // tell the old render view to run its beforeunload handler, since it |
941 // doesn't otherwise know that the cross-site request is happening. This | 982 // doesn't otherwise know that the cross-site request is happening. This |
942 // will trigger a call to ShouldClosePage with the reply. | 983 // will trigger a call to ShouldClosePage with the reply. |
943 if (!is_transfer) | 984 if (!is_transfer) |
944 render_view_host_->FirePageBeforeUnload(true); | 985 render_view_host_->FirePageBeforeUnload(true); |
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1045 RenderViewHostImpl* RenderViewHostManager::GetSwappedOutRenderViewHost( | 1086 RenderViewHostImpl* RenderViewHostManager::GetSwappedOutRenderViewHost( |
1046 SiteInstance* instance) { | 1087 SiteInstance* instance) { |
1047 RenderViewHostMap::iterator iter = swapped_out_hosts_.find(instance->GetId()); | 1088 RenderViewHostMap::iterator iter = swapped_out_hosts_.find(instance->GetId()); |
1048 if (iter != swapped_out_hosts_.end()) | 1089 if (iter != swapped_out_hosts_.end()) |
1049 return iter->second; | 1090 return iter->second; |
1050 | 1091 |
1051 return NULL; | 1092 return NULL; |
1052 } | 1093 } |
1053 | 1094 |
1054 } // namespace content | 1095 } // namespace content |
OLD | NEW |