blob: cdf05541e03328a2088f3a166dece1d3821fa5c9 [file] [log] [blame]
// 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/event_router.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/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<content::WebContents*, WebNavigationTabObserver*>
TabObserverMap;
static base::LazyInstance<TabObserverMap> 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<Profile>(source).ptr();
if (profile->GetOriginalProfile() == profile_) {
Retargeting(
content::Details<const RetargetingDetails>(details).ptr());
}
break;
}
case chrome::NOTIFICATION_TAB_ADDED:
TabAdded(content::Details<content::WebContents>(details).ptr());
break;
case content::NOTIFICATION_WEB_CONTENTS_DESTROYED:
TabDestroyed(content::Source<content::WebContents>(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<content::WebContents*, PendingWebContents>::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<content::WebContents*, PendingWebContents>::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_RESOURCE_RECEIVED_REDIRECT,
content::Source<content::WebContents>(web_contents));
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_RESOURCE_RECEIVED_REDIRECT: {
content::ResourceRedirectDetails* resource_redirect_details =
content::Details<content::ResourceRedirectDetails>(details).ptr();
ResourceType::Type resource_type =
resource_redirect_details->resource_type;
if (resource_type == ResourceType::MAIN_FRAME ||
resource_type == ResourceType::SUB_FRAME) {
content::RenderViewHost* render_view_host = NULL;
if (render_view_host_ &&
resource_redirect_details->origin_child_id ==
render_view_host_->GetProcess()->GetID() &&
resource_redirect_details->origin_route_id ==
render_view_host_->GetRoutingID()) {
render_view_host = render_view_host_;
} else if (pending_render_view_host_ &&
resource_redirect_details->origin_child_id ==
pending_render_view_host_->GetProcess()->GetID() &&
resource_redirect_details->origin_route_id ==
pending_render_view_host_->GetRoutingID()) {
render_view_host = pending_render_view_host_;
}
if (!render_view_host)
return;
FrameNavigationState::FrameID frame_id(
resource_redirect_details->frame_id, render_view_host);
navigation_state_.SetIsServerRedirected(frame_id);
}
break;
}
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<content::RenderViewHost>(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,
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<content::PageTransition>(
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,
bool is_main_frame,
const GURL& validated_url,
int error_code,
const 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 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::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<char> replacements;
replacements.ClearRef();
return existing_url.ReplaceComponents(replacements) ==
url.ReplaceComponents(replacements);
}
bool WebNavigationGetFrameFunction::RunImpl() {
scoped_ptr<GetFrame::Params> 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(Value::CreateNullValue());
content::WebContents* web_contents;
if (!ExtensionTabUtil::GetTabById(tab_id,
profile(),
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<GetAllFrames::Params> params(GetAllFrames::Params::Create(*args_));
EXTENSION_FUNCTION_VALIDATE(params.get());
int tab_id = params->details.tab_id;
SetResult(Value::CreateNullValue());
content::WebContents* web_contents;
if (!ExtensionTabUtil::GetTabById(tab_id,
profile(),
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<linked_ptr<GetAllFrames::Results::DetailsType> > 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<GetAllFrames::Results::DetailsType> 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<ProfileKeyedAPIFactory<WebNavigationAPI> >
g_factory = LAZY_INSTANCE_INITIALIZER;
// static
ProfileKeyedAPIFactory<WebNavigationAPI>*
WebNavigationAPI::GetFactoryInstance() {
return &g_factory.Get();
}
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