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 25 using content::V8ValueConverter; 26 27 namespace extensions { 28 29 ChromeV8Context::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 44 ChromeV8Context::~ChromeV8Context() { 45 VLOG(1) << "Destroyed context for extension\n" 46 << " extension id: " << GetExtensionID(); 47 Invalidate(); 48 } 49 50 void 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 59 std::string ChromeV8Context::GetExtensionID() const { 60 return extension_.get() ? extension_->id() : std::string(); 61 } 62 63 content::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 70 GURL ChromeV8Context::GetURL() const { 71 return web_frame_ ? 72 UserScriptSlave::GetDataSourceURLForFrame(web_frame_) : GURL(); 73 } 74 75 v8::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 96 bool 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 104 Feature::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 112 void ChromeV8Context::DispatchOnUnloadEvent() { 113 module_system_->CallModuleMethod("unload_event", "dispatch"); 114 } 115 116 std::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 128 ChromeV8Context* ChromeV8Context::GetContext() { 129 return this; 130 } 131 132 void 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