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->MatchesIdOrAllIds(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& reason) { |
| 584 ExtensionMessagePort port(source, MSG_ROUTING_CONTROL, ""); |
| 585 port.DispatchOnDisconnect(GET_OPPOSITE_PORT_ID(port_id), reason); |
| 586 } |
| 587 |
553 } // namespace extensions | 588 } // namespace extensions |
OLD | NEW |