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 |