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/api/extension_api.h" 12#include "chrome/common/extensions/extension.h" 13#include "chrome/common/extensions/extension_set.h" 14#include "chrome/common/extensions/features/base_feature_provider.h" 15#include "chrome/renderer/extensions/chrome_v8_extension.h" 16#include "chrome/renderer/extensions/module_system.h" 17#include "chrome/renderer/extensions/user_script_slave.h" 18#include "content/public/renderer/render_view.h" 19#include "content/public/renderer/v8_value_converter.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 25using content::V8ValueConverter; 26 27namespace extensions { 28 29ChromeV8Context::ChromeV8Context(v8::Handle<v8::Context> v8_context, 30 WebKit::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 VLOG(1) << "Created context:\n" 39 << " extension id: " << GetExtensionID() << "\n" 40 << " frame: " << web_frame_ << "\n" 41 << " context type: " << GetContextTypeDescription(); 42} 43 44ChromeV8Context::~ChromeV8Context() { 45 VLOG(1) << "Destroyed context for extension\n" 46 << " extension id: " << GetExtensionID(); 47 Invalidate(); 48} 49 50void ChromeV8Context::Invalidate() { 51 if (!is_valid()) 52 return; 53 if (module_system_) 54 module_system_->Invalidate(); 55 web_frame_ = NULL; 56 v8_context_.reset(); 57} 58 59std::string ChromeV8Context::GetExtensionID() const { 60 return extension_.get() ? extension_->id() : std::string(); 61} 62 63content::RenderView* ChromeV8Context::GetRenderView() const { 64 if (web_frame_ && web_frame_->view()) 65 return content::RenderView::FromWebView(web_frame_->view()); 66 else 67 return NULL; 68} 69 70GURL ChromeV8Context::GetURL() const { 71 return web_frame_ ? 72 UserScriptSlave::GetDataSourceURLForFrame(web_frame_) : GURL(); 73} 74 75v8::Local<v8::Value> ChromeV8Context::CallFunction( 76 v8::Handle<v8::Function> function, 77 int argc, 78 v8::Handle<v8::Value> argv[]) const { 79 v8::HandleScope handle_scope; 80 v8::Context::Scope scope(v8_context()); 81 82 WebKit::WebScopedMicrotaskSuppression suppression; 83 if (!is_valid()) 84 return handle_scope.Close(v8::Undefined()); 85 86 v8::Handle<v8::Object> global = v8_context()->Global(); 87 if (!web_frame_) 88 return handle_scope.Close(function->Call(global, argc, argv)); 89 return handle_scope.Close( 90 web_frame_->callFunctionEvenIfScriptDisabled(function, 91 global, 92 argc, 93 argv)); 94} 95 96bool ChromeV8Context::IsAnyFeatureAvailableToContext( 97 const std::string& api_name) { 98 return ExtensionAPI::GetSharedInstance()->IsAnyFeatureAvailableToContext( 99 api_name, 100 context_type_, 101 UserScriptSlave::GetDataSourceURLForFrame(web_frame_)); 102} 103 104Feature::Availability ChromeV8Context::GetAvailability( 105 const std::string& api_name) { 106 return ExtensionAPI::GetSharedInstance()->IsAvailable(api_name, 107 extension_.get(), 108 context_type_, 109 GetURL()); 110} 111 112void ChromeV8Context::DispatchOnUnloadEvent() { 113 module_system_->CallModuleMethod("unload_event", "dispatch"); 114} 115 116std::string ChromeV8Context::GetContextTypeDescription() { 117 switch (context_type_) { 118 case Feature::UNSPECIFIED_CONTEXT: return "UNSPECIFIED"; 119 case Feature::BLESSED_EXTENSION_CONTEXT: return "BLESSED_EXTENSION"; 120 case Feature::UNBLESSED_EXTENSION_CONTEXT: return "UNBLESSED_EXTENSION"; 121 case Feature::CONTENT_SCRIPT_CONTEXT: return "CONTENT_SCRIPT"; 122 case Feature::WEB_PAGE_CONTEXT: return "WEB_PAGE"; 123 } 124 NOTREACHED(); 125 return std::string(); 126} 127 128ChromeV8Context* ChromeV8Context::GetContext() { 129 return this; 130} 131 132void ChromeV8Context::OnResponseReceived(const std::string& name, 133 int request_id, 134 bool success, 135 const base::ListValue& response, 136 const std::string& error) { 137 v8::HandleScope handle_scope; 138 139 scoped_ptr<V8ValueConverter> converter(V8ValueConverter::create()); 140 v8::Handle<v8::Value> argv[] = { 141 v8::Integer::New(request_id), 142 v8::String::New(name.c_str()), 143 v8::Boolean::New(success), 144 converter->ToV8Value(&response, v8_context_.get()), 145 v8::String::New(error.c_str()) 146 }; 147 148 v8::Handle<v8::Value> retval = module_system_->CallModuleMethod( 149 "sendRequest", "handleResponse", arraysize(argv), argv); 150 151 // In debug, the js will validate the callback parameters and return a 152 // string if a validation error has occured. 153 if (DCHECK_IS_ON()) { 154 if (!retval.IsEmpty() && !retval->IsUndefined()) { 155 std::string error = *v8::String::AsciiValue(retval); 156 DCHECK(false) << error; 157 } 158 } 159} 160 161} // namespace extensions 162