1 // Copyright 2017 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 
5 #ifndef EXTENSIONS_RENDERER_GIN_PORT_H_
6 #define EXTENSIONS_RENDERER_GIN_PORT_H_
7 
8 #include <memory>
9 #include <string>
10 
11 #include "base/macros.h"
12 #include "base/memory/weak_ptr.h"
13 #include "base/optional.h"
14 #include "extensions/common/api/messaging/port_id.h"
15 #include "extensions/renderer/bindings/api_binding_util.h"
16 #include "gin/wrappable.h"
17 #include "v8/include/v8.h"
18 
19 namespace gin {
20 class Arguments;
21 }
22 
23 namespace extensions {
24 class APIEventHandler;
25 struct Message;
26 
27 // A gin::Wrappable implementation of runtime.Port exposed to extensions. This
28 // provides a means for extensions to communicate with themselves and each
29 // other. This message-passing usually involves IPCs to the browser; we delegate
30 // out this responsibility. This class only handles the JS interface (both calls
31 // from JS and forward events to JS).
32 class GinPort final : public gin::Wrappable<GinPort> {
33  public:
34   class Delegate {
35    public:
~Delegate()36     virtual ~Delegate() {}
37 
38     // Posts a message to the port.
39     virtual void PostMessageToPort(v8::Local<v8::Context> context,
40                                    const PortId& port_id,
41                                    int routing_id,
42                                    std::unique_ptr<Message> message) = 0;
43 
44     // Closes the port.
45     virtual void ClosePort(v8::Local<v8::Context> context,
46                            const PortId& port_id,
47                            int routing_id) = 0;
48   };
49 
50   GinPort(v8::Local<v8::Context> context,
51           const PortId& port_id,
52           int routing_id,
53           const std::string& name,
54           APIEventHandler* event_handler,
55           Delegate* delegate);
56   ~GinPort() override;
57 
58   static gin::WrapperInfo kWrapperInfo;
59 
60   // gin::Wrappable:
61   gin::ObjectTemplateBuilder GetObjectTemplateBuilder(
62       v8::Isolate* isolate) override;
63   const char* GetTypeName() override;
64 
65   // Dispatches an event to any listeners of the onMessage event.
66   void DispatchOnMessage(v8::Local<v8::Context> context,
67                          const Message& message);
68 
69   // Dispatches an event to any listeners of the onDisconnect event and closes
70   // the port.
71   void DispatchOnDisconnect(v8::Local<v8::Context> context);
72 
73   // Sets the |sender| property on the port. Note: this can only be called
74   // before the `sender` property is accessed on the JS object, since it is
75   // lazily set as a data property in first access.
76   void SetSender(v8::Local<v8::Context> context, v8::Local<v8::Value> sender);
77 
port_id()78   const PortId& port_id() const { return port_id_; }
routing_id()79   int routing_id() const { return routing_id_; }
name()80   const std::string& name() const { return name_; }
81 
is_closed_for_testing()82   bool is_closed_for_testing() const { return state_ == kDisconnected; }
83 
84  private:
85   enum State {
86     kActive,        // The port is currently active.
87     kDisconnected,  // The port was disconnected by calling port.disconnect().
88     kInvalidated,   // The associated v8::Context has been invalidated.
89   };
90 
91   // Handlers for the gin::Wrappable.
92   // Port.disconnect()
93   void DisconnectHandler(gin::Arguments* arguments);
94   // Port.postMessage()
95   void PostMessageHandler(gin::Arguments* arguments,
96                           v8::Local<v8::Value> v8_message);
97 
98   // Port.name
99   std::string GetName();
100   // Port.onDisconnect
101   v8::Local<v8::Value> GetOnDisconnectEvent(gin::Arguments* arguments);
102   // Port.onMessage
103   v8::Local<v8::Value> GetOnMessageEvent(gin::Arguments* arguments);
104   // Port.sender
105   v8::Local<v8::Value> GetSender(gin::Arguments* arguments);
106 
107   // Helper method to return the event with the given |name| (either
108   // onDisconnect or onMessage).
109   v8::Local<v8::Object> GetEvent(v8::Local<v8::Context> context,
110                                  base::StringPiece event_name);
111 
112   // Helper method to dispatch an event.
113   void DispatchEvent(v8::Local<v8::Context> context,
114                      std::vector<v8::Local<v8::Value>>* args,
115                      base::StringPiece event_name);
116 
117   // Invalidates the port (due to the context being removed). Any further calls
118   // to postMessage() or instantiating new events will fail.
119   void OnContextInvalidated();
120 
121   // Invalidates the port's events after the port has been disconnected.
122   void InvalidateEvents(v8::Local<v8::Context> context);
123 
124   // Throws the given |error|.
125   void ThrowError(v8::Isolate* isolate, base::StringPiece error);
126 
127   // The current state of the port.
128   State state_ = kActive;
129 
130   // The associated port id.
131   PortId port_id_;
132 
133   // The routing id associated with the port's context's render frame.
134   // TODO(devlin/lazyboy): This won't work with service workers.
135   int routing_id_;
136 
137   // The port's name.
138   std::string name_;
139 
140   // The associated APIEventHandler. Guaranteed to outlive this object.
141   APIEventHandler* const event_handler_;
142 
143   // The delegate for handling the message passing between ports. Guaranteed to
144   // outlive this object.
145   Delegate* const delegate_;
146 
147   // Whether the `sender` property has been accessed, and thus set on the
148   // port JS object.
149   bool accessed_sender_;
150 
151   // A listener for context invalidation. Note: this isn't actually optional;
152   // it just needs to be created after |weak_factory_|, which needs to be the
153   // final member.
154   base::Optional<binding::ContextInvalidationListener>
155       context_invalidation_listener_;
156 
157   base::WeakPtrFactory<GinPort> weak_factory_{this};
158 
159   DISALLOW_COPY_AND_ASSIGN(GinPort);
160 };
161 
162 }  // namespace extensions
163 
164 #endif  // EXTENSIONS_RENDERER_GIN_PORT_H_
165