summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/automation/automation_provider.cc8
-rw-r--r--chrome/browser/automation/automation_provider.h4
-rw-r--r--chrome/browser/external_tab_container.cc6
-rw-r--r--chrome/browser/external_tab_container.h4
-rw-r--r--chrome/browser/renderer_host/render_view_host.cc13
-rw-r--r--chrome/browser/renderer_host/render_view_host.h8
-rw-r--r--chrome/browser/renderer_host/render_view_host_delegate.h5
-rw-r--r--chrome/browser/tab_contents/tab_contents_delegate.h5
-rw-r--r--chrome/browser/tab_contents/web_contents.cc6
-rw-r--r--chrome/browser/tab_contents/web_contents.h4
-rw-r--r--chrome/common/render_messages_internal.h12
-rw-r--r--chrome/common/temp_scaffolding_stubs.cc3
-rw-r--r--chrome/renderer/external_host_bindings.cc144
-rw-r--r--chrome/renderer/external_host_bindings.h27
-rw-r--r--chrome/renderer/render_view.cc7
-rw-r--r--chrome/renderer/render_view.h4
-rw-r--r--chrome/test/automation/automation_messages_internal.h12
-rw-r--r--chrome/test/automation/automation_proxy_uitest.cc193
-rw-r--r--chrome/test/automation/tab_proxy.cc6
-rw-r--r--chrome/test/automation/tab_proxy.h4
-rw-r--r--chrome/test/ui/ui_test.cc7
-rw-r--r--chrome/test/ui/ui_test.h3
-rw-r--r--webkit/glue/webframe.h2
-rw-r--r--webkit/glue/webframe_impl.cc7
-rw-r--r--webkit/glue/webframe_impl.h2
25 files changed, 427 insertions, 69 deletions
diff --git a/chrome/browser/automation/automation_provider.cc b/chrome/browser/automation/automation_provider.cc
index 72767c5..d127040 100644
--- a/chrome/browser/automation/automation_provider.cc
+++ b/chrome/browser/automation/automation_provider.cc
@@ -2435,8 +2435,10 @@ void AutomationProvider::AutocompleteEditIsQueryInProgress(
}
}
-void AutomationProvider::OnMessageFromExternalHost(
- int handle, const std::string& message) {
+void AutomationProvider::OnMessageFromExternalHost(int handle,
+ const std::string& message,
+ const std::string& origin,
+ const std::string& target) {
if (tab_tracker_->ContainsHandle(handle)) {
NavigationController* tab = tab_tracker_->GetResource(handle);
if (!tab) {
@@ -2460,7 +2462,7 @@ void AutomationProvider::OnMessageFromExternalHost(
return;
}
- view_host->ForwardMessageFromExternalHost(message);
+ view_host->ForwardMessageFromExternalHost(message, origin, target);
}
}
diff --git a/chrome/browser/automation/automation_provider.h b/chrome/browser/automation/automation_provider.h
index 26fd979..c9aa0be 100644
--- a/chrome/browser/automation/automation_provider.h
+++ b/chrome/browser/automation/automation_provider.h
@@ -352,7 +352,9 @@ class AutomationProvider : public base::RefCounted<AutomationProvider>,
std::vector<AutocompleteMatchData>* matches);
// Handler for a message sent by the automation client.
- void OnMessageFromExternalHost(int handle, const std::string& message);
+ void OnMessageFromExternalHost(int handle, const std::string& message,
+ const std::string& origin,
+ const std::string& target);
// Retrieves the number of SSL related info-bars currently showing in |count|.
void GetSSLInfoBarCount(int handle, int* count);
diff --git a/chrome/browser/external_tab_container.cc b/chrome/browser/external_tab_container.cc
index be8cbdc..9fc97ce 100644
--- a/chrome/browser/external_tab_container.cc
+++ b/chrome/browser/external_tab_container.cc
@@ -260,10 +260,12 @@ void ExternalTabContainer::ToolbarSizeChanged(TabContents* source,
}
void ExternalTabContainer::ForwardMessageToExternalHost(
- const std::string& message) {
+ const std::string& message, const std::string& origin,
+ const std::string& target) {
if(automation_) {
automation_->Send(
- new AutomationMsg_ForwardMessageToExternalHost(0, message));
+ new AutomationMsg_ForwardMessageToExternalHost(0, message, origin,
+ target));
}
}
diff --git a/chrome/browser/external_tab_container.h b/chrome/browser/external_tab_container.h
index 1bde9f9..d1825d0 100644
--- a/chrome/browser/external_tab_container.h
+++ b/chrome/browser/external_tab_container.h
@@ -83,7 +83,9 @@ class ExternalTabContainer : public TabContentsDelegate,
virtual void UpdateTargetURL(TabContents* source, const GURL& url);
virtual void ContentsZoomChange(bool zoom_in);
virtual void ToolbarSizeChanged(TabContents* source, bool is_animating);
- virtual void ForwardMessageToExternalHost(const std::string& message);
+ virtual void ForwardMessageToExternalHost(const std::string& message,
+ const std::string& origin,
+ const std::string& target);
virtual bool IsExternalTabContainer() const {
return true;
};
diff --git a/chrome/browser/renderer_host/render_view_host.cc b/chrome/browser/renderer_host/render_view_host.cc
index 68654f4e..155f6a3 100644
--- a/chrome/browser/renderer_host/render_view_host.cc
+++ b/chrome/browser/renderer_host/render_view_host.cc
@@ -1048,8 +1048,9 @@ void RenderViewHost::OnMsgDOMUISend(
}
void RenderViewHost::OnMsgForwardMessageToExternalHost(
- const std::string& message) {
- delegate_->ProcessExternalHostMessage(message);
+ const std::string& message, const std::string& origin,
+ const std::string& target) {
+ delegate_->ProcessExternalHostMessage(message, origin, target);
}
#ifdef CHROME_PERSONALIZATION
@@ -1337,7 +1338,9 @@ void RenderViewHost::RaisePersonalizationEvent(std::string event_name,
}
#endif
-void RenderViewHost::ForwardMessageFromExternalHost(
- const std::string& message) {
- Send(new ViewMsg_HandleMessageFromExternalHost(routing_id(), message));
+void RenderViewHost::ForwardMessageFromExternalHost(const std::string& message,
+ const std::string& origin,
+ const std::string& target) {
+ Send(new ViewMsg_HandleMessageFromExternalHost(routing_id(), message, origin,
+ target));
}
diff --git a/chrome/browser/renderer_host/render_view_host.h b/chrome/browser/renderer_host/render_view_host.h
index a10f421..62bdd64 100644
--- a/chrome/browser/renderer_host/render_view_host.h
+++ b/chrome/browser/renderer_host/render_view_host.h
@@ -398,7 +398,9 @@ class RenderViewHost : public RenderWidgetHost {
#endif
// Forward a message from external host to chrome renderer.
- void ForwardMessageFromExternalHost(const std::string& message);
+ void ForwardMessageFromExternalHost(const std::string& message,
+ const std::string& origin,
+ const std::string& target);
// Message the renderer that we should be counted as a new document and not
// as a popup.
@@ -485,7 +487,9 @@ class RenderViewHost : public RenderWidgetHost {
int automation_id);
void OnMsgDOMUISend(const std::string& message,
const std::string& content);
- void OnMsgForwardMessageToExternalHost(const std::string& message);
+ void OnMsgForwardMessageToExternalHost(const std::string& message,
+ const std::string& origin,
+ const std::string& target);
#ifdef CHROME_PERSONALIZATION
void OnPersonalizationEvent(const std::string& message,
const std::string& content);
diff --git a/chrome/browser/renderer_host/render_view_host_delegate.h b/chrome/browser/renderer_host/render_view_host_delegate.h
index 302a1d0..db6623d 100644
--- a/chrome/browser/renderer_host/render_view_host_delegate.h
+++ b/chrome/browser/renderer_host/render_view_host_delegate.h
@@ -258,7 +258,10 @@ class RenderViewHostDelegate {
// A message for external host. By default we ignore such messages.
// |receiver| can be a receiving script and |message| is any
// arbitrary string that makes sense to the receiver.
- virtual void ProcessExternalHostMessage(const std::string& message) { }
+ virtual void ProcessExternalHostMessage(const std::string& message,
+ const std::string& origin,
+ const std::string& target) {
+ }
// Navigate to the history entry for the given offset from the current
// position within the NavigationController. Makes no change if offset is
diff --git a/chrome/browser/tab_contents/tab_contents_delegate.h b/chrome/browser/tab_contents/tab_contents_delegate.h
index f97a6dc50..74cee1e 100644
--- a/chrome/browser/tab_contents/tab_contents_delegate.h
+++ b/chrome/browser/tab_contents/tab_contents_delegate.h
@@ -138,7 +138,10 @@ class TabContentsDelegate : public PageNavigator {
}
// Send IPC to external host. Default implementation is do nothing.
- virtual void ForwardMessageToExternalHost(const std::string& message) {}
+ virtual void ForwardMessageToExternalHost(const std::string& message,
+ const std::string& origin,
+ const std::string& target) {
+ }
// If the delegate is hosting tabs externally.
virtual bool IsExternalTabContainer() const { return false; }
diff --git a/chrome/browser/tab_contents/web_contents.cc b/chrome/browser/tab_contents/web_contents.cc
index affa867..8f1a5ea 100644
--- a/chrome/browser/tab_contents/web_contents.cc
+++ b/chrome/browser/tab_contents/web_contents.cc
@@ -1007,9 +1007,11 @@ void WebContents::DomOperationResponse(const std::string& json_string,
Details<DomOperationNotificationDetails>(&details));
}
-void WebContents::ProcessExternalHostMessage(const std::string& message) {
+void WebContents::ProcessExternalHostMessage(const std::string& message,
+ const std::string& origin,
+ const std::string& target) {
if (delegate())
- delegate()->ForwardMessageToExternalHost(message);
+ delegate()->ForwardMessageToExternalHost(message, origin, target);
}
void WebContents::GoToEntryAtOffset(int offset) {
diff --git a/chrome/browser/tab_contents/web_contents.h b/chrome/browser/tab_contents/web_contents.h
index e1d21de..8496841 100644
--- a/chrome/browser/tab_contents/web_contents.h
+++ b/chrome/browser/tab_contents/web_contents.h
@@ -334,7 +334,9 @@ class WebContents : public TabContents,
WindowOpenDisposition disposition);
virtual void DomOperationResponse(const std::string& json_string,
int automation_id);
- virtual void ProcessExternalHostMessage(const std::string& message);
+ virtual void ProcessExternalHostMessage(const std::string& message,
+ const std::string& origin,
+ const std::string& target);
virtual void GoToEntryAtOffset(int offset);
virtual void GetHistoryListCount(int* back_list_count,
int* forward_list_count);
diff --git a/chrome/common/render_messages_internal.h b/chrome/common/render_messages_internal.h
index e0fd20c..80b78e1 100644
--- a/chrome/common/render_messages_internal.h
+++ b/chrome/common/render_messages_internal.h
@@ -457,8 +457,10 @@ IPC_BEGIN_MESSAGES(View)
std::string /* event arguments */)
#endif
// Posts a message to the renderer.
- IPC_MESSAGE_ROUTED1(ViewMsg_HandleMessageFromExternalHost,
- std::string /* The message */)
+ IPC_MESSAGE_ROUTED3(ViewMsg_HandleMessageFromExternalHost,
+ std::string /* The message */,
+ std::string /* The origin */,
+ std::string /* The target*/)
// Sent to the renderer when a popup window should no longer count against
// the current popup count (either because it's not a popup or because it was
@@ -807,8 +809,10 @@ IPC_BEGIN_MESSAGES(ViewHost)
std::string /* args (as a JSON string) */)
// A message for an external host.
- IPC_MESSAGE_ROUTED1(ViewHostMsg_ForwardMessageToExternalHost,
- std::string /* message */)
+ IPC_MESSAGE_ROUTED3(ViewHostMsg_ForwardMessageToExternalHost,
+ std::string /* message */,
+ std::string /* origin */,
+ std::string /* target */)
#ifdef CHROME_PERSONALIZATION
IPC_MESSAGE_ROUTED2(ViewHostMsg_PersonalizationEvent,
diff --git a/chrome/common/temp_scaffolding_stubs.cc b/chrome/common/temp_scaffolding_stubs.cc
index 969c615..3dd9cef 100644
--- a/chrome/common/temp_scaffolding_stubs.cc
+++ b/chrome/common/temp_scaffolding_stubs.cc
@@ -161,7 +161,8 @@ void AutomationProvider::AutocompleteEditIsQueryInProgress(
}
void AutomationProvider::OnMessageFromExternalHost(
- int handle, const std::string& message) {
+ int handle, const std::string& message, const std::string& origin,
+ const std::string& target) {
NOTIMPLEMENTED();
}
diff --git a/chrome/renderer/external_host_bindings.cc b/chrome/renderer/external_host_bindings.cc
index 27f4a88..09c8e78 100644
--- a/chrome/renderer/external_host_bindings.cc
+++ b/chrome/renderer/external_host_bindings.cc
@@ -6,43 +6,147 @@
#include "base/values.h"
#include "chrome/common/render_messages.h"
+#include "webkit/glue/webframe.h"
-ExternalHostBindings::ExternalHostBindings() {
- BindMethod("ForwardMessageToExternalHost",
- &ExternalHostBindings::ForwardMessageToExternalHost);
+ExternalHostBindings::ExternalHostBindings() : frame_(NULL) {
+ BindMethod("postMessage", &ExternalHostBindings::postMessage);
BindProperty("onmessage", &on_message_handler_);
}
-void ExternalHostBindings::ForwardMessageToExternalHost(
+void ExternalHostBindings::postMessage(
const CppArgumentList& args, CppVariant* result) {
- // We only accept a string message identifier.
- if (args.size() != 1)
- return;
+ DCHECK(result);
- // Args should be strings.
- if (!args[0].isString())
+ // We need at least one argument (message) and at most 2 arguments.
+ // Also, the first argument must be a string
+ if (args.size() < 1 || args.size() > 2 || !args[0].isString()) {
+ result->Set(false);
return;
+ }
const std::string& message = args[0].ToString();
+ std::string target;
+ if (args.size() >= 2 && args[1].isString()) {
+ target = args[1].ToString();
+ } else {
+ target = "*";
+ }
+
+ std::string origin;
+ GURL origin_url(frame_->GetURL().GetOrigin());
+ if (origin_url.is_empty()) {
+ // If the origin is not a scheme/host/port tuple, then return the literal
+ // string "null".
+ origin = "null";
+ } else {
+ origin = origin_url.spec();
+ }
- sender()->Send(new ViewHostMsg_ForwardMessageToExternalHost(
- routing_id(), message));
+ result->Set(sender()->Send(new ViewHostMsg_ForwardMessageToExternalHost(
+ routing_id(), message, origin, target)));
}
bool ExternalHostBindings::ForwardMessageFromExternalHost(
- const std::string& message) {
+ const std::string& message, const std::string& origin,
+ const std::string& target) {
if (!on_message_handler_.isObject())
return false;
- CppVariant result;
+ bool status = false;
+
+ // TODO(tommi): Do the appropriate target check and drop the event if
+ // the target doesn't match the url of the current document.
+ // See: http://dev.w3.org/html5/spec/Overview.html#posting-messages
+ if (target.compare("*") != 0) {
+ DLOG(WARNING) << "Dropping posted message since the target wasn't '*' "
+ "and we haven't implemented parsing of the target param";
+ return false;
+ }
+
+ // Construct an event object, assign the origin to the origin member and
+ // assign message parameter to the 'data' member of the event.
+ NPObject* event_obj = NULL;
+ CreateMessageEvent(&event_obj);
+ if (!event_obj) {
+ NOTREACHED() << "CreateMessageEvent failed";
+ } else {
+ NPIdentifier init_message_event =
+ NPN_GetStringIdentifier("initMessageEvent");
+ NPVariant init_args[8];
+ STRINGN_TO_NPVARIANT("message", sizeof("message") - 1,
+ init_args[0]); // type
+ BOOLEAN_TO_NPVARIANT(false, init_args[1]); // canBubble
+ BOOLEAN_TO_NPVARIANT(true, init_args[2]); // cancelable
+ STRINGN_TO_NPVARIANT(message.c_str(), message.length(), \
+ init_args[3]); // data
+ STRINGN_TO_NPVARIANT(origin.c_str(), origin.length(), \
+ init_args[4]); // origin
+ STRINGN_TO_NPVARIANT("", 0, init_args[5]); // lastEventId
+ NULL_TO_NPVARIANT(init_args[6]); // source
+ NULL_TO_NPVARIANT(init_args[7]); // messagePort
+
+ NPVariant result;
+ NULL_TO_NPVARIANT(result);
+ status = NPN_Invoke(NULL, event_obj, init_message_event, init_args,
+ arraysize(init_args), &result);
+ DCHECK(status) << "Failed to initialize MessageEvent";
+ NPN_ReleaseVariantValue(&result);
- NPVariant arg;
- arg.type = NPVariantType_String;
- arg.value.stringValue.UTF8Characters = message.c_str();
- arg.value.stringValue.UTF8Length = static_cast<int>(message.length());
+ if (status) {
+ NPVariant event_arg;
+ OBJECT_TO_NPVARIANT(event_obj, event_arg);
+ status = NPN_InvokeDefault(NULL, on_message_handler_.value.objectValue,
+ &event_arg, 1, &result);
+ // Don't DCHECK here in case the reason for the failure is a script error.
+ DLOG_IF(ERROR, !status) << "NPN_InvokeDefault failed";
+ NPN_ReleaseVariantValue(&result);
+ }
+
+ NPN_ReleaseObject(event_obj);
+ }
- bool status = NPN_InvokeDefault(NULL, on_message_handler_.value.objectValue,
- &arg, 1, &result);
- DCHECK(status);
return status;
}
+
+bool ExternalHostBindings::CreateMessageEvent(NPObject** message_event) {
+ DCHECK(message_event != NULL);
+ DCHECK(frame_ != NULL);
+
+ NPObject* window = frame_->GetWindowNPObject();
+ if (!window) {
+ NOTREACHED() << "frame_->GetWindowNPObject";
+ return false;
+ }
+
+ const char* identifier_names[] = {
+ "document",
+ "createEvent",
+ };
+
+ NPIdentifier identifiers[arraysize(identifier_names)] = {0};
+ NPN_GetStringIdentifiers(identifier_names, arraysize(identifier_names),
+ identifiers);
+
+ CppVariant document;
+ bool ok = NPN_GetProperty(NULL, window, identifiers[0], &document);
+ DCHECK(document.isObject());
+
+ bool success = false;
+ if (ok && document.isObject()) {
+ NPVariant result, event_type;
+ STRINGN_TO_NPVARIANT("MessageEvent", sizeof("MessageEvent") - 1, \
+ event_type);
+ success = NPN_Invoke(NULL, document.value.objectValue, identifiers[1],
+ &event_type, 1, &result);
+ DCHECK(!success || result.type == NPVariantType_Object);
+ if (result.type != NPVariantType_Object) {
+ DCHECK(success == false);
+ } else {
+ DCHECK(success != false);
+ // Pass the ownership to the caller (don't call ReleaseVariantValue).
+ *message_event = result.value.objectValue;
+ }
+ }
+
+ return success;
+}
diff --git a/chrome/renderer/external_host_bindings.h b/chrome/renderer/external_host_bindings.h
index b4c46ad..62caac6 100644
--- a/chrome/renderer/external_host_bindings.h
+++ b/chrome/renderer/external_host_bindings.h
@@ -12,22 +12,37 @@
// accessible from Javascript
//
// We expose one function, for sending a message to the external host:
-// ForwardMessageToExternalHost(String receiver, String message);
+// postMessage(String message[, String target]);
class ExternalHostBindings : public DOMBoundBrowserObject {
public:
ExternalHostBindings();
- virtual ~ExternalHostBindings() {};
+ virtual ~ExternalHostBindings() {
+ }
- // The ForwardMessageToExternalHost() function provided to Javascript.
- void ForwardMessageToExternalHost(const CppArgumentList& args,
- CppVariant* result);
+ // The postMessage() function provided to Javascript.
+ void postMessage(const CppArgumentList& args, CppVariant* result);
// Invokes the registered onmessage handler.
// Returns true on successful invocation.
- bool ForwardMessageFromExternalHost(const std::string& message);
+ bool ForwardMessageFromExternalHost(const std::string& message,
+ const std::string& origin,
+ const std::string& target);
+
+ // Overridden to hold onto a pointer back to the web frame.
+ void BindToJavascript(WebFrame* frame, const std::wstring& classname) {
+ frame_ = frame;
+ DOMBoundBrowserObject::BindToJavascript(frame, classname);
+ }
+
+ protected:
+ // Creates an uninitialized instance of a MessageEvent object.
+ // This is equivalent to calling window.document.createEvent("MessageEvent")
+ // in javascript.
+ bool CreateMessageEvent(NPObject** message_event);
private:
CppVariant on_message_handler_;
+ WebFrame* frame_;
DISALLOW_COPY_AND_ASSIGN(ExternalHostBindings);
};
diff --git a/chrome/renderer/render_view.cc b/chrome/renderer/render_view.cc
index 6251636..3f11ec2 100644
--- a/chrome/renderer/render_view.cc
+++ b/chrome/renderer/render_view.cc
@@ -2840,11 +2840,14 @@ void RenderView::DidAddHistoryItem() {
history_forward_list_count_ = 0;
}
-void RenderView::OnMessageFromExternalHost(const std::string& message) {
+void RenderView::OnMessageFromExternalHost(const std::string& message,
+ const std::string& origin,
+ const std::string& target) {
if (message.empty())
return;
- external_host_bindings_.ForwardMessageFromExternalHost(message);
+ external_host_bindings_.ForwardMessageFromExternalHost(message, origin,
+ target);
}
void RenderView::OnDisassociateFromPopupCount() {
diff --git a/chrome/renderer/render_view.h b/chrome/renderer/render_view.h
index 700faa9..17f4cd1 100644
--- a/chrome/renderer/render_view.h
+++ b/chrome/renderer/render_view.h
@@ -546,7 +546,9 @@ class RenderView : public RenderWidget,
#endif
// Handles messages posted from automation.
- void OnMessageFromExternalHost(const std::string& message);
+ void OnMessageFromExternalHost(const std::string& message,
+ const std::string& origin,
+ const std::string& target);
// Message that we should no longer be part of the current popup window
// grouping, and should form our own grouping.
diff --git a/chrome/test/automation/automation_messages_internal.h b/chrome/test/automation/automation_messages_internal.h
index 8fb532d..98474ac 100644
--- a/chrome/test/automation/automation_messages_internal.h
+++ b/chrome/test/automation/automation_messages_internal.h
@@ -723,13 +723,17 @@ IPC_BEGIN_MESSAGES(Automation)
int /* tab_handle */)
// Posts a message from external host to chrome renderer.
- IPC_MESSAGE_ROUTED2(AutomationMsg_HandleMessageFromExternalHost,
+ IPC_MESSAGE_ROUTED4(AutomationMsg_HandleMessageFromExternalHost,
int /* automation handle */,
- std::string /* message */ )
+ std::string /* message */,
+ std::string /* origin */,
+ std::string /* target */)
// A message for an external host.
- IPC_MESSAGE_ROUTED1(AutomationMsg_ForwardMessageToExternalHost,
- std::string /* message*/)
+ IPC_MESSAGE_ROUTED3(AutomationMsg_ForwardMessageToExternalHost,
+ std::string /* message */,
+ std::string /* origin */,
+ std::string /* target */)
// This message starts a find within a tab corresponding to the supplied
// tab handle. The parameter |request| specifies what to search for.
diff --git a/chrome/test/automation/automation_proxy_uitest.cc b/chrome/test/automation/automation_proxy_uitest.cc
index ee1d4db..e296f62 100644
--- a/chrome/test/automation/automation_proxy_uitest.cc
+++ b/chrome/test/automation/automation_proxy_uitest.cc
@@ -37,6 +37,21 @@ class AutomationProxyVisibleTest : public UITest {
}
};
+template <class AutomationProxyClass>
+class CustomAutomationProxyTest : public AutomationProxyVisibleTest {
+ protected:
+ CustomAutomationProxyTest() {
+ }
+
+ // Override UITest's CreateAutomationProxy to provide our the unit test
+ // with our special implementation of AutomationProxy.
+ // This function is called from within UITest::LaunchBrowserAndServer.
+ virtual AutomationProxy* CreateAutomationProxy(int execution_timeout) {
+ AutomationProxyClass* proxy = new AutomationProxyClass(execution_timeout);
+ return proxy;
+ }
+};
+
TEST_F(AutomationProxyTest, GetBrowserWindowCount) {
int window_count = 0;
EXPECT_TRUE(automation()->GetBrowserWindowCount(&window_count));
@@ -708,7 +723,13 @@ TEST_F(AutomationProxyTest, CantEscapeByOnloadMoveto) {
ASSERT_NE(20, rect.y());
}
-bool ExternalTabHandler(HWND external_tab_window) {
+// Creates a top-level window, makes the |external_tab_window| a child
+// of that window and displays them. After displaying the windows the function
+// enters a message loop that processes window messages as well as calling
+// MessageLoop::current()->RunAllPending() to process any incoming IPC messages.
+// The time_to_wait parameter is the maximum time the loop will run.
+// To end the loop earlier, post a quit message to the thread.
+bool ExternalTabHandler(HWND external_tab_window, int time_to_wait) {
static const wchar_t class_name[] = L"External_Tab_UI_Test_Class";
static const wchar_t window_title[] = L"External Tab Tester";
@@ -718,8 +739,9 @@ bool ExternalTabHandler(HWND external_tab_window) {
wnd_class.lpfnWndProc = DefWindowProc;
wnd_class.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wnd_class.lpszClassName = class_name;
- ATOM result = RegisterClassEx(&wnd_class);
- if (0 == result) {
+ ATOM atom = RegisterClassEx(&wnd_class);
+ if (0 == atom) {
+ NOTREACHED() << "RegisterClassEx";
return false;
}
@@ -741,26 +763,181 @@ bool ExternalTabHandler(HWND external_tab_window) {
ShowWindow(external_tab_ui_parent, SW_SHOW);
// Allow the renderers to connect.
- Sleep(1000);
+
+ const int kTimerIdQuit = 100;
+ const int kTimerIdProcessPendingMessages = 101;
+
+ ::SetTimer(external_tab_ui_parent, kTimerIdQuit, time_to_wait, NULL);
+ // Process pending messages every 50 milliseconds
+ ::SetTimer(external_tab_ui_parent, kTimerIdProcessPendingMessages, 50, NULL);
+
+ MSG msg;
+ bool quit = false;
+ do {
+ BOOL ok = ::GetMessage(&msg, NULL, 0, 0);
+ if (!ok || ok == -1)
+ break;
+
+ if (msg.message == WM_TIMER && msg.hwnd == external_tab_ui_parent) {
+ switch (msg.wParam) {
+ case kTimerIdProcessPendingMessages:
+ MessageLoop::current()->RunAllPending();
+ break;
+
+ case kTimerIdQuit:
+ ::KillTimer(external_tab_ui_parent, msg.wParam);
+ quit = true;
+ break;
+
+ default:
+ NOTREACHED() << "invalid timer id";
+ break;
+ }
+ } else if (msg.message == WM_QUIT) {
+ quit = true;
+ } else {
+ ::TranslateMessage(&msg);
+ ::DispatchMessage(&msg);
+ }
+ // In case there's an interactive user that closes the window.
+ } while (!quit && ::IsWindow(external_tab_ui_parent));
+
DestroyWindow(external_tab_ui_parent);
+
+ EXPECT_TRUE(UnregisterClassW(reinterpret_cast<const wchar_t*>(atom),
+ wnd_class.hInstance));
+
return true;
}
-TEST_F(AutomationProxyVisibleTest, CreateExternalTab) {
+// A single-use AutomationProxy implementation that's good
+// for a single navigation and a single ForwardMessageToExternalHost
+// message. Once the ForwardMessageToExternalHost message is received
+// the class posts a quit message to the thread on which the message
+// was received.
+class AutomationProxyForExternalTab : public AutomationProxy {
+ public:
+ AutomationProxyForExternalTab(int execution_timeout)
+ : AutomationProxy(execution_timeout),
+ messages_received_(0),
+ navigate_complete_(false) {
+ }
+
+ int messages_received() const {
+ return messages_received_;
+ }
+
+ const std::string& message() const {
+ return message_;
+ }
+
+ const std::string& origin() const {
+ return origin_;
+ }
+
+ const std::string& target() const {
+ return target_;
+ }
+
+ // Waits for the DidNavigate event to be processed on the current thread.
+ // Returns true if the event arrived, false if there was a timeout.
+ bool WaitForNavigationComplete(int max_time_to_wait_ms) {
+ base::TimeTicks start(base::TimeTicks::Now());
+ while (!navigate_complete_) {
+ Sleep(50);
+ MessageLoop::current()->RunAllPending();
+ base::TimeTicks end(base::TimeTicks::Now());
+ base::TimeDelta delta = end - start;
+ if (static_cast<int>(delta.InMilliseconds()) > max_time_to_wait_ms)
+ return false;
+ }
+ return true;
+ }
+
+ protected:
+ virtual void OnMessageReceived(const IPC::Message& msg) {
+ IPC_BEGIN_MESSAGE_MAP(AutomationProxyForExternalTab, msg)
+ IPC_MESSAGE_HANDLER(AutomationMsg_DidNavigate, OnDidNavigate)
+ IPC_MESSAGE_HANDLER(AutomationMsg_ForwardMessageToExternalHost,
+ OnForwardMessageToExternalHost)
+ IPC_END_MESSAGE_MAP()
+ }
+
+ void OnDidNavigate(int navigation_type, int relative_offset,
+ const GURL& url) {
+ navigate_complete_ = true;
+ }
+
+ void OnForwardMessageToExternalHost(const std::string& message,
+ const std::string& origin,
+ const std::string& target) {
+ messages_received_++;
+ message_ = message;
+ origin_ = origin;
+ target_ = target;
+ PostQuitMessage(0);
+ }
+
+ protected:
+ bool navigate_complete_;
+ int messages_received_;
+ std::string message_, origin_, target_;
+};
+
+typedef CustomAutomationProxyTest<AutomationProxyForExternalTab>
+ ExternalTabTestType;
+
+TEST_F(ExternalTabTestType, CreateExternalTab) {
HWND external_tab_container = NULL;
- scoped_ptr<TabProxy> tab(automation()->CreateExternalTab(
- NULL, gfx::Rect(), WS_POPUP, &external_tab_container));
+ scoped_ptr<TabProxy> tab(automation()->CreateExternalTab(NULL, gfx::Rect(),
+ WS_POPUP, &external_tab_container));
EXPECT_TRUE(tab != NULL);
EXPECT_NE(FALSE, ::IsWindow(external_tab_container));
if (tab != NULL) {
tab->NavigateInExternalTab(GURL(L"http://www.google.com"));
- EXPECT_EQ(true, ExternalTabHandler(external_tab_container));
+ EXPECT_EQ(true, ExternalTabHandler(external_tab_container, 1000));
// Since the tab goes away lazily, wait a bit
Sleep(1000);
EXPECT_FALSE(tab->is_valid());
}
}
+TEST_F(ExternalTabTestType, ExternalTabPostMessage) {
+ AutomationProxyForExternalTab* proxy =
+ static_cast<AutomationProxyForExternalTab*>(automation());
+
+ HWND external_tab_container = NULL;
+ scoped_ptr<TabProxy> tab(proxy->CreateExternalTab(NULL, gfx::Rect(),
+ WS_POPUP, &external_tab_container));
+ EXPECT_TRUE(tab != NULL);
+ EXPECT_NE(FALSE, ::IsWindow(external_tab_container));
+ if (tab != NULL) {
+ std::string content =
+ "data:text/html,<html><head><script>"
+ "function onload() {"
+ " window.externalHost.onmessage = onMessage;"
+ "}"
+ "function onMessage(evt) {"
+ " window.externalHost.postMessage(evt.data, '*');"
+ "}"
+ "</script></head>"
+ "<body onload='onload()'>external tab test<br></div>"
+ "</body></html>";
+ tab->NavigateInExternalTab(GURL(content));
+ EXPECT_TRUE(proxy->WaitForNavigationComplete(10000));
+
+ tab->HandleMessageFromExternalHost(tab->handle(), "Hello from gtest",
+ "null", "*");
+
+ EXPECT_TRUE(ExternalTabHandler(external_tab_container, 10000));
+ EXPECT_NE(0, proxy->messages_received());
+
+ if (proxy->messages_received()) {
+ EXPECT_EQ("Hello from gtest", proxy->message());
+ }
+ }
+}
+
TEST_F(AutomationProxyTest, AutocompleteGetSetText) {
scoped_ptr<BrowserProxy> browser(automation()->GetBrowserWindow(0));
ASSERT_TRUE(browser.get());
diff --git a/chrome/test/automation/tab_proxy.cc b/chrome/test/automation/tab_proxy.cc
index bca9c03..4033d65 100644
--- a/chrome/test/automation/tab_proxy.cc
+++ b/chrome/test/automation/tab_proxy.cc
@@ -535,13 +535,15 @@ bool TabProxy::SavePage(const std::wstring& file_name,
}
void TabProxy::HandleMessageFromExternalHost(AutomationHandle handle,
- const std::string& message) {
+ const std::string& message,
+ const std::string& origin,
+ const std::string& target) {
if (!is_valid())
return;
bool succeeded =
sender_->Send(new AutomationMsg_HandleMessageFromExternalHost(0, handle,
- message));
+ message, origin, target));
DCHECK(succeeded);
}
diff --git a/chrome/test/automation/tab_proxy.h b/chrome/test/automation/tab_proxy.h
index 26cdde5..54e5df4 100644
--- a/chrome/test/automation/tab_proxy.h
+++ b/chrome/test/automation/tab_proxy.h
@@ -253,7 +253,9 @@ class TabProxy : public AutomationResourceProxy {
// Posts a message to the external tab.
void HandleMessageFromExternalHost(AutomationHandle handle,
- const std::string& message);
+ const std::string& message,
+ const std::string& origin,
+ const std::string& target);
// Retrieves the number of SSL related info-bars currently showing in |count|.
bool GetSSLInfoBarCount(int* count);
diff --git a/chrome/test/ui/ui_test.cc b/chrome/test/ui/ui_test.cc
index 1861626..d9920c5 100644
--- a/chrome/test/ui/ui_test.cc
+++ b/chrome/test/ui/ui_test.cc
@@ -211,9 +211,14 @@ void UITest::InitializeTimeouts() {
}
}
+AutomationProxy* UITest::CreateAutomationProxy(int execution_timeout) {
+ // By default we create a plain vanilla AutomationProxy.
+ return new AutomationProxy(execution_timeout);
+}
+
void UITest::LaunchBrowserAndServer() {
// Set up IPC testing interface server.
- server_.reset(new AutomationProxy(command_execution_timeout_ms_));
+ server_.reset(CreateAutomationProxy(command_execution_timeout_ms_));
LaunchBrowser(launch_arguments_, clear_profile_);
if (wait_for_initial_loads_)
diff --git a/chrome/test/ui/ui_test.h b/chrome/test/ui/ui_test.h
index 794391b..2bd3b9e 100644
--- a/chrome/test/ui/ui_test.h
+++ b/chrome/test/ui/ui_test.h
@@ -71,6 +71,9 @@ class UITest : public testing::Test {
// Launches the browser and IPC testing server.
void LaunchBrowserAndServer();
+ // Overridable so that derived classes can provide their own AutomationProxy.
+ virtual AutomationProxy* CreateAutomationProxy(int execution_timeout);
+
// Closes the browser and IPC testing server.
void CloseBrowserAndServer();
diff --git a/webkit/glue/webframe.h b/webkit/glue/webframe.h
index 4a0cf01..d35376e 100644
--- a/webkit/glue/webframe.h
+++ b/webkit/glue/webframe.h
@@ -47,6 +47,8 @@ class WebFrame {
// TODO(fqian): Remove this method when V8 supports NP runtime.
virtual void* GetFrameImplementation() = 0;
+ virtual NPObject* GetWindowNPObject() = 0;
+
// Loads the given WebRequest.
virtual void LoadRequest(WebRequest* request) = 0;
diff --git a/webkit/glue/webframe_impl.cc b/webkit/glue/webframe_impl.cc
index 28ba59c..bf4fb03 100644
--- a/webkit/glue/webframe_impl.cc
+++ b/webkit/glue/webframe_impl.cc
@@ -741,6 +741,13 @@ void WebFrameImpl::GetContentAsPlainText(int max_chars,
FrameContentAsPlainText(max_chars, frame_, text);
}
+NPObject* WebFrameImpl::GetWindowNPObject() {
+ if (!frame_)
+ return NULL;
+
+ return frame_->script()->windowScriptNPObject();
+}
+
void WebFrameImpl::InvalidateArea(AreaToInvalidate area) {
ASSERT(frame() && frame()->view());
#if defined(OS_WIN)
diff --git a/webkit/glue/webframe_impl.h b/webkit/glue/webframe_impl.h
index 63950aa..ed7ee15 100644
--- a/webkit/glue/webframe_impl.h
+++ b/webkit/glue/webframe_impl.h
@@ -116,6 +116,8 @@ class WebFrameImpl : public WebFrame, public base::RefCounted<WebFrameImpl> {
virtual void* GetFrameImplementation() { return frame(); }
+ virtual NPObject* GetWindowNPObject();
+
virtual void GetContentAsPlainText(int max_chars, std::wstring* text) const;
virtual bool Find(const FindInPageRequest& request,
bool wrap_within_frame,