diff options
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. |