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 3 // found in the LICENSE file. 4 5 // Implements the Chrome Extensions WebNavigation API. 6 7 #include "chrome/browser/extensions/api/web_navigation/web_navigation_api.h" 8 9 #include "base/lazy_instance.h" 10 #include "chrome/browser/chrome_notification_types.h" 11 #include "chrome/browser/extensions/api/web_navigation/web_navigation_api_constants.h" 12 #include "chrome/browser/extensions/api/web_navigation/web_navigation_api_helpers.h" 13 #include "chrome/browser/extensions/event_router.h" 14 #include "chrome/browser/extensions/extension_system.h" 15 #include "chrome/browser/extensions/extension_tab_util.h" 16 #include "chrome/browser/profiles/profile.h" 17 #include "chrome/browser/tab_contents/retargeting_details.h" 18 #include "chrome/browser/ui/browser.h" 19 #include "chrome/browser/ui/browser_iterator.h" 20 #include "chrome/browser/ui/browser_list.h" 21 #include "chrome/common/extensions/api/web_navigation.h" 22 #include "content/public/browser/navigation_details.h" 23 #include "content/public/browser/notification_service.h" 24 #include "content/public/browser/notification_types.h" 25 #include "content/public/browser/render_process_host.h" 26 #include "content/public/browser/render_view_host.h" 27 #include "content/public/browser/resource_request_details.h" 28 #include "content/public/browser/web_contents.h" 29 #include "content/public/common/url_constants.h" 30 #include "extensions/browser/view_type_utils.h" 31 #include "net/base/net_errors.h" 32 33 namespace GetFrame = extensions::api::web_navigation::GetFrame; 34 namespace GetAllFrames = extensions::api::web_navigation::GetAllFrames; 35 36 DEFINE_WEB_CONTENTS_USER_DATA_KEY(extensions::WebNavigationTabObserver); 37 38 namespace extensions { 39 40 #if !defined(OS_ANDROID) 41 42 namespace helpers = web_navigation_api_helpers; 43 namespace keys = web_navigation_api_constants; 44 45 namespace { 46 47 typedef std::map<content::WebContents*, WebNavigationTabObserver*> 48 TabObserverMap; 49 static base::LazyInstance<TabObserverMap> g_tab_observer = 50 LAZY_INSTANCE_INITIALIZER; 51 52 } // namespace 53 54 // WebNavigtionEventRouter ------------------------------------------- 55 56 WebNavigationEventRouter::PendingWebContents::PendingWebContents() 57 : source_web_contents(NULL), 58 source_frame_id(0), 59 source_frame_is_main_frame(false), 60 target_web_contents(NULL), 61 target_url() { 62 } 63 64 WebNavigationEventRouter::PendingWebContents::PendingWebContents( 65 content::WebContents* source_web_contents, 66 int64 source_frame_id, 67 bool source_frame_is_main_frame, 68 content::WebContents* target_web_contents, 69 const GURL& target_url) 70 : source_web_contents(source_web_contents), 71 source_frame_id(source_frame_id), 72 source_frame_is_main_frame(source_frame_is_main_frame), 73 target_web_contents(target_web_contents), 74 target_url(target_url) { 75 } 76 77 WebNavigationEventRouter::PendingWebContents::~PendingWebContents() {} 78 79 WebNavigationEventRouter::WebNavigationEventRouter(Profile* profile) 80 : profile_(profile) { 81 CHECK(registrar_.IsEmpty()); 82 registrar_.Add(this, 83 chrome::NOTIFICATION_RETARGETING, 84 content::NotificationService::AllSources()); 85 registrar_.Add(this, 86 chrome::NOTIFICATION_TAB_ADDED, 87 content::NotificationService::AllSources()); 88 registrar_.Add(this, 89 content::NOTIFICATION_WEB_CONTENTS_DESTROYED, 90 content::NotificationService::AllSources()); 91 92 BrowserList::AddObserver(this); 93 for (chrome::BrowserIterator it; !it.done(); it.Next()) { 94 OnBrowserAdded(*it); 95 } 96 } 97 98 WebNavigationEventRouter::~WebNavigationEventRouter() { 99 BrowserList::RemoveObserver(this); 100 } 101 102 void WebNavigationEventRouter::OnBrowserAdded(Browser* browser) { 103 if (!profile_->IsSameProfile(browser->profile())) 104 return; 105 browser->tab_strip_model()->AddObserver(this); 106 } 107 108 void WebNavigationEventRouter::OnBrowserRemoved(Browser* browser) { 109 if (!profile_->IsSameProfile(browser->profile())) 110 return; 111 browser->tab_strip_model()->RemoveObserver(this); 112 } 113 114 void WebNavigationEventRouter::TabReplacedAt( 115 TabStripModel* tab_strip_model, 116 content::WebContents* old_contents, 117 content::WebContents* new_contents, 118 int index) { 119 WebNavigationTabObserver* tab_observer = 120 WebNavigationTabObserver::Get(old_contents); 121 if (!tab_observer) { 122 // If you hit this DCHECK(), please add reproduction steps to 123 // http://crbug.com/109464. 124 DCHECK(GetViewType(old_contents) != VIEW_TYPE_TAB_CONTENTS); 125 return; 126 } 127 const FrameNavigationState& frame_navigation_state = 128 tab_observer->frame_navigation_state(); 129 130 if (!frame_navigation_state.IsValidUrl(old_contents->GetURL()) || 131 !frame_navigation_state.IsValidUrl(new_contents->GetURL())) 132 return; 133 134 helpers::DispatchOnTabReplaced(old_contents, profile_, new_contents); 135 } 136 137 void WebNavigationEventRouter::Observe( 138 int type, 139 const content::NotificationSource& source, 140 const content::NotificationDetails& details) { 141 switch (type) { 142 case chrome::NOTIFICATION_RETARGETING: { 143 Profile* profile = content::Source<Profile>(source).ptr(); 144 if (profile->GetOriginalProfile() == profile_) { 145 Retargeting( 146 content::Details<const RetargetingDetails>(details).ptr()); 147 } 148 break; 149 } 150 151 case chrome::NOTIFICATION_TAB_ADDED: 152 TabAdded(content::Details<content::WebContents>(details).ptr()); 153 break; 154 155 case content::NOTIFICATION_WEB_CONTENTS_DESTROYED: 156 TabDestroyed(content::Source<content::WebContents>(source).ptr()); 157 break; 158 159 default: 160 NOTREACHED(); 161 } 162 } 163 164 void WebNavigationEventRouter::Retargeting(const RetargetingDetails* details) { 165 if (details->source_frame_id == 0) 166 return; 167 WebNavigationTabObserver* tab_observer = 168 WebNavigationTabObserver::Get(details->source_web_contents); 169 if (!tab_observer) { 170 // If you hit this DCHECK(), please add reproduction steps to 171 // http://crbug.com/109464. 172 DCHECK(GetViewType(details->source_web_contents) != VIEW_TYPE_TAB_CONTENTS); 173 return; 174 } 175 const FrameNavigationState& frame_navigation_state = 176 tab_observer->frame_navigation_state(); 177 178 FrameNavigationState::FrameID frame_id( 179 details->source_frame_id, 180 details->source_web_contents->GetRenderViewHost()); 181 if (!frame_navigation_state.CanSendEvents(frame_id)) 182 return; 183 184 // If the WebContents isn't yet inserted into a tab strip, we need to delay 185 // the extension event until the WebContents is fully initialized. 186 if (details->not_yet_in_tabstrip) { 187 pending_web_contents_[details->target_web_contents] = 188 PendingWebContents( 189 details->source_web_contents, 190 details->source_frame_id, 191 frame_navigation_state.IsMainFrame(frame_id), 192 details->target_web_contents, 193 details->target_url); 194 } else { 195 helpers::DispatchOnCreatedNavigationTarget( 196 details->source_web_contents, 197 details->target_web_contents->GetBrowserContext(), 198 details->source_frame_id, 199 frame_navigation_state.IsMainFrame(frame_id), 200 details->target_web_contents, 201 details->target_url); 202 } 203 } 204 205 void WebNavigationEventRouter::TabAdded(content::WebContents* tab) { 206 std::map<content::WebContents*, PendingWebContents>::iterator iter = 207 pending_web_contents_.find(tab); 208 if (iter == pending_web_contents_.end()) 209 return; 210 211 WebNavigationTabObserver* tab_observer = 212 WebNavigationTabObserver::Get(iter->second.source_web_contents); 213 if (!tab_observer) { 214 NOTREACHED(); 215 return; 216 } 217 const FrameNavigationState& frame_navigation_state = 218 tab_observer->frame_navigation_state(); 219 220 FrameNavigationState::FrameID frame_id( 221 iter->second.source_frame_id, 222 iter->second.source_web_contents->GetRenderViewHost()); 223 if (frame_navigation_state.CanSendEvents(frame_id)) { 224 helpers::DispatchOnCreatedNavigationTarget( 225 iter->second.source_web_contents, 226 iter->second.target_web_contents->GetBrowserContext(), 227 iter->second.source_frame_id, 228 iter->second.source_frame_is_main_frame, 229 iter->second.target_web_contents, 230 iter->second.target_url); 231 } 232 pending_web_contents_.erase(iter); 233 } 234 235 void WebNavigationEventRouter::TabDestroyed(content::WebContents* tab) { 236 pending_web_contents_.erase(tab); 237 for (std::map<content::WebContents*, PendingWebContents>::iterator i = 238 pending_web_contents_.begin(); i != pending_web_contents_.end(); ) { 239 if (i->second.source_web_contents == tab) 240 pending_web_contents_.erase(i++); 241 else 242 ++i; 243 } 244 } 245 246 // WebNavigationTabObserver ------------------------------------------ 247 248 WebNavigationTabObserver::WebNavigationTabObserver( 249 content::WebContents* web_contents) 250 : WebContentsObserver(web_contents), 251 render_view_host_(NULL), 252 pending_render_view_host_(NULL) { 253 g_tab_observer.Get().insert(TabObserverMap::value_type(web_contents, this)); 254 registrar_.Add(this, 255 content::NOTIFICATION_RESOURCE_RECEIVED_REDIRECT, 256 content::Source<content::WebContents>(web_contents)); 257 registrar_.Add(this, 258 content::NOTIFICATION_RENDER_VIEW_HOST_WILL_CLOSE_RENDER_VIEW, 259 content::NotificationService::AllSources()); 260 } 261 262 WebNavigationTabObserver::~WebNavigationTabObserver() {} 263 264 // static 265 WebNavigationTabObserver* WebNavigationTabObserver::Get( 266 content::WebContents* web_contents) { 267 TabObserverMap::iterator i = g_tab_observer.Get().find(web_contents); 268 return i == g_tab_observer.Get().end() ? NULL : i->second; 269 } 270 271 content::RenderViewHost* WebNavigationTabObserver::GetRenderViewHostInProcess( 272 int process_id) const { 273 if (render_view_host_ && 274 render_view_host_->GetProcess()->GetID() == process_id) { 275 return render_view_host_; 276 } 277 if (pending_render_view_host_ && 278 pending_render_view_host_->GetProcess()->GetID() == process_id) { 279 return pending_render_view_host_; 280 } 281 return NULL; 282 } 283 284 void WebNavigationTabObserver::Observe( 285 int type, 286 const content::NotificationSource& source, 287 const content::NotificationDetails& details) { 288 switch (type) { 289 case content::NOTIFICATION_RESOURCE_RECEIVED_REDIRECT: { 290 content::ResourceRedirectDetails* resource_redirect_details = 291 content::Details<content::ResourceRedirectDetails>(details).ptr(); 292 ResourceType::Type resource_type = 293 resource_redirect_details->resource_type; 294 if (resource_type == ResourceType::MAIN_FRAME || 295 resource_type == ResourceType::SUB_FRAME) { 296 content::RenderViewHost* render_view_host = NULL; 297 if (render_view_host_ && 298 resource_redirect_details->origin_child_id == 299 render_view_host_->GetProcess()->GetID() && 300 resource_redirect_details->origin_route_id == 301 render_view_host_->GetRoutingID()) { 302 render_view_host = render_view_host_; 303 } else if (pending_render_view_host_ && 304 resource_redirect_details->origin_child_id == 305 pending_render_view_host_->GetProcess()->GetID() && 306 resource_redirect_details->origin_route_id == 307 pending_render_view_host_->GetRoutingID()) { 308 render_view_host = pending_render_view_host_; 309 } 310 if (!render_view_host) 311 return; 312 FrameNavigationState::FrameID frame_id( 313 resource_redirect_details->frame_id, render_view_host); 314 navigation_state_.SetIsServerRedirected(frame_id); 315 } 316 break; 317 } 318 319 case content::NOTIFICATION_RENDER_VIEW_HOST_WILL_CLOSE_RENDER_VIEW: { 320 // The RenderView is technically not yet deleted, but the RenderViewHost 321 // already starts to filter out some IPCs. In order to not get confused, 322 // we consider the RenderView dead already now. 323 RenderViewDeleted(content::Source<content::RenderViewHost>(source).ptr()); 324 break; 325 } 326 327 default: 328 NOTREACHED(); 329 } 330 } 331 332 void WebNavigationTabObserver::RenderViewDeleted( 333 content::RenderViewHost* render_view_host) { 334 if (render_view_host == render_view_host_) { 335 render_view_host_ = NULL; 336 if (pending_render_view_host_) { 337 render_view_host_ = pending_render_view_host_; 338 pending_render_view_host_ = NULL; 339 } 340 } else if (render_view_host == pending_render_view_host_) { 341 pending_render_view_host_ = NULL; 342 } else { 343 return; 344 } 345 SendErrorEvents( 346 web_contents(), render_view_host, FrameNavigationState::FrameID()); 347 } 348 349 void WebNavigationTabObserver::AboutToNavigateRenderView( 350 content::RenderViewHost* render_view_host) { 351 if (!render_view_host_) { 352 render_view_host_ = render_view_host; 353 } else if (render_view_host != render_view_host_) { 354 if (pending_render_view_host_) { 355 SendErrorEvents(web_contents(), 356 pending_render_view_host_, 357 FrameNavigationState::FrameID()); 358 } 359 pending_render_view_host_ = render_view_host; 360 } 361 } 362 363 void WebNavigationTabObserver::DidStartProvisionalLoadForFrame( 364 int64 frame_num, 365 int64 parent_frame_num, 366 bool is_main_frame, 367 const GURL& validated_url, 368 bool is_error_page, 369 bool is_iframe_srcdoc, 370 content::RenderViewHost* render_view_host) { 371 DVLOG(2) << "DidStartProvisionalLoad(" 372 << "render_view_host=" << render_view_host 373 << ", frame_num=" << frame_num 374 << ", url=" << validated_url << ")"; 375 if (!render_view_host_) 376 render_view_host_ = render_view_host; 377 if (render_view_host != render_view_host_ && 378 render_view_host != pending_render_view_host_) 379 return; 380 381 FrameNavigationState::FrameID frame_id(frame_num, render_view_host); 382 FrameNavigationState::FrameID parent_frame_id( 383 parent_frame_num, render_view_host); 384 385 navigation_state_.TrackFrame(frame_id, 386 parent_frame_id, 387 validated_url, 388 is_main_frame, 389 is_error_page, 390 is_iframe_srcdoc); 391 392 if (!navigation_state_.CanSendEvents(frame_id)) 393 return; 394 395 helpers::DispatchOnBeforeNavigate( 396 web_contents(), 397 render_view_host->GetProcess()->GetID(), 398 frame_num, 399 is_main_frame, 400 parent_frame_num, 401 navigation_state_.IsMainFrame(parent_frame_id), 402 navigation_state_.GetUrl(frame_id)); 403 } 404 405 void WebNavigationTabObserver::DidCommitProvisionalLoadForFrame( 406 int64 frame_num, 407 bool is_main_frame, 408 const GURL& url, 409 content::PageTransition transition_type, 410 content::RenderViewHost* render_view_host) { 411 DVLOG(2) << "DidCommitProvisionalLoad(" 412 << "render_view_host=" << render_view_host 413 << ", frame_num=" << frame_num 414 << ", url=" << url << ")"; 415 if (render_view_host != render_view_host_ && 416 render_view_host != pending_render_view_host_) 417 return; 418 FrameNavigationState::FrameID frame_id(frame_num, render_view_host); 419 420 bool is_reference_fragment_navigation = 421 IsReferenceFragmentNavigation(frame_id, url); 422 bool is_history_state_modification = 423 navigation_state_.GetNavigationCommitted(frame_id); 424 425 if (is_main_frame && render_view_host_ == render_view_host) { 426 // Changing the reference fragment or the history state using 427 // history.pushState or history.replaceState does not cancel on-going 428 // iframe navigations. 429 if (!is_reference_fragment_navigation && !is_history_state_modification) 430 SendErrorEvents(web_contents(), render_view_host_, frame_id); 431 if (pending_render_view_host_) { 432 SendErrorEvents(web_contents(), 433 pending_render_view_host_, 434 FrameNavigationState::FrameID()); 435 pending_render_view_host_ = NULL; 436 } 437 } else if (pending_render_view_host_ == render_view_host) { 438 SendErrorEvents( 439 web_contents(), render_view_host_, FrameNavigationState::FrameID()); 440 render_view_host_ = pending_render_view_host_; 441 pending_render_view_host_ = NULL; 442 } 443 444 // Update the URL as it might have changed. 445 navigation_state_.UpdateFrame(frame_id, url); 446 navigation_state_.SetNavigationCommitted(frame_id); 447 448 if (is_reference_fragment_navigation || is_history_state_modification) 449 navigation_state_.SetNavigationCompleted(frame_id); 450 451 if (!navigation_state_.CanSendEvents(frame_id)) 452 return; 453 454 if (is_reference_fragment_navigation) { 455 helpers::DispatchOnCommitted( 456 keys::kOnReferenceFragmentUpdated, 457 web_contents(), 458 frame_num, 459 is_main_frame, 460 navigation_state_.GetUrl(frame_id), 461 transition_type); 462 } else if (is_history_state_modification) { 463 helpers::DispatchOnCommitted( 464 keys::kOnHistoryStateUpdated, 465 web_contents(), 466 frame_num, 467 is_main_frame, 468 navigation_state_.GetUrl(frame_id), 469 transition_type); 470 } else { 471 if (navigation_state_.GetIsServerRedirected(frame_id)) { 472 transition_type = static_cast<content::PageTransition>( 473 transition_type | content::PAGE_TRANSITION_SERVER_REDIRECT); 474 } 475 helpers::DispatchOnCommitted( 476 keys::kOnCommitted, 477 web_contents(), 478 frame_num, 479 is_main_frame, 480 navigation_state_.GetUrl(frame_id), 481 transition_type); 482 } 483 } 484 485 void WebNavigationTabObserver::DidFailProvisionalLoad( 486 int64 frame_num, 487 bool is_main_frame, 488 const GURL& validated_url, 489 int error_code, 490 const string16& error_description, 491 content::RenderViewHost* render_view_host) { 492 DVLOG(2) << "DidFailProvisionalLoad(" 493 << "render_view_host=" << render_view_host 494 << ", frame_num=" << frame_num 495 << ", url=" << validated_url << ")"; 496 if (render_view_host != render_view_host_ && 497 render_view_host != pending_render_view_host_) 498 return; 499 bool stop_tracking_frames = false; 500 if (render_view_host == pending_render_view_host_) { 501 pending_render_view_host_ = NULL; 502 stop_tracking_frames = true; 503 } 504 505 FrameNavigationState::FrameID frame_id(frame_num, render_view_host); 506 if (navigation_state_.CanSendEvents(frame_id)) { 507 helpers::DispatchOnErrorOccurred( 508 web_contents(), 509 render_view_host->GetProcess()->GetID(), 510 navigation_state_.GetUrl(frame_id), 511 frame_num, 512 is_main_frame, 513 error_code); 514 } 515 navigation_state_.SetErrorOccurredInFrame(frame_id); 516 if (stop_tracking_frames) { 517 navigation_state_.StopTrackingFramesInRVH(render_view_host, 518 FrameNavigationState::FrameID()); 519 } 520 } 521 522 void WebNavigationTabObserver::DocumentLoadedInFrame( 523 int64 frame_num, 524 content::RenderViewHost* render_view_host) { 525 DVLOG(2) << "DocumentLoadedInFrame(" 526 << "render_view_host=" << render_view_host 527 << ", frame_num=" << frame_num << ")"; 528 if (render_view_host != render_view_host_) 529 return; 530 FrameNavigationState::FrameID frame_id(frame_num, render_view_host); 531 if (!navigation_state_.CanSendEvents(frame_id)) 532 return; 533 navigation_state_.SetParsingFinished(frame_id); 534 helpers::DispatchOnDOMContentLoaded(web_contents(), 535 navigation_state_.GetUrl(frame_id), 536 navigation_state_.IsMainFrame(frame_id), 537 frame_num); 538 539 if (!navigation_state_.GetNavigationCompleted(frame_id)) 540 return; 541 542 // The load might already have finished by the time we finished parsing. For 543 // compatibility reasons, we artifically delay the load completed signal until 544 // after parsing was completed. 545 helpers::DispatchOnCompleted(web_contents(), 546 navigation_state_.GetUrl(frame_id), 547 navigation_state_.IsMainFrame(frame_id), 548 frame_num); 549 } 550 551 void WebNavigationTabObserver::DidFinishLoad( 552 int64 frame_num, 553 const GURL& validated_url, 554 bool is_main_frame, 555 content::RenderViewHost* render_view_host) { 556 DVLOG(2) << "DidFinishLoad(" 557 << "render_view_host=" << render_view_host 558 << ", frame_num=" << frame_num 559 << ", url=" << validated_url << ")"; 560 if (render_view_host != render_view_host_) 561 return; 562 FrameNavigationState::FrameID frame_id(frame_num, render_view_host); 563 // When showing replacement content, we might get load signals for frames 564 // that weren't reguarly loaded. 565 if (!navigation_state_.IsValidFrame(frame_id)) 566 return; 567 navigation_state_.SetNavigationCompleted(frame_id); 568 if (!navigation_state_.CanSendEvents(frame_id)) 569 return; 570 DCHECK( 571 navigation_state_.GetUrl(frame_id) == validated_url || 572 (navigation_state_.GetUrl(frame_id) == GURL(content::kAboutSrcDocURL) && 573 validated_url == GURL(content::kAboutBlankURL))) 574 << "validated URL is " << validated_url << " but we expected " 575 << navigation_state_.GetUrl(frame_id); 576 DCHECK_EQ(navigation_state_.IsMainFrame(frame_id), is_main_frame); 577 578 // The load might already have finished by the time we finished parsing. For 579 // compatibility reasons, we artifically delay the load completed signal until 580 // after parsing was completed. 581 if (!navigation_state_.GetParsingFinished(frame_id)) 582 return; 583 helpers::DispatchOnCompleted(web_contents(), 584 navigation_state_.GetUrl(frame_id), 585 is_main_frame, 586 frame_num); 587 } 588 589 void WebNavigationTabObserver::DidFailLoad( 590 int64 frame_num, 591 const GURL& validated_url, 592 bool is_main_frame, 593 int error_code, 594 const string16& error_description, 595 content::RenderViewHost* render_view_host) { 596 DVLOG(2) << "DidFailLoad(" 597 << "render_view_host=" << render_view_host 598 << ", frame_num=" << frame_num 599 << ", url=" << validated_url << ")"; 600 if (render_view_host != render_view_host_) 601 return; 602 FrameNavigationState::FrameID frame_id(frame_num, render_view_host); 603 // When showing replacement content, we might get load signals for frames 604 // that weren't reguarly loaded. 605 if (!navigation_state_.IsValidFrame(frame_id)) 606 return; 607 if (navigation_state_.CanSendEvents(frame_id)) { 608 helpers::DispatchOnErrorOccurred( 609 web_contents(), 610 render_view_host->GetProcess()->GetID(), 611 navigation_state_.GetUrl(frame_id), 612 frame_num, 613 is_main_frame, 614 error_code); 615 } 616 navigation_state_.SetErrorOccurredInFrame(frame_id); 617 } 618 619 void WebNavigationTabObserver::DidOpenRequestedURL( 620 content::WebContents* new_contents, 621 const GURL& url, 622 const content::Referrer& referrer, 623 WindowOpenDisposition disposition, 624 content::PageTransition transition, 625 int64 source_frame_num) { 626 FrameNavigationState::FrameID frame_id(source_frame_num, render_view_host_); 627 if (!navigation_state_.CanSendEvents(frame_id)) 628 return; 629 630 // We only send the onCreatedNavigationTarget if we end up creating a new 631 // window. 632 if (disposition != SINGLETON_TAB && 633 disposition != NEW_FOREGROUND_TAB && 634 disposition != NEW_BACKGROUND_TAB && 635 disposition != NEW_POPUP && 636 disposition != NEW_WINDOW && 637 disposition != OFF_THE_RECORD) 638 return; 639 640 helpers::DispatchOnCreatedNavigationTarget( 641 web_contents(), 642 new_contents->GetBrowserContext(), 643 source_frame_num, 644 navigation_state_.IsMainFrame(frame_id), 645 new_contents, 646 url); 647 } 648 649 void WebNavigationTabObserver::FrameDetached( 650 content::RenderViewHost* render_view_host, 651 int64 frame_num) { 652 if (render_view_host != render_view_host_ && 653 render_view_host != pending_render_view_host_) { 654 return; 655 } 656 FrameNavigationState::FrameID frame_id(frame_num, render_view_host); 657 if (navigation_state_.CanSendEvents(frame_id) && 658 !navigation_state_.GetNavigationCompleted(frame_id)) { 659 helpers::DispatchOnErrorOccurred( 660 web_contents(), 661 render_view_host->GetProcess()->GetID(), 662 navigation_state_.GetUrl(frame_id), 663 frame_num, 664 navigation_state_.IsMainFrame(frame_id), 665 net::ERR_ABORTED); 666 } 667 navigation_state_.FrameDetached(frame_id); 668 } 669 670 void WebNavigationTabObserver::WebContentsDestroyed(content::WebContents* tab) { 671 g_tab_observer.Get().erase(tab); 672 registrar_.RemoveAll(); 673 SendErrorEvents(tab, NULL, FrameNavigationState::FrameID()); 674 } 675 676 void WebNavigationTabObserver::SendErrorEvents( 677 content::WebContents* web_contents, 678 content::RenderViewHost* render_view_host, 679 FrameNavigationState::FrameID id_to_skip) { 680 for (FrameNavigationState::const_iterator frame = navigation_state_.begin(); 681 frame != navigation_state_.end(); ++frame) { 682 if (!navigation_state_.GetNavigationCompleted(*frame) && 683 navigation_state_.CanSendEvents(*frame) && 684 *frame != id_to_skip && 685 (!render_view_host || frame->render_view_host == render_view_host)) { 686 navigation_state_.SetErrorOccurredInFrame(*frame); 687 helpers::DispatchOnErrorOccurred( 688 web_contents, 689 frame->render_view_host->GetProcess()->GetID(), 690 navigation_state_.GetUrl(*frame), 691 frame->frame_num, 692 navigation_state_.IsMainFrame(*frame), 693 net::ERR_ABORTED); 694 } 695 } 696 if (render_view_host) 697 navigation_state_.StopTrackingFramesInRVH(render_view_host, id_to_skip); 698 } 699 700 // See also NavigationController::IsURLInPageNavigation. 701 bool WebNavigationTabObserver::IsReferenceFragmentNavigation( 702 FrameNavigationState::FrameID frame_id, 703 const GURL& url) { 704 GURL existing_url = navigation_state_.GetUrl(frame_id); 705 if (existing_url == url) 706 return false; 707 708 url_canon::Replacements<char> replacements; 709 replacements.ClearRef(); 710 return existing_url.ReplaceComponents(replacements) == 711 url.ReplaceComponents(replacements); 712 } 713 714 bool WebNavigationGetFrameFunction::RunImpl() { 715 scoped_ptr<GetFrame::Params> params(GetFrame::Params::Create(*args_)); 716 EXTENSION_FUNCTION_VALIDATE(params.get()); 717 int tab_id = params->details.tab_id; 718 int frame_id = params->details.frame_id; 719 int process_id = params->details.process_id; 720 721 SetResult(Value::CreateNullValue()); 722 723 content::WebContents* web_contents; 724 if (!ExtensionTabUtil::GetTabById(tab_id, 725 profile(), 726 include_incognito(), 727 NULL, NULL, 728 &web_contents, 729 NULL) || 730 !web_contents) { 731 return true; 732 } 733 734 WebNavigationTabObserver* observer = 735 WebNavigationTabObserver::Get(web_contents); 736 DCHECK(observer); 737 738 const FrameNavigationState& frame_navigation_state = 739 observer->frame_navigation_state(); 740 741 if (frame_id == 0) 742 frame_id = frame_navigation_state.GetMainFrameID().frame_num; 743 744 content::RenderViewHost* render_view_host = 745 observer->GetRenderViewHostInProcess(process_id); 746 if (!render_view_host) 747 return true; 748 749 FrameNavigationState::FrameID internal_frame_id(frame_id, render_view_host); 750 if (!frame_navigation_state.IsValidFrame(internal_frame_id)) 751 return true; 752 753 GURL frame_url = frame_navigation_state.GetUrl(internal_frame_id); 754 if (!frame_navigation_state.IsValidUrl(frame_url)) 755 return true; 756 757 GetFrame::Results::Details frame_details; 758 frame_details.url = frame_url.spec(); 759 frame_details.error_occurred = 760 frame_navigation_state.GetErrorOccurredInFrame(internal_frame_id); 761 FrameNavigationState::FrameID parent_frame_id = 762 frame_navigation_state.GetParentFrameID(internal_frame_id); 763 frame_details.parent_frame_id = helpers::GetFrameId( 764 frame_navigation_state.IsMainFrame(parent_frame_id), 765 parent_frame_id.frame_num); 766 results_ = GetFrame::Results::Create(frame_details); 767 return true; 768 } 769 770 bool WebNavigationGetAllFramesFunction::RunImpl() { 771 scoped_ptr<GetAllFrames::Params> params(GetAllFrames::Params::Create(*args_)); 772 EXTENSION_FUNCTION_VALIDATE(params.get()); 773 int tab_id = params->details.tab_id; 774 775 SetResult(Value::CreateNullValue()); 776 777 content::WebContents* web_contents; 778 if (!ExtensionTabUtil::GetTabById(tab_id, 779 profile(), 780 include_incognito(), 781 NULL, NULL, 782 &web_contents, 783 NULL) || 784 !web_contents) { 785 return true; 786 } 787 788 WebNavigationTabObserver* observer = 789 WebNavigationTabObserver::Get(web_contents); 790 DCHECK(observer); 791 792 const FrameNavigationState& navigation_state = 793 observer->frame_navigation_state(); 794 795 std::vector<linked_ptr<GetAllFrames::Results::DetailsType> > result_list; 796 for (FrameNavigationState::const_iterator it = navigation_state.begin(); 797 it != navigation_state.end(); ++it) { 798 FrameNavigationState::FrameID frame_id = *it; 799 FrameNavigationState::FrameID parent_frame_id = 800 navigation_state.GetParentFrameID(frame_id); 801 GURL frame_url = navigation_state.GetUrl(frame_id); 802 if (!navigation_state.IsValidUrl(frame_url)) 803 continue; 804 linked_ptr<GetAllFrames::Results::DetailsType> frame( 805 new GetAllFrames::Results::DetailsType()); 806 frame->url = frame_url.spec(); 807 frame->frame_id = helpers::GetFrameId( 808 navigation_state.IsMainFrame(frame_id), frame_id.frame_num); 809 frame->parent_frame_id = helpers::GetFrameId( 810 navigation_state.IsMainFrame(parent_frame_id), 811 parent_frame_id.frame_num); 812 frame->process_id = frame_id.render_view_host->GetProcess()->GetID(); 813 frame->error_occurred = navigation_state.GetErrorOccurredInFrame(frame_id); 814 result_list.push_back(frame); 815 } 816 results_ = GetAllFrames::Results::Create(result_list); 817 return true; 818 } 819 820 WebNavigationAPI::WebNavigationAPI(Profile* profile) 821 : profile_(profile) { 822 ExtensionSystem::Get(profile_)->event_router()->RegisterObserver( 823 this, keys::kOnBeforeNavigate); 824 ExtensionSystem::Get(profile_)->event_router()->RegisterObserver( 825 this, keys::kOnCommitted); 826 ExtensionSystem::Get(profile_)->event_router()->RegisterObserver( 827 this, keys::kOnCompleted); 828 ExtensionSystem::Get(profile_)->event_router()->RegisterObserver( 829 this, keys::kOnCreatedNavigationTarget); 830 ExtensionSystem::Get(profile_)->event_router()->RegisterObserver( 831 this, keys::kOnDOMContentLoaded); 832 ExtensionSystem::Get(profile_)->event_router()->RegisterObserver( 833 this, keys::kOnHistoryStateUpdated); 834 ExtensionSystem::Get(profile_)->event_router()->RegisterObserver( 835 this, keys::kOnErrorOccurred); 836 ExtensionSystem::Get(profile_)->event_router()->RegisterObserver( 837 this, keys::kOnReferenceFragmentUpdated); 838 ExtensionSystem::Get(profile_)->event_router()->RegisterObserver( 839 this, keys::kOnTabReplaced); 840 } 841 842 WebNavigationAPI::~WebNavigationAPI() { 843 } 844 845 void WebNavigationAPI::Shutdown() { 846 ExtensionSystem::Get(profile_)->event_router()->UnregisterObserver(this); 847 } 848 849 static base::LazyInstance<ProfileKeyedAPIFactory<WebNavigationAPI> > 850 g_factory = LAZY_INSTANCE_INITIALIZER; 851 852 // static 853 ProfileKeyedAPIFactory<WebNavigationAPI>* 854 WebNavigationAPI::GetFactoryInstance() { 855 return &g_factory.Get(); 856 } 857 858 void WebNavigationAPI::OnListenerAdded(const EventListenerInfo& details) { 859 web_navigation_event_router_.reset(new WebNavigationEventRouter(profile_)); 860 ExtensionSystem::Get(profile_)->event_router()->UnregisterObserver(this); 861 } 862 863 #endif // OS_ANDROID 864 865 } // namespace extensions 866