Chromium Code Reviews| 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 = true; | |
|
Jeffrey Yasskin
2013/06/08 00:28:09
Default this to false in order to fail safe. (i.e.
not at google - send to devlin
2013/06/08 02:02:33
Default to false, static function looks a bit cont
| |
| 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->MatchesIdOrAllIds(source_extension_id); | |
| 218 } | |
| 219 } else { | |
| 220 // Legacy behaviour. Any extension, no webpages. | |
|
Jeffrey Yasskin
2013/06/08 00:28:09
What makes this legacy? Is there a plan to require
not at google - send to devlin
2013/06/08 02:02:33
Fair enough, legacy is the wrong word. I don't see
| |
| 221 is_externally_connectable = !source_extension_id.empty(); | |
| 222 } | |
| 223 | |
| 224 if (!is_externally_connectable) { | |
| 225 DispatchOnDisconnect( | |
| 226 source, receiver_port_id, kReceivingEndDoesntExistError); | |
|
Jeffrey Yasskin
2013/06/08 00:28:09
This message is, of course, a lie. Please comment
not at google - send to devlin
2013/06/08 02:02:33
Done.
| |
| 227 return; | |
| 228 } | |
| 229 } | |
| 230 | |
| 197 // Note: we use the source's profile here. If the source is an incognito | 231 // 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, | 232 // 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. | 233 // which depends on whether the extension uses spanning or split mode. |
| 200 MessagePort* receiver = new ExtensionMessagePort( | 234 MessagePort* receiver = new ExtensionMessagePort( |
| 201 GetExtensionProcess(profile, target_extension_id), MSG_ROUTING_CONTROL, | 235 GetExtensionProcess(profile, target_extension_id), MSG_ROUTING_CONTROL, |
| 202 target_extension_id); | 236 target_extension_id); |
| 203 WebContents* source_contents = tab_util::GetWebContentsByID( | 237 WebContents* source_contents = tab_util::GetWebContentsByID( |
| 204 source_process_id, source_routing_id); | 238 source_process_id, source_routing_id); |
| 205 | 239 |
| 206 // Include info about the opener's tab (if it was a tab). | 240 // 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(); | 284 extensions::ExtensionSystem::Get(profile)->extension_service(); |
| 251 bool has_permission = false; | 285 bool has_permission = false; |
| 252 if (extension_service) { | 286 if (extension_service) { |
| 253 const Extension* extension = | 287 const Extension* extension = |
| 254 extension_service->GetExtensionById(source_extension_id, false); | 288 extension_service->GetExtensionById(source_extension_id, false); |
| 255 has_permission = extension && extension->HasAPIPermission( | 289 has_permission = extension && extension->HasAPIPermission( |
| 256 APIPermission::kNativeMessaging); | 290 APIPermission::kNativeMessaging); |
| 257 } | 291 } |
| 258 | 292 |
| 259 if (!has_permission) { | 293 if (!has_permission) { |
| 260 ExtensionMessagePort port(source, MSG_ROUTING_CONTROL, std::string()); | 294 DispatchOnDisconnect(source, receiver_port_id, kMissingPermissionError); |
| 261 port.DispatchOnDisconnect(GET_OPPOSITE_PORT_ID(receiver_port_id), | |
| 262 kMissingPermissionError); | |
| 263 return; | 295 return; |
| 264 } | 296 } |
| 265 | 297 |
| 266 scoped_ptr<MessageChannel> channel(new MessageChannel()); | 298 scoped_ptr<MessageChannel> channel(new MessageChannel()); |
| 267 channel->opener.reset(new ExtensionMessagePort(source, MSG_ROUTING_CONTROL, | 299 channel->opener.reset(new ExtensionMessagePort(source, MSG_ROUTING_CONTROL, |
| 268 source_extension_id)); | 300 source_extension_id)); |
| 269 | 301 |
| 270 scoped_ptr<NativeMessageProcessHost> native_process = | 302 scoped_ptr<NativeMessageProcessHost> native_process = |
| 271 NativeMessageProcessHost::Create( | 303 NativeMessageProcessHost::Create( |
| 272 base::WeakPtr<NativeMessageProcessHost::Client>( | 304 base::WeakPtr<NativeMessageProcessHost::Client>( |
| 273 weak_factory_.GetWeakPtr()), | 305 weak_factory_.GetWeakPtr()), |
| 274 source_extension_id, native_app_name, receiver_port_id); | 306 source_extension_id, native_app_name, receiver_port_id); |
| 275 | 307 |
| 276 // Abandon the channel. | 308 // Abandon the channel. |
| 277 if (!native_process.get()) { | 309 if (!native_process.get()) { |
| 278 LOG(ERROR) << "Failed to create native process."; | 310 LOG(ERROR) << "Failed to create native process."; |
| 279 // Treat it as a disconnect. | 311 DispatchOnDisconnect( |
| 280 ExtensionMessagePort port(source, MSG_ROUTING_CONTROL, std::string()); | 312 source, receiver_port_id, kReceivingEndDoesntExistError); |
| 281 port.DispatchOnDisconnect(GET_OPPOSITE_PORT_ID(receiver_port_id), | |
| 282 kReceivingEndDoesntExistError); | |
| 283 return; | 313 return; |
| 284 } | 314 } |
| 285 channel->receiver.reset(new NativeMessagePort(native_process.release())); | 315 channel->receiver.reset(new NativeMessagePort(native_process.release())); |
| 286 | 316 |
| 287 // Keep the opener alive until the channel is closed. | 317 // Keep the opener alive until the channel is closed. |
| 288 channel->opener->IncrementLazyKeepaliveCount(); | 318 channel->opener->IncrementLazyKeepaliveCount(); |
| 289 | 319 |
| 290 AddChannel(channel.release(), receiver_port_id); | 320 AddChannel(channel.release(), receiver_port_id); |
| 291 #else // !(defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX)) | 321 #else // !(defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX)) |
| 292 ExtensionMessagePort port(source, MSG_ROUTING_CONTROL, ""); | 322 DispatchOnDisconnect( |
| 293 port.DispatchOnDisconnect(GET_OPPOSITE_PORT_ID(receiver_port_id), | 323 source, receiver_port_id, kNativeMessagingNotSupportedError); |
| 294 kNativeMessagingNotSupportedError); | |
| 295 #endif // !(defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX)) | 324 #endif // !(defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX)) |
| 296 } | 325 } |
| 297 | 326 |
| 298 void MessageService::OpenChannelToTab( | 327 void MessageService::OpenChannelToTab( |
| 299 int source_process_id, int source_routing_id, int receiver_port_id, | 328 int source_process_id, int source_routing_id, int receiver_port_id, |
| 300 int tab_id, const std::string& extension_id, | 329 int tab_id, const std::string& extension_id, |
| 301 const std::string& channel_name) { | 330 const std::string& channel_name) { |
| 302 content::RenderProcessHost* source = | 331 content::RenderProcessHost* source = |
| 303 content::RenderProcessHost::FromID(source_process_id); | 332 content::RenderProcessHost::FromID(source_process_id); |
| 304 if (!source) | 333 if (!source) |
| 305 return; | 334 return; |
| 306 Profile* profile = Profile::FromBrowserContext(source->GetBrowserContext()); | 335 Profile* profile = Profile::FromBrowserContext(source->GetBrowserContext()); |
| 307 | 336 |
| 308 WebContents* contents = NULL; | 337 WebContents* contents = NULL; |
| 309 scoped_ptr<MessagePort> receiver; | 338 scoped_ptr<MessagePort> receiver; |
| 310 if (ExtensionTabUtil::GetTabById(tab_id, profile, true, | 339 if (ExtensionTabUtil::GetTabById(tab_id, profile, true, |
| 311 NULL, NULL, &contents, NULL)) { | 340 NULL, NULL, &contents, NULL)) { |
| 312 receiver.reset(new ExtensionMessagePort( | 341 receiver.reset(new ExtensionMessagePort( |
| 313 contents->GetRenderProcessHost(), | 342 contents->GetRenderProcessHost(), |
| 314 contents->GetRenderViewHost()->GetRoutingID(), | 343 contents->GetRenderViewHost()->GetRoutingID(), |
| 315 extension_id)); | 344 extension_id)); |
| 316 } | 345 } |
| 317 | 346 |
| 318 if (contents && contents->GetController().NeedsReload()) { | 347 if (contents && contents->GetController().NeedsReload()) { |
| 319 // The tab isn't loaded yet. Don't attempt to connect. Treat this as a | 348 // The tab isn't loaded yet. Don't attempt to connect. |
| 320 // disconnect. | 349 DispatchOnDisconnect(source, |
| 321 ExtensionMessagePort port(source, MSG_ROUTING_CONTROL, extension_id); | 350 receiver_port_id, |
| 322 port.DispatchOnDisconnect(GET_OPPOSITE_PORT_ID(receiver_port_id), | 351 extension_id, |
| 323 kReceivingEndDoesntExistError); | 352 kReceivingEndDoesntExistError); |
| 324 return; | 353 return; |
| 325 } | 354 } |
| 326 | 355 |
| 327 scoped_ptr<OpenChannelParams> params(new OpenChannelParams( | 356 scoped_ptr<OpenChannelParams> params(new OpenChannelParams( |
| 328 source, | 357 source, |
| 329 scoped_ptr<DictionaryValue>(), // Source tab doesn't make sense for | 358 scoped_ptr<DictionaryValue>(), // Source tab doesn't make sense for |
| 330 // opening to tabs. | 359 // opening to tabs. |
| 331 receiver.release(), | 360 receiver.release(), |
| 332 receiver_port_id, | 361 receiver_port_id, |
| 333 extension_id, | 362 extension_id, |
| 334 extension_id, | 363 extension_id, |
| 335 GURL(), // Source URL doesn't make sense for opening to tabs. | 364 GURL(), // Source URL doesn't make sense for opening to tabs. |
| 336 channel_name)); | 365 channel_name)); |
| 337 OpenChannelImpl(params.Pass()); | 366 OpenChannelImpl(params.Pass()); |
| 338 } | 367 } |
| 339 | 368 |
| 340 bool MessageService::OpenChannelImpl(scoped_ptr<OpenChannelParams> params) { | 369 bool MessageService::OpenChannelImpl(scoped_ptr<OpenChannelParams> params) { |
| 341 if (!params->source) | 370 if (!params->source) |
| 342 return false; // Closed while in flight. | 371 return false; // Closed while in flight. |
| 343 | 372 |
| 344 if (!params->receiver || !params->receiver->GetRenderProcessHost()) { | 373 if (!params->receiver || !params->receiver->GetRenderProcessHost()) { |
| 345 // Treat it as a disconnect. | 374 DispatchOnDisconnect(params->source, |
| 346 ExtensionMessagePort port( | 375 params->receiver_port_id, |
| 347 params->source, MSG_ROUTING_CONTROL, std::string()); | 376 kReceivingEndDoesntExistError); |
| 348 port.DispatchOnDisconnect(GET_OPPOSITE_PORT_ID(params->receiver_port_id), | |
| 349 kReceivingEndDoesntExistError); | |
| 350 return false; | 377 return false; |
| 351 } | 378 } |
| 352 | 379 |
| 353 // Add extra paranoid CHECKs, since we have crash reports of this being NULL. | 380 // Add extra paranoid CHECKs, since we have crash reports of this being NULL. |
| 354 // http://code.google.com/p/chromium/issues/detail?id=19067 | 381 // http://code.google.com/p/chromium/issues/detail?id=19067 |
| 355 CHECK(params->receiver->GetRenderProcessHost()); | 382 CHECK(params->receiver->GetRenderProcessHost()); |
| 356 | 383 |
| 357 MessageChannel* channel(new MessageChannel); | 384 MessageChannel* channel(new MessageChannel); |
| 358 channel->opener.reset(new ExtensionMessagePort(params->source, | 385 channel->opener.reset(new ExtensionMessagePort(params->source, |
| 359 MSG_ROUTING_CONTROL, | 386 MSG_ROUTING_CONTROL, |
| (...skipping 183 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 543 if (!source) | 570 if (!source) |
| 544 return; | 571 return; |
| 545 | 572 |
| 546 params->source = source; | 573 params->source = source; |
| 547 params->receiver.reset(new ExtensionMessagePort(host->render_process_host(), | 574 params->receiver.reset(new ExtensionMessagePort(host->render_process_host(), |
| 548 MSG_ROUTING_CONTROL, | 575 MSG_ROUTING_CONTROL, |
| 549 params->target_extension_id)); | 576 params->target_extension_id)); |
| 550 OpenChannelImpl(params.Pass()); | 577 OpenChannelImpl(params.Pass()); |
| 551 } | 578 } |
| 552 | 579 |
| 580 void MessageService::DispatchOnDisconnect(content::RenderProcessHost* source, | |
| 581 int port_id, | |
| 582 const std::string& extension_id, | |
| 583 const std::string& reason) { | |
| 584 ExtensionMessagePort port(source, MSG_ROUTING_CONTROL, extension_id); | |
| 585 port.DispatchOnDisconnect(GET_OPPOSITE_PORT_ID(port_id), reason); | |
| 586 } | |
| 587 | |
| 553 } // namespace extensions | 588 } // namespace extensions |
| OLD | NEW |