| OLD | NEW | 
|    1 // Copyright 2016 The Chromium Authors. All rights reserved. |    1 // Copyright 2016 The Chromium Authors. All rights reserved. | 
|    2 // Use of this source code is governed by a BSD-style license that can be |    2 // Use of this source code is governed by a BSD-style license that can be | 
|    3 // found in the LICENSE file. |    3 // found in the LICENSE file. | 
|    4  |    4  | 
|    5 #include "extensions/renderer/api_binding_hooks.h" |    5 #include "extensions/renderer/api_binding_hooks.h" | 
|    6  |    6  | 
|    7 #include "base/memory/ptr_util.h" |    7 #include "base/memory/ptr_util.h" | 
|    8 #include "base/strings/stringprintf.h" |    8 #include "base/strings/stringprintf.h" | 
|    9 #include "base/supports_user_data.h" |    9 #include "base/supports_user_data.h" | 
|   10 #include "extensions/renderer/api_signature.h" |   10 #include "extensions/renderer/api_signature.h" | 
| (...skipping 15 matching lines...) Expand all  Loading... | 
|   26       : api_name_(api_name) {} |   26       : api_name_(api_name) {} | 
|   27  |   27  | 
|   28   static gin::WrapperInfo kWrapperInfo; |   28   static gin::WrapperInfo kWrapperInfo; | 
|   29  |   29  | 
|   30   // gin::Wrappable: |   30   // gin::Wrappable: | 
|   31   gin::ObjectTemplateBuilder GetObjectTemplateBuilder( |   31   gin::ObjectTemplateBuilder GetObjectTemplateBuilder( | 
|   32       v8::Isolate* isolate) override { |   32       v8::Isolate* isolate) override { | 
|   33     return Wrappable<JSHookInterface>::GetObjectTemplateBuilder(isolate) |   33     return Wrappable<JSHookInterface>::GetObjectTemplateBuilder(isolate) | 
|   34         .SetMethod("setHandleRequest", &JSHookInterface::SetHandleRequest) |   34         .SetMethod("setHandleRequest", &JSHookInterface::SetHandleRequest) | 
|   35         .SetMethod("setUpdateArgumentsPreValidate", |   35         .SetMethod("setUpdateArgumentsPreValidate", | 
|   36                    &JSHookInterface::SetUpdateArgumentsPreValidate); |   36                    &JSHookInterface::SetUpdateArgumentsPreValidate) | 
 |   37         .SetMethod("setUpdateArgumentsPostValidate", | 
 |   38                    &JSHookInterface::SetUpdateArgumentsPostValidate); | 
|   37   } |   39   } | 
|   38  |   40  | 
|   39   void ClearHooks() { |   41   void ClearHooks() { | 
|   40     handle_request_hooks_.clear(); |   42     handle_request_hooks_.clear(); | 
|   41     pre_validation_hooks_.clear(); |   43     pre_validation_hooks_.clear(); | 
 |   44     post_validation_hooks_.clear(); | 
|   42   } |   45   } | 
|   43  |   46  | 
|   44   v8::Local<v8::Function> GetHandleRequestHook(const std::string& method_name, |   47   v8::Local<v8::Function> GetHandleRequestHook(const std::string& method_name, | 
|   45                                                v8::Isolate* isolate) const { |   48                                                v8::Isolate* isolate) const { | 
|   46     return GetHookFromMap(handle_request_hooks_, method_name, isolate); |   49     return GetHookFromMap(handle_request_hooks_, method_name, isolate); | 
|   47   } |   50   } | 
|   48  |   51  | 
|   49   v8::Local<v8::Function> GetPreValidationHook(const std::string& method_name, |   52   v8::Local<v8::Function> GetPreValidationHook(const std::string& method_name, | 
|   50                                                v8::Isolate* isolate) const { |   53                                                v8::Isolate* isolate) const { | 
|   51     return GetHookFromMap(pre_validation_hooks_, method_name, isolate); |   54     return GetHookFromMap(pre_validation_hooks_, method_name, isolate); | 
|   52   } |   55   } | 
|   53  |   56  | 
 |   57   v8::Local<v8::Function> GetPostValidationHook(const std::string& method_name, | 
 |   58                                                 v8::Isolate* isolate) const { | 
 |   59     return GetHookFromMap(post_validation_hooks_, method_name, isolate); | 
 |   60   } | 
 |   61  | 
|   54  private: |   62  private: | 
|   55   using JSHooks = std::map<std::string, v8::Global<v8::Function>>; |   63   using JSHooks = std::map<std::string, v8::Global<v8::Function>>; | 
|   56  |   64  | 
|   57   v8::Local<v8::Function> GetHookFromMap(const JSHooks& map, |   65   v8::Local<v8::Function> GetHookFromMap(const JSHooks& map, | 
|   58                                          const std::string& method_name, |   66                                          const std::string& method_name, | 
|   59                                          v8::Isolate* isolate) const { |   67                                          v8::Isolate* isolate) const { | 
|   60     auto iter = map.find(method_name); |   68     auto iter = map.find(method_name); | 
|   61     if (iter == map.end()) |   69     if (iter == map.end()) | 
|   62       return v8::Local<v8::Function>(); |   70       return v8::Local<v8::Function>(); | 
|   63     return iter->second.Get(isolate); |   71     return iter->second.Get(isolate); | 
| (...skipping 21 matching lines...) Expand all  Loading... | 
|   85   } |   93   } | 
|   86  |   94  | 
|   87   // Adds a hook to update the arguments passed to the API method before we do |   95   // Adds a hook to update the arguments passed to the API method before we do | 
|   88   // any kind of validation. |   96   // any kind of validation. | 
|   89   void SetUpdateArgumentsPreValidate(v8::Isolate* isolate, |   97   void SetUpdateArgumentsPreValidate(v8::Isolate* isolate, | 
|   90                                      const std::string& method_name, |   98                                      const std::string& method_name, | 
|   91                                      v8::Local<v8::Function> hook) { |   99                                      v8::Local<v8::Function> hook) { | 
|   92     AddHookToMap(&pre_validation_hooks_, isolate, method_name, hook); |  100     AddHookToMap(&pre_validation_hooks_, isolate, method_name, hook); | 
|   93   } |  101   } | 
|   94  |  102  | 
 |  103   void SetUpdateArgumentsPostValidate(v8::Isolate* isolate, | 
 |  104                                       const std::string& method_name, | 
 |  105                                       v8::Local<v8::Function> hook) { | 
 |  106     AddHookToMap(&post_validation_hooks_, isolate, method_name, hook); | 
 |  107   } | 
 |  108  | 
|   95   std::string api_name_; |  109   std::string api_name_; | 
|   96  |  110  | 
|   97   JSHooks handle_request_hooks_; |  111   JSHooks handle_request_hooks_; | 
|   98   JSHooks pre_validation_hooks_; |  112   JSHooks pre_validation_hooks_; | 
 |  113   JSHooks post_validation_hooks_; | 
|   99  |  114  | 
|  100   DISALLOW_COPY_AND_ASSIGN(JSHookInterface); |  115   DISALLOW_COPY_AND_ASSIGN(JSHookInterface); | 
|  101 }; |  116 }; | 
|  102  |  117  | 
|  103 const char kExtensionAPIHooksPerContextKey[] = "extension_api_hooks"; |  118 const char kExtensionAPIHooksPerContextKey[] = "extension_api_hooks"; | 
|  104  |  119  | 
|  105 struct APIHooksPerContextData : public base::SupportsUserData::Data { |  120 struct APIHooksPerContextData : public base::SupportsUserData::Data { | 
|  106   APIHooksPerContextData(v8::Isolate* isolate) : isolate(isolate) {} |  121   APIHooksPerContextData(v8::Isolate* isolate) : isolate(isolate) {} | 
|  107   ~APIHooksPerContextData() override { |  122   ~APIHooksPerContextData() override { | 
|  108     v8::HandleScope scope(isolate); |  123     v8::HandleScope scope(isolate); | 
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  178   DCHECK(!hooks_used_) << "Hooks must be registered before the first use!"; |  193   DCHECK(!hooks_used_) << "Hooks must be registered before the first use!"; | 
|  179   request_hooks_[method_name] = hook; |  194   request_hooks_[method_name] = hook; | 
|  180 } |  195 } | 
|  181  |  196  | 
|  182 void APIBindingHooks::RegisterJsSource(v8::Global<v8::String> source, |  197 void APIBindingHooks::RegisterJsSource(v8::Global<v8::String> source, | 
|  183                                        v8::Global<v8::String> resource_name) { |  198                                        v8::Global<v8::String> resource_name) { | 
|  184   js_hooks_source_ = std::move(source); |  199   js_hooks_source_ = std::move(source); | 
|  185   js_resource_name_ = std::move(resource_name); |  200   js_resource_name_ = std::move(resource_name); | 
|  186 } |  201 } | 
|  187  |  202  | 
|  188 APIBindingHooks::RequestResult APIBindingHooks::HandleRequest( |  203 APIBindingHooks::RequestResult APIBindingHooks::RunHooks( | 
|  189     const std::string& api_name, |  204     const std::string& api_name, | 
|  190     const std::string& method_name, |  205     const std::string& method_name, | 
|  191     v8::Local<v8::Context> context, |  206     v8::Local<v8::Context> context, | 
|  192     const APISignature* signature, |  207     const APISignature* signature, | 
|  193     std::vector<v8::Local<v8::Value>>* arguments, |  208     std::vector<v8::Local<v8::Value>>* arguments, | 
|  194     const ArgumentSpec::RefMap& type_refs) { |  209     const ArgumentSpec::RefMap& type_refs) { | 
|  195   // Easy case: a native custom hook. |  210   // Easy case: a native custom hook. | 
|  196   auto request_hooks_iter = request_hooks_.find(method_name); |  211   auto request_hooks_iter = request_hooks_.find(method_name); | 
|  197   if (request_hooks_iter != request_hooks_.end()) { |  212   if (request_hooks_iter != request_hooks_.end()) { | 
|  198     RequestResult result = |  213     RequestResult result = | 
| (...skipping 15 matching lines...) Expand all  Loading... | 
|  214   v8::Isolate* isolate = context->GetIsolate(); |  229   v8::Isolate* isolate = context->GetIsolate(); | 
|  215  |  230  | 
|  216   JSHookInterface* hook_interface = nullptr; |  231   JSHookInterface* hook_interface = nullptr; | 
|  217   gin::Converter<JSHookInterface*>::FromV8( |  232   gin::Converter<JSHookInterface*>::FromV8( | 
|  218       isolate, |  233       isolate, | 
|  219       hook_interface_object, &hook_interface); |  234       hook_interface_object, &hook_interface); | 
|  220   CHECK(hook_interface); |  235   CHECK(hook_interface); | 
|  221  |  236  | 
|  222   v8::Local<v8::Function> pre_validate_hook = |  237   v8::Local<v8::Function> pre_validate_hook = | 
|  223       hook_interface->GetPreValidationHook(method_name, isolate); |  238       hook_interface->GetPreValidationHook(method_name, isolate); | 
 |  239   v8::TryCatch try_catch(isolate); | 
|  224   if (!pre_validate_hook.IsEmpty()) { |  240   if (!pre_validate_hook.IsEmpty()) { | 
|  225     v8::TryCatch try_catch(isolate); |  | 
|  226     // TODO(devlin): What to do with the result of this function call? Can it |  241     // TODO(devlin): What to do with the result of this function call? Can it | 
|  227     // only fail in the case we've already thrown? |  242     // only fail in the case we've already thrown? | 
|  228     UpdateArguments(pre_validate_hook, context, arguments); |  243     UpdateArguments(pre_validate_hook, context, arguments); | 
|  229     if (try_catch.HasCaught()) { |  244     if (try_catch.HasCaught()) { | 
|  230       try_catch.ReThrow(); |  245       try_catch.ReThrow(); | 
|  231       return RequestResult(RequestResult::THROWN); |  246       return RequestResult(RequestResult::THROWN); | 
|  232     } |  247     } | 
|  233   } |  248   } | 
|  234  |  249  | 
 |  250   v8::Local<v8::Function> post_validate_hook = | 
 |  251       hook_interface->GetPostValidationHook(method_name, isolate); | 
|  235   v8::Local<v8::Function> handle_request = |  252   v8::Local<v8::Function> handle_request = | 
|  236       hook_interface->GetHandleRequestHook(method_name, isolate); |  253       hook_interface->GetHandleRequestHook(method_name, isolate); | 
|  237   if (!handle_request.IsEmpty()) { |  254   // If both the post validation hook and the handle request hook are empty, | 
|  238     v8::TryCatch try_catch(isolate); |  255   // we're done... | 
 |  256   if (post_validate_hook.IsEmpty() && handle_request.IsEmpty()) | 
 |  257     return RequestResult(RequestResult::NOT_HANDLED); | 
 |  258  | 
 |  259   { | 
 |  260     // ... otherwise, we have to validate the arguments. | 
|  239     std::vector<v8::Local<v8::Value>> parsed_v8_args; |  261     std::vector<v8::Local<v8::Value>> parsed_v8_args; | 
|  240     std::string error; |  262     std::string error; | 
|  241     bool success = signature->ParseArgumentsToV8(context, *arguments, type_refs, |  263     bool success = signature->ParseArgumentsToV8(context, *arguments, type_refs, | 
|  242                                                  &parsed_v8_args, &error); |  264                                                  &parsed_v8_args, &error); | 
|  243     if (try_catch.HasCaught()) { |  265     if (try_catch.HasCaught()) { | 
|  244       try_catch.ReThrow(); |  266       try_catch.ReThrow(); | 
|  245       return RequestResult(RequestResult::THROWN); |  267       return RequestResult(RequestResult::THROWN); | 
|  246     } |  268     } | 
|  247     if (!success) |  269     if (!success) | 
|  248       return RequestResult(RequestResult::INVALID_INVOCATION); |  270       return RequestResult(RequestResult::INVALID_INVOCATION); | 
 |  271     arguments->swap(parsed_v8_args); | 
 |  272   } | 
|  249  |  273  | 
|  250     v8::Global<v8::Value> global_result = |  274   if (!post_validate_hook.IsEmpty()) { | 
|  251         run_js_.Run(handle_request, context, parsed_v8_args.size(), |  275     UpdateArguments(post_validate_hook, context, arguments); | 
|  252                     parsed_v8_args.data()); |  | 
|  253     if (try_catch.HasCaught()) { |  276     if (try_catch.HasCaught()) { | 
|  254       try_catch.ReThrow(); |  277       try_catch.ReThrow(); | 
|  255       return RequestResult(RequestResult::THROWN); |  278       return RequestResult(RequestResult::THROWN); | 
|  256     } |  279     } | 
|  257     RequestResult result(RequestResult::HANDLED); |  | 
|  258     if (!global_result.IsEmpty()) |  | 
|  259       result.return_value = global_result.Get(isolate); |  | 
|  260     return result; |  | 
|  261   } |  280   } | 
|  262  |  281  | 
|  263   return RequestResult(RequestResult::NOT_HANDLED); |  282   if (handle_request.IsEmpty()) | 
 |  283     return RequestResult(RequestResult::NOT_HANDLED); | 
 |  284  | 
 |  285   v8::Global<v8::Value> global_result = | 
 |  286       run_js_.Run(handle_request, context, arguments->size(), | 
 |  287                   arguments->data()); | 
 |  288   if (try_catch.HasCaught()) { | 
 |  289     try_catch.ReThrow(); | 
 |  290     return RequestResult(RequestResult::THROWN); | 
 |  291   } | 
 |  292   RequestResult result(RequestResult::HANDLED); | 
 |  293   if (!global_result.IsEmpty()) | 
 |  294     result.return_value = global_result.Get(isolate); | 
 |  295   return result; | 
|  264 } |  296 } | 
|  265  |  297  | 
|  266 void APIBindingHooks::InitializeInContext( |  298 void APIBindingHooks::InitializeInContext( | 
|  267     v8::Local<v8::Context> context, |  299     v8::Local<v8::Context> context, | 
|  268     const std::string& api_name) { |  300     const std::string& api_name) { | 
|  269   if (js_hooks_source_.IsEmpty()) |  301   if (js_hooks_source_.IsEmpty()) | 
|  270     return; |  302     return; | 
|  271  |  303  | 
|  272   v8::Local<v8::String> source = js_hooks_source_.Get(context->GetIsolate()); |  304   v8::Local<v8::String> source = js_hooks_source_.Get(context->GetIsolate()); | 
|  273   v8::Local<v8::String> resource_name = |  305   v8::Local<v8::String> resource_name = | 
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  311   if (result.IsEmpty() || |  343   if (result.IsEmpty() || | 
|  312       !gin::Converter<std::vector<v8::Local<v8::Value>>>::FromV8( |  344       !gin::Converter<std::vector<v8::Local<v8::Value>>>::FromV8( | 
|  313           context->GetIsolate(), result, &new_args)) { |  345           context->GetIsolate(), result, &new_args)) { | 
|  314     return false; |  346     return false; | 
|  315   } |  347   } | 
|  316   arguments->swap(new_args); |  348   arguments->swap(new_args); | 
|  317   return true; |  349   return true; | 
|  318 } |  350 } | 
|  319  |  351  | 
|  320 }  // namespace extensions |  352 }  // namespace extensions | 
| OLD | NEW |