summaryrefslogtreecommitdiffstats
path: root/chrome/renderer
diff options
context:
space:
mode:
Diffstat (limited to 'chrome/renderer')
-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
4 files changed, 153 insertions, 29 deletions
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.