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