| 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], 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( | |
| 122 new ExtensionHostMsg_CloseChannel(port_id, std::string())); | |
| 123 ClearPortData(port_id); | |
| 124 } | 134 } |
| 135 // Send via the RenderThread because the RenderView might be closing. |
| 136 bool notify_browser = args[1]->BooleanValue(); |
| 137 if (notify_browser) |
| 138 content::RenderThread::Get()->Send( |
| 139 new ExtensionHostMsg_CloseChannel(port_id, std::string())); |
| 140 ClearPortData(port_id); |
| 141 |
| 125 return v8::Undefined(); | 142 return v8::Undefined(); |
| 126 } | 143 } |
| 127 | 144 |
| 128 // A new port has been created for a context. This occurs both when script | 145 // 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. | 146 // opens a connection, and when a connection is opened to this script. |
| 130 v8::Handle<v8::Value> PortAddRef(const v8::Arguments& args) { | 147 v8::Handle<v8::Value> PortAddRef(const v8::Arguments& args) { |
| 131 if (args.Length() >= 1 && args[0]->IsInt32()) { | 148 // Arguments are (int32 port_id). |
| 132 int port_id = args[0]->Int32Value(); | 149 CHECK_EQ(1, args.Length()); |
| 133 ++GetPortData(port_id).ref_count; | 150 CHECK(args[0]->IsInt32()); |
| 134 } | 151 |
| 152 int port_id = args[0]->Int32Value(); |
| 153 ++GetPortData(port_id).ref_count; |
| 154 |
| 135 return v8::Undefined(); | 155 return v8::Undefined(); |
| 136 } | 156 } |
| 137 | 157 |
| 138 // The frame a port lived in has been destroyed. When there are no more | 158 // 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 | 159 // frames with a reference to a given port, we will disconnect it and notify |
| 140 // the other end of the channel. | 160 // the other end of the channel. |
| 141 v8::Handle<v8::Value> PortRelease(const v8::Arguments& args) { | 161 v8::Handle<v8::Value> PortRelease(const v8::Arguments& args) { |
| 142 if (args.Length() >= 1 && args[0]->IsInt32()) { | 162 // Arguments are (int32 port_id). |
| 143 int port_id = args[0]->Int32Value(); | 163 CHECK_EQ(1, args.Length()); |
| 144 if (HasPortData(port_id) && --GetPortData(port_id).ref_count == 0) { | 164 CHECK(args[0]->IsInt32()); |
| 145 // Send via the RenderThread because the RenderView might be closing. | 165 |
| 146 content::RenderThread::Get()->Send( | 166 int port_id = args[0]->Int32Value(); |
| 147 new ExtensionHostMsg_CloseChannel(port_id, std::string())); | 167 if (HasPortData(port_id) && --GetPortData(port_id).ref_count == 0) { |
| 148 ClearPortData(port_id); | 168 // Send via the RenderThread because the RenderView might be closing. |
| 149 } | 169 content::RenderThread::Get()->Send( |
| 170 new ExtensionHostMsg_CloseChannel(port_id, std::string())); |
| 171 ClearPortData(port_id); |
| 150 } | 172 } |
| 173 |
| 151 return v8::Undefined(); | 174 return v8::Undefined(); |
| 152 } | 175 } |
| 153 | 176 |
| 154 struct GCCallbackArgs { | 177 struct GCCallbackArgs { |
| 155 GCCallbackArgs(v8::Handle<v8::Object> object, | 178 GCCallbackArgs(v8::Handle<v8::Object> object, |
| 156 v8::Handle<v8::Function> callback) | 179 v8::Handle<v8::Function> callback) |
| 157 : object(object), callback(callback) {} | 180 : object(object), callback(callback) {} |
| 158 | 181 |
| 159 extensions::ScopedPersistent<v8::Object> object; | 182 extensions::ScopedPersistent<v8::Object> object; |
| 160 extensions::ScopedPersistent<v8::Function> callback; | 183 extensions::ScopedPersistent<v8::Function> callback; |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 228 | 251 |
| 229 v8::Handle<v8::Value> arguments[] = { | 252 v8::Handle<v8::Value> arguments[] = { |
| 230 v8::Integer::New(target_port_id), | 253 v8::Integer::New(target_port_id), |
| 231 v8::String::New(channel_name.c_str(), channel_name.size()), | 254 v8::String::New(channel_name.c_str(), channel_name.size()), |
| 232 tab, | 255 tab, |
| 233 v8::String::New(source_extension_id.c_str(), source_extension_id.size()), | 256 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()), | 257 v8::String::New(target_extension_id.c_str(), target_extension_id.size()), |
| 235 v8::String::New(source_url_spec.c_str(), source_url_spec.size()) | 258 v8::String::New(source_url_spec.c_str(), source_url_spec.size()) |
| 236 }; | 259 }; |
| 237 | 260 |
| 238 v8::Handle<v8::Value> retval; | 261 v8::Handle<v8::Value> retval = (*it)->module_system()->CallModuleMethod( |
| 239 v8::TryCatch try_catch; | 262 "miscellaneous_bindings", |
| 240 if (!(*it)->CallChromeHiddenMethod("Port.dispatchOnConnect", | 263 "dispatchOnConnect", |
| 241 arraysize(arguments), arguments, | 264 arraysize(arguments), arguments); |
| 242 &retval)) { | |
| 243 continue; | |
| 244 } | |
| 245 | |
| 246 if (try_catch.HasCaught()) { | |
| 247 LOG(ERROR) << "Exception caught when calling Port.dispatchOnConnect."; | |
| 248 continue; | |
| 249 } | |
| 250 | 265 |
| 251 if (retval.IsEmpty()) { | 266 if (retval.IsEmpty()) { |
| 252 LOG(ERROR) << "Empty return value from Port.dispatchOnConnect."; | 267 LOG(ERROR) << "Empty return value from dispatchOnConnect."; |
| 253 continue; | 268 continue; |
| 254 } | 269 } |
| 255 | 270 |
| 256 CHECK(retval->IsBoolean()); | 271 CHECK(retval->IsBoolean()); |
| 257 if (retval->BooleanValue()) | 272 port_created |= retval->BooleanValue(); |
| 258 port_created = true; | |
| 259 } | 273 } |
| 260 | 274 |
| 261 // If we didn't create a port, notify the other end of the channel (treat it | 275 // If we didn't create a port, notify the other end of the channel (treat it |
| 262 // as a disconnect). | 276 // as a disconnect). |
| 263 if (!port_created) { | 277 if (!port_created) { |
| 278 LOG(WARNING) << "Port wasn't created"; |
| 264 content::RenderThread::Get()->Send( | 279 content::RenderThread::Get()->Send( |
| 265 new ExtensionHostMsg_CloseChannel( | 280 new ExtensionHostMsg_CloseChannel( |
| 266 target_port_id, kReceivingEndDoesntExistError)); | 281 target_port_id, kReceivingEndDoesntExistError)); |
| 267 } | 282 } |
| 268 } | 283 } |
| 269 | 284 |
| 270 // static | 285 // static |
| 271 void MiscellaneousBindings::DeliverMessage( | 286 void MiscellaneousBindings::DeliverMessage( |
| 272 const ChromeV8ContextSet::ContextSet& contexts, | 287 const ChromeV8ContextSet::ContextSet& contexts, |
| 273 int target_port_id, | 288 int target_port_id, |
| 274 const std::string& message, | 289 const base::ListValue& message, |
| 275 content::RenderView* restrict_to_render_view) { | 290 content::RenderView* restrict_to_render_view) { |
| 276 v8::HandleScope handle_scope; | 291 v8::HandleScope handle_scope; |
| 277 | 292 |
| 278 for (ChromeV8ContextSet::ContextSet::const_iterator it = contexts.begin(); | 293 for (ChromeV8ContextSet::ContextSet::const_iterator it = contexts.begin(); |
| 279 it != contexts.end(); ++it) { | 294 it != contexts.end(); ++it) { |
| 280 if (restrict_to_render_view && | 295 if (restrict_to_render_view && |
| 281 restrict_to_render_view != (*it)->GetRenderView()) { | 296 restrict_to_render_view != (*it)->GetRenderView()) { |
| 282 continue; | 297 continue; |
| 283 } | 298 } |
| 284 | 299 |
| 300 v8::Handle<v8::Context> context = (*it)->v8_context(); |
| 301 v8::Context::Scope context_scope(context); |
| 302 |
| 285 // Check to see whether the context has this port before bothering to create | 303 // Check to see whether the context has this port before bothering to create |
| 286 // the message. | 304 // the message. |
| 287 v8::Handle<v8::Value> port_id_handle = v8::Integer::New(target_port_id); | 305 v8::Handle<v8::Value> port_id_handle = v8::Integer::New(target_port_id); |
| 288 v8::Handle<v8::Value> has_port; | 306 v8::Handle<v8::Value> has_port = (*it)->module_system()->CallModuleMethod( |
| 289 v8::TryCatch try_catch; | 307 "miscellaneous_bindings", |
| 290 if (!(*it)->CallChromeHiddenMethod("Port.hasPort", 1, &port_id_handle, | 308 "hasPort", |
| 291 &has_port)) { | 309 1, &port_id_handle); |
| 292 continue; | |
| 293 } | |
| 294 | |
| 295 if (try_catch.HasCaught()) { | |
| 296 LOG(ERROR) << "Exception caught when calling Port.hasPort."; | |
| 297 continue; | |
| 298 } | |
| 299 | 310 |
| 300 CHECK(!has_port.IsEmpty()); | 311 CHECK(!has_port.IsEmpty()); |
| 301 if (!has_port->BooleanValue()) | 312 if (!has_port->BooleanValue()) |
| 302 continue; | 313 continue; |
| 303 | 314 |
| 304 std::vector<v8::Handle<v8::Value> > arguments; | 315 std::vector<v8::Handle<v8::Value> > arguments; |
| 305 arguments.push_back(v8::String::New(message.c_str(), message.size())); | 316 |
| 317 // Convert the message to a v8 object; either a value or undefined. |
| 318 // See PostMessage for more details. |
| 319 if (message.empty()) { |
| 320 arguments.push_back(v8::Undefined()); |
| 321 } else { |
| 322 CHECK_EQ(1u, message.GetSize()); |
| 323 const base::Value* message_value = NULL; |
| 324 message.Get(0, &message_value); |
| 325 scoped_ptr<V8ValueConverter> converter(V8ValueConverter::create()); |
| 326 arguments.push_back(converter->ToV8Value(message_value, context)); |
| 327 } |
| 328 |
| 306 arguments.push_back(port_id_handle); | 329 arguments.push_back(port_id_handle); |
| 307 CHECK((*it)->CallChromeHiddenMethod("Port.dispatchOnMessage", | 330 (*it)->module_system()->CallModuleMethod("miscellaneous_bindings", |
| 308 arguments.size(), | 331 "dispatchOnMessage", |
| 309 &arguments[0], | 332 &arguments); |
| 310 NULL)); | |
| 311 } | 333 } |
| 312 } | 334 } |
| 313 | 335 |
| 314 // static | 336 // static |
| 315 void MiscellaneousBindings::DispatchOnDisconnect( | 337 void MiscellaneousBindings::DispatchOnDisconnect( |
| 316 const ChromeV8ContextSet::ContextSet& contexts, | 338 const ChromeV8ContextSet::ContextSet& contexts, |
| 317 int port_id, | 339 int port_id, |
| 318 const std::string& error_message, | 340 const std::string& error_message, |
| 319 content::RenderView* restrict_to_render_view) { | 341 content::RenderView* restrict_to_render_view) { |
| 320 v8::HandleScope handle_scope; | 342 v8::HandleScope handle_scope; |
| 321 | 343 |
| 322 for (ChromeV8ContextSet::ContextSet::const_iterator it = contexts.begin(); | 344 for (ChromeV8ContextSet::ContextSet::const_iterator it = contexts.begin(); |
| 323 it != contexts.end(); ++it) { | 345 it != contexts.end(); ++it) { |
| 324 if (restrict_to_render_view && | 346 if (restrict_to_render_view && |
| 325 restrict_to_render_view != (*it)->GetRenderView()) { | 347 restrict_to_render_view != (*it)->GetRenderView()) { |
| 326 continue; | 348 continue; |
| 327 } | 349 } |
| 328 | 350 |
| 329 std::vector<v8::Handle<v8::Value> > arguments; | 351 std::vector<v8::Handle<v8::Value> > arguments; |
| 330 arguments.push_back(v8::Integer::New(port_id)); | 352 arguments.push_back(v8::Integer::New(port_id)); |
| 331 if (!error_message.empty()) { | 353 if (!error_message.empty()) { |
| 332 arguments.push_back(v8::String::New(error_message.c_str())); | 354 arguments.push_back(v8::String::New(error_message.c_str())); |
| 333 } else { | 355 } else { |
| 334 arguments.push_back(v8::Null()); | 356 arguments.push_back(v8::Null()); |
| 335 } | 357 } |
| 336 (*it)->CallChromeHiddenMethod("Port.dispatchOnDisconnect", | 358 (*it)->module_system()->CallModuleMethod("miscellaneous_bindings", |
| 337 arguments.size(), &arguments[0], | 359 "dispatchOnDisconnect", |
| 338 NULL); | 360 &arguments); |
| 339 } | 361 } |
| 340 } | 362 } |
| 341 | 363 |
| 342 } // namespace extensions | 364 } // namespace extensions |
| OLD | NEW |