module_system.h 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  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_MODULE_SYSTEM_H_
  5. #define EXTENSIONS_RENDERER_MODULE_SYSTEM_H_
  6. #include <map>
  7. #include <memory>
  8. #include <set>
  9. #include <string>
  10. #include <utility>
  11. #include <vector>
  12. #include "base/compiler_specific.h"
  13. #include "extensions/renderer/native_handler.h"
  14. #include "extensions/renderer/object_backed_native_handler.h"
  15. #include "third_party/blink/public/web/web_script_execution_callback.h"
  16. #include "v8/include/v8-forward.h"
  17. #include "v8/include/v8-object.h"
  18. #include "v8/include/v8-persistent-handle.h"
  19. namespace extensions {
  20. class ScriptContext;
  21. class SourceMap;
  22. // A module system for JS similar to node.js' require() function.
  23. // Each module has three variables in the global scope:
  24. // - exports, an object returned to dependencies who require() this
  25. // module.
  26. // - require, a function that takes a module name as an argument and returns
  27. // that module's exports object.
  28. // - requireNative, a function that takes the name of a registered
  29. // NativeHandler and returns an object that contains the functions the
  30. // NativeHandler defines.
  31. //
  32. // Each module in a ModuleSystem is executed at most once and its exports
  33. // object cached.
  34. //
  35. // Note that a ModuleSystem must be used only in conjunction with a single
  36. // v8::Context.
  37. // TODO(koz): Rename this to JavaScriptModuleSystem.
  38. class ModuleSystem : public ObjectBackedNativeHandler {
  39. public:
  40. class ExceptionHandler {
  41. public:
  42. explicit ExceptionHandler(ScriptContext* context) : context_(context) {}
  43. virtual ~ExceptionHandler() {}
  44. virtual void HandleUncaughtException(const v8::TryCatch& try_catch) = 0;
  45. protected:
  46. // Formats |try_catch| as a nice string.
  47. std::string CreateExceptionString(const v8::TryCatch& try_catch);
  48. // A script context associated with this handler. Owned by the module
  49. // system.
  50. ScriptContext* context_;
  51. };
  52. // Enables native bindings for the duration of its lifetime.
  53. class NativesEnabledScope {
  54. public:
  55. explicit NativesEnabledScope(ModuleSystem* module_system);
  56. NativesEnabledScope(const NativesEnabledScope&) = delete;
  57. NativesEnabledScope& operator=(const NativesEnabledScope&) = delete;
  58. ~NativesEnabledScope();
  59. private:
  60. ModuleSystem* module_system_;
  61. };
  62. // |source_map| is a weak pointer.
  63. ModuleSystem(ScriptContext* context, const SourceMap* source_map);
  64. ModuleSystem(const ModuleSystem&) = delete;
  65. ModuleSystem& operator=(const ModuleSystem&) = delete;
  66. ~ModuleSystem() override;
  67. // ObjectBackedNativeHandler:
  68. void AddRoutes() override;
  69. // Require the specified module. This is the equivalent of calling
  70. // require('module_name') from the loaded JS files.
  71. v8::MaybeLocal<v8::Object> Require(const std::string& module_name);
  72. // Calls the specified method exported by the specified module. This is
  73. // equivalent to calling require('module_name').method_name() from JS. Note:
  74. // this may result in asynchronous execution if javascript is presently
  75. // disabled.
  76. // TODO(devlin): Rename this to just CallModuleMethod()?
  77. void CallModuleMethodSafe(const std::string& module_name,
  78. const std::string& method_name);
  79. void CallModuleMethodSafe(const std::string& module_name,
  80. const std::string& method_name,
  81. std::vector<v8::Local<v8::Value>>* args);
  82. void CallModuleMethodSafe(const std::string& module_name,
  83. const std::string& method_name,
  84. int argc,
  85. v8::Local<v8::Value> argv[]);
  86. void CallModuleMethodSafe(const std::string& module_name,
  87. const std::string& method_name,
  88. int argc,
  89. v8::Local<v8::Value> argv[],
  90. blink::WebScriptExecutionCallback callback);
  91. // Register |native_handler| as a potential target for requireNative(), so
  92. // calls to requireNative(|name|) from JS will return a new object created by
  93. // |native_handler|.
  94. void RegisterNativeHandler(const std::string& name,
  95. std::unique_ptr<NativeHandler> native_handler);
  96. // Causes requireNative(|name|) to look for its module in |source_map_|
  97. // instead of using a registered native handler. This can be used in unit
  98. // tests to mock out native modules.
  99. void OverrideNativeHandlerForTest(const std::string& name);
  100. // Passes exceptions to |handler| rather than console::Fatal.
  101. void SetExceptionHandlerForTest(std::unique_ptr<ExceptionHandler> handler) {
  102. exception_handler_ = std::move(handler);
  103. }
  104. // Called when a native binding is created in order to run any custom binding
  105. // code to set up various hooks.
  106. // TODO(devlin): We can get rid of this once we convert all our custom
  107. // bindings.
  108. void OnNativeBindingCreated(const std::string& api_name,
  109. v8::Local<v8::Value> api_bridge_value);
  110. void SetGetInternalAPIHook(v8::Local<v8::FunctionTemplate> get_internal_api);
  111. using JSBindingUtilGetter =
  112. base::RepeatingCallback<void(v8::Local<v8::Context>,
  113. v8::Local<v8::Value>*)>;
  114. void SetJSBindingUtilGetter(const JSBindingUtilGetter& getter);
  115. protected:
  116. friend class ModuleSystemTestEnvironment;
  117. friend class ScriptContext;
  118. void Invalidate() override;
  119. private:
  120. typedef std::map<std::string, std::unique_ptr<NativeHandler>>
  121. NativeHandlerMap;
  122. // Run |code| in the current context with the name |name| used for stack
  123. // traces.
  124. v8::Local<v8::Value> RunString(v8::Local<v8::String> code,
  125. v8::Local<v8::String> name);
  126. // Make |object|.|field| lazily evaluate to the result of
  127. // require(|module_name|)[|module_field|].
  128. //
  129. // TODO(kalman): All targets for this method are ObjectBackedNativeHandlers,
  130. // move this logic into those classes (in fact, the chrome
  131. // object is the only client, only that needs to implement it).
  132. void SetLazyField(v8::Local<v8::Object> object,
  133. const std::string& field,
  134. const std::string& module_name,
  135. const std::string& module_field);
  136. // Retrieves the lazily defined field specified by |property|.
  137. static void LazyFieldGetter(v8::Local<v8::Name> property,
  138. const v8::PropertyCallbackInfo<v8::Value>& info);
  139. // Called when an exception is thrown but not caught.
  140. void HandleException(const v8::TryCatch& try_catch);
  141. void RequireForJs(const v8::FunctionCallbackInfo<v8::Value>& args);
  142. // Returns the module with the given |module_name|. If |create| is true, the
  143. // module will be loaded if it hasn't been already. Otherwise, the module
  144. // will only be returned if it has already been loaded.
  145. v8::Local<v8::Value> RequireForJsInner(v8::Local<v8::String> module_name,
  146. bool create);
  147. // Return the named source file stored in the source map.
  148. // |args[0]| - the name of a source file in source_map_.
  149. v8::Local<v8::Value> GetSource(const std::string& module_name);
  150. // Return an object that contains the native methods defined by the named
  151. // NativeHandler.
  152. // |args[0]| - the name of a native handler object.
  153. v8::MaybeLocal<v8::Object> RequireNativeFromString(
  154. const std::string& native_name);
  155. void RequireNative(const v8::FunctionCallbackInfo<v8::Value>& args);
  156. // |args[0]| - the name of a module.
  157. // This method directly executes the script in the current scope.
  158. void LoadScript(const v8::FunctionCallbackInfo<v8::Value>& args);
  159. // Wraps |source| in a (function(define, require, requireNative, ...) {...}).
  160. v8::Local<v8::String> WrapSource(v8::Local<v8::String> source);
  161. // NativeHandler implementation which returns the private area of an Object.
  162. void Private(const v8::FunctionCallbackInfo<v8::Value>& args);
  163. // Loads and runs a Javascript module.
  164. v8::Local<v8::Value> LoadModule(const std::string& module_name);
  165. v8::Local<v8::Value> LoadModuleWithNativeAPIBridge(
  166. const std::string& module_name,
  167. v8::Local<v8::Value> api_object);
  168. // Marks any existing NativeHandler named |name| as clobbered.
  169. // See |clobbered_native_handlers_|.
  170. void ClobberExistingNativeHandler(const std::string& name);
  171. // Returns the v8::Function associated with the given module and method name.
  172. // This will *not* load a module if it hasn't been loaded already.
  173. v8::Local<v8::Function> GetModuleFunction(const std::string& module_name,
  174. const std::string& method_name);
  175. ScriptContext* context_;
  176. // TODO(1276144): remove once investigation finished.
  177. bool has_been_invalidated_ = false;
  178. // A map from module names to the JS source for that module. GetSource()
  179. // performs a lookup on this map.
  180. const SourceMap* const source_map_;
  181. // A map from native handler names to native handlers.
  182. NativeHandlerMap native_handler_map_;
  183. // When 0, natives are disabled, otherwise indicates how many callers have
  184. // pinned natives as enabled.
  185. int natives_enabled_;
  186. // Called when an exception is thrown but not caught in JS. Overridable by
  187. // tests.
  188. std::unique_ptr<ExceptionHandler> exception_handler_;
  189. // A set of native handlers that should actually be require()d as non-native
  190. // handlers. This is used for tests to mock out native handlers in JS.
  191. std::set<std::string> overridden_native_handlers_;
  192. // A list of NativeHandlers that have been clobbered, either due to
  193. // registering a NativeHandler when one was already registered with the same
  194. // name, or due to OverrideNativeHandlerForTest. This is needed so that they
  195. // can be later Invalidated. It should only happen in tests.
  196. std::vector<std::unique_ptr<NativeHandler>> clobbered_native_handlers_;
  197. // The template to be used for retrieving an internal API.
  198. v8::Eternal<v8::FunctionTemplate> get_internal_api_;
  199. JSBindingUtilGetter js_binding_util_getter_;
  200. // The set of modules that we've attempted to load.
  201. std::set<std::string> loaded_modules_;
  202. };
  203. } // namespace extensions
  204. #endif // EXTENSIONS_RENDERER_MODULE_SYSTEM_H_