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.
5 #include "chrome/renderer/extensions/chrome_v8_context.h"
7 #include "base/debug/trace_event.h"
8 #include "base/logging.h"
9 #include "base/memory/scoped_ptr.h"
10 #include "base/strings/string_split.h"
11 #include "base/values.h"
12 #include "chrome/common/extensions/api/extension_api.h"
13 #include "chrome/common/extensions/extension.h"
14 #include "chrome/common/extensions/extension_set.h"
15 #include "chrome/common/extensions/features/base_feature_provider.h"
16 #include "chrome/renderer/extensions/chrome_v8_extension.h"
17 #include "chrome/renderer/extensions/module_system.h"
18 #include "chrome/renderer/extensions/user_script_slave.h"
19 #include "content/public/renderer/render_view.h"
20 #include "content/public/renderer/v8_value_converter.h"
21 #include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h"
22 #include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h"
23 #include "v8/include/v8.h"
25 using content::V8ValueConverter
;
27 namespace extensions
{
31 const char kChromeHidden
[] = "chromeHidden";
32 const char kValidateCallbacks
[] = "validateCallbacks";
33 const char kValidateAPI
[] = "validateAPI";
37 ChromeV8Context::ChromeV8Context(v8::Handle
<v8::Context
> v8_context
,
38 WebKit::WebFrame
* web_frame
,
39 const Extension
* extension
,
40 Feature::Context context_type
)
41 : v8_context_(v8_context
),
42 web_frame_(web_frame
),
43 extension_(extension
),
44 context_type_(context_type
) {
45 VLOG(1) << "Created context:\n"
46 << " extension id: " << GetExtensionID() << "\n"
47 << " frame: " << web_frame_
<< "\n"
48 << " context type: " << GetContextTypeDescription();
51 ChromeV8Context::~ChromeV8Context() {
52 VLOG(1) << "Destroyed context for extension\n"
53 << " extension id: " << GetExtensionID();
57 void ChromeV8Context::Invalidate() {
58 if (v8_context_
.get().IsEmpty())
61 module_system_
->Invalidate();
66 std::string
ChromeV8Context::GetExtensionID() {
67 return extension_
? extension_
->id() : std::string();
71 v8::Handle
<v8::Value
> ChromeV8Context::GetOrCreateChromeHidden(
72 v8::Handle
<v8::Context
> context
) {
73 v8::Local
<v8::Object
> global
= context
->Global();
74 v8::Local
<v8::Value
> hidden
= global
->GetHiddenValue(
75 v8::String::New(kChromeHidden
));
77 if (hidden
.IsEmpty() || hidden
->IsUndefined()) {
78 hidden
= v8::Object::New();
79 global
->SetHiddenValue(v8::String::New(kChromeHidden
), hidden
);
82 // Tell bindings.js to validate callbacks and events against their schema
84 v8::Local
<v8::Object
>::Cast(hidden
)->Set(
85 v8::String::New(kValidateCallbacks
), v8::True());
86 // Tell bindings.js to validate API for ambiguity.
87 v8::Local
<v8::Object
>::Cast(hidden
)->Set(
88 v8::String::New(kValidateAPI
), v8::True());
92 DCHECK(hidden
->IsObject());
93 return v8::Local
<v8::Object
>::Cast(hidden
);
96 v8::Handle
<v8::Value
> ChromeV8Context::GetChromeHidden() const {
97 v8::Local
<v8::Object
> global
= v8_context_
->Global();
98 return global
->GetHiddenValue(v8::String::New(kChromeHidden
));
101 content::RenderView
* ChromeV8Context::GetRenderView() const {
102 if (web_frame_
&& web_frame_
->view())
103 return content::RenderView::FromWebView(web_frame_
->view());
108 bool ChromeV8Context::CallChromeHiddenMethod(
109 const std::string
& function_name
,
111 v8::Handle
<v8::Value
>* argv
,
112 v8::Handle
<v8::Value
>* result
) const {
113 // ChromeV8ContextSet calls Invalidate() and then schedules a task to delete
114 // this object. This check prevents a race from attempting to execute script
115 // on a NULL web_frame_.
119 v8::Context::Scope
context_scope(v8_context_
.get());
121 // Look up the function name, which may be a sub-property like
122 // "Port.dispatchOnMessage" in the hidden global variable.
123 v8::Local
<v8::Value
> value
= v8::Local
<v8::Value
>::New(GetChromeHidden());
127 std::vector
<std::string
> components
;
128 base::SplitStringDontTrim(function_name
, '.', &components
);
129 for (size_t i
= 0; i
< components
.size(); ++i
) {
130 if (!value
.IsEmpty() && value
->IsObject()) {
131 value
= v8::Local
<v8::Object
>::Cast(value
)->Get(
132 v8::String::New(components
[i
].c_str()));
136 if (value
.IsEmpty() || !value
->IsFunction()) {
137 VLOG(1) << "Could not execute chrome hidden method: " << function_name
;
141 TRACE_EVENT1("v8", "v8.callChromeHiddenMethod",
142 "function_name", function_name
);
144 v8::Local
<v8::Function
> function
= v8::Local
<v8::Function
>::Cast(value
);
145 v8::Handle
<v8::Value
> result_temp
=
146 web_frame_
->callFunctionEvenIfScriptDisabled(function
,
151 *result
= result_temp
;
156 bool ChromeV8Context::IsAnyFeatureAvailableToContext(
157 const std::string
& api_name
) {
158 return ExtensionAPI::GetSharedInstance()->IsAnyFeatureAvailableToContext(
161 UserScriptSlave::GetDataSourceURLForFrame(web_frame_
));
164 Feature::Availability
ChromeV8Context::GetAvailability(
165 const std::string
& api_name
) {
166 return ExtensionAPI::GetSharedInstance()->IsAvailable(
170 UserScriptSlave::GetDataSourceURLForFrame(web_frame_
));
173 void ChromeV8Context::DispatchOnUnloadEvent() {
174 v8::HandleScope handle_scope
;
175 CallChromeHiddenMethod("dispatchOnUnload", 0, NULL
, NULL
);
178 std::string
ChromeV8Context::GetContextTypeDescription() {
179 switch (context_type_
) {
180 case Feature::UNSPECIFIED_CONTEXT
: return "UNSPECIFIED";
181 case Feature::BLESSED_EXTENSION_CONTEXT
: return "BLESSED_EXTENSION";
182 case Feature::UNBLESSED_EXTENSION_CONTEXT
: return "UNBLESSED_EXTENSION";
183 case Feature::CONTENT_SCRIPT_CONTEXT
: return "CONTENT_SCRIPT";
184 case Feature::WEB_PAGE_CONTEXT
: return "WEB_PAGE";
187 return std::string();
190 ChromeV8Context
* ChromeV8Context::GetContext() {
194 void ChromeV8Context::OnResponseReceived(const std::string
& name
,
197 const base::ListValue
& response
,
198 const std::string
& error
) {
199 v8::HandleScope handle_scope
;
201 scoped_ptr
<V8ValueConverter
> converter(V8ValueConverter::create());
202 v8::Handle
<v8::Value
> argv
[] = {
203 v8::Integer::New(request_id
),
204 v8::String::New(name
.c_str()),
205 v8::Boolean::New(success
),
206 converter
->ToV8Value(&response
, v8_context_
.get()),
207 v8::String::New(error
.c_str())
210 v8::Handle
<v8::Value
> retval
;
211 CHECK(CallChromeHiddenMethod("handleResponse", arraysize(argv
), argv
,
213 // In debug, the js will validate the callback parameters and return a
214 // string if a validation error has occured.
215 if (DCHECK_IS_ON()) {
216 if (!retval
.IsEmpty() && !retval
->IsUndefined()) {
217 std::string error
= *v8::String::AsciiValue(retval
);
218 DCHECK(false) << error
;
223 } // namespace extensions