Home | History | Annotate | Download | only in renderer
      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 
      5 #ifndef EXTENSIONS_RENDERER_MODULE_SYSTEM_H_
      6 #define EXTENSIONS_RENDERER_MODULE_SYSTEM_H_
      7 
      8 #include <map>
      9 #include <set>
     10 #include <string>
     11 #include <vector>
     12 
     13 #include "base/compiler_specific.h"
     14 #include "base/memory/linked_ptr.h"
     15 #include "base/memory/scoped_ptr.h"
     16 #include "extensions/renderer/native_handler.h"
     17 #include "extensions/renderer/object_backed_native_handler.h"
     18 #include "gin/modules/module_registry_observer.h"
     19 #include "v8/include/v8.h"
     20 
     21 namespace extensions {
     22 
     23 class ScriptContext;
     24 
     25 // A module system for JS similar to node.js' require() function.
     26 // Each module has three variables in the global scope:
     27 //   - exports, an object returned to dependencies who require() this
     28 //     module.
     29 //   - require, a function that takes a module name as an argument and returns
     30 //     that module's exports object.
     31 //   - requireNative, a function that takes the name of a registered
     32 //     NativeHandler and returns an object that contains the functions the
     33 //     NativeHandler defines.
     34 //
     35 // Each module in a ModuleSystem is executed at most once and its exports
     36 // object cached.
     37 //
     38 // Note that a ModuleSystem must be used only in conjunction with a single
     39 // v8::Context.
     40 // TODO(koz): Rename this to JavaScriptModuleSystem.
     41 class ModuleSystem : public ObjectBackedNativeHandler,
     42                      public gin::ModuleRegistryObserver {
     43  public:
     44   class SourceMap {
     45    public:
     46     virtual ~SourceMap() {}
     47     virtual v8::Handle<v8::Value> GetSource(v8::Isolate* isolate,
     48                                             const std::string& name) = 0;
     49     virtual bool Contains(const std::string& name) = 0;
     50   };
     51 
     52   class ExceptionHandler {
     53    public:
     54     virtual ~ExceptionHandler() {}
     55     virtual void HandleUncaughtException(const v8::TryCatch& try_catch) = 0;
     56 
     57    protected:
     58     // Formats |try_catch| as a nice string.
     59     std::string CreateExceptionString(const v8::TryCatch& try_catch);
     60   };
     61 
     62   // Enables native bindings for the duration of its lifetime.
     63   class NativesEnabledScope {
     64    public:
     65     explicit NativesEnabledScope(ModuleSystem* module_system);
     66     ~NativesEnabledScope();
     67 
     68    private:
     69     ModuleSystem* module_system_;
     70     DISALLOW_COPY_AND_ASSIGN(NativesEnabledScope);
     71   };
     72 
     73   // |source_map| is a weak pointer.
     74   ModuleSystem(ScriptContext* context, SourceMap* source_map);
     75   virtual ~ModuleSystem();
     76 
     77   // Require the specified module. This is the equivalent of calling
     78   // require('module_name') from the loaded JS files.
     79   v8::Handle<v8::Value> Require(const std::string& module_name);
     80   void Require(const v8::FunctionCallbackInfo<v8::Value>& args);
     81 
     82   // Run |code| in the current context with the name |name| used for stack
     83   // traces.
     84   v8::Handle<v8::Value> RunString(v8::Handle<v8::String> code,
     85                                   v8::Handle<v8::String> name);
     86 
     87   // Calls the specified method exported by the specified module. This is
     88   // equivalent to calling require('module_name').method_name() from JS.
     89   v8::Local<v8::Value> CallModuleMethod(const std::string& module_name,
     90                                         const std::string& method_name);
     91   v8::Local<v8::Value> CallModuleMethod(
     92       const std::string& module_name,
     93       const std::string& method_name,
     94       std::vector<v8::Handle<v8::Value> >* args);
     95   v8::Local<v8::Value> CallModuleMethod(const std::string& module_name,
     96                                         const std::string& method_name,
     97                                         int argc,
     98                                         v8::Handle<v8::Value> argv[]);
     99 
    100   // Register |native_handler| as a potential target for requireNative(), so
    101   // calls to requireNative(|name|) from JS will return a new object created by
    102   // |native_handler|.
    103   void RegisterNativeHandler(const std::string& name,
    104                              scoped_ptr<NativeHandler> native_handler);
    105 
    106   // Causes requireNative(|name|) to look for its module in |source_map_|
    107   // instead of using a registered native handler. This can be used in unit
    108   // tests to mock out native modules.
    109   void OverrideNativeHandlerForTest(const std::string& name);
    110 
    111   // Executes |code| in the current context with |name| as the filename.
    112   void RunString(const std::string& code, const std::string& name);
    113 
    114   // Make |object|.|field| lazily evaluate to the result of
    115   // require(|module_name|)[|module_field|].
    116   //
    117   // TODO(kalman): All targets for this method are ObjectBackedNativeHandlers,
    118   //               move this logic into those classes (in fact, the chrome
    119   //               object is the only client, only that needs to implement it).
    120   void SetLazyField(v8::Handle<v8::Object> object,
    121                     const std::string& field,
    122                     const std::string& module_name,
    123                     const std::string& module_field);
    124 
    125   void SetLazyField(v8::Handle<v8::Object> object,
    126                     const std::string& field,
    127                     const std::string& module_name,
    128                     const std::string& module_field,
    129                     v8::AccessorGetterCallback getter);
    130 
    131   // Make |object|.|field| lazily evaluate to the result of
    132   // requireNative(|module_name|)[|module_field|].
    133   // TODO(kalman): Same as above.
    134   void SetNativeLazyField(v8::Handle<v8::Object> object,
    135                           const std::string& field,
    136                           const std::string& module_name,
    137                           const std::string& module_field);
    138 
    139   // Passes exceptions to |handler| rather than console::Fatal.
    140   void SetExceptionHandlerForTest(scoped_ptr<ExceptionHandler> handler) {
    141     exception_handler_ = handler.Pass();
    142   }
    143 
    144  protected:
    145   friend class ScriptContext;
    146   virtual void Invalidate() OVERRIDE;
    147 
    148  private:
    149   typedef std::map<std::string, linked_ptr<NativeHandler> > NativeHandlerMap;
    150 
    151   // Retrieves the lazily defined field specified by |property|.
    152   static void LazyFieldGetter(v8::Local<v8::String> property,
    153                               const v8::PropertyCallbackInfo<v8::Value>& info);
    154   // Retrieves the lazily defined field specified by |property| on a native
    155   // object.
    156   static void NativeLazyFieldGetter(
    157       v8::Local<v8::String> property,
    158       const v8::PropertyCallbackInfo<v8::Value>& info);
    159 
    160   // Called when an exception is thrown but not caught.
    161   void HandleException(const v8::TryCatch& try_catch);
    162 
    163   void RequireForJs(const v8::FunctionCallbackInfo<v8::Value>& args);
    164   v8::Local<v8::Value> RequireForJsInner(v8::Handle<v8::String> module_name);
    165 
    166   typedef v8::Handle<v8::Value>(ModuleSystem::*RequireFunction)(
    167       const std::string&);
    168   // Base implementation of a LazyFieldGetter which uses |require_fn| to require
    169   // modules.
    170   static void LazyFieldGetterInner(
    171       v8::Local<v8::String> property,
    172       const v8::PropertyCallbackInfo<v8::Value>& info,
    173       RequireFunction require_function);
    174 
    175   // Return the named source file stored in the source map.
    176   // |args[0]| - the name of a source file in source_map_.
    177   v8::Handle<v8::Value> GetSource(const std::string& module_name);
    178 
    179   // Return an object that contains the native methods defined by the named
    180   // NativeHandler.
    181   // |args[0]| - the name of a native handler object.
    182   v8::Handle<v8::Value> RequireNativeFromString(const std::string& native_name);
    183   void RequireNative(const v8::FunctionCallbackInfo<v8::Value>& args);
    184 
    185   // Return a promise for a requested module.
    186   // |args[0]| - the name of a module.
    187   void RequireAsync(const v8::FunctionCallbackInfo<v8::Value>& args);
    188 
    189   // Wraps |source| in a (function(define, require, requireNative, ...) {...}).
    190   v8::Handle<v8::String> WrapSource(v8::Handle<v8::String> source);
    191 
    192   // NativeHandler implementation which returns the private area of an Object.
    193   void Private(const v8::FunctionCallbackInfo<v8::Value>& args);
    194 
    195   // Loads and runs a Javascript module.
    196   v8::Handle<v8::Value> LoadModule(const std::string& module_name);
    197 
    198   // Invoked when a module is loaded in response to a requireAsync call.
    199   // Resolves |resolver| with |value|.
    200   void OnModuleLoaded(
    201       scoped_ptr<v8::UniquePersistent<v8::Promise::Resolver> > resolver,
    202       v8::Handle<v8::Value> value);
    203 
    204   // gin::ModuleRegistryObserver overrides.
    205   virtual void OnDidAddPendingModule(
    206       const std::string& id,
    207       const std::vector<std::string>& dependencies) OVERRIDE;
    208 
    209   ScriptContext* context_;
    210 
    211   // A map from module names to the JS source for that module. GetSource()
    212   // performs a lookup on this map.
    213   SourceMap* source_map_;
    214 
    215   // A map from native handler names to native handlers.
    216   NativeHandlerMap native_handler_map_;
    217 
    218   // When 0, natives are disabled, otherwise indicates how many callers have
    219   // pinned natives as enabled.
    220   int natives_enabled_;
    221 
    222   // Called when an exception is thrown but not caught in JS. Overridable by
    223   // tests.
    224   scoped_ptr<ExceptionHandler> exception_handler_;
    225 
    226   std::set<std::string> overridden_native_handlers_;
    227 
    228   base::WeakPtrFactory<ModuleSystem> weak_factory_;
    229 
    230   DISALLOW_COPY_AND_ASSIGN(ModuleSystem);
    231 };
    232 
    233 }  // namespace extensions
    234 
    235 #endif  // EXTENSIONS_RENDERER_MODULE_SYSTEM_H_
    236