native_renderer_messaging_service.h 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. // Copyright 2014 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #ifndef EXTENSIONS_RENDERER_NATIVE_RENDERER_MESSAGING_SERVICE_H_
  5. #define EXTENSIONS_RENDERER_NATIVE_RENDERER_MESSAGING_SERVICE_H_
  6. #include <string>
  7. #include "extensions/common/extension_id.h"
  8. #include "extensions/renderer/bindings/api_binding_types.h"
  9. #include "extensions/renderer/gin_port.h"
  10. #include "extensions/renderer/one_time_message_handler.h"
  11. #include "gin/handle.h"
  12. #include "v8/include/v8-forward.h"
  13. struct ExtensionMsg_ExternalConnectionInfo;
  14. struct ExtensionMsg_TabConnectionInfo;
  15. namespace content {
  16. class RenderFrame;
  17. }
  18. namespace extensions {
  19. enum class SerializationFormat;
  20. class NativeExtensionBindingsSystem;
  21. class ScriptContextSetIterable;
  22. struct Message;
  23. struct MessageTarget;
  24. struct PortId;
  25. // The messaging service to handle dispatching extension messages and connection
  26. // events to different contexts.
  27. // This primarily handles long-lived port-based communications (like
  28. // runtime.connect). A basic flow will create an "opener" port and one ore more
  29. // "receiver" ports in different contexts (and possibly processes). This class
  30. // manages the communication with the browser to forward these messages along.
  31. // From JavaScript, a basic flow would be:
  32. // // page1.js
  33. // var port = chrome.runtime.connect();
  34. // port.onMessage.addListener(function() { <handle message> });
  35. // port.postMessage('hi!');
  36. // <eventually> port.disconnect();
  37. // // page2.js
  38. // chrome.runtime.onConnect.addListener(function(port) {
  39. // port.onMessage.addListener(function() { <handle message> });
  40. // port.postMessage('hey!');
  41. // });
  42. // This causes the following steps in the messaging service:
  43. // Connection:
  44. // * connect() triggers OpenChannelToExtension, which notifies the browser of
  45. // a new connection.
  46. // * The browser dispatches OnConnect messages to different renderers. If a
  47. // renderer has a listener, it will respond with an OpenMessagePort message.
  48. // If no renderer has a listener, the browser will close the port.
  49. // Message Posting
  50. // * Calls to postMessage() trigger a PostMessageToPort messge to the browser.
  51. // * The browser sends a DeliverMessage message to listening renderers. These
  52. // then dispatch the onMessage event to listeners.
  53. // Disconnecting
  54. // * disconnect() calls result in sending a CloseMessagePort message to the
  55. // browser.
  56. // * The browser then sends a DispatchOnDisconnect message to other renderers,
  57. // which triggers the onDisconnect() event.
  58. // TODO(devlin): This is a pretty large comment for a class, and it documents
  59. // browser/renderer interaction. I wonder if this would be better in a
  60. // messaging.md document?
  61. class NativeRendererMessagingService : public GinPort::Delegate {
  62. public:
  63. explicit NativeRendererMessagingService(
  64. NativeExtensionBindingsSystem* bindings_system);
  65. NativeRendererMessagingService(const NativeRendererMessagingService&) =
  66. delete;
  67. NativeRendererMessagingService& operator=(
  68. const NativeRendererMessagingService&) = delete;
  69. ~NativeRendererMessagingService() override;
  70. // Checks whether the port exists in the given frame. If it does not, a reply
  71. // is sent back to the browser.
  72. void ValidateMessagePort(ScriptContextSetIterable* context_set,
  73. const PortId& port_id,
  74. content::RenderFrame* render_frame);
  75. // Dispatches the onConnect content script messaging event to some contexts
  76. // in |context_set|. If |restrict_to_render_frame| is specified, only contexts
  77. // in that render frame will receive the message.
  78. void DispatchOnConnect(ScriptContextSetIterable* context_set,
  79. const PortId& target_port_id,
  80. const std::string& channel_name,
  81. const ExtensionMsg_TabConnectionInfo& source,
  82. const ExtensionMsg_ExternalConnectionInfo& info,
  83. content::RenderFrame* restrict_to_render_frame);
  84. // Delivers a message sent using content script messaging to some of the
  85. // contexts in |bindings_context_set|. If |restrict_to_render_frame| is
  86. // specified, only contexts in that render view will receive the message.
  87. void DeliverMessage(ScriptContextSetIterable* context_set,
  88. const PortId& target_port_id,
  89. const Message& message,
  90. content::RenderFrame* restrict_to_render_frame);
  91. // Dispatches the onDisconnect event in response to the channel being closed.
  92. void DispatchOnDisconnect(ScriptContextSetIterable* context_set,
  93. const PortId& port_id,
  94. const std::string& error_message,
  95. content::RenderFrame* restrict_to_render_frame);
  96. // Creates and opens a new message port in the specified context.
  97. gin::Handle<GinPort> Connect(ScriptContext* script_context,
  98. const MessageTarget& target,
  99. const std::string& name,
  100. SerializationFormat format);
  101. // Sends a one-time message, as is used by runtime.sendMessage. Returns a
  102. // Promise if used in a promise based API call, otherwise returns an empty
  103. // v8::Local<>.
  104. v8::Local<v8::Promise> SendOneTimeMessage(
  105. ScriptContext* script_context,
  106. const MessageTarget& target,
  107. const std::string& channel_name,
  108. const Message& message,
  109. binding::AsyncResponseType async_type,
  110. v8::Local<v8::Function> response_callback);
  111. // GinPort::Delegate:
  112. void PostMessageToPort(v8::Local<v8::Context> context,
  113. const PortId& port_id,
  114. int routing_id,
  115. std::unique_ptr<Message> message) override;
  116. void ClosePort(v8::Local<v8::Context> context,
  117. const PortId& port_id,
  118. int routing_id) override;
  119. gin::Handle<GinPort> CreatePortForTesting(ScriptContext* script_context,
  120. const std::string& channel_name,
  121. const PortId& port_id);
  122. gin::Handle<GinPort> GetPortForTesting(ScriptContext* script_context,
  123. const PortId& port_id);
  124. bool HasPortForTesting(ScriptContext* script_context, const PortId& port_id);
  125. private:
  126. // Helpers for the public methods to perform the action in a single
  127. // ScriptContext.
  128. void ValidateMessagePortInContext(const PortId& port_id,
  129. bool* has_port,
  130. ScriptContext* script_context);
  131. void DispatchOnConnectToScriptContext(
  132. const PortId& target_port_id,
  133. const std::string& channel_name,
  134. const ExtensionMsg_TabConnectionInfo* source,
  135. const ExtensionMsg_ExternalConnectionInfo& info,
  136. bool* port_created,
  137. ScriptContext* script_context);
  138. void DeliverMessageToScriptContext(const Message& message,
  139. const PortId& target_port_id,
  140. ScriptContext* script_context);
  141. void DeliverMessageToWorker(const Message& message,
  142. const PortId& target_port_id,
  143. ScriptContext* script_context);
  144. void DeliverMessageToBackgroundPage(const Message& message,
  145. const PortId& target_port_id,
  146. ScriptContext* script_context);
  147. void DispatchOnDisconnectToScriptContext(const PortId& port_id,
  148. const std::string& error_message,
  149. ScriptContext* script_context);
  150. // Returns true if the given |script_context| has a port with the given
  151. // |port_id|.
  152. bool ContextHasMessagePort(ScriptContext* script_context,
  153. const PortId& port_id);
  154. // Dispatches the onConnect event to listeners in the given |script_context|.
  155. void DispatchOnConnectToListeners(
  156. ScriptContext* script_context,
  157. const PortId& target_port_id,
  158. const ExtensionId& target_extension_id,
  159. const std::string& channel_name,
  160. const ExtensionMsg_TabConnectionInfo* source,
  161. const ExtensionMsg_ExternalConnectionInfo& info,
  162. const std::string& event_name);
  163. // Dispatches the onMessage event to listeners in the given |script_context|.
  164. // This will only be called if the context has a port with the given id.
  165. void DispatchOnMessageToListeners(ScriptContext* script_context,
  166. const Message& message,
  167. const PortId& target_port_id);
  168. // Dispatches the onDisconnect event to listeners in the given
  169. // |script_context|. This will only be called if the context has a port
  170. // with the given id.
  171. void DispatchOnDisconnectToListeners(ScriptContext* script_context,
  172. const PortId& port_id,
  173. const std::string& error);
  174. // Creates a new port in the given context, with the specified |channel_name|
  175. // and |port_id|. Assumes no such port exists.
  176. gin::Handle<GinPort> CreatePort(ScriptContext* script_context,
  177. const std::string& channel_name,
  178. const PortId& port_id);
  179. // Returns the port with the given |port_id| in the given |script_context|;
  180. // requires that such a port exists.
  181. gin::Handle<GinPort> GetPort(ScriptContext* script_context,
  182. const PortId& port_id);
  183. // The associated bindings system; guaranteed to outlive this object.
  184. NativeExtensionBindingsSystem* const bindings_system_;
  185. OneTimeMessageHandler one_time_message_handler_;
  186. };
  187. } // namespace extensions
  188. #endif // EXTENSIONS_RENDERER_NATIVE_RENDERER_MESSAGING_SERVICE_H_