Commit 420e5740 authored by jochen@chromium.org's avatar jochen@chromium.org

Implement the onBeforeRetarget event of the webNavigation API

TEST=none
BUG=50943

Review URL: http://codereview.chromium.org/6363002

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@72163 0039d316-1c4b-4281-b951-d872f2087c98
parent ad74a59d
...@@ -15,8 +15,9 @@ ...@@ -15,8 +15,9 @@
#include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile.h"
#include "chrome/browser/tab_contents/navigation_controller.h" #include "chrome/browser/tab_contents/navigation_controller.h"
#include "chrome/browser/tab_contents/provisional_load_details.h" #include "chrome/browser/tab_contents/provisional_load_details.h"
#include "chrome/common/notification_type.h" #include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/common/notification_service.h" #include "chrome/common/notification_service.h"
#include "chrome/common/render_messages_params.h"
#include "net/base/net_errors.h" #include "net/base/net_errors.h"
namespace keys = extension_webnavigation_api_constants; namespace keys = extension_webnavigation_api_constants;
...@@ -125,6 +126,9 @@ void ExtensionWebNavigationEventRouter::Init() { ...@@ -125,6 +126,9 @@ void ExtensionWebNavigationEventRouter::Init() {
registrar_.Add(this, registrar_.Add(this,
NotificationType::FAIL_PROVISIONAL_LOAD_WITH_ERROR, NotificationType::FAIL_PROVISIONAL_LOAD_WITH_ERROR,
NotificationService::AllSources()); NotificationService::AllSources());
registrar_.Add(this,
NotificationType::CREATING_NEW_WINDOW,
NotificationService::AllSources());
registrar_.Add(this, registrar_.Add(this,
NotificationType::TAB_CONTENTS_DESTROYED, NotificationType::TAB_CONTENTS_DESTROYED,
NotificationService::AllSources()); NotificationService::AllSources());
...@@ -161,6 +165,11 @@ void ExtensionWebNavigationEventRouter::Observe( ...@@ -161,6 +165,11 @@ void ExtensionWebNavigationEventRouter::Observe(
Source<NavigationController>(source).ptr(), Source<NavigationController>(source).ptr(),
Details<ProvisionalLoadDetails>(details).ptr()); Details<ProvisionalLoadDetails>(details).ptr());
break; break;
case NotificationType::CREATING_NEW_WINDOW:
CreatingNewWindow(
Source<TabContents>(source).ptr(),
Details<const ViewHostMsg_CreateWindow_Params>(details).ptr());
break;
case NotificationType::TAB_CONTENTS_DESTROYED: case NotificationType::TAB_CONTENTS_DESTROYED:
navigation_state_.RemoveTabContentsState( navigation_state_.RemoveTabContentsState(
Source<TabContents>(source).ptr()); Source<TabContents>(source).ptr());
...@@ -282,6 +291,24 @@ void ExtensionWebNavigationEventRouter::FailProvisionalLoadWithError( ...@@ -282,6 +291,24 @@ void ExtensionWebNavigationEventRouter::FailProvisionalLoadWithError(
DispatchEvent(controller->profile(), keys::kOnErrorOccurred, json_args); DispatchEvent(controller->profile(), keys::kOnErrorOccurred, json_args);
} }
void ExtensionWebNavigationEventRouter::CreatingNewWindow(
TabContents* tab_contents,
const ViewHostMsg_CreateWindow_Params* details) {
ListValue args;
DictionaryValue* dict = new DictionaryValue();
dict->SetInteger(keys::kSourceTabIdKey,
ExtensionTabUtil::GetTabId(tab_contents));
dict->SetString(keys::kSourceUrlKey, details->opener_url.spec());
dict->SetString(keys::kTargetUrlKey,
details->target_url.possibly_invalid_spec());
dict->SetReal(keys::kTimeStampKey, MilliSecondsFromTime(base::Time::Now()));
args.Append(dict);
std::string json_args;
base::JSONWriter::Write(&args, false, &json_args);
DispatchEvent(tab_contents->profile(), keys::kOnBeforeRetarget, json_args);
}
void ExtensionWebNavigationEventRouter::DispatchEvent( void ExtensionWebNavigationEventRouter::DispatchEvent(
Profile* profile, Profile* profile,
const char* event_name, const char* event_name,
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
class NavigationController; class NavigationController;
class ProvisionalLoadDetails; class ProvisionalLoadDetails;
class TabContents; class TabContents;
struct ViewHostMsg_CreateWindow_Params;
// Tracks the navigation state of all frames currently known to the // Tracks the navigation state of all frames currently known to the
// webNavigation API. It is mainly used to track in which frames an error // webNavigation API. It is mainly used to track in which frames an error
...@@ -121,6 +122,12 @@ class ExtensionWebNavigationEventRouter : public NotificationObserver { ...@@ -121,6 +122,12 @@ class ExtensionWebNavigationEventRouter : public NotificationObserver {
void FailProvisionalLoadWithError(NavigationController* controller, void FailProvisionalLoadWithError(NavigationController* controller,
ProvisionalLoadDetails* details); ProvisionalLoadDetails* details);
// Handler for the CREATING_NEW_WINDOW event. The method takes the details of
// such an event and constructs a suitable JSON formatted extension event from
// it.
void CreatingNewWindow(TabContents* tab_content,
const ViewHostMsg_CreateWindow_Params* details);
// Dispatches events to the extension message service. // Dispatches events to the extension message service.
void DispatchEvent(Profile* context, void DispatchEvent(Profile* context,
const char* event_name, const char* event_name,
......
...@@ -450,10 +450,7 @@ void RenderMessageFilter::OnMsgCreateWindow( ...@@ -450,10 +450,7 @@ void RenderMessageFilter::OnMsgCreateWindow(
*cloned_session_storage_namespace_id = *cloned_session_storage_namespace_id =
webkit_context_->dom_storage_context()->CloneSessionStorage( webkit_context_->dom_storage_context()->CloneSessionStorage(
params.session_storage_namespace_id); params.session_storage_namespace_id);
render_widget_helper_->CreateNewWindow(params.opener_id, render_widget_helper_->CreateNewWindow(params,
params.user_gesture,
params.window_container_type,
params.frame_name,
peer_handle(), peer_handle(),
route_id); route_id);
} }
......
...@@ -9,7 +9,9 @@ ...@@ -9,7 +9,9 @@
#include "chrome/browser/browser_thread.h" #include "chrome/browser/browser_thread.h"
#include "chrome/browser/renderer_host/render_process_host.h" #include "chrome/browser/renderer_host/render_process_host.h"
#include "chrome/browser/renderer_host/render_view_host.h" #include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/renderer_host/render_view_host_delegate.h"
#include "chrome/browser/renderer_host/resource_dispatcher_host.h" #include "chrome/browser/renderer_host/resource_dispatcher_host.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/render_messages_params.h" #include "chrome/common/render_messages_params.h"
// A Task used with InvokeLater that we hold a pointer to in pending_paints_. // A Task used with InvokeLater that we hold a pointer to in pending_paints_.
...@@ -200,10 +202,7 @@ void RenderWidgetHelper::OnCrossSiteClosePageACK( ...@@ -200,10 +202,7 @@ void RenderWidgetHelper::OnCrossSiteClosePageACK(
} }
void RenderWidgetHelper::CreateNewWindow( void RenderWidgetHelper::CreateNewWindow(
int opener_id, const ViewHostMsg_CreateWindow_Params& params,
bool user_gesture,
WindowContainerType window_container_type,
const string16& frame_name,
base::ProcessHandle render_process, base::ProcessHandle render_process,
int* route_id) { int* route_id) {
*route_id = GetNextRoutingID(); *route_id = GetNextRoutingID();
...@@ -215,18 +214,26 @@ void RenderWidgetHelper::CreateNewWindow( ...@@ -215,18 +214,26 @@ void RenderWidgetHelper::CreateNewWindow(
BrowserThread::PostTask( BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE, BrowserThread::UI, FROM_HERE,
NewRunnableMethod( NewRunnableMethod(
this, &RenderWidgetHelper::OnCreateWindowOnUI, opener_id, *route_id, this, &RenderWidgetHelper::OnCreateWindowOnUI, params, *route_id));
window_container_type, frame_name));
} }
void RenderWidgetHelper::OnCreateWindowOnUI( void RenderWidgetHelper::OnCreateWindowOnUI(
int opener_id, const ViewHostMsg_CreateWindow_Params& params,
int route_id, int route_id) {
WindowContainerType window_container_type, RenderViewHost* host =
string16 frame_name) { RenderViewHost::FromID(render_process_id_, params.opener_id);
RenderViewHost* host = RenderViewHost::FromID(render_process_id_, opener_id); if (host) {
if (host) host->CreateNewWindow(route_id,
host->CreateNewWindow(route_id, window_container_type, frame_name); params.window_container_type,
params.frame_name);
TabContents* tab_contents = host->delegate()->GetAsTabContents();
if (tab_contents) {
NotificationService::current()->Notify(
NotificationType::CREATING_NEW_WINDOW,
Source<TabContents>(tab_contents),
Details<const ViewHostMsg_CreateWindow_Params>(&params));
}
}
BrowserThread::PostTask( BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE, BrowserThread::IO, FROM_HERE,
......
...@@ -27,8 +27,10 @@ class TimeDelta; ...@@ -27,8 +27,10 @@ class TimeDelta;
} }
class ResourceDispatcherHost; class ResourceDispatcherHost;
struct ViewHostMsg_CreateWindow_Params;
struct ViewMsg_ClosePage_Params; struct ViewMsg_ClosePage_Params;
// Instantiated per RenderProcessHost to provide various optimizations on // Instantiated per RenderProcessHost to provide various optimizations on
// behalf of a RenderWidgetHost. This class bridges between the IO thread // behalf of a RenderWidgetHost. This class bridges between the IO thread
// where the RenderProcessHost's MessageFilter lives and the UI thread where // where the RenderProcessHost's MessageFilter lives and the UI thread where
...@@ -121,10 +123,7 @@ class RenderWidgetHelper ...@@ -121,10 +123,7 @@ class RenderWidgetHelper
// Called on the IO thread when a UpdateRect message is received. // Called on the IO thread when a UpdateRect message is received.
void DidReceiveUpdateMsg(const IPC::Message& msg); void DidReceiveUpdateMsg(const IPC::Message& msg);
void CreateNewWindow(int opener_id, void CreateNewWindow(const ViewHostMsg_CreateWindow_Params& params,
bool user_gesture,
WindowContainerType window_container_type,
const string16& frame_name,
base::ProcessHandle render_process, base::ProcessHandle render_process,
int* route_id); int* route_id);
void CreateNewWidget(int opener_id, void CreateNewWidget(int opener_id,
...@@ -167,10 +166,8 @@ class RenderWidgetHelper ...@@ -167,10 +166,8 @@ class RenderWidgetHelper
void OnDispatchUpdateMsg(UpdateMsgProxy* proxy); void OnDispatchUpdateMsg(UpdateMsgProxy* proxy);
// Called on the UI thread to finish creating a window. // Called on the UI thread to finish creating a window.
void OnCreateWindowOnUI(int opener_id, void OnCreateWindowOnUI(const ViewHostMsg_CreateWindow_Params& params,
int route_id, int route_id);
WindowContainerType window_container_type,
string16 frame_name);
// Called on the IO thread after a window was created on the UI thread. // Called on the IO thread after a window was created on the UI thread.
void OnCreateWindowOnIO(int route_id); void OnCreateWindowOnIO(int route_id);
......
...@@ -149,6 +149,12 @@ class NotificationType { ...@@ -149,6 +149,12 @@ class NotificationType {
// are provided. // are provided.
RESOURCE_RECEIVED_REDIRECT, RESOURCE_RECEIVED_REDIRECT,
// A new window is created in response to a request from a renderer. The
// source will be a Source<TabContents> corresponding to the tab the
// request originates from. Details in the form of a
// ViewHostMsg_CreateWindow_Params object are provided.
CREATING_NEW_WINDOW,
// SSL --------------------------------------------------------------------- // SSL ---------------------------------------------------------------------
// Updating the SSL security indicators (the lock icon and such) proceeds // Updating the SSL security indicators (the lock icon and such) proceeds
......
<script>window.setTimeout('window.open("b.html")', 500);</script>
<html><body><iframe src="a.html"></iframe></body></html>
...@@ -3,12 +3,16 @@ var expectedEventData; ...@@ -3,12 +3,16 @@ var expectedEventData;
var capturedEventData; var capturedEventData;
var nextFrameId; var nextFrameId;
var frameIds; var frameIds;
var nextTabId;
var tabIds;
function expect(data) { function expect(data) {
expectedEventData = data; expectedEventData = data;
capturedEventData = []; capturedEventData = [];
nextFrameId = 1; nextFrameId = 1;
frameIds = {}; frameIds = {};
nextTabId = 0;
tabIds = {};
} }
function checkExpectations() { function checkExpectations() {
...@@ -22,13 +26,27 @@ function checkExpectations() { ...@@ -22,13 +26,27 @@ function checkExpectations() {
function captureEvent(name, details) { function captureEvent(name, details) {
// normalize details. // normalize details.
if ('timeStamp' in details) {
details.timeStamp = 0; details.timeStamp = 0;
if (details.frameId != 0) { }
if (('frameId' in details) && (details.frameId != 0)) {
if (frameIds[details.frameId] === undefined) { if (frameIds[details.frameId] === undefined) {
frameIds[details.frameId] = nextFrameId++; frameIds[details.frameId] = nextFrameId++;
} }
details.frameId = frameIds[details.frameId]; details.frameId = frameIds[details.frameId];
} }
if ('tabId' in details) {
if (tabIds[details.tabId] === undefined) {
tabIds[details.tabId] = nextTabId++;
}
details.tabId = tabIds[details.tabId];
}
if ('sourceTabId' in details) {
if (tabIds[details.sourceTabId] === undefined) {
tabIds[details.sourceTabId] = nextTabId++;
}
details.sourceTabId = tabIds[details.sourceTabId];
}
capturedEventData.push([name, details]); capturedEventData.push([name, details]);
checkExpectations(); checkExpectations();
} }
...@@ -52,6 +70,11 @@ chrome.experimental.webNavigation.onCompleted.addListener( ...@@ -52,6 +70,11 @@ chrome.experimental.webNavigation.onCompleted.addListener(
captureEvent("onCompleted", details); captureEvent("onCompleted", details);
}); });
chrome.experimental.webNavigation.onBeforeRetarget.addListener(
function(details) {
captureEvent("onBeforeRetarget", details);
});
chrome.experimental.webNavigation.onErrorOccurred.addListener( chrome.experimental.webNavigation.onErrorOccurred.addListener(
function(details) { function(details) {
captureEvent("onErrorOccurred", details); captureEvent("onErrorOccurred", details);
...@@ -68,13 +91,13 @@ chrome.tabs.getSelected(null, function(tab) { ...@@ -68,13 +91,13 @@ chrome.tabs.getSelected(null, function(tab) {
[ "onBeforeNavigate", [ "onBeforeNavigate",
{ frameId: 0, { frameId: 0,
requestId: 0, requestId: 0,
tabId: tabId, tabId: 0,
timeStamp: 0, timeStamp: 0,
url: getURL('nonexistant.html') }], url: getURL('nonexistant.html') }],
[ "onErrorOccurred", [ "onErrorOccurred",
{ error: "net::ERR_FILE_NOT_FOUND", { error: "net::ERR_FILE_NOT_FOUND",
frameId: 0, frameId: 0,
tabId: tabId, tabId: 0,
timeStamp: 0, timeStamp: 0,
url: getURL('nonexistant.html') }]]); url: getURL('nonexistant.html') }]]);
chrome.tabs.update(tabId, { url: getURL('nonexistant.html') }); chrome.tabs.update(tabId, { url: getURL('nonexistant.html') });
...@@ -86,12 +109,12 @@ chrome.tabs.getSelected(null, function(tab) { ...@@ -86,12 +109,12 @@ chrome.tabs.getSelected(null, function(tab) {
[ "onBeforeNavigate", [ "onBeforeNavigate",
{ frameId: 0, { frameId: 0,
requestId: 0, requestId: 0,
tabId: tabId, tabId: 0,
timeStamp: 0, timeStamp: 0,
url: getURL('iframeFail/d.html') }], url: getURL('iframeFail/d.html') }],
[ "onCommitted", [ "onCommitted",
{ frameId: 0, { frameId: 0,
tabId: tabId, tabId: 0,
timeStamp: 0, timeStamp: 0,
transitionQualifiers: "", transitionQualifiers: "",
transitionType: "link", transitionType: "link",
...@@ -99,23 +122,23 @@ chrome.tabs.getSelected(null, function(tab) { ...@@ -99,23 +122,23 @@ chrome.tabs.getSelected(null, function(tab) {
[ "onBeforeNavigate", [ "onBeforeNavigate",
{ frameId: 1, { frameId: 1,
requestId: 0, requestId: 0,
tabId: tabId, tabId: 0,
timeStamp: 0, timeStamp: 0,
url: getURL('iframeFail/c.html') }], url: getURL('iframeFail/c.html') }],
[ "onDOMContentLoaded", [ "onDOMContentLoaded",
{ frameId: 0, { frameId: 0,
tabId: tabId, tabId: 0,
timeStamp: 0, timeStamp: 0,
url: getURL('iframeFail/d.html') }], url: getURL('iframeFail/d.html') }],
[ "onErrorOccurred", [ "onErrorOccurred",
{ error: "net::ERR_FILE_NOT_FOUND", { error: "net::ERR_FILE_NOT_FOUND",
frameId: 1, frameId: 1,
tabId: tabId, tabId: 0,
timeStamp: 0, timeStamp: 0,
url: getURL('iframeFail/c.html') }], url: getURL('iframeFail/c.html') }],
[ "onCompleted", [ "onCompleted",
{ frameId: 0, { frameId: 0,
tabId: tabId, tabId: 0,
timeStamp: 0, timeStamp: 0,
url: getURL('iframeFail/d.html') }]]); url: getURL('iframeFail/d.html') }]]);
chrome.tabs.update(tabId, { url: getURL('iframeFail/d.html') }); chrome.tabs.update(tabId, { url: getURL('iframeFail/d.html') });
...@@ -127,12 +150,12 @@ chrome.tabs.getSelected(null, function(tab) { ...@@ -127,12 +150,12 @@ chrome.tabs.getSelected(null, function(tab) {
[ "onBeforeNavigate", [ "onBeforeNavigate",
{ frameId: 0, { frameId: 0,
requestId: 0, requestId: 0,
tabId: tabId, tabId: 0,
timeStamp: 0, timeStamp: 0,
url: getURL('iframeFail/a.html') }], url: getURL('iframeFail/a.html') }],
[ "onCommitted", [ "onCommitted",
{ frameId: 0, { frameId: 0,
tabId: tabId, tabId: 0,
timeStamp: 0, timeStamp: 0,
transitionQualifiers: "", transitionQualifiers: "",
transitionType: "link", transitionType: "link",
...@@ -140,46 +163,46 @@ chrome.tabs.getSelected(null, function(tab) { ...@@ -140,46 +163,46 @@ chrome.tabs.getSelected(null, function(tab) {
[ "onBeforeNavigate", [ "onBeforeNavigate",
{ frameId: 1, { frameId: 1,
requestId: 0, requestId: 0,
tabId: tabId, tabId: 0,
timeStamp: 0, timeStamp: 0,
url: getURL('iframeFail/b.html') }], url: getURL('iframeFail/b.html') }],
[ "onDOMContentLoaded", [ "onDOMContentLoaded",
{ frameId: 0, { frameId: 0,
tabId: tabId, tabId: 0,
timeStamp: 0, timeStamp: 0,
url: getURL('iframeFail/a.html') }], url: getURL('iframeFail/a.html') }],
[ "onCommitted", [ "onCommitted",
{ frameId: 1, { frameId: 1,
tabId: tabId, tabId: 0,
timeStamp: 0, timeStamp: 0,
transitionQualifiers: "", transitionQualifiers: "",
transitionType: "auto_subframe", transitionType: "auto_subframe",
url: getURL('iframeFail/b.html') }], url: getURL('iframeFail/b.html') }],
[ "onDOMContentLoaded", [ "onDOMContentLoaded",
{ frameId: 1, { frameId: 1,
tabId: tabId, tabId: 0,
timeStamp: 0, timeStamp: 0,
url: getURL('iframeFail/b.html') }], url: getURL('iframeFail/b.html') }],
[ "onCompleted", [ "onCompleted",
{ frameId: 1, { frameId: 1,
tabId: tabId, tabId: 0,
timeStamp: 0, timeStamp: 0,
url: getURL('iframeFail/b.html') }], url: getURL('iframeFail/b.html') }],
[ "onCompleted", [ "onCompleted",
{ frameId: 0, { frameId: 0,
tabId: tabId, tabId: 0,
timeStamp: 0, timeStamp: 0,
url: getURL('iframeFail/a.html') }], url: getURL('iframeFail/a.html') }],
[ "onBeforeNavigate", [ "onBeforeNavigate",
{ frameId: 1, { frameId: 1,
requestId: 0, requestId: 0,
tabId: tabId, tabId: 0,
timeStamp: 0, timeStamp: 0,
url: getURL('iframeFail/c.html') }], url: getURL('iframeFail/c.html') }],
[ "onErrorOccurred", [ "onErrorOccurred",
{ error: "net::ERR_FILE_NOT_FOUND", { error: "net::ERR_FILE_NOT_FOUND",
frameId: 1, frameId: 1,
tabId: tabId, tabId: 0,
timeStamp: 0, timeStamp: 0,
url: getURL('iframeFail/c.html') }]]); url: getURL('iframeFail/c.html') }]]);
chrome.tabs.update(tabId, { url: getURL('iframeFail/a.html') }); chrome.tabs.update(tabId, { url: getURL('iframeFail/a.html') });
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment