Home | History | Annotate | Download | only in extensions
      1 // Copyright (c) 2012 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 #include "chrome/renderer/extensions/chrome_v8_context.h"
      6 
      7 #include "base/logging.h"
      8 #include "base/memory/scoped_ptr.h"
      9 #include "base/strings/string_split.h"
     10 #include "base/values.h"
     11 #include "chrome/common/extensions/extension_set.h"
     12 #include "chrome/common/extensions/features/base_feature_provider.h"
     13 #include "chrome/renderer/extensions/chrome_v8_extension.h"
     14 #include "chrome/renderer/extensions/module_system.h"
     15 #include "chrome/renderer/extensions/user_script_slave.h"
     16 #include "content/public/renderer/render_view.h"
     17 #include "content/public/renderer/v8_value_converter.h"
     18 #include "extensions/common/extension.h"
     19 #include "extensions/common/extension_api.h"
     20 #include "third_party/WebKit/public/web/WebFrame.h"
     21 #include "third_party/WebKit/public/web/WebScopedMicrotaskSuppression.h"
     22 #include "third_party/WebKit/public/web/WebView.h"
     23 #include "v8/include/v8.h"
     24 
     25 using content::V8ValueConverter;
     26 
     27 namespace extensions {
     28 
     29 ChromeV8Context::ChromeV8Context(v8::Handle<v8::Context> v8_context,
     30                                  blink::WebFrame* web_frame,
     31                                  const Extension* extension,
     32                                  Feature::Context context_type)
     33     : v8_context_(v8_context),
     34       web_frame_(web_frame),
     35       extension_(extension),
     36       context_type_(context_type),
     37       safe_builtins_(this),
     38       pepper_request_proxy_(this),
     39       isolate_(v8_context->GetIsolate()) {
     40   VLOG(1) << "Created context:\n"
     41           << "  extension id: " << GetExtensionID() << "\n"
     42           << "  frame:        " << web_frame_ << "\n"
     43           << "  context type: " << GetContextTypeDescription();
     44 }
     45 
     46 ChromeV8Context::~ChromeV8Context() {
     47   VLOG(1) << "Destroyed context for extension\n"
     48           << "  extension id: " << GetExtensionID();
     49   Invalidate();
     50 }
     51 
     52 void ChromeV8Context::Invalidate() {
     53   if (!is_valid())
     54     return;
     55   if (module_system_)
     56     module_system_->Invalidate();
     57   web_frame_ = NULL;
     58   v8_context_.reset();
     59 }
     60 
     61 std::string ChromeV8Context::GetExtensionID() const {
     62   return extension_.get() ? extension_->id() : std::string();
     63 }
     64 
     65 content::RenderView* ChromeV8Context::GetRenderView() const {
     66   if (web_frame_ && web_frame_->view())
     67     return content::RenderView::FromWebView(web_frame_->view());
     68   else
     69     return NULL;
     70 }
     71 
     72 GURL ChromeV8Context::GetURL() const {
     73   return web_frame_ ?
     74       UserScriptSlave::GetDataSourceURLForFrame(web_frame_) : GURL();
     75 }
     76 
     77 v8::Local<v8::Value> ChromeV8Context::CallFunction(
     78     v8::Handle<v8::Function> function,
     79     int argc,
     80     v8::Handle<v8::Value> argv[]) const {
     81   v8::EscapableHandleScope handle_scope(isolate());
     82   v8::Context::Scope scope(v8_context());
     83 
     84   blink::WebScopedMicrotaskSuppression suppression;
     85   if (!is_valid()) {
     86     return handle_scope.Escape(
     87         v8::Local<v8::Primitive>(v8::Undefined(isolate())));
     88   }
     89 
     90   v8::Handle<v8::Object> global = v8_context()->Global();
     91   if (!web_frame_)
     92     return handle_scope.Escape(function->Call(global, argc, argv));
     93   return handle_scope.Escape(
     94       v8::Local<v8::Value>(web_frame_->callFunctionEvenIfScriptDisabled(
     95           function, global, argc, argv)));
     96 }
     97 
     98 bool ChromeV8Context::IsAnyFeatureAvailableToContext(
     99     const std::string& api_name) {
    100   return ExtensionAPI::GetSharedInstance()->IsAnyFeatureAvailableToContext(
    101       api_name,
    102       extension_.get(),
    103       context_type_,
    104       UserScriptSlave::GetDataSourceURLForFrame(web_frame_));
    105 }
    106 
    107 Feature::Availability ChromeV8Context::GetAvailability(
    108     const std::string& api_name) {
    109   // Hack: Hosted apps should have the availability of messaging APIs based on
    110   // the URL of the page (which might have access depending on some extension
    111   // with externally_connectable), not whether the app has access to messaging
    112   // (which it won't).
    113   const Extension* extension = extension_.get();
    114   if (extension && extension->is_hosted_app() &&
    115       (api_name == "runtime.connect" || api_name == "runtime.sendMessage")) {
    116     extension = NULL;
    117   }
    118   return ExtensionAPI::GetSharedInstance()->IsAvailable(api_name,
    119                                                         extension,
    120                                                         context_type_,
    121                                                         GetURL());
    122 }
    123 
    124 void ChromeV8Context::DispatchOnUnloadEvent() {
    125   module_system_->CallModuleMethod("unload_event", "dispatch");
    126 }
    127 
    128 std::string ChromeV8Context::GetContextTypeDescription() {
    129   switch (context_type_) {
    130     case Feature::UNSPECIFIED_CONTEXT:         return "UNSPECIFIED";
    131     case Feature::BLESSED_EXTENSION_CONTEXT:   return "BLESSED_EXTENSION";
    132     case Feature::UNBLESSED_EXTENSION_CONTEXT: return "UNBLESSED_EXTENSION";
    133     case Feature::CONTENT_SCRIPT_CONTEXT:      return "CONTENT_SCRIPT";
    134     case Feature::WEB_PAGE_CONTEXT:            return "WEB_PAGE";
    135     case Feature::BLESSED_WEB_PAGE_CONTEXT:    return "BLESSED_WEB_PAGE";
    136   }
    137   NOTREACHED();
    138   return std::string();
    139 }
    140 
    141 ChromeV8Context* ChromeV8Context::GetContext() {
    142   return this;
    143 }
    144 
    145 void ChromeV8Context::OnResponseReceived(const std::string& name,
    146                                          int request_id,
    147                                          bool success,
    148                                          const base::ListValue& response,
    149                                          const std::string& error) {
    150   v8::HandleScope handle_scope(isolate());
    151 
    152   scoped_ptr<V8ValueConverter> converter(V8ValueConverter::create());
    153   v8::Handle<v8::Value> argv[] = {
    154     v8::Integer::New(request_id),
    155     v8::String::NewFromUtf8(isolate(), name.c_str()),
    156     v8::Boolean::New(isolate(), success),
    157     converter->ToV8Value(&response, v8_context_.NewHandle(isolate())),
    158     v8::String::NewFromUtf8(isolate(), error.c_str())
    159   };
    160 
    161   v8::Handle<v8::Value> retval = module_system_->CallModuleMethod(
    162       "sendRequest", "handleResponse", arraysize(argv), argv);
    163 
    164   // In debug, the js will validate the callback parameters and return a
    165   // string if a validation error has occured.
    166   if (DCHECK_IS_ON()) {
    167     if (!retval.IsEmpty() && !retval->IsUndefined()) {
    168       std::string error = *v8::String::Utf8Value(retval);
    169       DCHECK(false) << error;
    170     }
    171   }
    172 }
    173 
    174 }  // namespace extensions
    175