1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/renderer/external_host_bindings.h"
8 #include "base/bind_helpers.h"
9 #include "base/values.h"
10 #include "chrome/common/render_messages.h"
11 #include "third_party/WebKit/Source/WebKit/chromium/public/WebBindings.h"
12 #include "third_party/WebKit/Source/WebKit/chromium/public/WebDocument.h"
13 #include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h"
15 using WebKit::WebBindings
;
16 using webkit_glue::CppArgumentList
;
17 using webkit_glue::CppVariant
;
19 ExternalHostBindings::ExternalHostBindings(IPC::Sender
* sender
, int routing_id
)
20 : frame_(NULL
), sender_(sender
), routing_id_(routing_id
) {
21 BindCallback("postMessage", base::Bind(&ExternalHostBindings::PostMessage
,
22 base::Unretained(this)));
23 BindProperty("onmessage", &on_message_handler_
);
26 ExternalHostBindings::~ExternalHostBindings() {
29 void ExternalHostBindings::PostMessage(
30 const CppArgumentList
& args
, CppVariant
* result
) {
33 // We need at least one argument (message) and at most 2 arguments.
34 // Also, the first argument must be a string
35 if (args
.size() < 1 || args
.size() > 2 || !args
[0].isString()) {
40 const std::string
& message
= args
[0].ToString();
42 if (args
.size() >= 2 && args
[1].isString()) {
43 target
= args
[1].ToString();
44 if (target
.compare("*") != 0) {
45 GURL
resolved(target
);
46 if (!resolved
.is_valid()) {
47 DLOG(WARNING
) << "Unable to parse the specified target URL. " << target
;
51 target
= resolved
.spec();
57 std::string origin
= frame_
->document().securityOrigin().toString().utf8();
59 result
->Set(sender_
->Send(
60 new ChromeViewHostMsg_ForwardMessageToExternalHost(
61 routing_id_
, message
, origin
, target
)));
64 bool ExternalHostBindings::ForwardMessageFromExternalHost(
65 const std::string
& message
, const std::string
& origin
,
66 const std::string
& target
) {
67 if (!on_message_handler_
.isObject())
72 if (target
.compare("*") != 0) {
73 // TODO(abarth): This code should use WebSecurityOrigin::toString to
74 // make origin strings. GURL::GetOrigin() doesn't understand all the
75 // cases that WebSecurityOrigin::toString understands.
76 GURL
document_url(frame_
->document().url());
77 GURL
document_origin(document_url
.GetOrigin());
78 GURL
target_origin(GURL(target
).GetOrigin());
80 // We want to compare the origins of the two URLs but first
81 // we need to make sure that we don't compare an invalid one
83 bool drop
= (document_origin
.is_valid() != target_origin
.is_valid());
86 if (!document_origin
.is_valid()) {
87 // Both origins are invalid, so compare the URLs as opaque strings.
88 drop
= (document_url
.spec().compare(target
) != 0);
90 drop
= (document_origin
!= target_origin
);
95 DLOG(WARNING
) << "Dropping posted message. Origins don't match";
100 // Construct an event object, assign the origin to the origin member and
101 // assign message parameter to the 'data' member of the event.
102 NPObject
* event_obj
= NULL
;
103 CreateMessageEvent(&event_obj
);
105 NOTREACHED() << "CreateMessageEvent failed";
107 NPIdentifier init_message_event
=
108 WebBindings::getStringIdentifier("initMessageEvent");
109 NPVariant init_args
[8];
110 STRINGN_TO_NPVARIANT("message", sizeof("message") - 1,
111 init_args
[0]); // type
112 BOOLEAN_TO_NPVARIANT(false, init_args
[1]); // canBubble
113 BOOLEAN_TO_NPVARIANT(true, init_args
[2]); // cancelable
114 STRINGN_TO_NPVARIANT(message
.c_str(), message
.length(), \
115 init_args
[3]); // data
116 STRINGN_TO_NPVARIANT(origin
.c_str(), origin
.length(), \
117 init_args
[4]); // origin
118 STRINGN_TO_NPVARIANT("", 0, init_args
[5]); // lastEventId
119 NULL_TO_NPVARIANT(init_args
[6]); // source
120 NULL_TO_NPVARIANT(init_args
[7]); // messagePort
123 NULL_TO_NPVARIANT(result
);
124 status
= WebBindings::invoke(NULL
, event_obj
, init_message_event
, init_args
,
125 arraysize(init_args
), &result
);
126 DCHECK(status
) << "Failed to initialize MessageEvent";
127 WebBindings::releaseVariantValue(&result
);
131 OBJECT_TO_NPVARIANT(event_obj
, event_arg
);
132 status
= WebBindings::invokeDefault(NULL
,
133 on_message_handler_
.value
.objectValue
,
134 &event_arg
, 1, &result
);
135 // Don't DCHECK here in case the reason for the failure is a script error.
136 DLOG_IF(ERROR
, !status
) << "NPN_InvokeDefault failed";
137 WebBindings::releaseVariantValue(&result
);
140 WebBindings::releaseObject(event_obj
);
146 void ExternalHostBindings::BindToJavascript(WebKit::WebFrame
* frame
,
147 const std::string
& classname
) {
149 CppBoundClass::BindToJavascript(frame
, classname
);
152 bool ExternalHostBindings::CreateMessageEvent(NPObject
** message_event
) {
153 DCHECK(message_event
!= NULL
);
154 DCHECK(frame_
!= NULL
);
156 NPObject
* window
= frame_
->windowObject();
158 NOTREACHED() << "frame_->windowObject";
162 const char* identifier_names
[] = {
167 NPIdentifier identifiers
[arraysize(identifier_names
)] = {0};
168 WebBindings::getStringIdentifiers(identifier_names
,
169 arraysize(identifier_names
), identifiers
);
172 bool ok
= WebBindings::getProperty(NULL
, window
, identifiers
[0], &document
);
173 DCHECK(document
.isObject());
175 bool success
= false;
176 if (ok
&& document
.isObject()) {
177 NPVariant result
, event_type
;
178 STRINGN_TO_NPVARIANT("MessageEvent", sizeof("MessageEvent") - 1, \
180 success
= WebBindings::invoke(NULL
, document
.value
.objectValue
,
181 identifiers
[1], &event_type
, 1, &result
);
182 DCHECK(!success
|| result
.type
== NPVariantType_Object
);
183 if (result
.type
!= NPVariantType_Object
) {
184 DCHECK(success
== false);
186 DCHECK(success
!= false);
187 // Pass the ownership to the caller (don't call ReleaseVariantValue).
188 *message_event
= result
.value
.objectValue
;