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