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