| 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 <stdint.h> | 7 #include <stdint.h> |
| 8 | |
| 9 #include <limits> | 8 #include <limits> |
| 9 #include <utility> |
| 10 | 10 |
| 11 #include "base/atomic_sequence_num.h" | 11 #include "base/atomic_sequence_num.h" |
| 12 #include "base/bind.h" | 12 #include "base/bind.h" |
| 13 #include "base/callback.h" | 13 #include "base/callback.h" |
| 14 #include "base/json/json_writer.h" | 14 #include "base/json/json_writer.h" |
| 15 #include "base/lazy_instance.h" | 15 #include "base/lazy_instance.h" |
| 16 #include "base/macros.h" | 16 #include "base/macros.h" |
| 17 #include "base/metrics/histogram.h" | 17 #include "base/metrics/histogram.h" |
| 18 #include "base/prefs/pref_service.h" | 18 #include "base/prefs/pref_service.h" |
| 19 #include "base/stl_util.h" | 19 #include "base/stl_util.h" |
| (...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 168 target_frame_id(target_frame_id), | 168 target_frame_id(target_frame_id), |
| 169 receiver(receiver), | 169 receiver(receiver), |
| 170 receiver_port_id(receiver_port_id), | 170 receiver_port_id(receiver_port_id), |
| 171 source_extension_id(source_extension_id), | 171 source_extension_id(source_extension_id), |
| 172 target_extension_id(target_extension_id), | 172 target_extension_id(target_extension_id), |
| 173 source_url(source_url), | 173 source_url(source_url), |
| 174 channel_name(channel_name), | 174 channel_name(channel_name), |
| 175 include_tls_channel_id(include_tls_channel_id), | 175 include_tls_channel_id(include_tls_channel_id), |
| 176 include_guest_process_info(include_guest_process_info) { | 176 include_guest_process_info(include_guest_process_info) { |
| 177 if (source_tab) | 177 if (source_tab) |
| 178 this->source_tab = source_tab.Pass(); | 178 this->source_tab = std::move(source_tab); |
| 179 } | 179 } |
| 180 | 180 |
| 181 private: | 181 private: |
| 182 DISALLOW_COPY_AND_ASSIGN(OpenChannelParams); | 182 DISALLOW_COPY_AND_ASSIGN(OpenChannelParams); |
| 183 }; | 183 }; |
| 184 | 184 |
| 185 namespace { | 185 namespace { |
| 186 | 186 |
| 187 static base::StaticAtomicSequenceNumber g_next_channel_id; | 187 static base::StaticAtomicSequenceNumber g_next_channel_id; |
| 188 | 188 |
| (...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 355 auto* rfh = content::RenderFrameHost::FromID(source_process_id, | 355 auto* rfh = content::RenderFrameHost::FromID(source_process_id, |
| 356 source_routing_id); | 356 source_routing_id); |
| 357 // Include |source_frame_id| so that we can retrieve the guest's frame | 357 // Include |source_frame_id| so that we can retrieve the guest's frame |
| 358 // routing id in OpenChannelImpl. | 358 // routing id in OpenChannelImpl. |
| 359 if (rfh) | 359 if (rfh) |
| 360 source_frame_id = source_routing_id; | 360 source_frame_id = source_routing_id; |
| 361 } | 361 } |
| 362 } | 362 } |
| 363 | 363 |
| 364 scoped_ptr<OpenChannelParams> params(new OpenChannelParams( | 364 scoped_ptr<OpenChannelParams> params(new OpenChannelParams( |
| 365 source_process_id, source_tab.Pass(), source_frame_id, -1, | 365 source_process_id, std::move(source_tab), source_frame_id, -1, |
| 366 -1, // no target_tab_id/target_frame_id for connections to extensions | 366 -1, // no target_tab_id/target_frame_id for connections to extensions |
| 367 nullptr, receiver_port_id, source_extension_id, target_extension_id, | 367 nullptr, receiver_port_id, source_extension_id, target_extension_id, |
| 368 source_url, channel_name, include_tls_channel_id, | 368 source_url, channel_name, include_tls_channel_id, |
| 369 include_guest_process_info)); | 369 include_guest_process_info)); |
| 370 | 370 |
| 371 pending_incognito_channels_[GET_CHANNEL_ID(params->receiver_port_id)] = | 371 pending_incognito_channels_[GET_CHANNEL_ID(params->receiver_port_id)] = |
| 372 PendingMessagesQueue(); | 372 PendingMessagesQueue(); |
| 373 if (context->IsOffTheRecord() && | 373 if (context->IsOffTheRecord() && |
| 374 !util::IsIncognitoEnabled(target_extension_id, context)) { | 374 !util::IsIncognitoEnabled(target_extension_id, context)) { |
| 375 // Give the user a chance to accept an incognito connection from the web if | 375 // Give the user a chance to accept an incognito connection from the web if |
| 376 // they haven't already, with the conditions: | 376 // they haven't already, with the conditions: |
| 377 // - Only for spanning-mode incognito. We don't want the complication of | 377 // - Only for spanning-mode incognito. We don't want the complication of |
| 378 // spinning up an additional process here which might need to do some | 378 // spinning up an additional process here which might need to do some |
| 379 // setup that we're not expecting. | 379 // setup that we're not expecting. |
| 380 // - Only for extensions that can't normally be enabled in incognito, since | 380 // - Only for extensions that can't normally be enabled in incognito, since |
| 381 // that surface (e.g. chrome://extensions) should be the only one for | 381 // that surface (e.g. chrome://extensions) should be the only one for |
| 382 // enabling in incognito. In practice this means platform apps only. | 382 // enabling in incognito. In practice this means platform apps only. |
| 383 if (!is_web_connection || IncognitoInfo::IsSplitMode(target_extension) || | 383 if (!is_web_connection || IncognitoInfo::IsSplitMode(target_extension) || |
| 384 util::CanBeIncognitoEnabled(target_extension)) { | 384 util::CanBeIncognitoEnabled(target_extension)) { |
| 385 OnOpenChannelAllowed(params.Pass(), false); | 385 OnOpenChannelAllowed(std::move(params), false); |
| 386 return; | 386 return; |
| 387 } | 387 } |
| 388 | 388 |
| 389 // If the target extension isn't even listening for connect/message events, | 389 // If the target extension isn't even listening for connect/message events, |
| 390 // there is no need to go any further and the connection should be | 390 // there is no need to go any further and the connection should be |
| 391 // rejected without showing a prompt. See http://crbug.com/442497 | 391 // rejected without showing a prompt. See http://crbug.com/442497 |
| 392 EventRouter* event_router = EventRouter::Get(context); | 392 EventRouter* event_router = EventRouter::Get(context); |
| 393 const char* const events[] = {"runtime.onConnectExternal", | 393 const char* const events[] = {"runtime.onConnectExternal", |
| 394 "runtime.onMessageExternal", | 394 "runtime.onMessageExternal", |
| 395 "extension.onRequestExternal", | 395 "extension.onRequestExternal", |
| 396 nullptr}; | 396 nullptr}; |
| 397 bool has_event_listener = false; | 397 bool has_event_listener = false; |
| 398 for (const char* const* event = events; *event; event++) { | 398 for (const char* const* event = events; *event; event++) { |
| 399 has_event_listener |= | 399 has_event_listener |= |
| 400 event_router->ExtensionHasEventListener(target_extension_id, *event); | 400 event_router->ExtensionHasEventListener(target_extension_id, *event); |
| 401 } | 401 } |
| 402 if (!has_event_listener) { | 402 if (!has_event_listener) { |
| 403 OnOpenChannelAllowed(params.Pass(), false); | 403 OnOpenChannelAllowed(std::move(params), false); |
| 404 return; | 404 return; |
| 405 } | 405 } |
| 406 | 406 |
| 407 // This check may show a dialog. | 407 // This check may show a dialog. |
| 408 IncognitoConnectability::Get(context) | 408 IncognitoConnectability::Get(context) |
| 409 ->Query(target_extension, source_contents, source_url, | 409 ->Query(target_extension, source_contents, source_url, |
| 410 base::Bind(&MessageService::OnOpenChannelAllowed, | 410 base::Bind(&MessageService::OnOpenChannelAllowed, |
| 411 weak_factory_.GetWeakPtr(), base::Passed(¶ms))); | 411 weak_factory_.GetWeakPtr(), base::Passed(¶ms))); |
| 412 return; | 412 return; |
| 413 } | 413 } |
| 414 | 414 |
| 415 OnOpenChannelAllowed(params.Pass(), true); | 415 OnOpenChannelAllowed(std::move(params), true); |
| 416 } | 416 } |
| 417 | 417 |
| 418 void MessageService::OpenChannelToNativeApp( | 418 void MessageService::OpenChannelToNativeApp( |
| 419 int source_process_id, | 419 int source_process_id, |
| 420 int source_routing_id, | 420 int source_routing_id, |
| 421 int receiver_port_id, | 421 int receiver_port_id, |
| 422 const std::string& source_extension_id, | 422 const std::string& source_extension_id, |
| 423 const std::string& native_app_name) { | 423 const std::string& native_app_name) { |
| 424 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 424 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 425 | 425 |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 474 policy_permission == ALLOW_ALL, | 474 policy_permission == ALLOW_ALL, |
| 475 &error); | 475 &error); |
| 476 | 476 |
| 477 // Abandon the channel. | 477 // Abandon the channel. |
| 478 if (!native_host.get()) { | 478 if (!native_host.get()) { |
| 479 LOG(ERROR) << "Failed to create native process."; | 479 LOG(ERROR) << "Failed to create native process."; |
| 480 DispatchOnDisconnect(source, receiver_port_id, error); | 480 DispatchOnDisconnect(source, receiver_port_id, error); |
| 481 return; | 481 return; |
| 482 } | 482 } |
| 483 channel->receiver.reset(new NativeMessagePort( | 483 channel->receiver.reset(new NativeMessagePort( |
| 484 weak_factory_.GetWeakPtr(), receiver_port_id, native_host.Pass())); | 484 weak_factory_.GetWeakPtr(), receiver_port_id, std::move(native_host))); |
| 485 | 485 |
| 486 // Keep the opener alive until the channel is closed. | 486 // Keep the opener alive until the channel is closed. |
| 487 channel->opener->IncrementLazyKeepaliveCount(); | 487 channel->opener->IncrementLazyKeepaliveCount(); |
| 488 | 488 |
| 489 AddChannel(channel.release(), receiver_port_id); | 489 AddChannel(channel.release(), receiver_port_id); |
| 490 #else // !(defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX)) | 490 #else // !(defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX)) |
| 491 const char kNativeMessagingNotSupportedError[] = | 491 const char kNativeMessagingNotSupportedError[] = |
| 492 "Native Messaging is not supported on this platform."; | 492 "Native Messaging is not supported on this platform."; |
| 493 DispatchOnDisconnect( | 493 DispatchOnDisconnect( |
| 494 source, receiver_port_id, kNativeMessagingNotSupportedError); | 494 source, receiver_port_id, kNativeMessagingNotSupportedError); |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 558 source_process_id, | 558 source_process_id, |
| 559 scoped_ptr<base::DictionaryValue>(), // Source tab doesn't make sense | 559 scoped_ptr<base::DictionaryValue>(), // Source tab doesn't make sense |
| 560 // for opening to tabs. | 560 // for opening to tabs. |
| 561 -1, // If there is no tab, then there is no frame either. | 561 -1, // If there is no tab, then there is no frame either. |
| 562 tab_id, frame_id, receiver.release(), receiver_port_id, extension_id, | 562 tab_id, frame_id, receiver.release(), receiver_port_id, extension_id, |
| 563 extension_id, | 563 extension_id, |
| 564 GURL(), // Source URL doesn't make sense for opening to tabs. | 564 GURL(), // Source URL doesn't make sense for opening to tabs. |
| 565 channel_name, | 565 channel_name, |
| 566 false, // Connections to tabs don't get TLS channel IDs. | 566 false, // Connections to tabs don't get TLS channel IDs. |
| 567 false)); // Connections to tabs aren't webview guests. | 567 false)); // Connections to tabs aren't webview guests. |
| 568 OpenChannelImpl(contents->GetBrowserContext(), params.Pass(), extension, | 568 OpenChannelImpl(contents->GetBrowserContext(), std::move(params), extension, |
| 569 false /* did_enqueue */); | 569 false /* did_enqueue */); |
| 570 } | 570 } |
| 571 | 571 |
| 572 void MessageService::OpenChannelImpl(BrowserContext* browser_context, | 572 void MessageService::OpenChannelImpl(BrowserContext* browser_context, |
| 573 scoped_ptr<OpenChannelParams> params, | 573 scoped_ptr<OpenChannelParams> params, |
| 574 const Extension* target_extension, | 574 const Extension* target_extension, |
| 575 bool did_enqueue) { | 575 bool did_enqueue) { |
| 576 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 576 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 577 DCHECK_EQ(target_extension != nullptr, !params->target_extension_id.empty()); | 577 DCHECK_EQ(target_extension != nullptr, !params->target_extension_id.empty()); |
| 578 | 578 |
| (...skipping 25 matching lines...) Expand all Loading... |
| 604 params->source_frame_id = -1; | 604 params->source_frame_id = -1; |
| 605 | 605 |
| 606 DCHECK(guest_rfh == nullptr || | 606 DCHECK(guest_rfh == nullptr || |
| 607 WebViewGuest::FromWebContents( | 607 WebViewGuest::FromWebContents( |
| 608 WebContents::FromRenderFrameHost(guest_rfh)) != nullptr); | 608 WebContents::FromRenderFrameHost(guest_rfh)) != nullptr); |
| 609 } | 609 } |
| 610 | 610 |
| 611 // Send the connect event to the receiver. Give it the opener's port ID (the | 611 // Send the connect event to the receiver. Give it the opener's port ID (the |
| 612 // opener has the opposite port ID). | 612 // opener has the opposite port ID). |
| 613 channel->receiver->DispatchOnConnect( | 613 channel->receiver->DispatchOnConnect( |
| 614 params->receiver_port_id, params->channel_name, params->source_tab.Pass(), | 614 params->receiver_port_id, params->channel_name, |
| 615 params->source_frame_id, params->target_tab_id, params->target_frame_id, | 615 std::move(params->source_tab), params->source_frame_id, |
| 616 guest_process_id, guest_render_frame_routing_id, | 616 params->target_tab_id, params->target_frame_id, guest_process_id, |
| 617 params->source_extension_id, params->target_extension_id, | 617 guest_render_frame_routing_id, params->source_extension_id, |
| 618 params->source_url, params->tls_channel_id); | 618 params->target_extension_id, params->source_url, params->tls_channel_id); |
| 619 | 619 |
| 620 // Report the event to the event router, if the target is an extension. | 620 // Report the event to the event router, if the target is an extension. |
| 621 // | 621 // |
| 622 // First, determine what event this will be (runtime.onConnect vs | 622 // First, determine what event this will be (runtime.onConnect vs |
| 623 // runtime.onMessage etc), and what the event target is (view vs background | 623 // runtime.onMessage etc), and what the event target is (view vs background |
| 624 // page etc). | 624 // page etc). |
| 625 // | 625 // |
| 626 // Yes - even though this is opening a channel, they may actually be | 626 // Yes - even though this is opening a channel, they may actually be |
| 627 // runtime.onRequest/onMessage events because those single-use events are | 627 // runtime.onRequest/onMessage events because those single-use events are |
| 628 // built using the connect framework (see messaging.js). | 628 // built using the connect framework (see messaging.js). |
| (...skipping 297 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 926 DispatchOnDisconnect(source, params->receiver_port_id, | 926 DispatchOnDisconnect(source, params->receiver_port_id, |
| 927 kReceivingEndDoesntExistError); | 927 kReceivingEndDoesntExistError); |
| 928 return; | 928 return; |
| 929 } | 929 } |
| 930 | 930 |
| 931 // The target might be a lazy background page. In that case, we have to check | 931 // The target might be a lazy background page. In that case, we have to check |
| 932 // if it is loaded and ready, and if not, queue up the task and load the | 932 // if it is loaded and ready, and if not, queue up the task and load the |
| 933 // page. | 933 // page. |
| 934 if (!MaybeAddPendingLazyBackgroundPageOpenChannelTask( | 934 if (!MaybeAddPendingLazyBackgroundPageOpenChannelTask( |
| 935 context, target_extension, ¶ms, pending_messages)) { | 935 context, target_extension, ¶ms, pending_messages)) { |
| 936 OpenChannelImpl(context, params.Pass(), target_extension, | 936 OpenChannelImpl(context, std::move(params), target_extension, |
| 937 false /* did_enqueue */); | 937 false /* did_enqueue */); |
| 938 DispatchPendingMessages(pending_messages, channel_id); | 938 DispatchPendingMessages(pending_messages, channel_id); |
| 939 } | 939 } |
| 940 } | 940 } |
| 941 | 941 |
| 942 void MessageService::GotChannelID(scoped_ptr<OpenChannelParams> params, | 942 void MessageService::GotChannelID(scoped_ptr<OpenChannelParams> params, |
| 943 const std::string& tls_channel_id) { | 943 const std::string& tls_channel_id) { |
| 944 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 944 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 945 | 945 |
| 946 params->tls_channel_id.assign(tls_channel_id); | 946 params->tls_channel_id.assign(tls_channel_id); |
| (...skipping 21 matching lines...) Expand all Loading... |
| 968 const Extension* target_extension = | 968 const Extension* target_extension = |
| 969 registry->enabled_extensions().GetByID(params->target_extension_id); | 969 registry->enabled_extensions().GetByID(params->target_extension_id); |
| 970 if (!target_extension) { | 970 if (!target_extension) { |
| 971 DispatchOnDisconnect(source, params->receiver_port_id, | 971 DispatchOnDisconnect(source, params->receiver_port_id, |
| 972 kReceivingEndDoesntExistError); | 972 kReceivingEndDoesntExistError); |
| 973 return; | 973 return; |
| 974 } | 974 } |
| 975 | 975 |
| 976 if (!MaybeAddPendingLazyBackgroundPageOpenChannelTask( | 976 if (!MaybeAddPendingLazyBackgroundPageOpenChannelTask( |
| 977 context, target_extension, ¶ms, pending_messages)) { | 977 context, target_extension, ¶ms, pending_messages)) { |
| 978 OpenChannelImpl(context, params.Pass(), target_extension, | 978 OpenChannelImpl(context, std::move(params), target_extension, |
| 979 false /* did_enqueue */); | 979 false /* did_enqueue */); |
| 980 DispatchPendingMessages(pending_messages, channel_id); | 980 DispatchPendingMessages(pending_messages, channel_id); |
| 981 } | 981 } |
| 982 } | 982 } |
| 983 | 983 |
| 984 void MessageService::PendingLazyBackgroundPageOpenChannel( | 984 void MessageService::PendingLazyBackgroundPageOpenChannel( |
| 985 scoped_ptr<OpenChannelParams> params, | 985 scoped_ptr<OpenChannelParams> params, |
| 986 int source_process_id, | 986 int source_process_id, |
| 987 ExtensionHost* host) { | 987 ExtensionHost* host) { |
| 988 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 988 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 989 | 989 |
| 990 if (!host) | 990 if (!host) |
| 991 return; // TODO(mpcomplete): notify source of disconnect? | 991 return; // TODO(mpcomplete): notify source of disconnect? |
| 992 | 992 |
| 993 params->receiver.reset(new ExtensionMessagePort(host->render_process_host(), | 993 params->receiver.reset(new ExtensionMessagePort(host->render_process_host(), |
| 994 MSG_ROUTING_CONTROL, | 994 MSG_ROUTING_CONTROL, |
| 995 params->target_extension_id)); | 995 params->target_extension_id)); |
| 996 OpenChannelImpl(host->browser_context(), params.Pass(), host->extension(), | 996 OpenChannelImpl(host->browser_context(), std::move(params), host->extension(), |
| 997 true /* did_enqueue */); | 997 true /* did_enqueue */); |
| 998 } | 998 } |
| 999 | 999 |
| 1000 void MessageService::DispatchOnDisconnect(content::RenderProcessHost* source, | 1000 void MessageService::DispatchOnDisconnect(content::RenderProcessHost* source, |
| 1001 int port_id, | 1001 int port_id, |
| 1002 const std::string& error_message) { | 1002 const std::string& error_message) { |
| 1003 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 1003 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 1004 | 1004 |
| 1005 ExtensionMessagePort port(source, MSG_ROUTING_CONTROL, ""); | 1005 ExtensionMessagePort port(source, MSG_ROUTING_CONTROL, ""); |
| 1006 port.DispatchOnDisconnect(GET_OPPOSITE_PORT_ID(port_id), error_message); | 1006 port.DispatchOnDisconnect(GET_OPPOSITE_PORT_ID(port_id), error_message); |
| 1007 } | 1007 } |
| 1008 | 1008 |
| 1009 void MessageService::DispatchPendingMessages(const PendingMessagesQueue& queue, | 1009 void MessageService::DispatchPendingMessages(const PendingMessagesQueue& queue, |
| 1010 int channel_id) { | 1010 int channel_id) { |
| 1011 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 1011 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 1012 | 1012 |
| 1013 MessageChannelMap::iterator channel_iter = channels_.find(channel_id); | 1013 MessageChannelMap::iterator channel_iter = channels_.find(channel_id); |
| 1014 if (channel_iter != channels_.end()) { | 1014 if (channel_iter != channels_.end()) { |
| 1015 for (const PendingMessage& message : queue) { | 1015 for (const PendingMessage& message : queue) { |
| 1016 DispatchMessage(message.first, channel_iter->second, message.second); | 1016 DispatchMessage(message.first, channel_iter->second, message.second); |
| 1017 } | 1017 } |
| 1018 } | 1018 } |
| 1019 } | 1019 } |
| 1020 | 1020 |
| 1021 } // namespace extensions | 1021 } // namespace extensions |
| OLD | NEW |