1 // Copyright 2013 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "content/browser/frame_host/render_frame_host_impl.h" 6 7 #include "base/bind.h" 8 #include "base/command_line.h" 9 #include "base/containers/hash_tables.h" 10 #include "base/lazy_instance.h" 11 #include "base/metrics/histogram.h" 12 #include "base/metrics/user_metrics_action.h" 13 #include "base/time/time.h" 14 #include "content/browser/accessibility/accessibility_mode_helper.h" 15 #include "content/browser/accessibility/browser_accessibility_manager.h" 16 #include "content/browser/accessibility/browser_accessibility_state_impl.h" 17 #include "content/browser/child_process_security_policy_impl.h" 18 #include "content/browser/frame_host/cross_process_frame_connector.h" 19 #include "content/browser/frame_host/cross_site_transferring_request.h" 20 #include "content/browser/frame_host/frame_accessibility.h" 21 #include "content/browser/frame_host/frame_tree.h" 22 #include "content/browser/frame_host/frame_tree_node.h" 23 #include "content/browser/frame_host/navigator.h" 24 #include "content/browser/frame_host/render_frame_host_delegate.h" 25 #include "content/browser/frame_host/render_frame_proxy_host.h" 26 #include "content/browser/frame_host/render_widget_host_view_child_frame.h" 27 #include "content/browser/renderer_host/input/input_router.h" 28 #include "content/browser/renderer_host/input/timeout_monitor.h" 29 #include "content/browser/renderer_host/render_process_host_impl.h" 30 #include "content/browser/renderer_host/render_view_host_delegate.h" 31 #include "content/browser/renderer_host/render_view_host_delegate_view.h" 32 #include "content/browser/renderer_host/render_view_host_impl.h" 33 #include "content/browser/renderer_host/render_widget_host_impl.h" 34 #include "content/browser/renderer_host/render_widget_host_view_base.h" 35 #include "content/browser/transition_request_manager.h" 36 #include "content/common/accessibility_messages.h" 37 #include "content/common/desktop_notification_messages.h" 38 #include "content/common/frame_messages.h" 39 #include "content/common/input_messages.h" 40 #include "content/common/inter_process_time_ticks_converter.h" 41 #include "content/common/platform_notification_messages.h" 42 #include "content/common/render_frame_setup.mojom.h" 43 #include "content/common/swapped_out_messages.h" 44 #include "content/public/browser/ax_event_notification_details.h" 45 #include "content/public/browser/browser_accessibility_state.h" 46 #include "content/public/browser/browser_context.h" 47 #include "content/public/browser/browser_plugin_guest_manager.h" 48 #include "content/public/browser/browser_thread.h" 49 #include "content/public/browser/content_browser_client.h" 50 #include "content/public/browser/desktop_notification_delegate.h" 51 #include "content/public/browser/render_process_host.h" 52 #include "content/public/browser/render_widget_host_view.h" 53 #include "content/public/browser/user_metrics.h" 54 #include "content/public/common/content_constants.h" 55 #include "content/public/common/content_switches.h" 56 #include "content/public/common/url_constants.h" 57 #include "content/public/common/url_utils.h" 58 #include "ui/accessibility/ax_tree.h" 59 #include "url/gurl.h" 60 61 #if defined(OS_MACOSX) 62 #include "content/browser/frame_host/popup_menu_helper_mac.h" 63 #endif 64 65 using base::TimeDelta; 66 67 namespace content { 68 69 namespace { 70 71 // The next value to use for the accessibility reset token. 72 int g_next_accessibility_reset_token = 1; 73 74 // The (process id, routing id) pair that identifies one RenderFrame. 75 typedef std::pair<int32, int32> RenderFrameHostID; 76 typedef base::hash_map<RenderFrameHostID, RenderFrameHostImpl*> 77 RoutingIDFrameMap; 78 base::LazyInstance<RoutingIDFrameMap> g_routing_id_frame_map = 79 LAZY_INSTANCE_INITIALIZER; 80 81 class DesktopNotificationDelegateImpl : public DesktopNotificationDelegate { 82 public: 83 DesktopNotificationDelegateImpl(RenderFrameHost* render_frame_host, 84 int notification_id) 85 : render_process_id_(render_frame_host->GetProcess()->GetID()), 86 render_frame_id_(render_frame_host->GetRoutingID()), 87 notification_id_(notification_id) {} 88 89 virtual ~DesktopNotificationDelegateImpl() {} 90 91 virtual void NotificationDisplayed() OVERRIDE { 92 RenderFrameHost* rfh = 93 RenderFrameHost::FromID(render_process_id_, render_frame_id_); 94 if (!rfh) 95 return; 96 97 rfh->Send(new DesktopNotificationMsg_PostDisplay( 98 rfh->GetRoutingID(), notification_id_)); 99 } 100 101 virtual void NotificationError() OVERRIDE { 102 RenderFrameHost* rfh = 103 RenderFrameHost::FromID(render_process_id_, render_frame_id_); 104 if (!rfh) 105 return; 106 107 rfh->Send(new DesktopNotificationMsg_PostError( 108 rfh->GetRoutingID(), notification_id_)); 109 } 110 111 virtual void NotificationClosed(bool by_user) OVERRIDE { 112 RenderFrameHost* rfh = 113 RenderFrameHost::FromID(render_process_id_, render_frame_id_); 114 if (!rfh) 115 return; 116 117 rfh->Send(new DesktopNotificationMsg_PostClose( 118 rfh->GetRoutingID(), notification_id_, by_user)); 119 static_cast<RenderFrameHostImpl*>(rfh)->NotificationClosed( 120 notification_id_); 121 } 122 123 virtual void NotificationClick() OVERRIDE { 124 RenderFrameHost* rfh = 125 RenderFrameHost::FromID(render_process_id_, render_frame_id_); 126 if (!rfh) 127 return; 128 129 rfh->Send(new DesktopNotificationMsg_PostClick( 130 rfh->GetRoutingID(), notification_id_)); 131 } 132 133 private: 134 int render_process_id_; 135 int render_frame_id_; 136 int notification_id_; 137 }; 138 139 // Translate a WebKit text direction into a base::i18n one. 140 base::i18n::TextDirection WebTextDirectionToChromeTextDirection( 141 blink::WebTextDirection dir) { 142 switch (dir) { 143 case blink::WebTextDirectionLeftToRight: 144 return base::i18n::LEFT_TO_RIGHT; 145 case blink::WebTextDirectionRightToLeft: 146 return base::i18n::RIGHT_TO_LEFT; 147 default: 148 NOTREACHED(); 149 return base::i18n::UNKNOWN_DIRECTION; 150 } 151 } 152 153 } // namespace 154 155 RenderFrameHost* RenderFrameHost::FromID(int render_process_id, 156 int render_frame_id) { 157 return RenderFrameHostImpl::FromID(render_process_id, render_frame_id); 158 } 159 160 // static 161 RenderFrameHostImpl* RenderFrameHostImpl::FromID(int process_id, 162 int routing_id) { 163 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 164 RoutingIDFrameMap* frames = g_routing_id_frame_map.Pointer(); 165 RoutingIDFrameMap::iterator it = frames->find( 166 RenderFrameHostID(process_id, routing_id)); 167 return it == frames->end() ? NULL : it->second; 168 } 169 170 RenderFrameHostImpl::RenderFrameHostImpl(RenderViewHostImpl* render_view_host, 171 RenderFrameHostDelegate* delegate, 172 FrameTree* frame_tree, 173 FrameTreeNode* frame_tree_node, 174 int routing_id, 175 bool is_swapped_out) 176 : render_view_host_(render_view_host), 177 delegate_(delegate), 178 cross_process_frame_connector_(NULL), 179 render_frame_proxy_host_(NULL), 180 frame_tree_(frame_tree), 181 frame_tree_node_(frame_tree_node), 182 routing_id_(routing_id), 183 is_swapped_out_(is_swapped_out), 184 render_frame_created_(false), 185 navigations_suspended_(false), 186 accessibility_reset_token_(0), 187 accessibility_reset_count_(0), 188 disallow_browser_accessibility_manager_for_testing_(false), 189 weak_ptr_factory_(this) { 190 frame_tree_->RegisterRenderFrameHost(this); 191 GetProcess()->AddRoute(routing_id_, this); 192 g_routing_id_frame_map.Get().insert(std::make_pair( 193 RenderFrameHostID(GetProcess()->GetID(), routing_id_), 194 this)); 195 196 if (GetProcess()->GetServiceRegistry()) { 197 RenderFrameSetupPtr setup; 198 GetProcess()->GetServiceRegistry()->ConnectToRemoteService(&setup); 199 mojo::ServiceProviderPtr service_provider; 200 setup->GetServiceProviderForFrame(routing_id_, 201 mojo::Get(&service_provider)); 202 service_registry_.BindRemoteServiceProvider( 203 service_provider.PassMessagePipe()); 204 } 205 } 206 207 RenderFrameHostImpl::~RenderFrameHostImpl() { 208 GetProcess()->RemoveRoute(routing_id_); 209 g_routing_id_frame_map.Get().erase( 210 RenderFrameHostID(GetProcess()->GetID(), routing_id_)); 211 212 if (delegate_) 213 delegate_->RenderFrameDeleted(this); 214 215 FrameAccessibility::GetInstance()->OnRenderFrameHostDestroyed(this); 216 217 // Notify the FrameTree that this RFH is going away, allowing it to shut down 218 // the corresponding RenderViewHost if it is no longer needed. 219 frame_tree_->UnregisterRenderFrameHost(this); 220 } 221 222 int RenderFrameHostImpl::GetRoutingID() { 223 return routing_id_; 224 } 225 226 SiteInstance* RenderFrameHostImpl::GetSiteInstance() { 227 return render_view_host_->GetSiteInstance(); 228 } 229 230 RenderProcessHost* RenderFrameHostImpl::GetProcess() { 231 // TODO(nasko): This should return its own process, once we have working 232 // cross-process navigation for subframes. 233 return render_view_host_->GetProcess(); 234 } 235 236 RenderFrameHost* RenderFrameHostImpl::GetParent() { 237 FrameTreeNode* parent_node = frame_tree_node_->parent(); 238 if (!parent_node) 239 return NULL; 240 return parent_node->current_frame_host(); 241 } 242 243 const std::string& RenderFrameHostImpl::GetFrameName() { 244 return frame_tree_node_->frame_name(); 245 } 246 247 bool RenderFrameHostImpl::IsCrossProcessSubframe() { 248 FrameTreeNode* parent_node = frame_tree_node_->parent(); 249 if (!parent_node) 250 return false; 251 return GetSiteInstance() != 252 parent_node->current_frame_host()->GetSiteInstance(); 253 } 254 255 GURL RenderFrameHostImpl::GetLastCommittedURL() { 256 return frame_tree_node_->current_url(); 257 } 258 259 gfx::NativeView RenderFrameHostImpl::GetNativeView() { 260 RenderWidgetHostView* view = render_view_host_->GetView(); 261 if (!view) 262 return NULL; 263 return view->GetNativeView(); 264 } 265 266 void RenderFrameHostImpl::ExecuteJavaScript( 267 const base::string16& javascript) { 268 Send(new FrameMsg_JavaScriptExecuteRequest(routing_id_, 269 javascript, 270 0, false)); 271 } 272 273 void RenderFrameHostImpl::ExecuteJavaScript( 274 const base::string16& javascript, 275 const JavaScriptResultCallback& callback) { 276 static int next_id = 1; 277 int key = next_id++; 278 Send(new FrameMsg_JavaScriptExecuteRequest(routing_id_, 279 javascript, 280 key, true)); 281 javascript_callbacks_.insert(std::make_pair(key, callback)); 282 } 283 284 void RenderFrameHostImpl::ExecuteJavaScriptForTests( 285 const base::string16& javascript) { 286 Send(new FrameMsg_JavaScriptExecuteRequestForTests(routing_id_, 287 javascript, 288 0, false)); 289 } 290 291 RenderViewHost* RenderFrameHostImpl::GetRenderViewHost() { 292 return render_view_host_; 293 } 294 295 ServiceRegistry* RenderFrameHostImpl::GetServiceRegistry() { 296 static_cast<RenderProcessHostImpl*>(GetProcess())->EnsureMojoActivated(); 297 return &service_registry_; 298 } 299 300 bool RenderFrameHostImpl::Send(IPC::Message* message) { 301 if (IPC_MESSAGE_ID_CLASS(message->type()) == InputMsgStart) { 302 return render_view_host_->input_router()->SendInput( 303 make_scoped_ptr(message)); 304 } 305 306 // Route IPCs through the RenderFrameProxyHost when in swapped out state. 307 // Note: For subframes in --site-per-process mode, we don't use swapped out 308 // RenderFrameHosts. 309 if (frame_tree_node_->IsMainFrame() && render_view_host_->IsSwappedOut()) { 310 DCHECK(render_frame_proxy_host_); 311 return render_frame_proxy_host_->Send(message); 312 } 313 314 return GetProcess()->Send(message); 315 } 316 317 bool RenderFrameHostImpl::OnMessageReceived(const IPC::Message &msg) { 318 // Filter out most IPC messages if this renderer is swapped out. 319 // We still want to handle certain ACKs to keep our state consistent. 320 // TODO(nasko): Only check RenderViewHost state, as this object's own state 321 // isn't yet properly updated. Transition this check once the swapped out 322 // state is correct in RenderFrameHost itself. 323 if (render_view_host_->IsSwappedOut()) { 324 if (!SwappedOutMessages::CanHandleWhileSwappedOut(msg)) { 325 // If this is a synchronous message and we decided not to handle it, 326 // we must send an error reply, or else the renderer will be stuck 327 // and won't respond to future requests. 328 if (msg.is_sync()) { 329 IPC::Message* reply = IPC::SyncMessage::GenerateReply(&msg); 330 reply->set_reply_error(); 331 Send(reply); 332 } 333 // Don't continue looking for someone to handle it. 334 return true; 335 } 336 } 337 338 if (delegate_->OnMessageReceived(this, msg)) 339 return true; 340 341 RenderFrameProxyHost* proxy = 342 frame_tree_node_->render_manager()->GetProxyToParent(); 343 if (proxy && proxy->cross_process_frame_connector() && 344 proxy->cross_process_frame_connector()->OnMessageReceived(msg)) 345 return true; 346 347 bool handled = true; 348 IPC_BEGIN_MESSAGE_MAP(RenderFrameHostImpl, msg) 349 IPC_MESSAGE_HANDLER(FrameHostMsg_AddMessageToConsole, OnAddMessageToConsole) 350 IPC_MESSAGE_HANDLER(FrameHostMsg_Detach, OnDetach) 351 IPC_MESSAGE_HANDLER(FrameHostMsg_FrameFocused, OnFrameFocused) 352 IPC_MESSAGE_HANDLER(FrameHostMsg_DidStartProvisionalLoadForFrame, 353 OnDidStartProvisionalLoadForFrame) 354 IPC_MESSAGE_HANDLER(FrameHostMsg_DidFailProvisionalLoadWithError, 355 OnDidFailProvisionalLoadWithError) 356 IPC_MESSAGE_HANDLER(FrameHostMsg_DidFailLoadWithError, 357 OnDidFailLoadWithError) 358 IPC_MESSAGE_HANDLER_GENERIC(FrameHostMsg_DidCommitProvisionalLoad, 359 OnDidCommitProvisionalLoad(msg)) 360 IPC_MESSAGE_HANDLER(FrameHostMsg_OpenURL, OnOpenURL) 361 IPC_MESSAGE_HANDLER(FrameHostMsg_DocumentOnLoadCompleted, 362 OnDocumentOnLoadCompleted) 363 IPC_MESSAGE_HANDLER(FrameHostMsg_BeforeUnload_ACK, OnBeforeUnloadACK) 364 IPC_MESSAGE_HANDLER(FrameHostMsg_SwapOut_ACK, OnSwapOutACK) 365 IPC_MESSAGE_HANDLER(FrameHostMsg_ContextMenu, OnContextMenu) 366 IPC_MESSAGE_HANDLER(FrameHostMsg_JavaScriptExecuteResponse, 367 OnJavaScriptExecuteResponse) 368 IPC_MESSAGE_HANDLER_DELAY_REPLY(FrameHostMsg_RunJavaScriptMessage, 369 OnRunJavaScriptMessage) 370 IPC_MESSAGE_HANDLER_DELAY_REPLY(FrameHostMsg_RunBeforeUnloadConfirm, 371 OnRunBeforeUnloadConfirm) 372 IPC_MESSAGE_HANDLER(FrameHostMsg_DidAccessInitialDocument, 373 OnDidAccessInitialDocument) 374 IPC_MESSAGE_HANDLER(FrameHostMsg_DidDisownOpener, OnDidDisownOpener) 375 IPC_MESSAGE_HANDLER(FrameHostMsg_DidAssignPageId, OnDidAssignPageId) 376 IPC_MESSAGE_HANDLER(FrameHostMsg_UpdateTitle, OnUpdateTitle) 377 IPC_MESSAGE_HANDLER(FrameHostMsg_UpdateEncoding, OnUpdateEncoding) 378 IPC_MESSAGE_HANDLER(FrameHostMsg_BeginNavigation, 379 OnBeginNavigation) 380 IPC_MESSAGE_HANDLER(PlatformNotificationHostMsg_RequestPermission, 381 OnRequestPlatformNotificationPermission) 382 IPC_MESSAGE_HANDLER(DesktopNotificationHostMsg_Show, 383 OnShowDesktopNotification) 384 IPC_MESSAGE_HANDLER(DesktopNotificationHostMsg_Cancel, 385 OnCancelDesktopNotification) 386 IPC_MESSAGE_HANDLER(FrameHostMsg_TextSurroundingSelectionResponse, 387 OnTextSurroundingSelectionResponse) 388 IPC_MESSAGE_HANDLER(AccessibilityHostMsg_Events, OnAccessibilityEvents) 389 IPC_MESSAGE_HANDLER(AccessibilityHostMsg_LocationChanges, 390 OnAccessibilityLocationChanges) 391 #if defined(OS_MACOSX) || defined(OS_ANDROID) 392 IPC_MESSAGE_HANDLER(FrameHostMsg_ShowPopup, OnShowPopup) 393 IPC_MESSAGE_HANDLER(FrameHostMsg_HidePopup, OnHidePopup) 394 #endif 395 IPC_END_MESSAGE_MAP() 396 397 return handled; 398 } 399 400 void RenderFrameHostImpl::AccessibilitySetFocus(int object_id) { 401 Send(new AccessibilityMsg_SetFocus(routing_id_, object_id)); 402 } 403 404 void RenderFrameHostImpl::AccessibilityDoDefaultAction(int object_id) { 405 Send(new AccessibilityMsg_DoDefaultAction(routing_id_, object_id)); 406 } 407 408 void RenderFrameHostImpl::AccessibilityShowMenu( 409 const gfx::Point& global_point) { 410 RenderWidgetHostViewBase* view = static_cast<RenderWidgetHostViewBase*>( 411 render_view_host_->GetView()); 412 if (view) 413 view->AccessibilityShowMenu(global_point); 414 } 415 416 void RenderFrameHostImpl::AccessibilityScrollToMakeVisible( 417 int acc_obj_id, const gfx::Rect& subfocus) { 418 Send(new AccessibilityMsg_ScrollToMakeVisible( 419 routing_id_, acc_obj_id, subfocus)); 420 } 421 422 void RenderFrameHostImpl::AccessibilityScrollToPoint( 423 int acc_obj_id, const gfx::Point& point) { 424 Send(new AccessibilityMsg_ScrollToPoint( 425 routing_id_, acc_obj_id, point)); 426 } 427 428 void RenderFrameHostImpl::AccessibilitySetTextSelection( 429 int object_id, int start_offset, int end_offset) { 430 Send(new AccessibilityMsg_SetTextSelection( 431 routing_id_, object_id, start_offset, end_offset)); 432 } 433 434 bool RenderFrameHostImpl::AccessibilityViewHasFocus() const { 435 RenderWidgetHostView* view = render_view_host_->GetView(); 436 if (view) 437 return view->HasFocus(); 438 return false; 439 } 440 441 gfx::Rect RenderFrameHostImpl::AccessibilityGetViewBounds() const { 442 RenderWidgetHostView* view = render_view_host_->GetView(); 443 if (view) 444 return view->GetViewBounds(); 445 return gfx::Rect(); 446 } 447 448 gfx::Point RenderFrameHostImpl::AccessibilityOriginInScreen( 449 const gfx::Rect& bounds) const { 450 RenderWidgetHostViewBase* view = static_cast<RenderWidgetHostViewBase*>( 451 render_view_host_->GetView()); 452 if (view) 453 return view->AccessibilityOriginInScreen(bounds); 454 return gfx::Point(); 455 } 456 457 void RenderFrameHostImpl::AccessibilityHitTest(const gfx::Point& point) { 458 Send(new AccessibilityMsg_HitTest(routing_id_, point)); 459 } 460 461 void RenderFrameHostImpl::AccessibilityFatalError() { 462 browser_accessibility_manager_.reset(NULL); 463 if (accessibility_reset_token_) 464 return; 465 466 accessibility_reset_count_++; 467 if (accessibility_reset_count_ >= kMaxAccessibilityResets) { 468 Send(new AccessibilityMsg_FatalError(routing_id_)); 469 } else { 470 accessibility_reset_token_ = g_next_accessibility_reset_token++; 471 UMA_HISTOGRAM_COUNTS("Accessibility.FrameResetCount", 1); 472 Send(new AccessibilityMsg_Reset(routing_id_, accessibility_reset_token_)); 473 } 474 } 475 476 gfx::AcceleratedWidget 477 RenderFrameHostImpl::AccessibilityGetAcceleratedWidget() { 478 RenderWidgetHostViewBase* view = static_cast<RenderWidgetHostViewBase*>( 479 render_view_host_->GetView()); 480 if (view) 481 return view->AccessibilityGetAcceleratedWidget(); 482 return gfx::kNullAcceleratedWidget; 483 } 484 485 gfx::NativeViewAccessible 486 RenderFrameHostImpl::AccessibilityGetNativeViewAccessible() { 487 RenderWidgetHostViewBase* view = static_cast<RenderWidgetHostViewBase*>( 488 render_view_host_->GetView()); 489 if (view) 490 return view->AccessibilityGetNativeViewAccessible(); 491 return NULL; 492 } 493 494 BrowserAccessibilityManager* RenderFrameHostImpl::AccessibilityGetChildFrame( 495 int accessibility_node_id) { 496 RenderFrameHostImpl* child_frame = 497 FrameAccessibility::GetInstance()->GetChild(this, accessibility_node_id); 498 if (!child_frame) 499 return NULL; 500 501 // Return NULL if this isn't an out-of-process iframe. Same-process iframes 502 // are already part of the accessibility tree. 503 if (child_frame->GetProcess()->GetID() == GetProcess()->GetID()) 504 return NULL; 505 506 // As a sanity check, make sure the frame we're going to return belongs 507 // to the same BrowserContext. 508 if (GetSiteInstance()->GetBrowserContext() != 509 child_frame->GetSiteInstance()->GetBrowserContext()) { 510 NOTREACHED(); 511 return NULL; 512 } 513 514 return child_frame->GetOrCreateBrowserAccessibilityManager(); 515 } 516 517 BrowserAccessibility* RenderFrameHostImpl::AccessibilityGetParentFrame() { 518 RenderFrameHostImpl* parent_frame = NULL; 519 int parent_node_id = 0; 520 if (!FrameAccessibility::GetInstance()->GetParent( 521 this, &parent_frame, &parent_node_id)) { 522 return NULL; 523 } 524 525 // As a sanity check, make sure the frame we're going to return belongs 526 // to the same BrowserContext. 527 if (GetSiteInstance()->GetBrowserContext() != 528 parent_frame->GetSiteInstance()->GetBrowserContext()) { 529 NOTREACHED(); 530 return NULL; 531 } 532 533 BrowserAccessibilityManager* manager = 534 parent_frame->browser_accessibility_manager(); 535 if (!manager) 536 return NULL; 537 538 return manager->GetFromID(parent_node_id); 539 } 540 541 bool RenderFrameHostImpl::CreateRenderFrame(int parent_routing_id) { 542 TRACE_EVENT0("navigation", "RenderFrameHostImpl::CreateRenderFrame"); 543 DCHECK(!IsRenderFrameLive()) << "Creating frame twice"; 544 545 // The process may (if we're sharing a process with another host that already 546 // initialized it) or may not (we have our own process or the old process 547 // crashed) have been initialized. Calling Init multiple times will be 548 // ignored, so this is safe. 549 if (!GetProcess()->Init()) 550 return false; 551 552 DCHECK(GetProcess()->HasConnection()); 553 554 Send(new FrameMsg_NewFrame(routing_id_, parent_routing_id)); 555 556 // The renderer now has a RenderFrame for this RenderFrameHost. Note that 557 // this path is only used for out-of-process iframes. Main frame RenderFrames 558 // are created with their RenderView, and same-site iframes are created at the 559 // time of OnCreateChildFrame. 560 set_render_frame_created(true); 561 562 return true; 563 } 564 565 bool RenderFrameHostImpl::IsRenderFrameLive() { 566 // RenderFrames are created for main frames at the same time as RenderViews, 567 // so we rely on IsRenderViewLive. For subframes, we keep track of each 568 // RenderFrame individually with render_frame_created_. 569 bool is_live = !GetParent() ? 570 render_view_host_->IsRenderViewLive() : 571 GetProcess()->HasConnection() && render_frame_created_; 572 573 // Sanity check: the RenderView should always be live if the RenderFrame is. 574 DCHECK(!is_live || render_view_host_->IsRenderViewLive()); 575 576 return is_live; 577 } 578 579 void RenderFrameHostImpl::Init() { 580 GetProcess()->ResumeRequestsForView(routing_id_); 581 } 582 583 void RenderFrameHostImpl::OnAddMessageToConsole( 584 int32 level, 585 const base::string16& message, 586 int32 line_no, 587 const base::string16& source_id) { 588 if (delegate_->AddMessageToConsole(level, message, line_no, source_id)) 589 return; 590 591 // Pass through log level only on WebUI pages to limit console spew. 592 int32 resolved_level = 593 HasWebUIScheme(delegate_->GetMainFrameLastCommittedURL()) ? level : 0; 594 595 if (resolved_level >= ::logging::GetMinLogLevel()) { 596 logging::LogMessage("CONSOLE", line_no, resolved_level).stream() << "\"" << 597 message << "\", source: " << source_id << " (" << line_no << ")"; 598 } 599 } 600 601 void RenderFrameHostImpl::OnCreateChildFrame(int new_routing_id, 602 const std::string& frame_name) { 603 RenderFrameHostImpl* new_frame = frame_tree_->AddFrame( 604 frame_tree_node_, GetProcess()->GetID(), new_routing_id, frame_name); 605 if (!new_frame) 606 return; 607 608 // We know that the RenderFrame has been created in this case, immediately 609 // after the CreateChildFrame IPC was sent. 610 new_frame->set_render_frame_created(true); 611 612 if (delegate_) 613 delegate_->RenderFrameCreated(new_frame); 614 } 615 616 void RenderFrameHostImpl::OnDetach() { 617 frame_tree_->RemoveFrame(frame_tree_node_); 618 } 619 620 void RenderFrameHostImpl::OnFrameFocused() { 621 frame_tree_->SetFocusedFrame(frame_tree_node_); 622 } 623 624 void RenderFrameHostImpl::OnOpenURL( 625 const FrameHostMsg_OpenURL_Params& params) { 626 GURL validated_url(params.url); 627 GetProcess()->FilterURL(false, &validated_url); 628 629 TRACE_EVENT1("navigation", "RenderFrameHostImpl::OnOpenURL", 630 "url", validated_url.possibly_invalid_spec()); 631 frame_tree_node_->navigator()->RequestOpenURL( 632 this, validated_url, params.referrer, params.disposition, 633 params.should_replace_current_entry, params.user_gesture); 634 } 635 636 void RenderFrameHostImpl::OnDocumentOnLoadCompleted() { 637 // This message is only sent for top-level frames. TODO(avi): when frame tree 638 // mirroring works correctly, add a check here to enforce it. 639 delegate_->DocumentOnLoadCompleted(this); 640 } 641 642 void RenderFrameHostImpl::OnDidStartProvisionalLoadForFrame( 643 const GURL& url, 644 bool is_transition_navigation) { 645 frame_tree_node_->navigator()->DidStartProvisionalLoad( 646 this, url, is_transition_navigation); 647 } 648 649 void RenderFrameHostImpl::OnDidFailProvisionalLoadWithError( 650 const FrameHostMsg_DidFailProvisionalLoadWithError_Params& params) { 651 frame_tree_node_->navigator()->DidFailProvisionalLoadWithError(this, params); 652 } 653 654 void RenderFrameHostImpl::OnDidFailLoadWithError( 655 const GURL& url, 656 int error_code, 657 const base::string16& error_description) { 658 GURL validated_url(url); 659 GetProcess()->FilterURL(false, &validated_url); 660 661 frame_tree_node_->navigator()->DidFailLoadWithError( 662 this, validated_url, error_code, error_description); 663 } 664 665 // Called when the renderer navigates. For every frame loaded, we'll get this 666 // notification containing parameters identifying the navigation. 667 // 668 // Subframes are identified by the page transition type. For subframes loaded 669 // as part of a wider page load, the page_id will be the same as for the top 670 // level frame. If the user explicitly requests a subframe navigation, we will 671 // get a new page_id because we need to create a new navigation entry for that 672 // action. 673 void RenderFrameHostImpl::OnDidCommitProvisionalLoad(const IPC::Message& msg) { 674 // Read the parameters out of the IPC message directly to avoid making another 675 // copy when we filter the URLs. 676 PickleIterator iter(msg); 677 FrameHostMsg_DidCommitProvisionalLoad_Params validated_params; 678 if (!IPC::ParamTraits<FrameHostMsg_DidCommitProvisionalLoad_Params>:: 679 Read(&msg, &iter, &validated_params)) 680 return; 681 TRACE_EVENT1("navigation", "RenderFrameHostImpl::OnDidCommitProvisionalLoad", 682 "url", validated_params.url.possibly_invalid_spec()); 683 684 // If we're waiting for a cross-site beforeunload ack from this renderer and 685 // we receive a Navigate message from the main frame, then the renderer was 686 // navigating already and sent it before hearing the FrameMsg_Stop message. 687 // We do not want to cancel the pending navigation in this case, since the 688 // old page will soon be stopped. Instead, treat this as a beforeunload ack 689 // to allow the pending navigation to continue. 690 if (render_view_host_->is_waiting_for_beforeunload_ack_ && 691 render_view_host_->unload_ack_is_for_cross_site_transition_ && 692 ui::PageTransitionIsMainFrame(validated_params.transition)) { 693 OnBeforeUnloadACK(true, send_before_unload_start_time_, 694 base::TimeTicks::Now()); 695 return; 696 } 697 698 // If we're waiting for an unload ack from this renderer and we receive a 699 // Navigate message, then the renderer was navigating before it received the 700 // unload request. It will either respond to the unload request soon or our 701 // timer will expire. Either way, we should ignore this message, because we 702 // have already committed to closing this renderer. 703 if (render_view_host_->IsWaitingForUnloadACK()) 704 return; 705 706 RenderProcessHost* process = GetProcess(); 707 708 // Attempts to commit certain off-limits URL should be caught more strictly 709 // than our FilterURL checks below. If a renderer violates this policy, it 710 // should be killed. 711 if (!CanCommitURL(validated_params.url)) { 712 VLOG(1) << "Blocked URL " << validated_params.url.spec(); 713 validated_params.url = GURL(url::kAboutBlankURL); 714 RecordAction(base::UserMetricsAction("CanCommitURL_BlockedAndKilled")); 715 // Kills the process. 716 process->ReceivedBadMessage(); 717 } 718 719 // Without this check, an evil renderer can trick the browser into creating 720 // a navigation entry for a banned URL. If the user clicks the back button 721 // followed by the forward button (or clicks reload, or round-trips through 722 // session restore, etc), we'll think that the browser commanded the 723 // renderer to load the URL and grant the renderer the privileges to request 724 // the URL. To prevent this attack, we block the renderer from inserting 725 // banned URLs into the navigation controller in the first place. 726 process->FilterURL(false, &validated_params.url); 727 process->FilterURL(true, &validated_params.referrer.url); 728 for (std::vector<GURL>::iterator it(validated_params.redirects.begin()); 729 it != validated_params.redirects.end(); ++it) { 730 process->FilterURL(false, &(*it)); 731 } 732 process->FilterURL(true, &validated_params.searchable_form_url); 733 734 // Without this check, the renderer can trick the browser into using 735 // filenames it can't access in a future session restore. 736 if (!render_view_host_->CanAccessFilesOfPageState( 737 validated_params.page_state)) { 738 GetProcess()->ReceivedBadMessage(); 739 return; 740 } 741 742 accessibility_reset_count_ = 0; 743 frame_tree_node()->navigator()->DidNavigate(this, validated_params); 744 } 745 746 RenderWidgetHostImpl* RenderFrameHostImpl::GetRenderWidgetHost() { 747 return static_cast<RenderWidgetHostImpl*>(render_view_host_); 748 } 749 750 int RenderFrameHostImpl::GetEnabledBindings() { 751 return render_view_host_->GetEnabledBindings(); 752 } 753 754 void RenderFrameHostImpl::OnCrossSiteResponse( 755 const GlobalRequestID& global_request_id, 756 scoped_ptr<CrossSiteTransferringRequest> cross_site_transferring_request, 757 const std::vector<GURL>& transfer_url_chain, 758 const Referrer& referrer, 759 ui::PageTransition page_transition, 760 bool should_replace_current_entry) { 761 frame_tree_node_->render_manager()->OnCrossSiteResponse( 762 this, global_request_id, cross_site_transferring_request.Pass(), 763 transfer_url_chain, referrer, page_transition, 764 should_replace_current_entry); 765 } 766 767 void RenderFrameHostImpl::OnDeferredAfterResponseStarted( 768 const GlobalRequestID& global_request_id, 769 const TransitionLayerData& transition_data) { 770 frame_tree_node_->render_manager()->OnDeferredAfterResponseStarted( 771 global_request_id, this); 772 773 if (GetParent() || !delegate_->WillHandleDeferAfterResponseStarted()) 774 frame_tree_node_->render_manager()->ResumeResponseDeferredAtStart(); 775 else 776 delegate_->DidDeferAfterResponseStarted(transition_data); 777 } 778 779 void RenderFrameHostImpl::SwapOut(RenderFrameProxyHost* proxy) { 780 // The end of this event is in OnSwapOutACK when the RenderFrame has completed 781 // the operation and sends back an IPC message. 782 // The trace event may not end properly if the ACK times out. We expect this 783 // to be fixed when RenderViewHostImpl::OnSwapOut moves to RenderFrameHost. 784 TRACE_EVENT_ASYNC_BEGIN0("navigation", "RenderFrameHostImpl::SwapOut", this); 785 786 // TODO(creis): Move swapped out state to RFH. Until then, only update it 787 // when swapping out the main frame. 788 if (!GetParent()) { 789 // If this RenderViewHost is not in the default state, it must have already 790 // gone through this, therefore just return. 791 if (render_view_host_->rvh_state_ != RenderViewHostImpl::STATE_DEFAULT) 792 return; 793 794 render_view_host_->SetState( 795 RenderViewHostImpl::STATE_PENDING_SWAP_OUT); 796 render_view_host_->unload_event_monitor_timeout_->Start( 797 base::TimeDelta::FromMilliseconds( 798 RenderViewHostImpl::kUnloadTimeoutMS)); 799 } 800 801 set_render_frame_proxy_host(proxy); 802 803 if (IsRenderFrameLive()) 804 Send(new FrameMsg_SwapOut(routing_id_, proxy->GetRoutingID())); 805 806 if (!GetParent()) 807 delegate_->SwappedOut(this); 808 else 809 set_swapped_out(true); 810 } 811 812 void RenderFrameHostImpl::OnBeforeUnloadACK( 813 bool proceed, 814 const base::TimeTicks& renderer_before_unload_start_time, 815 const base::TimeTicks& renderer_before_unload_end_time) { 816 TRACE_EVENT_ASYNC_END0( 817 "navigation", "RenderFrameHostImpl::BeforeUnload", this); 818 // TODO(creis): Support properly beforeunload on subframes. For now just 819 // pretend that the handler ran and allowed the navigation to proceed. 820 if (GetParent()) { 821 render_view_host_->is_waiting_for_beforeunload_ack_ = false; 822 frame_tree_node_->render_manager()->OnBeforeUnloadACK( 823 render_view_host_->unload_ack_is_for_cross_site_transition_, proceed, 824 renderer_before_unload_end_time); 825 return; 826 } 827 828 render_view_host_->decrement_in_flight_event_count(); 829 render_view_host_->StopHangMonitorTimeout(); 830 // If this renderer navigated while the beforeunload request was in flight, we 831 // may have cleared this state in OnDidCommitProvisionalLoad, in which case we 832 // can ignore this message. 833 // However renderer might also be swapped out but we still want to proceed 834 // with navigation, otherwise it would block future navigations. This can 835 // happen when pending cross-site navigation is canceled by a second one just 836 // before OnDidCommitProvisionalLoad while current RVH is waiting for commit 837 // but second navigation is started from the beginning. 838 if (!render_view_host_->is_waiting_for_beforeunload_ack_) { 839 return; 840 } 841 842 render_view_host_->is_waiting_for_beforeunload_ack_ = false; 843 844 base::TimeTicks before_unload_end_time; 845 if (!send_before_unload_start_time_.is_null() && 846 !renderer_before_unload_start_time.is_null() && 847 !renderer_before_unload_end_time.is_null()) { 848 // When passing TimeTicks across process boundaries, we need to compensate 849 // for any skew between the processes. Here we are converting the 850 // renderer's notion of before_unload_end_time to TimeTicks in the browser 851 // process. See comments in inter_process_time_ticks_converter.h for more. 852 InterProcessTimeTicksConverter converter( 853 LocalTimeTicks::FromTimeTicks(send_before_unload_start_time_), 854 LocalTimeTicks::FromTimeTicks(base::TimeTicks::Now()), 855 RemoteTimeTicks::FromTimeTicks(renderer_before_unload_start_time), 856 RemoteTimeTicks::FromTimeTicks(renderer_before_unload_end_time)); 857 LocalTimeTicks browser_before_unload_end_time = 858 converter.ToLocalTimeTicks( 859 RemoteTimeTicks::FromTimeTicks(renderer_before_unload_end_time)); 860 before_unload_end_time = browser_before_unload_end_time.ToTimeTicks(); 861 862 // Collect UMA on the inter-process skew. 863 bool is_skew_additive = false; 864 if (converter.IsSkewAdditiveForMetrics()) { 865 is_skew_additive = true; 866 base::TimeDelta skew = converter.GetSkewForMetrics(); 867 if (skew >= base::TimeDelta()) { 868 UMA_HISTOGRAM_TIMES( 869 "InterProcessTimeTicks.BrowserBehind_RendererToBrowser", skew); 870 } else { 871 UMA_HISTOGRAM_TIMES( 872 "InterProcessTimeTicks.BrowserAhead_RendererToBrowser", -skew); 873 } 874 } 875 UMA_HISTOGRAM_BOOLEAN( 876 "InterProcessTimeTicks.IsSkewAdditive_RendererToBrowser", 877 is_skew_additive); 878 } 879 frame_tree_node_->render_manager()->OnBeforeUnloadACK( 880 render_view_host_->unload_ack_is_for_cross_site_transition_, proceed, 881 before_unload_end_time); 882 883 // If canceled, notify the delegate to cancel its pending navigation entry. 884 if (!proceed) 885 render_view_host_->GetDelegate()->DidCancelLoading(); 886 } 887 888 void RenderFrameHostImpl::OnSwapOutACK() { 889 OnSwappedOut(false); 890 TRACE_EVENT_ASYNC_END0("navigation", "RenderFrameHostImpl::SwapOut", this); 891 } 892 893 void RenderFrameHostImpl::OnSwappedOut(bool timed_out) { 894 // For now, we only need to update the RVH state machine for top-level swaps. 895 if (!GetParent()) 896 render_view_host_->OnSwappedOut(timed_out); 897 } 898 899 void RenderFrameHostImpl::OnContextMenu(const ContextMenuParams& params) { 900 // Validate the URLs in |params|. If the renderer can't request the URLs 901 // directly, don't show them in the context menu. 902 ContextMenuParams validated_params(params); 903 RenderProcessHost* process = GetProcess(); 904 905 // We don't validate |unfiltered_link_url| so that this field can be used 906 // when users want to copy the original link URL. 907 process->FilterURL(true, &validated_params.link_url); 908 process->FilterURL(true, &validated_params.src_url); 909 process->FilterURL(false, &validated_params.page_url); 910 process->FilterURL(true, &validated_params.frame_url); 911 912 delegate_->ShowContextMenu(this, validated_params); 913 } 914 915 void RenderFrameHostImpl::OnJavaScriptExecuteResponse( 916 int id, const base::ListValue& result) { 917 const base::Value* result_value; 918 if (!result.Get(0, &result_value)) { 919 // Programming error or rogue renderer. 920 NOTREACHED() << "Got bad arguments for OnJavaScriptExecuteResponse"; 921 return; 922 } 923 924 std::map<int, JavaScriptResultCallback>::iterator it = 925 javascript_callbacks_.find(id); 926 if (it != javascript_callbacks_.end()) { 927 it->second.Run(result_value); 928 javascript_callbacks_.erase(it); 929 } else { 930 NOTREACHED() << "Received script response for unknown request"; 931 } 932 } 933 934 void RenderFrameHostImpl::OnRunJavaScriptMessage( 935 const base::string16& message, 936 const base::string16& default_prompt, 937 const GURL& frame_url, 938 JavaScriptMessageType type, 939 IPC::Message* reply_msg) { 940 // While a JS message dialog is showing, tabs in the same process shouldn't 941 // process input events. 942 GetProcess()->SetIgnoreInputEvents(true); 943 render_view_host_->StopHangMonitorTimeout(); 944 delegate_->RunJavaScriptMessage(this, message, default_prompt, 945 frame_url, type, reply_msg); 946 } 947 948 void RenderFrameHostImpl::OnRunBeforeUnloadConfirm( 949 const GURL& frame_url, 950 const base::string16& message, 951 bool is_reload, 952 IPC::Message* reply_msg) { 953 // While a JS before unload dialog is showing, tabs in the same process 954 // shouldn't process input events. 955 GetProcess()->SetIgnoreInputEvents(true); 956 render_view_host_->StopHangMonitorTimeout(); 957 delegate_->RunBeforeUnloadConfirm(this, message, is_reload, reply_msg); 958 } 959 960 void RenderFrameHostImpl::OnRequestPlatformNotificationPermission( 961 const GURL& origin, int request_id) { 962 base::Callback<void(blink::WebNotificationPermission)> done_callback = 963 base::Bind( 964 &RenderFrameHostImpl::PlatformNotificationPermissionRequestDone, 965 weak_ptr_factory_.GetWeakPtr(), 966 request_id); 967 968 GetContentClient()->browser()->RequestDesktopNotificationPermission( 969 origin, this, done_callback); 970 } 971 972 void RenderFrameHostImpl::OnShowDesktopNotification( 973 int notification_id, 974 const ShowDesktopNotificationHostMsgParams& params) { 975 scoped_ptr<DesktopNotificationDelegateImpl> delegate( 976 new DesktopNotificationDelegateImpl(this, notification_id)); 977 978 base::Closure cancel_callback; 979 GetContentClient()->browser()->ShowDesktopNotification( 980 params, 981 this, 982 delegate.PassAs<DesktopNotificationDelegate>(), 983 &cancel_callback); 984 cancel_notification_callbacks_[notification_id] = cancel_callback; 985 } 986 987 void RenderFrameHostImpl::OnCancelDesktopNotification(int notification_id) { 988 if (!cancel_notification_callbacks_.count(notification_id)) { 989 NOTREACHED(); 990 return; 991 } 992 cancel_notification_callbacks_[notification_id].Run(); 993 cancel_notification_callbacks_.erase(notification_id); 994 } 995 996 void RenderFrameHostImpl::OnTextSurroundingSelectionResponse( 997 const base::string16& content, 998 size_t start_offset, 999 size_t end_offset) { 1000 render_view_host_->OnTextSurroundingSelectionResponse( 1001 content, start_offset, end_offset); 1002 } 1003 1004 void RenderFrameHostImpl::OnDidAccessInitialDocument() { 1005 delegate_->DidAccessInitialDocument(); 1006 } 1007 1008 void RenderFrameHostImpl::OnDidDisownOpener() { 1009 // This message is only sent for top-level frames. TODO(avi): when frame tree 1010 // mirroring works correctly, add a check here to enforce it. 1011 delegate_->DidDisownOpener(this); 1012 } 1013 1014 void RenderFrameHostImpl::OnDidAssignPageId(int32 page_id) { 1015 // Update the RVH's current page ID so that future IPCs from the renderer 1016 // correspond to the new page. 1017 render_view_host_->page_id_ = page_id; 1018 } 1019 1020 void RenderFrameHostImpl::OnUpdateTitle( 1021 int32 page_id, 1022 const base::string16& title, 1023 blink::WebTextDirection title_direction) { 1024 // This message is only sent for top-level frames. TODO(avi): when frame tree 1025 // mirroring works correctly, add a check here to enforce it. 1026 if (title.length() > kMaxTitleChars) { 1027 NOTREACHED() << "Renderer sent too many characters in title."; 1028 return; 1029 } 1030 1031 delegate_->UpdateTitle(this, page_id, title, 1032 WebTextDirectionToChromeTextDirection( 1033 title_direction)); 1034 } 1035 1036 void RenderFrameHostImpl::OnUpdateEncoding(const std::string& encoding_name) { 1037 // This message is only sent for top-level frames. TODO(avi): when frame tree 1038 // mirroring works correctly, add a check here to enforce it. 1039 delegate_->UpdateEncoding(this, encoding_name); 1040 } 1041 1042 void RenderFrameHostImpl::OnBeginNavigation( 1043 const FrameHostMsg_BeginNavigation_Params& params) { 1044 CHECK(CommandLine::ForCurrentProcess()->HasSwitch( 1045 switches::kEnableBrowserSideNavigation)); 1046 frame_tree_node()->render_manager()->OnBeginNavigation(params); 1047 } 1048 1049 void RenderFrameHostImpl::OnAccessibilityEvents( 1050 const std::vector<AccessibilityHostMsg_EventParams>& params, 1051 int reset_token) { 1052 // Don't process this IPC if either we're waiting on a reset and this 1053 // IPC doesn't have the matching token ID, or if we're not waiting on a 1054 // reset but this message includes a reset token. 1055 if (accessibility_reset_token_ != reset_token) { 1056 Send(new AccessibilityMsg_Events_ACK(routing_id_)); 1057 return; 1058 } 1059 accessibility_reset_token_ = 0; 1060 1061 RenderWidgetHostViewBase* view = static_cast<RenderWidgetHostViewBase*>( 1062 render_view_host_->GetView()); 1063 1064 AccessibilityMode accessibility_mode = delegate_->GetAccessibilityMode(); 1065 if ((accessibility_mode != AccessibilityModeOff) && view && 1066 RenderViewHostImpl::IsRVHStateActive(render_view_host_->rvh_state())) { 1067 if (accessibility_mode & AccessibilityModeFlagPlatform) { 1068 GetOrCreateBrowserAccessibilityManager(); 1069 if (browser_accessibility_manager_) 1070 browser_accessibility_manager_->OnAccessibilityEvents(params); 1071 } 1072 1073 if (browser_accessibility_manager_) { 1074 // Get the frame routing ids from out-of-process iframes and 1075 // browser plugin instance ids from guests and update the mappings in 1076 // FrameAccessibility. 1077 for (unsigned int i = 0; i < params.size(); ++i) { 1078 const AccessibilityHostMsg_EventParams& param = params[i]; 1079 UpdateCrossProcessIframeAccessibility( 1080 param.node_to_frame_routing_id_map); 1081 UpdateGuestFrameAccessibility( 1082 param.node_to_browser_plugin_instance_id_map); 1083 } 1084 } 1085 1086 // Send the updates to the automation extension API. 1087 std::vector<AXEventNotificationDetails> details; 1088 details.reserve(params.size()); 1089 for (size_t i = 0; i < params.size(); ++i) { 1090 const AccessibilityHostMsg_EventParams& param = params[i]; 1091 AXEventNotificationDetails detail(param.update.node_id_to_clear, 1092 param.update.nodes, 1093 param.event_type, 1094 param.id, 1095 GetProcess()->GetID(), 1096 routing_id_); 1097 details.push_back(detail); 1098 } 1099 1100 delegate_->AccessibilityEventReceived(details); 1101 } 1102 1103 // Always send an ACK or the renderer can be in a bad state. 1104 Send(new AccessibilityMsg_Events_ACK(routing_id_)); 1105 1106 // The rest of this code is just for testing; bail out if we're not 1107 // in that mode. 1108 if (accessibility_testing_callback_.is_null()) 1109 return; 1110 1111 for (size_t i = 0; i < params.size(); i++) { 1112 const AccessibilityHostMsg_EventParams& param = params[i]; 1113 if (static_cast<int>(param.event_type) < 0) 1114 continue; 1115 1116 if (!ax_tree_for_testing_) { 1117 if (browser_accessibility_manager_) { 1118 ax_tree_for_testing_.reset(new ui::AXTree( 1119 browser_accessibility_manager_->SnapshotAXTreeForTesting())); 1120 } else { 1121 ax_tree_for_testing_.reset(new ui::AXTree()); 1122 CHECK(ax_tree_for_testing_->Unserialize(param.update)) 1123 << ax_tree_for_testing_->error(); 1124 } 1125 } else { 1126 CHECK(ax_tree_for_testing_->Unserialize(param.update)) 1127 << ax_tree_for_testing_->error(); 1128 } 1129 accessibility_testing_callback_.Run(param.event_type, param.id); 1130 } 1131 } 1132 1133 void RenderFrameHostImpl::OnAccessibilityLocationChanges( 1134 const std::vector<AccessibilityHostMsg_LocationChangeParams>& params) { 1135 if (accessibility_reset_token_) 1136 return; 1137 1138 RenderWidgetHostViewBase* view = static_cast<RenderWidgetHostViewBase*>( 1139 render_view_host_->GetView()); 1140 if (view && 1141 RenderViewHostImpl::IsRVHStateActive(render_view_host_->rvh_state())) { 1142 AccessibilityMode accessibility_mode = delegate_->GetAccessibilityMode(); 1143 if (accessibility_mode & AccessibilityModeFlagPlatform) { 1144 if (!browser_accessibility_manager_) { 1145 browser_accessibility_manager_.reset( 1146 view->CreateBrowserAccessibilityManager(this)); 1147 } 1148 if (browser_accessibility_manager_) 1149 browser_accessibility_manager_->OnLocationChanges(params); 1150 } 1151 // TODO(aboxhall): send location change events to web contents observers too 1152 } 1153 } 1154 1155 #if defined(OS_MACOSX) || defined(OS_ANDROID) 1156 void RenderFrameHostImpl::OnShowPopup( 1157 const FrameHostMsg_ShowPopup_Params& params) { 1158 RenderViewHostDelegateView* view = 1159 render_view_host_->delegate_->GetDelegateView(); 1160 if (view) { 1161 view->ShowPopupMenu(this, 1162 params.bounds, 1163 params.item_height, 1164 params.item_font_size, 1165 params.selected_item, 1166 params.popup_items, 1167 params.right_aligned, 1168 params.allow_multiple_selection); 1169 } 1170 } 1171 1172 void RenderFrameHostImpl::OnHidePopup() { 1173 RenderViewHostDelegateView* view = 1174 render_view_host_->delegate_->GetDelegateView(); 1175 if (view) 1176 view->HidePopupMenu(); 1177 } 1178 #endif 1179 1180 void RenderFrameHostImpl::SetPendingShutdown(const base::Closure& on_swap_out) { 1181 render_view_host_->SetPendingShutdown(on_swap_out); 1182 } 1183 1184 bool RenderFrameHostImpl::CanCommitURL(const GURL& url) { 1185 // TODO(creis): We should also check for WebUI pages here. Also, when the 1186 // out-of-process iframes implementation is ready, we should check for 1187 // cross-site URLs that are not allowed to commit in this process. 1188 1189 // Give the client a chance to disallow URLs from committing. 1190 return GetContentClient()->browser()->CanCommitURL(GetProcess(), url); 1191 } 1192 1193 void RenderFrameHostImpl::Navigate(const FrameMsg_Navigate_Params& params) { 1194 TRACE_EVENT0("navigation", "RenderFrameHostImpl::Navigate"); 1195 // Browser plugin guests are not allowed to navigate outside web-safe schemes, 1196 // so do not grant them the ability to request additional URLs. 1197 if (!GetProcess()->IsIsolatedGuest()) { 1198 ChildProcessSecurityPolicyImpl::GetInstance()->GrantRequestURL( 1199 GetProcess()->GetID(), params.url); 1200 if (params.url.SchemeIs(url::kDataScheme) && 1201 params.base_url_for_data_url.SchemeIs(url::kFileScheme)) { 1202 // If 'data:' is used, and we have a 'file:' base url, grant access to 1203 // local files. 1204 ChildProcessSecurityPolicyImpl::GetInstance()->GrantRequestURL( 1205 GetProcess()->GetID(), params.base_url_for_data_url); 1206 } 1207 } 1208 1209 // Only send the message if we aren't suspended at the start of a cross-site 1210 // request. 1211 if (navigations_suspended_) { 1212 // Shouldn't be possible to have a second navigation while suspended, since 1213 // navigations will only be suspended during a cross-site request. If a 1214 // second navigation occurs, RenderFrameHostManager will cancel this pending 1215 // RFH and create a new pending RFH. 1216 DCHECK(!suspended_nav_params_.get()); 1217 suspended_nav_params_.reset(new FrameMsg_Navigate_Params(params)); 1218 } else { 1219 // Get back to a clean state, in case we start a new navigation without 1220 // completing a RVH swap or unload handler. 1221 render_view_host_->SetState(RenderViewHostImpl::STATE_DEFAULT); 1222 1223 Send(new FrameMsg_Navigate(routing_id_, params)); 1224 } 1225 1226 // Force the throbber to start. We do this because Blink's "started 1227 // loading" message will be received asynchronously from the UI of the 1228 // browser. But we want to keep the throbber in sync with what's happening 1229 // in the UI. For example, we want to start throbbing immediately when the 1230 // user naivgates even if the renderer is delayed. There is also an issue 1231 // with the throbber starting because the WebUI (which controls whether the 1232 // favicon is displayed) happens synchronously. If the start loading 1233 // messages was asynchronous, then the default favicon would flash in. 1234 // 1235 // Blink doesn't send throb notifications for JavaScript URLs, so we 1236 // don't want to either. 1237 if (!params.url.SchemeIs(url::kJavaScriptScheme)) 1238 delegate_->DidStartLoading(this, true); 1239 } 1240 1241 void RenderFrameHostImpl::NavigateToURL(const GURL& url) { 1242 FrameMsg_Navigate_Params params; 1243 params.page_id = -1; 1244 params.pending_history_list_offset = -1; 1245 params.current_history_list_offset = -1; 1246 params.current_history_list_length = 0; 1247 params.url = url; 1248 params.transition = ui::PAGE_TRANSITION_LINK; 1249 params.navigation_type = FrameMsg_Navigate_Type::NORMAL; 1250 params.browser_navigation_start = base::TimeTicks::Now(); 1251 Navigate(params); 1252 } 1253 1254 void RenderFrameHostImpl::Stop() { 1255 Send(new FrameMsg_Stop(routing_id_)); 1256 } 1257 1258 void RenderFrameHostImpl::DispatchBeforeUnload(bool for_cross_site_transition) { 1259 TRACE_EVENT_ASYNC_BEGIN0( 1260 "navigation", "RenderFrameHostImpl::BeforeUnload", this); 1261 // TODO(creis): Support subframes. 1262 if (GetParent() || !IsRenderFrameLive()) { 1263 // We don't have a live renderer, so just skip running beforeunload. 1264 render_view_host_->is_waiting_for_beforeunload_ack_ = true; 1265 render_view_host_->unload_ack_is_for_cross_site_transition_ = 1266 for_cross_site_transition; 1267 base::TimeTicks now = base::TimeTicks::Now(); 1268 OnBeforeUnloadACK(true, now, now); 1269 return; 1270 } 1271 1272 // This may be called more than once (if the user clicks the tab close button 1273 // several times, or if she clicks the tab close button then the browser close 1274 // button), and we only send the message once. 1275 if (render_view_host_->is_waiting_for_beforeunload_ack_) { 1276 // Some of our close messages could be for the tab, others for cross-site 1277 // transitions. We always want to think it's for closing the tab if any 1278 // of the messages were, since otherwise it might be impossible to close 1279 // (if there was a cross-site "close" request pending when the user clicked 1280 // the close button). We want to keep the "for cross site" flag only if 1281 // both the old and the new ones are also for cross site. 1282 render_view_host_->unload_ack_is_for_cross_site_transition_ = 1283 render_view_host_->unload_ack_is_for_cross_site_transition_ && 1284 for_cross_site_transition; 1285 } else { 1286 // Start the hang monitor in case the renderer hangs in the beforeunload 1287 // handler. 1288 render_view_host_->is_waiting_for_beforeunload_ack_ = true; 1289 render_view_host_->unload_ack_is_for_cross_site_transition_ = 1290 for_cross_site_transition; 1291 // Increment the in-flight event count, to ensure that input events won't 1292 // cancel the timeout timer. 1293 render_view_host_->increment_in_flight_event_count(); 1294 render_view_host_->StartHangMonitorTimeout( 1295 TimeDelta::FromMilliseconds(RenderViewHostImpl::kUnloadTimeoutMS)); 1296 send_before_unload_start_time_ = base::TimeTicks::Now(); 1297 Send(new FrameMsg_BeforeUnload(routing_id_)); 1298 } 1299 } 1300 1301 void RenderFrameHostImpl::DisownOpener() { 1302 Send(new FrameMsg_DisownOpener(GetRoutingID())); 1303 } 1304 1305 void RenderFrameHostImpl::ExtendSelectionAndDelete(size_t before, 1306 size_t after) { 1307 Send(new InputMsg_ExtendSelectionAndDelete(routing_id_, before, after)); 1308 } 1309 1310 void RenderFrameHostImpl::JavaScriptDialogClosed( 1311 IPC::Message* reply_msg, 1312 bool success, 1313 const base::string16& user_input, 1314 bool dialog_was_suppressed) { 1315 GetProcess()->SetIgnoreInputEvents(false); 1316 bool is_waiting = render_view_host_->is_waiting_for_beforeunload_ack() || 1317 render_view_host_->IsWaitingForUnloadACK(); 1318 1319 // If we are executing as part of (before)unload event handling, we don't 1320 // want to use the regular hung_renderer_delay_ms_ if the user has agreed to 1321 // leave the current page. In this case, use the regular timeout value used 1322 // during the (before)unload handling. 1323 if (is_waiting) { 1324 render_view_host_->StartHangMonitorTimeout(TimeDelta::FromMilliseconds( 1325 success ? RenderViewHostImpl::kUnloadTimeoutMS 1326 : render_view_host_->hung_renderer_delay_ms_)); 1327 } 1328 1329 FrameHostMsg_RunJavaScriptMessage::WriteReplyParams(reply_msg, 1330 success, user_input); 1331 Send(reply_msg); 1332 1333 // If we are waiting for an unload or beforeunload ack and the user has 1334 // suppressed messages, kill the tab immediately; a page that's spamming 1335 // alerts in onbeforeunload is presumably malicious, so there's no point in 1336 // continuing to run its script and dragging out the process. 1337 // This must be done after sending the reply since RenderView can't close 1338 // correctly while waiting for a response. 1339 if (is_waiting && dialog_was_suppressed) 1340 render_view_host_->delegate_->RendererUnresponsive( 1341 render_view_host_, 1342 render_view_host_->is_waiting_for_beforeunload_ack(), 1343 render_view_host_->IsWaitingForUnloadACK()); 1344 } 1345 1346 void RenderFrameHostImpl::NotificationClosed(int notification_id) { 1347 cancel_notification_callbacks_.erase(notification_id); 1348 } 1349 1350 void RenderFrameHostImpl::PlatformNotificationPermissionRequestDone( 1351 int request_id, blink::WebNotificationPermission permission) { 1352 Send(new PlatformNotificationMsg_PermissionRequestComplete( 1353 routing_id_, request_id, permission)); 1354 } 1355 1356 void RenderFrameHostImpl::UpdateCrossProcessIframeAccessibility( 1357 const std::map<int32, int> node_to_frame_routing_id_map) { 1358 std::map<int32, int>::const_iterator iter; 1359 for (iter = node_to_frame_routing_id_map.begin(); 1360 iter != node_to_frame_routing_id_map.end(); 1361 ++iter) { 1362 // This is the id of the accessibility node that has a child frame. 1363 int32 node_id = iter->first; 1364 // The routing id from either a RenderFrame or a RenderFrameProxy. 1365 int frame_routing_id = iter->second; 1366 1367 FrameTree* frame_tree = frame_tree_node()->frame_tree(); 1368 FrameTreeNode* child_frame_tree_node = frame_tree->FindByRoutingID( 1369 GetProcess()->GetID(), frame_routing_id); 1370 if (child_frame_tree_node) { 1371 FrameAccessibility::GetInstance()->AddChildFrame( 1372 this, node_id, child_frame_tree_node->frame_tree_node_id()); 1373 } 1374 } 1375 } 1376 1377 void RenderFrameHostImpl::UpdateGuestFrameAccessibility( 1378 const std::map<int32, int> node_to_browser_plugin_instance_id_map) { 1379 std::map<int32, int>::const_iterator iter; 1380 for (iter = node_to_browser_plugin_instance_id_map.begin(); 1381 iter != node_to_browser_plugin_instance_id_map.end(); 1382 ++iter) { 1383 // This is the id of the accessibility node that hosts a plugin. 1384 int32 node_id = iter->first; 1385 // The id of the browser plugin. 1386 int browser_plugin_instance_id = iter->second; 1387 FrameAccessibility::GetInstance()->AddGuestWebContents( 1388 this, node_id, browser_plugin_instance_id); 1389 } 1390 } 1391 1392 void RenderFrameHostImpl::SetAccessibilityMode(AccessibilityMode mode) { 1393 Send(new FrameMsg_SetAccessibilityMode(routing_id_, mode)); 1394 } 1395 1396 void RenderFrameHostImpl::SetAccessibilityCallbackForTesting( 1397 const base::Callback<void(ui::AXEvent, int)>& callback) { 1398 accessibility_testing_callback_ = callback; 1399 } 1400 1401 const ui::AXTree* RenderFrameHostImpl::GetAXTreeForTesting() { 1402 return ax_tree_for_testing_.get(); 1403 } 1404 1405 BrowserAccessibilityManager* 1406 RenderFrameHostImpl::GetOrCreateBrowserAccessibilityManager() { 1407 if (disallow_browser_accessibility_manager_for_testing_) 1408 return NULL; 1409 1410 RenderWidgetHostViewBase* view = static_cast<RenderWidgetHostViewBase*>( 1411 render_view_host_->GetView()); 1412 if (view && !browser_accessibility_manager_) { 1413 browser_accessibility_manager_.reset( 1414 view->CreateBrowserAccessibilityManager(this)); 1415 if (browser_accessibility_manager_) 1416 UMA_HISTOGRAM_COUNTS("Accessibility.FrameEnabledCount", 1); 1417 else 1418 UMA_HISTOGRAM_COUNTS("Accessibility.FrameDidNotEnableCount", 1); 1419 } 1420 return browser_accessibility_manager_.get(); 1421 } 1422 1423 #if defined(OS_WIN) 1424 1425 void RenderFrameHostImpl::SetParentNativeViewAccessible( 1426 gfx::NativeViewAccessible accessible_parent) { 1427 RenderWidgetHostViewBase* view = static_cast<RenderWidgetHostViewBase*>( 1428 render_view_host_->GetView()); 1429 if (view) 1430 view->SetParentNativeViewAccessible(accessible_parent); 1431 } 1432 1433 gfx::NativeViewAccessible 1434 RenderFrameHostImpl::GetParentNativeViewAccessible() const { 1435 return delegate_->GetParentNativeViewAccessible(); 1436 } 1437 1438 #elif defined(OS_MACOSX) 1439 1440 void RenderFrameHostImpl::DidSelectPopupMenuItem(int selected_index) { 1441 Send(new FrameMsg_SelectPopupMenuItem(routing_id_, selected_index)); 1442 } 1443 1444 void RenderFrameHostImpl::DidCancelPopupMenu() { 1445 Send(new FrameMsg_SelectPopupMenuItem(routing_id_, -1)); 1446 } 1447 1448 #elif defined(OS_ANDROID) 1449 1450 void RenderFrameHostImpl::DidSelectPopupMenuItems( 1451 const std::vector<int>& selected_indices) { 1452 Send(new FrameMsg_SelectPopupMenuItems(routing_id_, false, selected_indices)); 1453 } 1454 1455 void RenderFrameHostImpl::DidCancelPopupMenu() { 1456 Send(new FrameMsg_SelectPopupMenuItems( 1457 routing_id_, true, std::vector<int>())); 1458 } 1459 1460 #endif 1461 1462 void RenderFrameHostImpl::ClearPendingTransitionRequestData() { 1463 BrowserThread::PostTask( 1464 BrowserThread::IO, 1465 FROM_HERE, 1466 base::Bind( 1467 &TransitionRequestManager::ClearPendingTransitionRequestData, 1468 base::Unretained(TransitionRequestManager::GetInstance()), 1469 GetProcess()->GetID(), 1470 routing_id_)); 1471 } 1472 1473 void RenderFrameHostImpl::SetNavigationsSuspended( 1474 bool suspend, 1475 const base::TimeTicks& proceed_time) { 1476 // This should only be called to toggle the state. 1477 DCHECK(navigations_suspended_ != suspend); 1478 1479 navigations_suspended_ = suspend; 1480 if (navigations_suspended_) { 1481 TRACE_EVENT_ASYNC_BEGIN0("navigation", 1482 "RenderFrameHostImpl navigation suspended", this); 1483 } else { 1484 TRACE_EVENT_ASYNC_END0("navigation", 1485 "RenderFrameHostImpl navigation suspended", this); 1486 } 1487 1488 if (!suspend && suspended_nav_params_) { 1489 // There's navigation message params waiting to be sent. Now that we're not 1490 // suspended anymore, resume navigation by sending them. If we were swapped 1491 // out, we should also stop filtering out the IPC messages now. 1492 render_view_host_->SetState(RenderViewHostImpl::STATE_DEFAULT); 1493 1494 DCHECK(!proceed_time.is_null()); 1495 suspended_nav_params_->browser_navigation_start = proceed_time; 1496 Send(new FrameMsg_Navigate(routing_id_, *suspended_nav_params_)); 1497 suspended_nav_params_.reset(); 1498 } 1499 } 1500 1501 void RenderFrameHostImpl::CancelSuspendedNavigations() { 1502 // Clear any state if a pending navigation is canceled or preempted. 1503 if (suspended_nav_params_) 1504 suspended_nav_params_.reset(); 1505 1506 TRACE_EVENT_ASYNC_END0("navigation", 1507 "RenderFrameHostImpl navigation suspended", this); 1508 navigations_suspended_ = false; 1509 } 1510 1511 } // namespace content 1512