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