// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Implements the Chrome Extensions WebNavigation API. #include "chrome/browser/extensions/api/web_navigation/web_navigation_api.h" #include "base/lazy_instance.h" #include "chrome/browser/chrome_notification_types.h" #include "chrome/browser/extensions/api/web_navigation/web_navigation_api_constants.h" #include "chrome/browser/extensions/api/web_navigation/web_navigation_api_helpers.h" #include "chrome/browser/extensions/extension_system.h" #include "chrome/browser/extensions/extension_tab_util.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/tab_contents/retargeting_details.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_iterator.h" #include "chrome/browser/ui/browser_list.h" #include "chrome/common/extensions/api/web_navigation.h" #include "content/public/browser/navigation_details.h" #include "content/public/browser/notification_service.h" #include "content/public/browser/notification_types.h" #include "content/public/browser/render_process_host.h" #include "content/public/browser/render_view_host.h" #include "content/public/browser/resource_request_details.h" #include "content/public/browser/web_contents.h" #include "content/public/common/url_constants.h" #include "extensions/browser/event_router.h" #include "extensions/browser/view_type_utils.h" #include "net/base/net_errors.h" namespace GetFrame = extensions::api::web_navigation::GetFrame; namespace GetAllFrames = extensions::api::web_navigation::GetAllFrames; DEFINE_WEB_CONTENTS_USER_DATA_KEY(extensions::WebNavigationTabObserver); namespace extensions { #if !defined(OS_ANDROID) namespace helpers = web_navigation_api_helpers; namespace keys = web_navigation_api_constants; namespace web_navigation = api::web_navigation; namespace { typedef std::map TabObserverMap; static base::LazyInstance g_tab_observer = LAZY_INSTANCE_INITIALIZER; } // namespace // WebNavigtionEventRouter ------------------------------------------- WebNavigationEventRouter::PendingWebContents::PendingWebContents() : source_web_contents(NULL), source_frame_id(0), source_frame_is_main_frame(false), target_web_contents(NULL), target_url() { } WebNavigationEventRouter::PendingWebContents::PendingWebContents( content::WebContents* source_web_contents, int64 source_frame_id, bool source_frame_is_main_frame, content::WebContents* target_web_contents, const GURL& target_url) : source_web_contents(source_web_contents), source_frame_id(source_frame_id), source_frame_is_main_frame(source_frame_is_main_frame), target_web_contents(target_web_contents), target_url(target_url) { } WebNavigationEventRouter::PendingWebContents::~PendingWebContents() {} WebNavigationEventRouter::WebNavigationEventRouter(Profile* profile) : profile_(profile) { CHECK(registrar_.IsEmpty()); registrar_.Add(this, chrome::NOTIFICATION_RETARGETING, content::NotificationService::AllSources()); registrar_.Add(this, chrome::NOTIFICATION_TAB_ADDED, content::NotificationService::AllSources()); registrar_.Add(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED, content::NotificationService::AllSources()); BrowserList::AddObserver(this); for (chrome::BrowserIterator it; !it.done(); it.Next()) OnBrowserAdded(*it); } WebNavigationEventRouter::~WebNavigationEventRouter() { for (chrome::BrowserIterator it; !it.done(); it.Next()) OnBrowserRemoved(*it); BrowserList::RemoveObserver(this); } void WebNavigationEventRouter::OnBrowserAdded(Browser* browser) { if (!profile_->IsSameProfile(browser->profile())) return; browser->tab_strip_model()->AddObserver(this); } void WebNavigationEventRouter::OnBrowserRemoved(Browser* browser) { if (!profile_->IsSameProfile(browser->profile())) return; browser->tab_strip_model()->RemoveObserver(this); } void WebNavigationEventRouter::TabReplacedAt( TabStripModel* tab_strip_model, content::WebContents* old_contents, content::WebContents* new_contents, int index) { WebNavigationTabObserver* tab_observer = WebNavigationTabObserver::Get(old_contents); if (!tab_observer) { // If you hit this DCHECK(), please add reproduction steps to // http://crbug.com/109464. DCHECK(GetViewType(old_contents) != VIEW_TYPE_TAB_CONTENTS); return; } const FrameNavigationState& frame_navigation_state = tab_observer->frame_navigation_state(); if (!frame_navigation_state.IsValidUrl(old_contents->GetURL()) || !frame_navigation_state.IsValidUrl(new_contents->GetURL())) return; helpers::DispatchOnTabReplaced(old_contents, profile_, new_contents); } void WebNavigationEventRouter::Observe( int type, const content::NotificationSource& source, const content::NotificationDetails& details) { switch (type) { case chrome::NOTIFICATION_RETARGETING: { Profile* profile = content::Source(source).ptr(); if (profile->GetOriginalProfile() == profile_) { Retargeting( content::Details(details).ptr()); } break; } case chrome::NOTIFICATION_TAB_ADDED: TabAdded(content::Details(details).ptr()); break; case content::NOTIFICATION_WEB_CONTENTS_DESTROYED: TabDestroyed(content::Source(source).ptr()); break; default: NOTREACHED(); } } void WebNavigationEventRouter::Retargeting(const RetargetingDetails* details) { if (details->source_frame_id == 0) return; WebNavigationTabObserver* tab_observer = WebNavigationTabObserver::Get(details->source_web_contents); if (!tab_observer) { // If you hit this DCHECK(), please add reproduction steps to // http://crbug.com/109464. DCHECK(GetViewType(details->source_web_contents) != VIEW_TYPE_TAB_CONTENTS); return; } const FrameNavigationState& frame_navigation_state = tab_observer->frame_navigation_state(); FrameNavigationState::FrameID frame_id( details->source_frame_id, details->source_web_contents->GetRenderViewHost()); if (!frame_navigation_state.CanSendEvents(frame_id)) return; // If the WebContents isn't yet inserted into a tab strip, we need to delay // the extension event until the WebContents is fully initialized. if (details->not_yet_in_tabstrip) { pending_web_contents_[details->target_web_contents] = PendingWebContents( details->source_web_contents, details->source_frame_id, frame_navigation_state.IsMainFrame(frame_id), details->target_web_contents, details->target_url); } else { helpers::DispatchOnCreatedNavigationTarget( details->source_web_contents, details->target_web_contents->GetBrowserContext(), details->source_frame_id, frame_navigation_state.IsMainFrame(frame_id), details->target_web_contents, details->target_url); } } void WebNavigationEventRouter::TabAdded(content::WebContents* tab) { std::map::iterator iter = pending_web_contents_.find(tab); if (iter == pending_web_contents_.end()) return; WebNavigationTabObserver* tab_observer = WebNavigationTabObserver::Get(iter->second.source_web_contents); if (!tab_observer) { NOTREACHED(); return; } const FrameNavigationState& frame_navigation_state = tab_observer->frame_navigation_state(); FrameNavigationState::FrameID frame_id( iter->second.source_frame_id, iter->second.source_web_contents->GetRenderViewHost()); if (frame_navigation_state.CanSendEvents(frame_id)) { helpers::DispatchOnCreatedNavigationTarget( iter->second.source_web_contents, iter->second.target_web_contents->GetBrowserContext(), iter->second.source_frame_id, iter->second.source_frame_is_main_frame, iter->second.target_web_contents, iter->second.target_url); } pending_web_contents_.erase(iter); } void WebNavigationEventRouter::TabDestroyed(content::WebContents* tab) { pending_web_contents_.erase(tab); for (std::map::iterator i = pending_web_contents_.begin(); i != pending_web_contents_.end(); ) { if (i->second.source_web_contents == tab) pending_web_contents_.erase(i++); else ++i; } } // WebNavigationTabObserver ------------------------------------------ WebNavigationTabObserver::WebNavigationTabObserver( content::WebContents* web_contents) : WebContentsObserver(web_contents), render_view_host_(NULL), pending_render_view_host_(NULL) { g_tab_observer.Get().insert(TabObserverMap::value_type(web_contents, this)); registrar_.Add(this, content::NOTIFICATION_RENDER_VIEW_HOST_WILL_CLOSE_RENDER_VIEW, content::NotificationService::AllSources()); } WebNavigationTabObserver::~WebNavigationTabObserver() {} // static WebNavigationTabObserver* WebNavigationTabObserver::Get( content::WebContents* web_contents) { TabObserverMap::iterator i = g_tab_observer.Get().find(web_contents); return i == g_tab_observer.Get().end() ? NULL : i->second; } content::RenderViewHost* WebNavigationTabObserver::GetRenderViewHostInProcess( int process_id) const { if (render_view_host_ && render_view_host_->GetProcess()->GetID() == process_id) { return render_view_host_; } if (pending_render_view_host_ && pending_render_view_host_->GetProcess()->GetID() == process_id) { return pending_render_view_host_; } return NULL; } void WebNavigationTabObserver::Observe( int type, const content::NotificationSource& source, const content::NotificationDetails& details) { switch (type) { case content::NOTIFICATION_RENDER_VIEW_HOST_WILL_CLOSE_RENDER_VIEW: { // The RenderView is technically not yet deleted, but the RenderViewHost // already starts to filter out some IPCs. In order to not get confused, // we consider the RenderView dead already now. RenderViewDeleted(content::Source(source).ptr()); break; } default: NOTREACHED(); } } void WebNavigationTabObserver::RenderViewDeleted( content::RenderViewHost* render_view_host) { if (render_view_host == render_view_host_) { render_view_host_ = NULL; if (pending_render_view_host_) { render_view_host_ = pending_render_view_host_; pending_render_view_host_ = NULL; } } else if (render_view_host == pending_render_view_host_) { pending_render_view_host_ = NULL; } else { return; } SendErrorEvents( web_contents(), render_view_host, FrameNavigationState::FrameID()); } void WebNavigationTabObserver::AboutToNavigateRenderView( content::RenderViewHost* render_view_host) { if (!render_view_host_) { render_view_host_ = render_view_host; } else if (render_view_host != render_view_host_) { if (pending_render_view_host_) { SendErrorEvents(web_contents(), pending_render_view_host_, FrameNavigationState::FrameID()); } pending_render_view_host_ = render_view_host; } } void WebNavigationTabObserver::DidStartProvisionalLoadForFrame( int64 frame_num, int64 parent_frame_num, bool is_main_frame, const GURL& validated_url, bool is_error_page, bool is_iframe_srcdoc, content::RenderViewHost* render_view_host) { DVLOG(2) << "DidStartProvisionalLoad(" << "render_view_host=" << render_view_host << ", frame_num=" << frame_num << ", url=" << validated_url << ")"; if (!render_view_host_) render_view_host_ = render_view_host; if (render_view_host != render_view_host_ && render_view_host != pending_render_view_host_) return; FrameNavigationState::FrameID frame_id(frame_num, render_view_host); FrameNavigationState::FrameID parent_frame_id( parent_frame_num, render_view_host); navigation_state_.TrackFrame(frame_id, parent_frame_id, validated_url, is_main_frame, is_error_page, is_iframe_srcdoc); if (!navigation_state_.CanSendEvents(frame_id)) return; helpers::DispatchOnBeforeNavigate( web_contents(), render_view_host->GetProcess()->GetID(), frame_num, is_main_frame, parent_frame_num, navigation_state_.IsMainFrame(parent_frame_id), navigation_state_.GetUrl(frame_id)); } void WebNavigationTabObserver::DidCommitProvisionalLoadForFrame( int64 frame_num, const base::string16& frame_unique_name, bool is_main_frame, const GURL& url, content::PageTransition transition_type, content::RenderViewHost* render_view_host) { DVLOG(2) << "DidCommitProvisionalLoad(" << "render_view_host=" << render_view_host << ", frame_num=" << frame_num << ", url=" << url << ")"; if (render_view_host != render_view_host_ && render_view_host != pending_render_view_host_) return; FrameNavigationState::FrameID frame_id(frame_num, render_view_host); bool is_reference_fragment_navigation = IsReferenceFragmentNavigation(frame_id, url); bool is_history_state_modification = navigation_state_.GetNavigationCommitted(frame_id); if (is_main_frame && render_view_host_ == render_view_host) { // Changing the reference fragment or the history state using // history.pushState or history.replaceState does not cancel on-going // iframe navigations. if (!is_reference_fragment_navigation && !is_history_state_modification) SendErrorEvents(web_contents(), render_view_host_, frame_id); if (pending_render_view_host_) { SendErrorEvents(web_contents(), pending_render_view_host_, FrameNavigationState::FrameID()); pending_render_view_host_ = NULL; } } else if (pending_render_view_host_ == render_view_host) { SendErrorEvents( web_contents(), render_view_host_, FrameNavigationState::FrameID()); render_view_host_ = pending_render_view_host_; pending_render_view_host_ = NULL; } // Update the URL as it might have changed. navigation_state_.UpdateFrame(frame_id, url); navigation_state_.SetNavigationCommitted(frame_id); if (!navigation_state_.CanSendEvents(frame_id)) return; if (is_reference_fragment_navigation) { helpers::DispatchOnCommitted( web_navigation::OnReferenceFragmentUpdated::kEventName, web_contents(), frame_num, is_main_frame, navigation_state_.GetUrl(frame_id), transition_type); } else if (is_history_state_modification) { helpers::DispatchOnCommitted( web_navigation::OnHistoryStateUpdated::kEventName, web_contents(), frame_num, is_main_frame, navigation_state_.GetUrl(frame_id), transition_type); } else { if (navigation_state_.GetIsServerRedirected(frame_id)) { transition_type = static_cast( transition_type | content::PAGE_TRANSITION_SERVER_REDIRECT); } helpers::DispatchOnCommitted( web_navigation::OnCommitted::kEventName, web_contents(), frame_num, is_main_frame, navigation_state_.GetUrl(frame_id), transition_type); } } void WebNavigationTabObserver::DidFailProvisionalLoad( int64 frame_num, const base::string16& frame_unique_id, bool is_main_frame, const GURL& validated_url, int error_code, const base::string16& error_description, content::RenderViewHost* render_view_host) { DVLOG(2) << "DidFailProvisionalLoad(" << "render_view_host=" << render_view_host << ", frame_num=" << frame_num << ", url=" << validated_url << ")"; if (render_view_host != render_view_host_ && render_view_host != pending_render_view_host_) return; bool stop_tracking_frames = false; if (render_view_host == pending_render_view_host_) { pending_render_view_host_ = NULL; stop_tracking_frames = true; } FrameNavigationState::FrameID frame_id(frame_num, render_view_host); if (navigation_state_.CanSendEvents(frame_id)) { helpers::DispatchOnErrorOccurred( web_contents(), render_view_host->GetProcess()->GetID(), navigation_state_.GetUrl(frame_id), frame_num, is_main_frame, error_code); } navigation_state_.SetErrorOccurredInFrame(frame_id); if (stop_tracking_frames) { navigation_state_.StopTrackingFramesInRVH(render_view_host, FrameNavigationState::FrameID()); } } void WebNavigationTabObserver::DocumentLoadedInFrame( int64 frame_num, content::RenderViewHost* render_view_host) { DVLOG(2) << "DocumentLoadedInFrame(" << "render_view_host=" << render_view_host << ", frame_num=" << frame_num << ")"; if (render_view_host != render_view_host_) return; FrameNavigationState::FrameID frame_id(frame_num, render_view_host); if (!navigation_state_.CanSendEvents(frame_id)) return; navigation_state_.SetParsingFinished(frame_id); helpers::DispatchOnDOMContentLoaded(web_contents(), navigation_state_.GetUrl(frame_id), navigation_state_.IsMainFrame(frame_id), frame_num); if (!navigation_state_.GetNavigationCompleted(frame_id)) return; // The load might already have finished by the time we finished parsing. For // compatibility reasons, we artifically delay the load completed signal until // after parsing was completed. helpers::DispatchOnCompleted(web_contents(), navigation_state_.GetUrl(frame_id), navigation_state_.IsMainFrame(frame_id), frame_num); } void WebNavigationTabObserver::DidFinishLoad( int64 frame_num, const GURL& validated_url, bool is_main_frame, content::RenderViewHost* render_view_host) { DVLOG(2) << "DidFinishLoad(" << "render_view_host=" << render_view_host << ", frame_num=" << frame_num << ", url=" << validated_url << ")"; if (render_view_host != render_view_host_) return; FrameNavigationState::FrameID frame_id(frame_num, render_view_host); // When showing replacement content, we might get load signals for frames // that weren't reguarly loaded. if (!navigation_state_.IsValidFrame(frame_id)) return; navigation_state_.SetNavigationCompleted(frame_id); if (!navigation_state_.CanSendEvents(frame_id)) return; DCHECK( navigation_state_.GetUrl(frame_id) == validated_url || (navigation_state_.GetUrl(frame_id) == GURL(content::kAboutSrcDocURL) && validated_url == GURL(content::kAboutBlankURL))) << "validated URL is " << validated_url << " but we expected " << navigation_state_.GetUrl(frame_id); DCHECK_EQ(navigation_state_.IsMainFrame(frame_id), is_main_frame); // The load might already have finished by the time we finished parsing. For // compatibility reasons, we artifically delay the load completed signal until // after parsing was completed. if (!navigation_state_.GetParsingFinished(frame_id)) return; helpers::DispatchOnCompleted(web_contents(), navigation_state_.GetUrl(frame_id), is_main_frame, frame_num); } void WebNavigationTabObserver::DidFailLoad( int64 frame_num, const GURL& validated_url, bool is_main_frame, int error_code, const base::string16& error_description, content::RenderViewHost* render_view_host) { DVLOG(2) << "DidFailLoad(" << "render_view_host=" << render_view_host << ", frame_num=" << frame_num << ", url=" << validated_url << ")"; if (render_view_host != render_view_host_) return; FrameNavigationState::FrameID frame_id(frame_num, render_view_host); // When showing replacement content, we might get load signals for frames // that weren't reguarly loaded. if (!navigation_state_.IsValidFrame(frame_id)) return; if (navigation_state_.CanSendEvents(frame_id)) { helpers::DispatchOnErrorOccurred( web_contents(), render_view_host->GetProcess()->GetID(), navigation_state_.GetUrl(frame_id), frame_num, is_main_frame, error_code); } navigation_state_.SetErrorOccurredInFrame(frame_id); } void WebNavigationTabObserver::DidGetRedirectForResourceRequest( content::RenderViewHost* render_view_host, const content::ResourceRedirectDetails& details) { if (details.resource_type != ResourceType::MAIN_FRAME && details.resource_type != ResourceType::SUB_FRAME) { return; } FrameNavigationState::FrameID frame_id(details.frame_id, render_view_host); navigation_state_.SetIsServerRedirected(frame_id); } void WebNavigationTabObserver::DidOpenRequestedURL( content::WebContents* new_contents, const GURL& url, const content::Referrer& referrer, WindowOpenDisposition disposition, content::PageTransition transition, int64 source_frame_num) { FrameNavigationState::FrameID frame_id(source_frame_num, render_view_host_); if (!navigation_state_.CanSendEvents(frame_id)) return; // We only send the onCreatedNavigationTarget if we end up creating a new // window. if (disposition != SINGLETON_TAB && disposition != NEW_FOREGROUND_TAB && disposition != NEW_BACKGROUND_TAB && disposition != NEW_POPUP && disposition != NEW_WINDOW && disposition != OFF_THE_RECORD) return; helpers::DispatchOnCreatedNavigationTarget( web_contents(), new_contents->GetBrowserContext(), source_frame_num, navigation_state_.IsMainFrame(frame_id), new_contents, url); } void WebNavigationTabObserver::FrameDetached( content::RenderViewHost* render_view_host, int64 frame_num) { if (render_view_host != render_view_host_ && render_view_host != pending_render_view_host_) { return; } FrameNavigationState::FrameID frame_id(frame_num, render_view_host); if (navigation_state_.CanSendEvents(frame_id) && !navigation_state_.GetNavigationCompleted(frame_id)) { helpers::DispatchOnErrorOccurred( web_contents(), render_view_host->GetProcess()->GetID(), navigation_state_.GetUrl(frame_id), frame_num, navigation_state_.IsMainFrame(frame_id), net::ERR_ABORTED); } navigation_state_.FrameDetached(frame_id); } void WebNavigationTabObserver::WebContentsDestroyed(content::WebContents* tab) { g_tab_observer.Get().erase(tab); registrar_.RemoveAll(); SendErrorEvents(tab, NULL, FrameNavigationState::FrameID()); } void WebNavigationTabObserver::SendErrorEvents( content::WebContents* web_contents, content::RenderViewHost* render_view_host, FrameNavigationState::FrameID id_to_skip) { for (FrameNavigationState::const_iterator frame = navigation_state_.begin(); frame != navigation_state_.end(); ++frame) { if (!navigation_state_.GetNavigationCompleted(*frame) && navigation_state_.CanSendEvents(*frame) && *frame != id_to_skip && (!render_view_host || frame->render_view_host == render_view_host)) { navigation_state_.SetErrorOccurredInFrame(*frame); helpers::DispatchOnErrorOccurred( web_contents, frame->render_view_host->GetProcess()->GetID(), navigation_state_.GetUrl(*frame), frame->frame_num, navigation_state_.IsMainFrame(*frame), net::ERR_ABORTED); } } if (render_view_host) navigation_state_.StopTrackingFramesInRVH(render_view_host, id_to_skip); } // See also NavigationController::IsURLInPageNavigation. bool WebNavigationTabObserver::IsReferenceFragmentNavigation( FrameNavigationState::FrameID frame_id, const GURL& url) { GURL existing_url = navigation_state_.GetUrl(frame_id); if (existing_url == url) return false; url_canon::Replacements replacements; replacements.ClearRef(); return existing_url.ReplaceComponents(replacements) == url.ReplaceComponents(replacements); } bool WebNavigationGetFrameFunction::RunImpl() { scoped_ptr params(GetFrame::Params::Create(*args_)); EXTENSION_FUNCTION_VALIDATE(params.get()); int tab_id = params->details.tab_id; int frame_id = params->details.frame_id; int process_id = params->details.process_id; SetResult(base::Value::CreateNullValue()); content::WebContents* web_contents; if (!ExtensionTabUtil::GetTabById(tab_id, GetProfile(), include_incognito(), NULL, NULL, &web_contents, NULL) || !web_contents) { return true; } WebNavigationTabObserver* observer = WebNavigationTabObserver::Get(web_contents); DCHECK(observer); const FrameNavigationState& frame_navigation_state = observer->frame_navigation_state(); if (frame_id == 0) frame_id = frame_navigation_state.GetMainFrameID().frame_num; content::RenderViewHost* render_view_host = observer->GetRenderViewHostInProcess(process_id); if (!render_view_host) return true; FrameNavigationState::FrameID internal_frame_id(frame_id, render_view_host); if (!frame_navigation_state.IsValidFrame(internal_frame_id)) return true; GURL frame_url = frame_navigation_state.GetUrl(internal_frame_id); if (!frame_navigation_state.IsValidUrl(frame_url)) return true; GetFrame::Results::Details frame_details; frame_details.url = frame_url.spec(); frame_details.error_occurred = frame_navigation_state.GetErrorOccurredInFrame(internal_frame_id); FrameNavigationState::FrameID parent_frame_id = frame_navigation_state.GetParentFrameID(internal_frame_id); frame_details.parent_frame_id = helpers::GetFrameId( frame_navigation_state.IsMainFrame(parent_frame_id), parent_frame_id.frame_num); results_ = GetFrame::Results::Create(frame_details); return true; } bool WebNavigationGetAllFramesFunction::RunImpl() { scoped_ptr params(GetAllFrames::Params::Create(*args_)); EXTENSION_FUNCTION_VALIDATE(params.get()); int tab_id = params->details.tab_id; SetResult(base::Value::CreateNullValue()); content::WebContents* web_contents; if (!ExtensionTabUtil::GetTabById(tab_id, GetProfile(), include_incognito(), NULL, NULL, &web_contents, NULL) || !web_contents) { return true; } WebNavigationTabObserver* observer = WebNavigationTabObserver::Get(web_contents); DCHECK(observer); const FrameNavigationState& navigation_state = observer->frame_navigation_state(); std::vector > result_list; for (FrameNavigationState::const_iterator it = navigation_state.begin(); it != navigation_state.end(); ++it) { FrameNavigationState::FrameID frame_id = *it; FrameNavigationState::FrameID parent_frame_id = navigation_state.GetParentFrameID(frame_id); GURL frame_url = navigation_state.GetUrl(frame_id); if (!navigation_state.IsValidUrl(frame_url)) continue; linked_ptr frame( new GetAllFrames::Results::DetailsType()); frame->url = frame_url.spec(); frame->frame_id = helpers::GetFrameId( navigation_state.IsMainFrame(frame_id), frame_id.frame_num); frame->parent_frame_id = helpers::GetFrameId( navigation_state.IsMainFrame(parent_frame_id), parent_frame_id.frame_num); frame->process_id = frame_id.render_view_host->GetProcess()->GetID(); frame->error_occurred = navigation_state.GetErrorOccurredInFrame(frame_id); result_list.push_back(frame); } results_ = GetAllFrames::Results::Create(result_list); return true; } WebNavigationAPI::WebNavigationAPI(Profile* profile) : profile_(profile) { ExtensionSystem::Get(profile_)->event_router()->RegisterObserver( this, web_navigation::OnBeforeNavigate::kEventName); ExtensionSystem::Get(profile_)->event_router()->RegisterObserver( this, web_navigation::OnCommitted::kEventName); ExtensionSystem::Get(profile_)->event_router()->RegisterObserver( this, web_navigation::OnCompleted::kEventName); ExtensionSystem::Get(profile_)->event_router()->RegisterObserver( this, web_navigation::OnCreatedNavigationTarget::kEventName); ExtensionSystem::Get(profile_)->event_router()->RegisterObserver( this, web_navigation::OnDOMContentLoaded::kEventName); ExtensionSystem::Get(profile_)->event_router()->RegisterObserver( this, web_navigation::OnHistoryStateUpdated::kEventName); ExtensionSystem::Get(profile_)->event_router()->RegisterObserver( this, web_navigation::OnErrorOccurred::kEventName); ExtensionSystem::Get(profile_)->event_router()->RegisterObserver( this, web_navigation::OnReferenceFragmentUpdated::kEventName); ExtensionSystem::Get(profile_)->event_router()->RegisterObserver( this, web_navigation::OnTabReplaced::kEventName); } WebNavigationAPI::~WebNavigationAPI() { } void WebNavigationAPI::Shutdown() { ExtensionSystem::Get(profile_)->event_router()->UnregisterObserver(this); } static base::LazyInstance > g_factory = LAZY_INSTANCE_INITIALIZER; // static ProfileKeyedAPIFactory* WebNavigationAPI::GetFactoryInstance() { return g_factory.Pointer(); } void WebNavigationAPI::OnListenerAdded(const EventListenerInfo& details) { web_navigation_event_router_.reset(new WebNavigationEventRouter(profile_)); ExtensionSystem::Get(profile_)->event_router()->UnregisterObserver(this); } #endif // OS_ANDROID } // namespace extensions