[email protected] | f55c90ee6 | 2014-04-12 00:50:03 | [diff] [blame] | 1 | // Copyright 2014 The Chromium Authors. All rights reserved. |
[email protected] | 4f1633f | 2013-03-09 14:26:24 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
[email protected] | f55c90ee6 | 2014-04-12 00:50:03 | [diff] [blame] | 5 | #ifndef EXTENSIONS_RENDERER_OBJECT_BACKED_NATIVE_HANDLER_H_ |
| 6 | #define EXTENSIONS_RENDERER_OBJECT_BACKED_NATIVE_HANDLER_H_ |
[email protected] | 4f1633f | 2013-03-09 14:26:24 | [diff] [blame] | 7 | |
| 8 | #include <string> |
| 9 | #include <vector> |
| 10 | |
| 11 | #include "base/bind.h" |
avi | 2d124c0 | 2015-12-23 06:36:42 | [diff] [blame] | 12 | #include "base/macros.h" |
[email protected] | b8ce52f | 2014-04-04 22:45:15 | [diff] [blame] | 13 | #include "extensions/renderer/native_handler.h" |
[email protected] | b61750a | 2014-04-04 18:27:53 | [diff] [blame] | 14 | #include "v8/include/v8-util.h" |
[email protected] | 4f1633f | 2013-03-09 14:26:24 | [diff] [blame] | 15 | #include "v8/include/v8.h" |
| 16 | |
| 17 | namespace extensions { |
[email protected] | f55c90ee6 | 2014-04-12 00:50:03 | [diff] [blame] | 18 | class ScriptContext; |
[email protected] | 4f1633f | 2013-03-09 14:26:24 | [diff] [blame] | 19 | |
| 20 | // An ObjectBackedNativeHandler is a factory for JS objects with functions on |
Devlin Cronin | d9ea834 | 2018-01-27 06:00:04 | [diff] [blame] | 21 | // them that map to native C++ functions. Subclasses should call |
| 22 | // RouteHandlerFunction() in their constructor to define functions on the |
| 23 | // created JS objects. |
[email protected] | 4f1633f | 2013-03-09 14:26:24 | [diff] [blame] | 24 | class ObjectBackedNativeHandler : public NativeHandler { |
| 25 | public: |
[email protected] | f55c90ee6 | 2014-04-12 00:50:03 | [diff] [blame] | 26 | explicit ObjectBackedNativeHandler(ScriptContext* context); |
dcheng | 9168b2f | 2014-10-21 12:38:24 | [diff] [blame] | 27 | ~ObjectBackedNativeHandler() override; |
[email protected] | 4f1633f | 2013-03-09 14:26:24 | [diff] [blame] | 28 | |
Devlin Cronin | d9ea834 | 2018-01-27 06:00:04 | [diff] [blame] | 29 | // NativeHandler: |
| 30 | void Initialize() final; |
Devlin Cronin | 6fed7f0 | 2018-01-31 22:38:20 | [diff] [blame] | 31 | bool IsInitialized() final; |
[email protected] | 4f1633f | 2013-03-09 14:26:24 | [diff] [blame] | 32 | // Create an object with bindings to the native functions defined through |
Devlin Cronin | d9ea834 | 2018-01-27 06:00:04 | [diff] [blame] | 33 | // RouteHandlerFunction(). |
tfarina | f85316f | 2015-04-29 17:03:40 | [diff] [blame] | 34 | v8::Local<v8::Object> NewInstance() override; |
[email protected] | 4f1633f | 2013-03-09 14:26:24 | [diff] [blame] | 35 | |
[email protected] | 2a35687 | 2014-02-21 23:18:52 | [diff] [blame] | 36 | v8::Isolate* GetIsolate() const; |
| 37 | |
rdevlin.cronin | c827ac2 | 2016-05-09 14:17:49 | [diff] [blame] | 38 | protected: |
Devlin Cronin | cc02a0c | 2019-01-03 22:15:07 | [diff] [blame] | 39 | using HandlerFunction = |
| 40 | base::RepeatingCallback<void(const v8::FunctionCallbackInfo<v8::Value>&)>; |
[email protected] | 4f1633f | 2013-03-09 14:26:24 | [diff] [blame] | 41 | |
Devlin Cronin | d9ea834 | 2018-01-27 06:00:04 | [diff] [blame] | 42 | virtual void AddRoutes() = 0; |
| 43 | |
[email protected] | 4f1633f | 2013-03-09 14:26:24 | [diff] [blame] | 44 | // Installs a new 'route' from |name| to |handler_function|. This means that |
| 45 | // NewInstance()s of this ObjectBackedNativeHandler will have a property |
| 46 | // |name| which will be handled by |handler_function|. |
kalman | b0c1c50 | 2015-04-15 00:25:06 | [diff] [blame] | 47 | // |
| 48 | // Routed functions are destroyed along with the destruction of this class, |
| 49 | // and are never called back into, therefore it's safe for |handler_function| |
| 50 | // to bind to base::Unretained. |
rdevlin.cronin | 14ff9d0 | 2016-04-05 20:56:55 | [diff] [blame] | 51 | // |
rdevlin.cronin | c827ac2 | 2016-05-09 14:17:49 | [diff] [blame] | 52 | // |feature_name| corresponds to the api feature the native handler is used |
rdevlin.cronin | 14ff9d0 | 2016-04-05 20:56:55 | [diff] [blame] | 53 | // for. If the associated ScriptContext does not have access to that feature, |
| 54 | // the |handler_function| is not invoked. |
| 55 | // TODO(devlin): Deprecate the version that doesn't take a |feature_name|. |
Devlin Cronin | d9ea834 | 2018-01-27 06:00:04 | [diff] [blame] | 56 | void RouteHandlerFunction(const std::string& name, |
Devlin Cronin | cc02a0c | 2019-01-03 22:15:07 | [diff] [blame] | 57 | HandlerFunction handler_function); |
Devlin Cronin | d9ea834 | 2018-01-27 06:00:04 | [diff] [blame] | 58 | void RouteHandlerFunction(const std::string& name, |
| 59 | const std::string& feature_name, |
Devlin Cronin | cc02a0c | 2019-01-03 22:15:07 | [diff] [blame] | 60 | HandlerFunction handler_function); |
[email protected] | 4f1633f | 2013-03-09 14:26:24 | [diff] [blame] | 61 | |
[email protected] | f55c90ee6 | 2014-04-12 00:50:03 | [diff] [blame] | 62 | ScriptContext* context() const { return context_; } |
[email protected] | 4f1633f | 2013-03-09 14:26:24 | [diff] [blame] | 63 | |
dcheng | 9168b2f | 2014-10-21 12:38:24 | [diff] [blame] | 64 | void Invalidate() override; |
[email protected] | 4f1633f | 2013-03-09 14:26:24 | [diff] [blame] | 65 | |
rdevlin.cronin | a794ae4 | 2016-04-15 18:05:11 | [diff] [blame] | 66 | // Returns true if the given |context| is allowed to access the given |
| 67 | // |object|. This should be checked before returning any objects from another |
| 68 | // context. |
| 69 | // |allow_null_context| indicates that if there is no ScriptContext associated |
| 70 | // with the |object|, it should be allowed. |
| 71 | // TODO(devlin): It'd be nice to track down when when there's no ScriptContext |
| 72 | // and remove |allow_null_context|. |
| 73 | static bool ContextCanAccessObject(const v8::Local<v8::Context>& context, |
| 74 | const v8::Local<v8::Object>& object, |
| 75 | bool allow_null_context); |
| 76 | |
jochen | 300abe23 | 2015-11-06 21:17:53 | [diff] [blame] | 77 | // The following methods are convenience wrappers for methods on v8::Object |
| 78 | // with the corresponding names. |
| 79 | void SetPrivate(v8::Local<v8::Object> obj, |
| 80 | const char* key, |
| 81 | v8::Local<v8::Value> value); |
| 82 | static void SetPrivate(v8::Local<v8::Context> context, |
| 83 | v8::Local<v8::Object> obj, |
| 84 | const char* key, |
| 85 | v8::Local<v8::Value> value); |
| 86 | bool GetPrivate(v8::Local<v8::Object> obj, |
| 87 | const char* key, |
| 88 | v8::Local<v8::Value>* result); |
| 89 | static bool GetPrivate(v8::Local<v8::Context> context, |
| 90 | v8::Local<v8::Object> obj, |
| 91 | const char* key, |
| 92 | v8::Local<v8::Value>* result); |
| 93 | void DeletePrivate(v8::Local<v8::Object> obj, const char* key); |
| 94 | static void DeletePrivate(v8::Local<v8::Context> context, |
| 95 | v8::Local<v8::Object> obj, |
| 96 | const char* key); |
| 97 | |
[email protected] | 4f1633f | 2013-03-09 14:26:24 | [diff] [blame] | 98 | private: |
Devlin Cronin | d9ea834 | 2018-01-27 06:00:04 | [diff] [blame] | 99 | // Callback for RouteHandlerFunction which routes the V8 call to the correct |
[email protected] | d876ffdf | 2013-03-14 03:40:26 | [diff] [blame] | 100 | // base::Bound callback. |
[email protected] | d8c5fbb | 2013-06-14 11:35:25 | [diff] [blame] | 101 | static void Router(const v8::FunctionCallbackInfo<v8::Value>& args); |
[email protected] | 4f1633f | 2013-03-09 14:26:24 | [diff] [blame] | 102 | |
Devlin Cronin | d9ea834 | 2018-01-27 06:00:04 | [diff] [blame] | 103 | enum InitState { |
| 104 | kUninitialized, |
| 105 | kInitializingRoutes, |
| 106 | kInitialized, |
| 107 | }; |
| 108 | InitState init_state_ = kUninitialized; |
| 109 | |
| 110 | // When RouteHandlerFunction is called we create a v8::Object to hold the data |
| 111 | // we need when handling it in Router() - this is the base::Bound function to |
[email protected] | d876ffdf | 2013-03-14 03:40:26 | [diff] [blame] | 112 | // route to. |
| 113 | // |
| 114 | // We need a v8::Object because it's possible for v8 to outlive the |
| 115 | // base::Bound function; the lifetime of an ObjectBackedNativeHandler is the |
| 116 | // lifetime of webkit's involvement with it, not the life of the v8 context. |
| 117 | // A scenario when v8 will outlive us is if a frame holds onto the |
| 118 | // contentWindow of an iframe after it's removed. |
| 119 | // |
| 120 | // So, we use v8::Objects here to hold that data, effectively refcounting |
| 121 | // the data. When |this| is destroyed we remove the base::Bound function from |
| 122 | // the object to indicate that it shoudn't be called. |
[email protected] | b61750a | 2014-04-04 18:27:53 | [diff] [blame] | 123 | typedef v8::PersistentValueVector<v8::Object> RouterData; |
[email protected] | d876ffdf | 2013-03-14 03:40:26 | [diff] [blame] | 124 | RouterData router_data_; |
[email protected] | 4f1633f | 2013-03-09 14:26:24 | [diff] [blame] | 125 | |
[email protected] | f55c90ee6 | 2014-04-12 00:50:03 | [diff] [blame] | 126 | ScriptContext* context_; |
[email protected] | 4f1633f | 2013-03-09 14:26:24 | [diff] [blame] | 127 | |
kalman | 83292b8 | 2015-03-12 16:40:25 | [diff] [blame] | 128 | v8::Global<v8::ObjectTemplate> object_template_; |
[email protected] | 4f1633f | 2013-03-09 14:26:24 | [diff] [blame] | 129 | |
| 130 | DISALLOW_COPY_AND_ASSIGN(ObjectBackedNativeHandler); |
| 131 | }; |
| 132 | |
[email protected] | 1002d343 | 2013-06-13 09:04:54 | [diff] [blame] | 133 | } // namespace extensions |
[email protected] | 4f1633f | 2013-03-09 14:26:24 | [diff] [blame] | 134 | |
[email protected] | f55c90ee6 | 2014-04-12 00:50:03 | [diff] [blame] | 135 | #endif // EXTENSIONS_RENDERER_OBJECT_BACKED_NATIVE_HANDLER_H_ |