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 @@
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/tab_contents/navigation_controller.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/render_messages_params.h"
#include "net/base/net_errors.h"
namespace keys = extension_webnavigation_api_constants;
......@@ -125,6 +126,9 @@ void ExtensionWebNavigationEventRouter::Init() {
registrar_.Add(this,
NotificationType::FAIL_PROVISIONAL_LOAD_WITH_ERROR,
NotificationService::AllSources());
registrar_.Add(this,
NotificationType::CREATING_NEW_WINDOW,
NotificationService::AllSources());
registrar_.Add(this,
NotificationType::TAB_CONTENTS_DESTROYED,
NotificationService::AllSources());
......@@ -161,6 +165,11 @@ void ExtensionWebNavigationEventRouter::Observe(
Source<NavigationController>(source).ptr(),
Details<ProvisionalLoadDetails>(details).ptr());
break;
case NotificationType::CREATING_NEW_WINDOW:
CreatingNewWindow(
Source<TabContents>(source).ptr(),
Details<const ViewHostMsg_CreateWindow_Params>(details).ptr());
break;
case NotificationType::TAB_CONTENTS_DESTROYED:
navigation_state_.RemoveTabContentsState(
Source<TabContents>(source).ptr());
......@@ -282,6 +291,24 @@ void ExtensionWebNavigationEventRouter::FailProvisionalLoadWithError(
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(
Profile* profile,
const char* event_name,
......
......@@ -21,6 +21,7 @@
class NavigationController;
class ProvisionalLoadDetails;
class TabContents;
struct ViewHostMsg_CreateWindow_Params;
// Tracks the navigation state of all frames currently known to the
// webNavigation API. It is mainly used to track in which frames an error
......@@ -121,6 +122,12 @@ class ExtensionWebNavigationEventRouter : public NotificationObserver {
void FailProvisionalLoadWithError(NavigationController* controller,
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.
void DispatchEvent(Profile* context,
const char* event_name,
......
......@@ -450,10 +450,7 @@ void RenderMessageFilter::OnMsgCreateWindow(
*cloned_session_storage_namespace_id =
webkit_context_->dom_storage_context()->CloneSessionStorage(
params.session_storage_namespace_id);
render_widget_helper_->CreateNewWindow(params.opener_id,
params.user_gesture,
params.window_container_type,
params.frame_name,
render_widget_helper_->CreateNewWindow(params,
peer_handle(),
route_id);
}
......
......@@ -9,7 +9,9 @@
#include "chrome/browser/browser_thread.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_delegate.h"
#include "chrome/browser/renderer_host/resource_dispatcher_host.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/render_messages_params.h"
// A Task used with InvokeLater that we hold a pointer to in pending_paints_.
......@@ -200,10 +202,7 @@ void RenderWidgetHelper::OnCrossSiteClosePageACK(
}
void RenderWidgetHelper::CreateNewWindow(
int opener_id,
bool user_gesture,
WindowContainerType window_container_type,
const string16& frame_name,
const ViewHostMsg_CreateWindow_Params& params,
base::ProcessHandle render_process,
int* route_id) {
*route_id = GetNextRoutingID();
......@@ -215,18 +214,26 @@ void RenderWidgetHelper::CreateNewWindow(
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
NewRunnableMethod(
this, &RenderWidgetHelper::OnCreateWindowOnUI, opener_id, *route_id,
window_container_type, frame_name));
this, &RenderWidgetHelper::OnCreateWindowOnUI, params, *route_id));
}
void RenderWidgetHelper::OnCreateWindowOnUI(
int opener_id,
int route_id,
WindowContainerType window_container_type,
string16 frame_name) {
RenderViewHost* host = RenderViewHost::FromID(render_process_id_, opener_id);
if (host)
host->CreateNewWindow(route_id, window_container_type, frame_name);
const ViewHostMsg_CreateWindow_Params& params,
int route_id) {
RenderViewHost* host =
RenderViewHost::FromID(render_process_id_, params.opener_id);
if (host) {
host->CreateNewWindow(route_id,
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::IO, FROM_HERE,
......
......@@ -27,8 +27,10 @@ class TimeDelta;
}
class ResourceDispatcherHost;
struct ViewHostMsg_CreateWindow_Params;
struct ViewMsg_ClosePage_Params;
// Instantiated per RenderProcessHost to provide various optimizations on
// behalf of a RenderWidgetHost. This class bridges between the IO thread
// where the RenderProcessHost's MessageFilter lives and the UI thread where
......@@ -121,10 +123,7 @@ class RenderWidgetHelper
// Called on the IO thread when a UpdateRect message is received.
void DidReceiveUpdateMsg(const IPC::Message& msg);
void CreateNewWindow(int opener_id,
bool user_gesture,
WindowContainerType window_container_type,
const string16& frame_name,
void CreateNewWindow(const ViewHostMsg_CreateWindow_Params& params,
base::ProcessHandle render_process,
int* route_id);
void CreateNewWidget(int opener_id,
......@@ -167,10 +166,8 @@ class RenderWidgetHelper
void OnDispatchUpdateMsg(UpdateMsgProxy* proxy);
// Called on the UI thread to finish creating a window.
void OnCreateWindowOnUI(int opener_id,
int route_id,
WindowContainerType window_container_type,
string16 frame_name);
void OnCreateWindowOnUI(const ViewHostMsg_CreateWindow_Params& params,
int route_id);
// Called on the IO thread after a window was created on the UI thread.
void OnCreateWindowOnIO(int route_id);
......
......@@ -149,6 +149,12 @@ class NotificationType {
// are provided.
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 ---------------------------------------------------------------------
// 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;
var capturedEventData;
var nextFrameId;
var frameIds;
var nextTabId;
var tabIds;
function expect(data) {
expectedEventData = data;
capturedEventData = [];
nextFrameId = 1;
frameIds = {};
nextTabId = 0;
tabIds = {};
}
function checkExpectations() {
......@@ -22,13 +26,27 @@ function checkExpectations() {
function captureEvent(name, details) {
// normalize details.
details.timeStamp = 0;
if (details.frameId != 0) {
if ('timeStamp' in details) {
details.timeStamp = 0;
}
if (('frameId' in details) && (details.frameId != 0)) {
if (frameIds[details.frameId] === undefined) {
frameIds[details.frameId] = nextFrameId++;
}
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]);
checkExpectations();
}
......@@ -52,6 +70,11 @@ chrome.experimental.webNavigation.onCompleted.addListener(
captureEvent("onCompleted", details);
});
chrome.experimental.webNavigation.onBeforeRetarget.addListener(
function(details) {
captureEvent("onBeforeRetarget", details);
});
chrome.experimental.webNavigation.onErrorOccurred.addListener(
function(details) {
captureEvent("onErrorOccurred", details);
......@@ -68,13 +91,13 @@ chrome.tabs.getSelected(null, function(tab) {
[ "onBeforeNavigate",
{ frameId: 0,
requestId: 0,
tabId: tabId,
tabId: 0,
timeStamp: 0,
url: getURL('nonexistant.html') }],
[ "onErrorOccurred",
{ error: "net::ERR_FILE_NOT_FOUND",
frameId: 0,
tabId: tabId,
tabId: 0,
timeStamp: 0,
url: getURL('nonexistant.html') }]]);
chrome.tabs.update(tabId, { url: getURL('nonexistant.html') });
......@@ -86,12 +109,12 @@ chrome.tabs.getSelected(null, function(tab) {
[ "onBeforeNavigate",
{ frameId: 0,
requestId: 0,
tabId: tabId,
tabId: 0,
timeStamp: 0,
url: getURL('iframeFail/d.html') }],
[ "onCommitted",
{ frameId: 0,
tabId: tabId,
tabId: 0,
timeStamp: 0,
transitionQualifiers: "",
transitionType: "link",
......@@ -99,23 +122,23 @@ chrome.tabs.getSelected(null, function(tab) {
[ "onBeforeNavigate",
{ frameId: 1,
requestId: 0,
tabId: tabId,
tabId: 0,
timeStamp: 0,
url: getURL('iframeFail/c.html') }],
[ "onDOMContentLoaded",
{ frameId: 0,
tabId: tabId,
tabId: 0,
timeStamp: 0,
url: getURL('iframeFail/d.html') }],
[ "onErrorOccurred",
{ error: "net::ERR_FILE_NOT_FOUND",
frameId: 1,
tabId: tabId,
tabId: 0,
timeStamp: 0,
url: getURL('iframeFail/c.html') }],
[ "onCompleted",
{ frameId: 0,
tabId: tabId,
tabId: 0,
timeStamp: 0,
url: getURL('iframeFail/d.html') }]]);
chrome.tabs.update(tabId, { url: getURL('iframeFail/d.html') });
......@@ -127,12 +150,12 @@ chrome.tabs.getSelected(null, function(tab) {
[ "onBeforeNavigate",
{ frameId: 0,
requestId: 0,
tabId: tabId,
tabId: 0,
timeStamp: 0,
url: getURL('iframeFail/a.html') }],
[ "onCommitted",
{ frameId: 0,
tabId: tabId,
tabId: 0,
timeStamp: 0,
transitionQualifiers: "",
transitionType: "link",
......@@ -140,46 +163,46 @@ chrome.tabs.getSelected(null, function(tab) {
[ "onBeforeNavigate",
{ frameId: 1,
requestId: 0,
tabId: tabId,
tabId: 0,
timeStamp: 0,
url: getURL('iframeFail/b.html') }],
[ "onDOMContentLoaded",
{ frameId: 0,
tabId: tabId,
tabId: 0,
timeStamp: 0,
url: getURL('iframeFail/a.html') }],
[ "onCommitted",
{ frameId: 1,
tabId: tabId,
tabId: 0,
timeStamp: 0,
transitionQualifiers: "",
transitionType: "auto_subframe",
url: getURL('iframeFail/b.html') }],
[ "onDOMContentLoaded",
{ frameId: 1,
tabId: tabId,
tabId: 0,
timeStamp: 0,
url: getURL('iframeFail/b.html') }],
[ "onCompleted",
{ frameId: 1,
tabId: tabId,
tabId: 0,
timeStamp: 0,
url: getURL('iframeFail/b.html') }],
[ "onCompleted",
{ frameId: 0,
tabId: tabId,
tabId: 0,
timeStamp: 0,
url: getURL('iframeFail/a.html') }],
[ "onBeforeNavigate",
{ frameId: 1,
requestId: 0,
tabId: tabId,
tabId: 0,
timeStamp: 0,
url: getURL('iframeFail/c.html') }],
[ "onErrorOccurred",
{ error: "net::ERR_FILE_NOT_FOUND",
frameId: 1,
tabId: tabId,
tabId: 0,
timeStamp: 0,
url: getURL('iframeFail/c.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