| 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/browser/extensions/api/messaging/message_service.h" | 5 #include "chrome/browser/extensions/api/messaging/message_service.h" |
| 6 | 6 |
| 7 #include "base/atomic_sequence_num.h" | 7 #include "base/atomic_sequence_num.h" |
| 8 #include "base/bind.h" | 8 #include "base/bind.h" |
| 9 #include "base/bind_helpers.h" | 9 #include "base/bind_helpers.h" |
| 10 #include "base/callback.h" | 10 #include "base/callback.h" |
| 11 #include "base/json/json_writer.h" | 11 #include "base/json/json_writer.h" |
| 12 #include "base/lazy_instance.h" | 12 #include "base/lazy_instance.h" |
| 13 #include "base/stl_util.h" | 13 #include "base/stl_util.h" |
| 14 #include "base/values.h" | 14 #include "base/values.h" |
| 15 #include "chrome/browser/extensions/api/messaging/extension_message_port.h" | 15 #include "chrome/browser/extensions/api/messaging/extension_message_port.h" |
| 16 #include "chrome/browser/extensions/api/messaging/native_message_port.h" | 16 #include "chrome/browser/extensions/api/messaging/native_message_port.h" |
| 17 #include "chrome/browser/extensions/extension_host.h" | 17 #include "chrome/browser/extensions/extension_host.h" |
| 18 #include "chrome/browser/extensions/extension_process_manager.h" | 18 #include "chrome/browser/extensions/extension_process_manager.h" |
| 19 #include "chrome/browser/extensions/extension_service.h" | 19 #include "chrome/browser/extensions/extension_service.h" |
| 20 #include "chrome/browser/extensions/extension_system.h" | 20 #include "chrome/browser/extensions/extension_system.h" |
| 21 #include "chrome/browser/extensions/extension_tab_util.h" | 21 #include "chrome/browser/extensions/extension_tab_util.h" |
| 22 #include "chrome/browser/extensions/lazy_background_task_queue.h" | 22 #include "chrome/browser/extensions/lazy_background_task_queue.h" |
| 23 #include "chrome/browser/extensions/process_map.h" | 23 #include "chrome/browser/extensions/process_map.h" |
| 24 #include "chrome/browser/profiles/profile.h" | 24 #include "chrome/browser/profiles/profile.h" |
| 25 #include "chrome/browser/tab_contents/tab_util.h" | 25 #include "chrome/browser/tab_contents/tab_util.h" |
| 26 #include "chrome/common/chrome_notification_types.h" | 26 #include "chrome/common/chrome_notification_types.h" |
| 27 #include "chrome/common/extensions/background_info.h" | 27 #include "chrome/common/extensions/background_info.h" |
| 28 #include "chrome/common/extensions/extension.h" | 28 #include "chrome/common/extensions/extension.h" |
| 29 #include "chrome/common/extensions/extension_manifest_constants.h" |
| 29 #include "chrome/common/extensions/extension_messages.h" | 30 #include "chrome/common/extensions/extension_messages.h" |
| 30 #include "chrome/common/extensions/incognito_handler.h" | 31 #include "chrome/common/extensions/incognito_handler.h" |
| 32 #include "chrome/common/extensions/manifest_handlers/externally_connectable.h" |
| 31 #include "content/public/browser/browser_thread.h" | 33 #include "content/public/browser/browser_thread.h" |
| 32 #include "content/public/browser/notification_service.h" | 34 #include "content/public/browser/notification_service.h" |
| 33 #include "content/public/browser/render_process_host.h" | 35 #include "content/public/browser/render_process_host.h" |
| 34 #include "content/public/browser/render_view_host.h" | 36 #include "content/public/browser/render_view_host.h" |
| 35 #include "content/public/browser/site_instance.h" | 37 #include "content/public/browser/site_instance.h" |
| 36 #include "content/public/browser/web_contents.h" | 38 #include "content/public/browser/web_contents.h" |
| 37 #include "googleurl/src/gurl.h" | 39 #include "googleurl/src/gurl.h" |
| 38 | 40 |
| 39 using content::SiteInstance; | 41 using content::SiteInstance; |
| 40 using content::WebContents; | 42 using content::WebContents; |
| (...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 180 const std::string& channel_name) { | 182 const std::string& channel_name) { |
| 181 content::RenderProcessHost* source = | 183 content::RenderProcessHost* source = |
| 182 content::RenderProcessHost::FromID(source_process_id); | 184 content::RenderProcessHost::FromID(source_process_id); |
| 183 if (!source) | 185 if (!source) |
| 184 return; | 186 return; |
| 185 Profile* profile = Profile::FromBrowserContext(source->GetBrowserContext()); | 187 Profile* profile = Profile::FromBrowserContext(source->GetBrowserContext()); |
| 186 | 188 |
| 187 const Extension* target_extension = ExtensionSystem::Get(profile)-> | 189 const Extension* target_extension = ExtensionSystem::Get(profile)-> |
| 188 extension_service()->extensions()->GetByID(target_extension_id); | 190 extension_service()->extensions()->GetByID(target_extension_id); |
| 189 if (!target_extension) { | 191 if (!target_extension) { |
| 190 // Treat it as a disconnect. | 192 DispatchOnDisconnect( |
| 191 ExtensionMessagePort port(source, MSG_ROUTING_CONTROL, std::string()); | 193 source, receiver_port_id, kReceivingEndDoesntExistError); |
| 192 port.DispatchOnDisconnect(GET_OPPOSITE_PORT_ID(receiver_port_id), | |
| 193 kReceivingEndDoesntExistError); | |
| 194 return; | 194 return; |
| 195 } | 195 } |
| 196 | 196 |
| 197 if (source_extension_id != target_extension_id) { |
| 198 // It's an external connection. Check the externally_connectable manifest |
| 199 // key if it's present. If it's not, we allow connection from any extension |
| 200 // but not webpages. |
| 201 ExternallyConnectableInfo* externally_connectable = |
| 202 static_cast<ExternallyConnectableInfo*>( |
| 203 target_extension->GetManifestData( |
| 204 extension_manifest_keys::kExternallyConnectable)); |
| 205 bool is_externally_connectable = false; |
| 206 |
| 207 if (externally_connectable) { |
| 208 if (source_extension_id.empty()) { |
| 209 // No source extension ID so the source was a web page. Check that the |
| 210 // URL matches. |
| 211 is_externally_connectable = |
| 212 externally_connectable->matches.MatchesURL(source_url); |
| 213 } else { |
| 214 // Source extension ID so the source was an extension. Check that the |
| 215 // extension matches. |
| 216 is_externally_connectable = |
| 217 externally_connectable->IdCanConnect(source_extension_id); |
| 218 } |
| 219 } else { |
| 220 // Default behaviour. Any extension, no webpages. |
| 221 is_externally_connectable = !source_extension_id.empty(); |
| 222 } |
| 223 |
| 224 if (!is_externally_connectable) { |
| 225 // Important: use kReceivingEndDoesntExistError here so that we don't |
| 226 // leak information about this extension to callers. This way it's |
| 227 // indistinguishable from the extension just not existing. |
| 228 DispatchOnDisconnect( |
| 229 source, receiver_port_id, kReceivingEndDoesntExistError); |
| 230 return; |
| 231 } |
| 232 } |
| 233 |
| 197 // Note: we use the source's profile here. If the source is an incognito | 234 // Note: we use the source's profile here. If the source is an incognito |
| 198 // process, we will use the incognito EPM to find the right extension process, | 235 // process, we will use the incognito EPM to find the right extension process, |
| 199 // which depends on whether the extension uses spanning or split mode. | 236 // which depends on whether the extension uses spanning or split mode. |
| 200 MessagePort* receiver = new ExtensionMessagePort( | 237 MessagePort* receiver = new ExtensionMessagePort( |
| 201 GetExtensionProcess(profile, target_extension_id), MSG_ROUTING_CONTROL, | 238 GetExtensionProcess(profile, target_extension_id), MSG_ROUTING_CONTROL, |
| 202 target_extension_id); | 239 target_extension_id); |
| 203 WebContents* source_contents = tab_util::GetWebContentsByID( | 240 WebContents* source_contents = tab_util::GetWebContentsByID( |
| 204 source_process_id, source_routing_id); | 241 source_process_id, source_routing_id); |
| 205 | 242 |
| 206 // Include info about the opener's tab (if it was a tab). | 243 // Include info about the opener's tab (if it was a tab). |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 250 extensions::ExtensionSystem::Get(profile)->extension_service(); | 287 extensions::ExtensionSystem::Get(profile)->extension_service(); |
| 251 bool has_permission = false; | 288 bool has_permission = false; |
| 252 if (extension_service) { | 289 if (extension_service) { |
| 253 const Extension* extension = | 290 const Extension* extension = |
| 254 extension_service->GetExtensionById(source_extension_id, false); | 291 extension_service->GetExtensionById(source_extension_id, false); |
| 255 has_permission = extension && extension->HasAPIPermission( | 292 has_permission = extension && extension->HasAPIPermission( |
| 256 APIPermission::kNativeMessaging); | 293 APIPermission::kNativeMessaging); |
| 257 } | 294 } |
| 258 | 295 |
| 259 if (!has_permission) { | 296 if (!has_permission) { |
| 260 ExtensionMessagePort port(source, MSG_ROUTING_CONTROL, std::string()); | 297 DispatchOnDisconnect(source, receiver_port_id, kMissingPermissionError); |
| 261 port.DispatchOnDisconnect(GET_OPPOSITE_PORT_ID(receiver_port_id), | |
| 262 kMissingPermissionError); | |
| 263 return; | 298 return; |
| 264 } | 299 } |
| 265 | 300 |
| 266 scoped_ptr<MessageChannel> channel(new MessageChannel()); | 301 scoped_ptr<MessageChannel> channel(new MessageChannel()); |
| 267 channel->opener.reset(new ExtensionMessagePort(source, MSG_ROUTING_CONTROL, | 302 channel->opener.reset(new ExtensionMessagePort(source, MSG_ROUTING_CONTROL, |
| 268 source_extension_id)); | 303 source_extension_id)); |
| 269 | 304 |
| 270 scoped_ptr<NativeMessageProcessHost> native_process = | 305 scoped_ptr<NativeMessageProcessHost> native_process = |
| 271 NativeMessageProcessHost::Create( | 306 NativeMessageProcessHost::Create( |
| 272 base::WeakPtr<NativeMessageProcessHost::Client>( | 307 base::WeakPtr<NativeMessageProcessHost::Client>( |
| 273 weak_factory_.GetWeakPtr()), | 308 weak_factory_.GetWeakPtr()), |
| 274 source_extension_id, native_app_name, receiver_port_id); | 309 source_extension_id, native_app_name, receiver_port_id); |
| 275 | 310 |
| 276 // Abandon the channel. | 311 // Abandon the channel. |
| 277 if (!native_process.get()) { | 312 if (!native_process.get()) { |
| 278 LOG(ERROR) << "Failed to create native process."; | 313 LOG(ERROR) << "Failed to create native process."; |
| 279 // Treat it as a disconnect. | 314 DispatchOnDisconnect( |
| 280 ExtensionMessagePort port(source, MSG_ROUTING_CONTROL, std::string()); | 315 source, receiver_port_id, kReceivingEndDoesntExistError); |
| 281 port.DispatchOnDisconnect(GET_OPPOSITE_PORT_ID(receiver_port_id), | |
| 282 kReceivingEndDoesntExistError); | |
| 283 return; | 316 return; |
| 284 } | 317 } |
| 285 channel->receiver.reset(new NativeMessagePort(native_process.release())); | 318 channel->receiver.reset(new NativeMessagePort(native_process.release())); |
| 286 | 319 |
| 287 // Keep the opener alive until the channel is closed. | 320 // Keep the opener alive until the channel is closed. |
| 288 channel->opener->IncrementLazyKeepaliveCount(); | 321 channel->opener->IncrementLazyKeepaliveCount(); |
| 289 | 322 |
| 290 AddChannel(channel.release(), receiver_port_id); | 323 AddChannel(channel.release(), receiver_port_id); |
| 291 #else // !(defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX)) | 324 #else // !(defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX)) |
| 292 ExtensionMessagePort port(source, MSG_ROUTING_CONTROL, ""); | 325 DispatchOnDisconnect( |
| 293 port.DispatchOnDisconnect(GET_OPPOSITE_PORT_ID(receiver_port_id), | 326 source, receiver_port_id, kNativeMessagingNotSupportedError); |
| 294 kNativeMessagingNotSupportedError); | |
| 295 #endif // !(defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX)) | 327 #endif // !(defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX)) |
| 296 } | 328 } |
| 297 | 329 |
| 298 void MessageService::OpenChannelToTab( | 330 void MessageService::OpenChannelToTab( |
| 299 int source_process_id, int source_routing_id, int receiver_port_id, | 331 int source_process_id, int source_routing_id, int receiver_port_id, |
| 300 int tab_id, const std::string& extension_id, | 332 int tab_id, const std::string& extension_id, |
| 301 const std::string& channel_name) { | 333 const std::string& channel_name) { |
| 302 content::RenderProcessHost* source = | 334 content::RenderProcessHost* source = |
| 303 content::RenderProcessHost::FromID(source_process_id); | 335 content::RenderProcessHost::FromID(source_process_id); |
| 304 if (!source) | 336 if (!source) |
| 305 return; | 337 return; |
| 306 Profile* profile = Profile::FromBrowserContext(source->GetBrowserContext()); | 338 Profile* profile = Profile::FromBrowserContext(source->GetBrowserContext()); |
| 307 | 339 |
| 308 WebContents* contents = NULL; | 340 WebContents* contents = NULL; |
| 309 scoped_ptr<MessagePort> receiver; | 341 scoped_ptr<MessagePort> receiver; |
| 310 if (ExtensionTabUtil::GetTabById(tab_id, profile, true, | 342 if (ExtensionTabUtil::GetTabById(tab_id, profile, true, |
| 311 NULL, NULL, &contents, NULL)) { | 343 NULL, NULL, &contents, NULL)) { |
| 312 receiver.reset(new ExtensionMessagePort( | 344 receiver.reset(new ExtensionMessagePort( |
| 313 contents->GetRenderProcessHost(), | 345 contents->GetRenderProcessHost(), |
| 314 contents->GetRenderViewHost()->GetRoutingID(), | 346 contents->GetRenderViewHost()->GetRoutingID(), |
| 315 extension_id)); | 347 extension_id)); |
| 316 } | 348 } |
| 317 | 349 |
| 318 if (contents && contents->GetController().NeedsReload()) { | 350 if (contents && contents->GetController().NeedsReload()) { |
| 319 // The tab isn't loaded yet. Don't attempt to connect. Treat this as a | 351 // The tab isn't loaded yet. Don't attempt to connect. |
| 320 // disconnect. | 352 DispatchOnDisconnect( |
| 321 ExtensionMessagePort port(source, MSG_ROUTING_CONTROL, extension_id); | 353 source, receiver_port_id, kReceivingEndDoesntExistError); |
| 322 port.DispatchOnDisconnect(GET_OPPOSITE_PORT_ID(receiver_port_id), | |
| 323 kReceivingEndDoesntExistError); | |
| 324 return; | 354 return; |
| 325 } | 355 } |
| 326 | 356 |
| 327 scoped_ptr<OpenChannelParams> params(new OpenChannelParams( | 357 scoped_ptr<OpenChannelParams> params(new OpenChannelParams( |
| 328 source, | 358 source, |
| 329 scoped_ptr<DictionaryValue>(), // Source tab doesn't make sense for | 359 scoped_ptr<DictionaryValue>(), // Source tab doesn't make sense for |
| 330 // opening to tabs. | 360 // opening to tabs. |
| 331 receiver.release(), | 361 receiver.release(), |
| 332 receiver_port_id, | 362 receiver_port_id, |
| 333 extension_id, | 363 extension_id, |
| 334 extension_id, | 364 extension_id, |
| 335 GURL(), // Source URL doesn't make sense for opening to tabs. | 365 GURL(), // Source URL doesn't make sense for opening to tabs. |
| 336 channel_name)); | 366 channel_name)); |
| 337 OpenChannelImpl(params.Pass()); | 367 OpenChannelImpl(params.Pass()); |
| 338 } | 368 } |
| 339 | 369 |
| 340 bool MessageService::OpenChannelImpl(scoped_ptr<OpenChannelParams> params) { | 370 bool MessageService::OpenChannelImpl(scoped_ptr<OpenChannelParams> params) { |
| 341 if (!params->source) | 371 if (!params->source) |
| 342 return false; // Closed while in flight. | 372 return false; // Closed while in flight. |
| 343 | 373 |
| 344 if (!params->receiver || !params->receiver->GetRenderProcessHost()) { | 374 if (!params->receiver || !params->receiver->GetRenderProcessHost()) { |
| 345 // Treat it as a disconnect. | 375 DispatchOnDisconnect(params->source, |
| 346 ExtensionMessagePort port( | 376 params->receiver_port_id, |
| 347 params->source, MSG_ROUTING_CONTROL, std::string()); | 377 kReceivingEndDoesntExistError); |
| 348 port.DispatchOnDisconnect(GET_OPPOSITE_PORT_ID(params->receiver_port_id), | |
| 349 kReceivingEndDoesntExistError); | |
| 350 return false; | 378 return false; |
| 351 } | 379 } |
| 352 | 380 |
| 353 // Add extra paranoid CHECKs, since we have crash reports of this being NULL. | 381 // Add extra paranoid CHECKs, since we have crash reports of this being NULL. |
| 354 // http://code.google.com/p/chromium/issues/detail?id=19067 | 382 // http://code.google.com/p/chromium/issues/detail?id=19067 |
| 355 CHECK(params->receiver->GetRenderProcessHost()); | 383 CHECK(params->receiver->GetRenderProcessHost()); |
| 356 | 384 |
| 357 MessageChannel* channel(new MessageChannel); | 385 MessageChannel* channel(new MessageChannel); |
| 358 channel->opener.reset(new ExtensionMessagePort(params->source, | 386 channel->opener.reset(new ExtensionMessagePort(params->source, |
| 359 MSG_ROUTING_CONTROL, | 387 MSG_ROUTING_CONTROL, |
| (...skipping 183 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 543 if (!source) | 571 if (!source) |
| 544 return; | 572 return; |
| 545 | 573 |
| 546 params->source = source; | 574 params->source = source; |
| 547 params->receiver.reset(new ExtensionMessagePort(host->render_process_host(), | 575 params->receiver.reset(new ExtensionMessagePort(host->render_process_host(), |
| 548 MSG_ROUTING_CONTROL, | 576 MSG_ROUTING_CONTROL, |
| 549 params->target_extension_id)); | 577 params->target_extension_id)); |
| 550 OpenChannelImpl(params.Pass()); | 578 OpenChannelImpl(params.Pass()); |
| 551 } | 579 } |
| 552 | 580 |
| 581 void MessageService::DispatchOnDisconnect(content::RenderProcessHost* source, |
| 582 int port_id, |
| 583 const std::string& error_message) { |
| 584 ExtensionMessagePort port(source, MSG_ROUTING_CONTROL, ""); |
| 585 port.DispatchOnDisconnect(GET_OPPOSITE_PORT_ID(port_id), error_message); |
| 586 } |
| 587 |
| 553 } // namespace extensions | 588 } // namespace extensions |
| OLD | NEW |