diff options
author | tommi@chromium.org <tommi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-03-09 19:48:37 +0000 |
---|---|---|
committer | tommi@chromium.org <tommi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-03-09 19:48:37 +0000 |
commit | 2879092e01ea4ebb93c1b80925c81e059b24607b (patch) | |
tree | 53638b170c3c9c3146d13238d1ed20993cdb4257 /chrome/renderer | |
parent | 12a6f036f3859f88b439dba009172f5c1dd03dc9 (diff) | |
download | chromium_src-2879092e01ea4ebb93c1b80925c81e059b24607b.zip chromium_src-2879092e01ea4ebb93c1b80925c81e059b24607b.tar.gz chromium_src-2879092e01ea4ebb93c1b80925c81e059b24607b.tar.bz2 |
Changing ForwardMessageToExternalHost to postMessage and passing a proper
MessageEvent object to the onmessage handler.
Also adding support for origin and target parameters. The origin parameter is
implicit but target can be specified when calling postMessage. If no target
is specified we default to "*".
At the moment I'm only allowing target == "*" messages to pass through since
I haven't implemented support for matching more complicated patterns :)
Review URL: http://codereview.chromium.org/40128
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@11275 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/renderer')
-rw-r--r-- | chrome/renderer/external_host_bindings.cc | 144 | ||||
-rw-r--r-- | chrome/renderer/external_host_bindings.h | 27 | ||||
-rw-r--r-- | chrome/renderer/render_view.cc | 7 | ||||
-rw-r--r-- | chrome/renderer/render_view.h | 4 |
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. |