Home | History | Annotate | Download | only in web_navigation
      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