OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/renderer/extensions/miscellaneous_bindings.h" | 5 #include "chrome/renderer/extensions/miscellaneous_bindings.h" |
6 | 6 |
7 #include <map> | 7 #include <map> |
8 #include <string> | 8 #include <string> |
9 | 9 |
10 #include "base/basictypes.h" | 10 #include "base/basictypes.h" |
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
88 } | 88 } |
89 | 89 |
90 virtual ~ExtensionImpl() {} | 90 virtual ~ExtensionImpl() {} |
91 | 91 |
92 // Sends a message along the given channel. | 92 // Sends a message along the given channel. |
93 v8::Handle<v8::Value> PostMessage(const v8::Arguments& args) { | 93 v8::Handle<v8::Value> PostMessage(const v8::Arguments& args) { |
94 content::RenderView* renderview = GetRenderView(); | 94 content::RenderView* renderview = GetRenderView(); |
95 if (!renderview) | 95 if (!renderview) |
96 return v8::Undefined(); | 96 return v8::Undefined(); |
97 | 97 |
98 if (args.Length() >= 2 && args[0]->IsInt32() && args[1]->IsString()) { | 98 // Arguments are (int32 port_id, object message). |
99 int port_id = args[0]->Int32Value(); | 99 CHECK_EQ(2, args.Length()); |
100 if (!HasPortData(port_id)) { | 100 CHECK(args[0]->IsInt32()); |
101 return v8::ThrowException(v8::Exception::Error( | 101 |
102 v8::String::New(kPortClosedError))); | 102 int port_id = args[0]->Int32Value(); |
103 } | 103 if (!HasPortData(port_id)) { |
104 std::string message = *v8::String::Utf8Value(args[1]->ToString()); | 104 return v8::ThrowException(v8::Exception::Error( |
105 renderview->Send(new ExtensionHostMsg_PostMessage( | 105 v8::String::New(kPortClosedError))); |
106 renderview->GetRoutingID(), port_id, message)); | |
107 } | 106 } |
| 107 |
| 108 // The message can be any base::Value but IPC can't serialize that, so we |
| 109 // give it a singleton base::ListValue instead, or an empty list if the |
| 110 // argument was undefined (v8 value converter will return NULL for this). |
| 111 scoped_ptr<V8ValueConverter> converter(V8ValueConverter::create()); |
| 112 scoped_ptr<base::Value> message( |
| 113 converter->FromV8Value(args[1], context()->v8_context())); |
| 114 ListValue message_as_list; |
| 115 if (message) |
| 116 message_as_list.Append(message.release()); |
| 117 |
| 118 renderview->Send(new ExtensionHostMsg_PostMessage( |
| 119 renderview->GetRoutingID(), port_id, message_as_list)); |
| 120 |
108 return v8::Undefined(); | 121 return v8::Undefined(); |
109 } | 122 } |
110 | 123 |
111 // Forcefully disconnects a port. | 124 // Forcefully disconnects a port. |
112 v8::Handle<v8::Value> CloseChannel(const v8::Arguments& args) { | 125 v8::Handle<v8::Value> CloseChannel(const v8::Arguments& args) { |
113 if (args.Length() >= 2 && args[0]->IsInt32() && args[1]->IsBoolean()) { | 126 // Arguments are (int32 port_id, boolean notify_browser). |
114 int port_id = args[0]->Int32Value(); | 127 CHECK_EQ(2, args.Length()); |
115 if (!HasPortData(port_id)) { | 128 CHECK(args[0]->IsInt32()); |
116 return v8::Undefined(); | 129 CHECK(args[1]->IsBoolean()); |
117 } | 130 |
118 // Send via the RenderThread because the RenderView might be closing. | 131 int port_id = args[0]->Int32Value(); |
119 bool notify_browser = args[1]->BooleanValue(); | 132 if (!HasPortData(port_id)) |
120 if (notify_browser) | 133 return v8::Undefined(); |
121 content::RenderThread::Get()->Send( | 134 |
122 new ExtensionHostMsg_CloseChannel(port_id, std::string())); | 135 // Send via the RenderThread because the RenderView might be closing. |
123 ClearPortData(port_id); | 136 bool notify_browser = args[1]->BooleanValue(); |
| 137 if (notify_browser) { |
| 138 content::RenderThread::Get()->Send( |
| 139 new ExtensionHostMsg_CloseChannel(port_id, std::string())); |
124 } | 140 } |
| 141 |
| 142 ClearPortData(port_id); |
| 143 |
125 return v8::Undefined(); | 144 return v8::Undefined(); |
126 } | 145 } |
127 | 146 |
128 // A new port has been created for a context. This occurs both when script | 147 // A new port has been created for a context. This occurs both when script |
129 // opens a connection, and when a connection is opened to this script. | 148 // opens a connection, and when a connection is opened to this script. |
130 v8::Handle<v8::Value> PortAddRef(const v8::Arguments& args) { | 149 v8::Handle<v8::Value> PortAddRef(const v8::Arguments& args) { |
131 if (args.Length() >= 1 && args[0]->IsInt32()) { | 150 // Arguments are (int32 port_id). |
132 int port_id = args[0]->Int32Value(); | 151 CHECK_EQ(1, args.Length()); |
133 ++GetPortData(port_id).ref_count; | 152 CHECK(args[0]->IsInt32()); |
134 } | 153 |
| 154 int port_id = args[0]->Int32Value(); |
| 155 ++GetPortData(port_id).ref_count; |
| 156 |
135 return v8::Undefined(); | 157 return v8::Undefined(); |
136 } | 158 } |
137 | 159 |
138 // The frame a port lived in has been destroyed. When there are no more | 160 // The frame a port lived in has been destroyed. When there are no more |
139 // frames with a reference to a given port, we will disconnect it and notify | 161 // frames with a reference to a given port, we will disconnect it and notify |
140 // the other end of the channel. | 162 // the other end of the channel. |
141 v8::Handle<v8::Value> PortRelease(const v8::Arguments& args) { | 163 v8::Handle<v8::Value> PortRelease(const v8::Arguments& args) { |
142 if (args.Length() >= 1 && args[0]->IsInt32()) { | 164 // Arguments are (int32 port_id). |
143 int port_id = args[0]->Int32Value(); | 165 CHECK_EQ(1, args.Length()); |
144 if (HasPortData(port_id) && --GetPortData(port_id).ref_count == 0) { | 166 CHECK(args[0]->IsInt32()); |
145 // Send via the RenderThread because the RenderView might be closing. | 167 |
146 content::RenderThread::Get()->Send( | 168 int port_id = args[0]->Int32Value(); |
147 new ExtensionHostMsg_CloseChannel(port_id, std::string())); | 169 if (HasPortData(port_id) && --GetPortData(port_id).ref_count == 0) { |
148 ClearPortData(port_id); | 170 // Send via the RenderThread because the RenderView might be closing. |
149 } | 171 content::RenderThread::Get()->Send( |
| 172 new ExtensionHostMsg_CloseChannel(port_id, std::string())); |
| 173 ClearPortData(port_id); |
150 } | 174 } |
| 175 |
151 return v8::Undefined(); | 176 return v8::Undefined(); |
152 } | 177 } |
153 | 178 |
154 struct GCCallbackArgs { | 179 struct GCCallbackArgs { |
155 GCCallbackArgs(v8::Handle<v8::Object> object, | 180 GCCallbackArgs(v8::Handle<v8::Object> object, |
156 v8::Handle<v8::Function> callback) | 181 v8::Handle<v8::Function> callback) |
157 : object(object), callback(callback) {} | 182 : object(object), callback(callback) {} |
158 | 183 |
159 extensions::ScopedPersistent<v8::Object> object; | 184 extensions::ScopedPersistent<v8::Object> object; |
160 extensions::ScopedPersistent<v8::Function> callback; | 185 extensions::ScopedPersistent<v8::Function> callback; |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
215 bool port_created = false; | 240 bool port_created = false; |
216 std::string source_url_spec = source_url.spec(); | 241 std::string source_url_spec = source_url.spec(); |
217 | 242 |
218 for (ChromeV8ContextSet::ContextSet::const_iterator it = contexts.begin(); | 243 for (ChromeV8ContextSet::ContextSet::const_iterator it = contexts.begin(); |
219 it != contexts.end(); ++it) { | 244 it != contexts.end(); ++it) { |
220 if (restrict_to_render_view && | 245 if (restrict_to_render_view && |
221 restrict_to_render_view != (*it)->GetRenderView()) { | 246 restrict_to_render_view != (*it)->GetRenderView()) { |
222 continue; | 247 continue; |
223 } | 248 } |
224 | 249 |
| 250 // TODO(kalman): remove when ContextSet::ForEach is available. |
| 251 if ((*it)->v8_context().IsEmpty()) |
| 252 continue; |
| 253 |
225 v8::Handle<v8::Value> tab = v8::Null(); | 254 v8::Handle<v8::Value> tab = v8::Null(); |
226 if (!source_tab.empty()) | 255 if (!source_tab.empty()) |
227 tab = converter->ToV8Value(&source_tab, (*it)->v8_context()); | 256 tab = converter->ToV8Value(&source_tab, (*it)->v8_context()); |
228 | 257 |
229 v8::Handle<v8::Value> arguments[] = { | 258 v8::Handle<v8::Value> arguments[] = { |
230 v8::Integer::New(target_port_id), | 259 v8::Integer::New(target_port_id), |
231 v8::String::New(channel_name.c_str(), channel_name.size()), | 260 v8::String::New(channel_name.c_str(), channel_name.size()), |
232 tab, | 261 tab, |
233 v8::String::New(source_extension_id.c_str(), source_extension_id.size()), | 262 v8::String::New(source_extension_id.c_str(), source_extension_id.size()), |
234 v8::String::New(target_extension_id.c_str(), target_extension_id.size()), | 263 v8::String::New(target_extension_id.c_str(), target_extension_id.size()), |
(...skipping 29 matching lines...) Expand all Loading... |
264 content::RenderThread::Get()->Send( | 293 content::RenderThread::Get()->Send( |
265 new ExtensionHostMsg_CloseChannel( | 294 new ExtensionHostMsg_CloseChannel( |
266 target_port_id, kReceivingEndDoesntExistError)); | 295 target_port_id, kReceivingEndDoesntExistError)); |
267 } | 296 } |
268 } | 297 } |
269 | 298 |
270 // static | 299 // static |
271 void MiscellaneousBindings::DeliverMessage( | 300 void MiscellaneousBindings::DeliverMessage( |
272 const ChromeV8ContextSet::ContextSet& contexts, | 301 const ChromeV8ContextSet::ContextSet& contexts, |
273 int target_port_id, | 302 int target_port_id, |
274 const std::string& message, | 303 const base::ListValue& message, |
275 content::RenderView* restrict_to_render_view) { | 304 content::RenderView* restrict_to_render_view) { |
276 v8::HandleScope handle_scope; | 305 v8::HandleScope handle_scope; |
277 | 306 |
278 for (ChromeV8ContextSet::ContextSet::const_iterator it = contexts.begin(); | 307 for (ChromeV8ContextSet::ContextSet::const_iterator it = contexts.begin(); |
279 it != contexts.end(); ++it) { | 308 it != contexts.end(); ++it) { |
280 if (restrict_to_render_view && | 309 if (restrict_to_render_view && |
281 restrict_to_render_view != (*it)->GetRenderView()) { | 310 restrict_to_render_view != (*it)->GetRenderView()) { |
282 continue; | 311 continue; |
283 } | 312 } |
284 | 313 |
| 314 // TODO(kalman): remove when ContextSet::ForEach is available. |
| 315 if ((*it)->v8_context().IsEmpty()) |
| 316 continue; |
| 317 |
| 318 v8::Handle<v8::Context> context = (*it)->v8_context(); |
| 319 v8::Context::Scope context_scope(context); |
| 320 |
285 // Check to see whether the context has this port before bothering to create | 321 // Check to see whether the context has this port before bothering to create |
286 // the message. | 322 // the message. |
287 v8::Handle<v8::Value> port_id_handle = v8::Integer::New(target_port_id); | 323 v8::Handle<v8::Value> port_id_handle = v8::Integer::New(target_port_id); |
288 v8::Handle<v8::Value> has_port; | 324 v8::Handle<v8::Value> has_port; |
289 v8::TryCatch try_catch; | 325 v8::TryCatch try_catch; |
290 if (!(*it)->CallChromeHiddenMethod("Port.hasPort", 1, &port_id_handle, | 326 if (!(*it)->CallChromeHiddenMethod("Port.hasPort", 1, &port_id_handle, |
291 &has_port)) { | 327 &has_port)) { |
292 continue; | 328 continue; |
293 } | 329 } |
294 | 330 |
295 if (try_catch.HasCaught()) { | 331 if (try_catch.HasCaught()) { |
296 LOG(ERROR) << "Exception caught when calling Port.hasPort."; | 332 LOG(ERROR) << "Exception caught when calling Port.hasPort."; |
297 continue; | 333 continue; |
298 } | 334 } |
299 | 335 |
300 CHECK(!has_port.IsEmpty()); | 336 CHECK(!has_port.IsEmpty()); |
301 if (!has_port->BooleanValue()) | 337 if (!has_port->BooleanValue()) |
302 continue; | 338 continue; |
303 | 339 |
304 std::vector<v8::Handle<v8::Value> > arguments; | 340 std::vector<v8::Handle<v8::Value> > arguments; |
305 arguments.push_back(v8::String::New(message.c_str(), message.size())); | 341 |
| 342 // Convert the message to a v8 object; either a value or undefined. |
| 343 // See PostMessage for more details. |
| 344 if (message.empty()) { |
| 345 arguments.push_back(v8::Undefined()); |
| 346 } else { |
| 347 CHECK_EQ(1u, message.GetSize()); |
| 348 const base::Value* message_value = NULL; |
| 349 message.Get(0, &message_value); |
| 350 scoped_ptr<V8ValueConverter> converter(V8ValueConverter::create()); |
| 351 arguments.push_back(converter->ToV8Value(message_value, context)); |
| 352 } |
| 353 |
306 arguments.push_back(port_id_handle); | 354 arguments.push_back(port_id_handle); |
307 CHECK((*it)->CallChromeHiddenMethod("Port.dispatchOnMessage", | 355 CHECK((*it)->CallChromeHiddenMethod("Port.dispatchOnMessage", |
308 arguments.size(), | 356 arguments.size(), |
309 &arguments[0], | 357 &arguments[0], |
310 NULL)); | 358 NULL)); |
311 } | 359 } |
312 } | 360 } |
313 | 361 |
314 // static | 362 // static |
315 void MiscellaneousBindings::DispatchOnDisconnect( | 363 void MiscellaneousBindings::DispatchOnDisconnect( |
316 const ChromeV8ContextSet::ContextSet& contexts, | 364 const ChromeV8ContextSet::ContextSet& contexts, |
317 int port_id, | 365 int port_id, |
318 const std::string& error_message, | 366 const std::string& error_message, |
319 content::RenderView* restrict_to_render_view) { | 367 content::RenderView* restrict_to_render_view) { |
320 v8::HandleScope handle_scope; | 368 v8::HandleScope handle_scope; |
321 | 369 |
322 for (ChromeV8ContextSet::ContextSet::const_iterator it = contexts.begin(); | 370 for (ChromeV8ContextSet::ContextSet::const_iterator it = contexts.begin(); |
323 it != contexts.end(); ++it) { | 371 it != contexts.end(); ++it) { |
324 if (restrict_to_render_view && | 372 if (restrict_to_render_view && |
325 restrict_to_render_view != (*it)->GetRenderView()) { | 373 restrict_to_render_view != (*it)->GetRenderView()) { |
326 continue; | 374 continue; |
327 } | 375 } |
328 | 376 |
| 377 // TODO(kalman): remove when ContextSet::ForEach is available. |
| 378 if ((*it)->v8_context().IsEmpty()) |
| 379 continue; |
| 380 |
329 std::vector<v8::Handle<v8::Value> > arguments; | 381 std::vector<v8::Handle<v8::Value> > arguments; |
330 arguments.push_back(v8::Integer::New(port_id)); | 382 arguments.push_back(v8::Integer::New(port_id)); |
331 if (!error_message.empty()) { | 383 if (!error_message.empty()) { |
332 arguments.push_back(v8::String::New(error_message.c_str())); | 384 arguments.push_back(v8::String::New(error_message.c_str())); |
333 } else { | 385 } else { |
334 arguments.push_back(v8::Null()); | 386 arguments.push_back(v8::Null()); |
335 } | 387 } |
336 (*it)->CallChromeHiddenMethod("Port.dispatchOnDisconnect", | 388 (*it)->CallChromeHiddenMethod("Port.dispatchOnDisconnect", |
337 arguments.size(), &arguments[0], | 389 arguments.size(), &arguments[0], |
338 NULL); | 390 NULL); |
339 } | 391 } |
340 } | 392 } |
341 | 393 |
342 } // namespace extensions | 394 } // namespace extensions |
OLD | NEW |