// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "chrome/renderer/extensions/chrome_v8_extension.h" #include "base/logging.h" #include "base/lazy_instance.h" #include "base/stringprintf.h" #include "base/string_util.h" #include "chrome/common/extensions/extension.h" #include "chrome/common/extensions/extension_set.h" #include "chrome/renderer/extensions/extension_dispatcher.h" #include "content/renderer/render_view.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebDocument.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h" #include "ui/base/resource/resource_bundle.h" #include "v8/include/v8.h" using WebKit::WebFrame; using WebKit::WebView; namespace { const char kChromeHidden[] = "chromeHidden"; #ifndef NDEBUG const char kValidateCallbacks[] = "validateCallbacks"; #endif typedef std::map<int, std::string> StringMap; static base::LazyInstance<StringMap> g_string_map(base::LINKER_INITIALIZED); } // namespace // static const char* ChromeV8Extension::GetStringResource(int resource_id) { StringMap* strings = g_string_map.Pointer(); StringMap::iterator it = strings->find(resource_id); if (it == strings->end()) { it = strings->insert(std::make_pair( resource_id, ResourceBundle::GetSharedInstance().GetRawDataResource( resource_id).as_string())).first; } return it->second.c_str(); } // static RenderView* ChromeV8Extension::GetCurrentRenderView() { WebFrame* webframe = WebFrame::frameForCurrentContext(); DCHECK(webframe) << "RetrieveCurrentFrame called when not in a V8 context."; if (!webframe) return NULL; WebView* webview = webframe->view(); if (!webview) return NULL; // can happen during closing RenderView* renderview = RenderView::FromWebView(webview); DCHECK(renderview) << "Encountered a WebView without a WebViewDelegate"; return renderview; } ChromeV8Extension::ChromeV8Extension(const char* name, int resource_id, ExtensionDispatcher* extension_dispatcher) : v8::Extension(name, GetStringResource(resource_id), 0, // num dependencies NULL), // dependencies array extension_dispatcher_(extension_dispatcher) { } ChromeV8Extension::ChromeV8Extension(const char* name, int resource_id, int dependency_count, const char** dependencies, ExtensionDispatcher* extension_dispatcher) : v8::Extension(name, GetStringResource(resource_id), dependency_count, dependencies), extension_dispatcher_(extension_dispatcher) { } const Extension* ChromeV8Extension::GetExtensionForCurrentRenderView() const { RenderView* renderview = GetCurrentRenderView(); if (!renderview) return NULL; // this can happen as a tab is closing. GURL url = renderview->webview()->mainFrame()->document().url(); const ExtensionSet* extensions = extension_dispatcher_->extensions(); if (!extensions->ExtensionBindingsAllowed(url)) return NULL; return extensions->GetByURL(url); } bool ChromeV8Extension::CheckPermissionForCurrentRenderView( const std::string& function_name) const { const ::Extension* extension = GetExtensionForCurrentRenderView(); if (extension && extension_dispatcher_->IsExtensionActive(extension->id()) && extension->HasAPIPermission(function_name)) return true; static const char kMessage[] = "You do not have permission to use '%s'. Be sure to declare" " in your manifest what permissions you need."; std::string error_msg = base::StringPrintf(kMessage, function_name.c_str()); v8::ThrowException(v8::Exception::Error(v8::String::New(error_msg.c_str()))); return false; } v8::Handle<v8::FunctionTemplate> ChromeV8Extension::GetNativeFunction(v8::Handle<v8::String> name) { if (name->Equals(v8::String::New("GetChromeHidden"))) { return v8::FunctionTemplate::New(GetChromeHidden); } if (name->Equals(v8::String::New("Print"))) { return v8::FunctionTemplate::New(Print); } return v8::Handle<v8::FunctionTemplate>(); } v8::Handle<v8::Value> ChromeV8Extension::GetChromeHidden( const v8::Arguments& args) { return GetChromeHidden(v8::Context::GetCurrent()); } v8::Handle<v8::Value> ChromeV8Extension::GetChromeHidden( const v8::Handle<v8::Context>& context) { v8::Local<v8::Object> global = context->Global(); v8::Local<v8::Value> hidden = global->GetHiddenValue( v8::String::New(kChromeHidden)); if (hidden.IsEmpty() || hidden->IsUndefined()) { hidden = v8::Object::New(); global->SetHiddenValue(v8::String::New(kChromeHidden), hidden); #ifndef NDEBUG // Tell extension_process_bindings.js to validate callbacks and events // against their schema definitions in api/extension_api.json. v8::Local<v8::Object>::Cast(hidden) ->Set(v8::String::New(kValidateCallbacks), v8::True()); #endif } DCHECK(hidden->IsObject()); return v8::Local<v8::Object>::Cast(hidden); } v8::Handle<v8::Value> ChromeV8Extension::Print(const v8::Arguments& args) { if (args.Length() < 1) return v8::Undefined(); std::vector<std::string> components; for (int i = 0; i < args.Length(); ++i) components.push_back(*v8::String::Utf8Value(args[i]->ToString())); LOG(ERROR) << JoinString(components, ','); return v8::Undefined(); }