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