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