blob: 4ae044ecdb2fa56af49c7e0da7b0ac214c2fa528 [file] [log] [blame]
[email protected]42ff47b2011-01-10 23:01:201// Copyright (c) 2011 The Chromium Authors. All rights reserved.
[email protected]5c21a2e2010-08-17 00:37:532// 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/extension_process_bindings.h"
6
7#include <map>
8#include <set>
9#include <string>
10#include <vector>
11
12#include "base/command_line.h"
13#include "base/json/json_reader.h"
[email protected]864b5582010-12-04 23:00:1014#include "base/lazy_instance.h"
[email protected]3b63f8f42011-03-28 01:54:1515#include "base/memory/scoped_ptr.h"
[email protected]c41fe662011-02-15 01:19:2616#include "base/string_number_conversions.h"
[email protected]5c21a2e2010-08-17 00:37:5317#include "base/string_util.h"
[email protected]5c21a2e2010-08-17 00:37:5318#include "chrome/common/extensions/extension.h"
19#include "chrome/common/extensions/extension_constants.h"
[email protected]ec7db282011-01-29 01:11:3620#include "chrome/common/extensions/extension_set.h"
[email protected]5c21a2e2010-08-17 00:37:5321#include "chrome/common/extensions/url_pattern.h"
22#include "chrome/common/render_messages.h"
[email protected]939856a2010-08-24 20:29:0223#include "chrome/common/render_messages_params.h"
[email protected]5c21a2e2010-08-17 00:37:5324#include "chrome/common/url_constants.h"
25#include "chrome/renderer/extensions/bindings_utils.h"
26#include "chrome/renderer/extensions/event_bindings.h"
27#include "chrome/renderer/extensions/js_only_v8_extensions.h"
28#include "chrome/renderer/extensions/renderer_extension_bindings.h"
29#include "chrome/renderer/user_script_slave.h"
30#include "chrome/renderer/render_thread.h"
[email protected]60916042011-03-19 00:43:3631#include "content/renderer/render_view.h"
32#include "content/renderer/render_view_visitor.h"
[email protected]5c21a2e2010-08-17 00:37:5333#include "grit/common_resources.h"
34#include "grit/renderer_resources.h"
35#include "third_party/skia/include/core/SkBitmap.h"
36#include "third_party/skia/include/core/SkColor.h"
[email protected]8bd0fe62011-01-17 06:44:3737#include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h"
38#include "third_party/WebKit/Source/WebKit/chromium/public/WebURL.h"
39#include "third_party/WebKit/Source/WebKit/chromium/public/WebKit.h"
40#include "third_party/WebKit/Source/WebKit/chromium/public/WebSecurityPolicy.h"
41#include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h"
[email protected]5c21a2e2010-08-17 00:37:5342
43using bindings_utils::GetStringResource;
44using bindings_utils::ContextInfo;
45using bindings_utils::ContextList;
46using bindings_utils::GetContexts;
47using bindings_utils::GetPendingRequestMap;
48using bindings_utils::PendingRequest;
49using bindings_utils::PendingRequestMap;
50using bindings_utils::ExtensionBase;
51using WebKit::WebFrame;
52using WebKit::WebSecurityPolicy;
53using WebKit::WebView;
54
55namespace {
56
57// A map of extension ID to vector of page action ids.
58typedef std::map< std::string, std::vector<std::string> > PageActionIdMap;
59
[email protected]583d45c12010-08-31 02:48:1260// A list of permissions that are enabled for this extension.
[email protected]0df165f2010-09-28 16:49:4061typedef std::set<std::string> PermissionsList;
[email protected]5c21a2e2010-08-17 00:37:5362
63// A map of extension ID to permissions map.
[email protected]583d45c12010-08-31 02:48:1264typedef std::map<std::string, PermissionsList> ExtensionPermissionsList;
[email protected]5c21a2e2010-08-17 00:37:5365
[email protected]5c21a2e2010-08-17 00:37:5366const char kExtensionName[] = "chrome/ExtensionProcessBindings";
67const char* kExtensionDeps[] = {
68 BaseJsV8Extension::kName,
69 EventBindings::kName,
70 JsonSchemaJsV8Extension::kName,
71 RendererExtensionBindings::kName,
72 ExtensionApiTestV8Extension::kName,
73};
74
[email protected]5c21a2e2010-08-17 00:37:5375struct SingletonData {
76 std::set<std::string> function_names_;
77 PageActionIdMap page_action_ids_;
[email protected]583d45c12010-08-31 02:48:1278 ExtensionPermissionsList permissions_;
[email protected]5c21a2e2010-08-17 00:37:5379};
80
[email protected]864b5582010-12-04 23:00:1081static base::LazyInstance<SingletonData> g_singleton_data(
82 base::LINKER_INITIALIZED);
83
[email protected]5c21a2e2010-08-17 00:37:5384static std::set<std::string>* GetFunctionNameSet() {
[email protected]864b5582010-12-04 23:00:1085 return &g_singleton_data.Get().function_names_;
[email protected]5c21a2e2010-08-17 00:37:5386}
87
88static PageActionIdMap* GetPageActionMap() {
[email protected]864b5582010-12-04 23:00:1089 return &g_singleton_data.Get().page_action_ids_;
[email protected]5c21a2e2010-08-17 00:37:5390}
91
[email protected]583d45c12010-08-31 02:48:1292static PermissionsList* GetPermissionsList(const std::string& extension_id) {
[email protected]864b5582010-12-04 23:00:1093 return &g_singleton_data.Get().permissions_[extension_id];
[email protected]5c21a2e2010-08-17 00:37:5394}
95
[email protected]5c21a2e2010-08-17 00:37:5396static void GetActiveExtensionIDs(std::set<std::string>* extension_ids) {
[email protected]864b5582010-12-04 23:00:1097 ExtensionPermissionsList& permissions = g_singleton_data.Get().permissions_;
[email protected]5c21a2e2010-08-17 00:37:5398
[email protected]583d45c12010-08-31 02:48:1299 for (ExtensionPermissionsList::iterator iter = permissions.begin();
[email protected]5c21a2e2010-08-17 00:37:53100 iter != permissions.end(); ++iter) {
101 extension_ids->insert(iter->first);
102 }
103}
104
105// A RenderViewVisitor class that iterates through the set of available
106// views, looking for a view of the given type, in the given browser window
107// and within the given extension.
108// Used to accumulate the list of views associated with an extension.
109class ExtensionViewAccumulator : public RenderViewVisitor {
110 public:
111 ExtensionViewAccumulator(const std::string& extension_id,
112 int browser_window_id,
113 ViewType::Type view_type)
114 : extension_id_(extension_id),
115 browser_window_id_(browser_window_id),
116 view_type_(view_type),
117 views_(v8::Array::New()),
118 index_(0) {
119 }
120
121 v8::Local<v8::Array> views() { return views_; }
122
123 virtual bool Visit(RenderView* render_view) {
124 if (!ViewTypeMatches(render_view->view_type(), view_type_))
125 return true;
126
127 GURL url = render_view->webview()->mainFrame()->url();
128 if (!url.SchemeIs(chrome::kExtensionScheme))
129 return true;
130 const std::string& extension_id = url.host();
131 if (extension_id != extension_id_)
132 return true;
133
[email protected]9e92f7c2011-02-14 18:56:04134 if (browser_window_id_ != extension_misc::kUnknownWindowId &&
135 render_view->browser_window_id() != browser_window_id_) {
136 return true;
[email protected]5c21a2e2010-08-17 00:37:53137 }
138
139 v8::Local<v8::Context> context =
140 render_view->webview()->mainFrame()->mainWorldScriptContext();
141 if (!context.IsEmpty()) {
142 v8::Local<v8::Value> window = context->Global();
143 DCHECK(!window.IsEmpty());
144
145 if (!OnMatchedView(window))
146 return false;
147 }
148 return true;
149 }
150
151 private:
152 // Called on each view found matching the search criteria. Returns false
153 // to terminate the iteration.
154 bool OnMatchedView(const v8::Local<v8::Value>& view_window) {
155 views_->Set(v8::Integer::New(index_), view_window);
156 index_++;
157
158 if (view_type_ == ViewType::EXTENSION_BACKGROUND_PAGE)
159 return false; // There can be only one...
160
161 return true;
162 }
163
164 // Returns true is |type| "isa" |match|.
165 static bool ViewTypeMatches(ViewType::Type type, ViewType::Type match) {
166 if (type == match)
167 return true;
168
169 // INVALID means match all.
170 if (match == ViewType::INVALID)
171 return true;
172
173 return false;
174 }
175
176 std::string extension_id_;
177 int browser_window_id_;
178 ViewType::Type view_type_;
179 v8::Local<v8::Array> views_;
180 int index_;
181};
182
183class ExtensionImpl : public ExtensionBase {
184 public:
185 ExtensionImpl() : ExtensionBase(
[email protected]687b9602010-12-08 10:43:08186 kExtensionName, GetStringResource(IDR_EXTENSION_PROCESS_BINDINGS_JS),
[email protected]5c21a2e2010-08-17 00:37:53187 arraysize(kExtensionDeps), kExtensionDeps) {}
188
189 static void SetFunctionNames(const std::vector<std::string>& names) {
190 std::set<std::string>* name_set = GetFunctionNameSet();
191 for (size_t i = 0; i < names.size(); ++i) {
192 name_set->insert(names[i]);
193 }
194 }
195
196 // Note: do not call this function before or during the chromeHidden.onLoad
197 // event dispatch. The URL might not have been committed yet and might not
198 // be an extension URL.
199 static std::string ExtensionIdForCurrentContext() {
200 RenderView* renderview = bindings_utils::GetRenderViewForCurrentContext();
201 if (!renderview)
202 return std::string(); // this can happen as a tab is closing.
203
204 GURL url = renderview->webview()->mainFrame()->url();
[email protected]ec7db282011-01-29 01:11:36205 const ExtensionSet* extensions =
[email protected]2a521c52011-01-26 18:45:21206 EventBindings::GetRenderThread()->GetExtensions();
207 if (!extensions->ExtensionBindingsAllowed(url))
[email protected]5c21a2e2010-08-17 00:37:53208 return std::string();
209
[email protected]2a521c52011-01-26 18:45:21210 return extensions->GetIdByURL(url);
[email protected]5c21a2e2010-08-17 00:37:53211 }
212
213 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
214 v8::Handle<v8::String> name) {
215 if (name->Equals(v8::String::New("GetExtensionAPIDefinition"))) {
216 return v8::FunctionTemplate::New(GetExtensionAPIDefinition);
217 } else if (name->Equals(v8::String::New("GetExtensionViews"))) {
218 return v8::FunctionTemplate::New(GetExtensionViews);
219 } else if (name->Equals(v8::String::New("GetNextRequestId"))) {
220 return v8::FunctionTemplate::New(GetNextRequestId);
221 } else if (name->Equals(v8::String::New("OpenChannelToTab"))) {
222 return v8::FunctionTemplate::New(OpenChannelToTab);
223 } else if (name->Equals(v8::String::New("GetCurrentPageActions"))) {
224 return v8::FunctionTemplate::New(GetCurrentPageActions);
225 } else if (name->Equals(v8::String::New("StartRequest"))) {
226 return v8::FunctionTemplate::New(StartRequest);
227 } else if (name->Equals(v8::String::New("GetRenderViewId"))) {
228 return v8::FunctionTemplate::New(GetRenderViewId);
[email protected]8b8e7c92010-08-19 18:05:56229 } else if (name->Equals(v8::String::New("SetIconCommon"))) {
230 return v8::FunctionTemplate::New(SetIconCommon);
[email protected]5c21a2e2010-08-17 00:37:53231 } else if (name->Equals(v8::String::New("IsExtensionProcess"))) {
232 return v8::FunctionTemplate::New(IsExtensionProcess);
[email protected]bc535ee52010-08-31 18:40:32233 } else if (name->Equals(v8::String::New("IsIncognitoProcess"))) {
234 return v8::FunctionTemplate::New(IsIncognitoProcess);
[email protected]c41fe662011-02-15 01:19:26235 } else if (name->Equals(v8::String::New("GetUniqueSubEventName"))) {
236 return v8::FunctionTemplate::New(GetUniqueSubEventName);
[email protected]55d9bed2011-03-25 20:37:59237 } else if (name->Equals(v8::String::New("GetLocalFileSystem"))) {
238 return v8::FunctionTemplate::New(GetLocalFileSystem);
[email protected]5c21a2e2010-08-17 00:37:53239 }
240
241 return ExtensionBase::GetNativeFunction(name);
242 }
243
244 private:
245 static v8::Handle<v8::Value> GetExtensionAPIDefinition(
246 const v8::Arguments& args) {
[email protected]687b9602010-12-08 10:43:08247 return v8::String::New(GetStringResource(IDR_EXTENSION_API_JSON));
[email protected]5c21a2e2010-08-17 00:37:53248 }
249
[email protected]5c21a2e2010-08-17 00:37:53250 static v8::Handle<v8::Value> GetExtensionViews(const v8::Arguments& args) {
251 if (args.Length() != 2)
252 return v8::Undefined();
253
254 if (!args[0]->IsInt32() || !args[1]->IsString())
255 return v8::Undefined();
256
257 // |browser_window_id| == extension_misc::kUnknownWindowId means getting
258 // views attached to any browser window.
259 int browser_window_id = args[0]->Int32Value();
260
261 std::string view_type_string = *v8::String::Utf8Value(args[1]->ToString());
262 StringToUpperASCII(&view_type_string);
263 // |view_type| == ViewType::INVALID means getting any type of views.
264 ViewType::Type view_type = ViewType::INVALID;
265 if (view_type_string == ViewType::kBackgroundPage) {
266 view_type = ViewType::EXTENSION_BACKGROUND_PAGE;
267 } else if (view_type_string == ViewType::kInfobar) {
268 view_type = ViewType::EXTENSION_INFOBAR;
269 } else if (view_type_string == ViewType::kNotification) {
270 view_type = ViewType::NOTIFICATION;
271 } else if (view_type_string == ViewType::kTabContents) {
272 view_type = ViewType::TAB_CONTENTS;
273 } else if (view_type_string == ViewType::kPopup) {
274 view_type = ViewType::EXTENSION_POPUP;
275 } else if (view_type_string != ViewType::kAll) {
276 return v8::Undefined();
277 }
278
279 std::string extension_id = ExtensionIdForCurrentContext();
280 if (extension_id.empty())
281 return v8::Undefined();
282
283 ExtensionViewAccumulator accumulator(extension_id, browser_window_id,
284 view_type);
285 RenderView::ForEach(&accumulator);
286 return accumulator.views();
287 }
288
289 static v8::Handle<v8::Value> GetNextRequestId(const v8::Arguments& args) {
290 static int next_request_id = 0;
291 return v8::Integer::New(next_request_id++);
292 }
293
[email protected]c41fe662011-02-15 01:19:26294 // Attach an event name to an object.
295 static v8::Handle<v8::Value> GetUniqueSubEventName(
296 const v8::Arguments& args) {
297 static int next_event_id = 0;
298 DCHECK(args.Length() == 1);
299 DCHECK(args[0]->IsString());
300 std::string event_name(*v8::String::AsciiValue(args[0]));
301 std::string unique_event_name =
302 event_name + "/" + base::IntToString(++next_event_id);
303 return v8::String::New(unique_event_name.c_str());
304 }
305
[email protected]55d9bed2011-03-25 20:37:59306 // Attach an event name to an object.
307 static v8::Handle<v8::Value> GetLocalFileSystem(
308 const v8::Arguments& args) {
309 DCHECK(args.Length() == 2);
310 DCHECK(args[0]->IsString());
311 DCHECK(args[1]->IsString());
312 std::string name(*v8::String::Utf8Value(args[0]));
313 std::string path(*v8::String::Utf8Value(args[1]));
314
315 WebFrame* webframe = WebFrame::frameForCurrentContext();
316 return webframe->createFileSystem(fileapi::kFileSystemTypeLocal,
317 WebKit::WebString::fromUTF8(name.c_str()),
318 WebKit::WebString::fromUTF8(path.c_str()));
319 }
320
[email protected]5c21a2e2010-08-17 00:37:53321 // Creates a new messaging channel to the tab with the given ID.
322 static v8::Handle<v8::Value> OpenChannelToTab(const v8::Arguments& args) {
323 // Get the current RenderView so that we can send a routed IPC message from
324 // the correct source.
325 RenderView* renderview = bindings_utils::GetRenderViewForCurrentContext();
326 if (!renderview)
327 return v8::Undefined();
328
329 if (args.Length() >= 3 && args[0]->IsInt32() && args[1]->IsString() &&
330 args[2]->IsString()) {
331 int tab_id = args[0]->Int32Value();
332 std::string extension_id = *v8::String::Utf8Value(args[1]->ToString());
333 std::string channel_name = *v8::String::Utf8Value(args[2]->ToString());
334 int port_id = -1;
335 renderview->Send(new ViewHostMsg_OpenChannelToTab(
336 renderview->routing_id(), tab_id, extension_id, channel_name,
337 &port_id));
338 return v8::Integer::New(port_id);
339 }
340 return v8::Undefined();
341 }
342
343 static v8::Handle<v8::Value> GetCurrentPageActions(
344 const v8::Arguments& args) {
345 std::string extension_id = *v8::String::Utf8Value(args[0]->ToString());
346 PageActionIdMap* page_action_map = GetPageActionMap();
347 PageActionIdMap::const_iterator it = page_action_map->find(extension_id);
348
349 std::vector<std::string> page_actions;
350 size_t size = 0;
351 if (it != page_action_map->end()) {
352 page_actions = it->second;
353 size = page_actions.size();
354 }
355
356 v8::Local<v8::Array> page_action_vector = v8::Array::New(size);
357 for (size_t i = 0; i < size; ++i) {
358 std::string page_action_id = page_actions[i];
359 page_action_vector->Set(v8::Integer::New(i),
360 v8::String::New(page_action_id.c_str()));
361 }
362
363 return page_action_vector;
364 }
365
366 // Common code for starting an API request to the browser. |value_args|
367 // contains the request's arguments.
[email protected]8b8e7c92010-08-19 18:05:56368 // Steals value_args contents for efficiency.
[email protected]5c21a2e2010-08-17 00:37:53369 static v8::Handle<v8::Value> StartRequestCommon(
[email protected]8b8e7c92010-08-19 18:05:56370 const v8::Arguments& args, ListValue* value_args) {
[email protected]5c21a2e2010-08-17 00:37:53371 // Get the current RenderView so that we can send a routed IPC message from
372 // the correct source.
373 RenderView* renderview = bindings_utils::GetRenderViewForCurrentContext();
374 if (!renderview)
375 return v8::Undefined();
376
377 std::string name = *v8::String::AsciiValue(args[0]);
378 if (GetFunctionNameSet()->find(name) == GetFunctionNameSet()->end()) {
379 NOTREACHED() << "Unexpected function " << name;
380 return v8::Undefined();
381 }
382
383 if (!ExtensionProcessBindings::CurrentContextHasPermission(name)) {
384 return ExtensionProcessBindings::ThrowPermissionDeniedException(name);
385 }
386
387 GURL source_url;
388 WebFrame* webframe = WebFrame::frameForCurrentContext();
389 if (webframe)
390 source_url = webframe->url();
391
392 int request_id = args[2]->Int32Value();
393 bool has_callback = args[3]->BooleanValue();
394
395 v8::Persistent<v8::Context> current_context =
396 v8::Persistent<v8::Context>::New(v8::Context::GetCurrent());
397 DCHECK(!current_context.IsEmpty());
398 GetPendingRequestMap()[request_id].reset(new PendingRequest(
399 current_context, name));
400
[email protected]8b8e7c92010-08-19 18:05:56401 ViewHostMsg_DomMessage_Params params;
402 params.name = name;
403 params.arguments.Swap(value_args);
404 params.source_url = source_url;
405 params.request_id = request_id;
406 params.has_callback = has_callback;
407 params.user_gesture = webframe->isProcessingUserGesture();
408 renderview->SendExtensionRequest(params);
[email protected]5c21a2e2010-08-17 00:37:53409
410 return v8::Undefined();
411 }
412
413 // Starts an API request to the browser, with an optional callback. The
414 // callback will be dispatched to EventBindings::HandleResponse.
415 static v8::Handle<v8::Value> StartRequest(const v8::Arguments& args) {
416 std::string str_args = *v8::String::Utf8Value(args[1]);
417 base::JSONReader reader;
418 scoped_ptr<Value> value_args;
419 value_args.reset(reader.JsonToValue(str_args, false, false));
420
421 // Since we do the serialization in the v8 extension, we should always get
422 // valid JSON.
423 if (!value_args.get() || !value_args->IsType(Value::TYPE_LIST)) {
424 NOTREACHED() << "Invalid JSON passed to StartRequest.";
425 return v8::Undefined();
426 }
427
[email protected]8b8e7c92010-08-19 18:05:56428 return StartRequestCommon(args, static_cast<ListValue*>(value_args.get()));
[email protected]5c21a2e2010-08-17 00:37:53429 }
430
[email protected]8b8e7c92010-08-19 18:05:56431 static bool ConvertImageDataToBitmapValue(
432 const v8::Arguments& args, Value** bitmap_value) {
[email protected]5c21a2e2010-08-17 00:37:53433 v8::Local<v8::Object> extension_args = args[1]->ToObject();
434 v8::Local<v8::Object> details =
435 extension_args->Get(v8::String::New("0"))->ToObject();
436 v8::Local<v8::Object> image_data =
437 details->Get(v8::String::New("imageData"))->ToObject();
438 v8::Local<v8::Object> data =
439 image_data->Get(v8::String::New("data"))->ToObject();
440 int width = image_data->Get(v8::String::New("width"))->Int32Value();
441 int height = image_data->Get(v8::String::New("height"))->Int32Value();
442
443 int data_length = data->Get(v8::String::New("length"))->Int32Value();
444 if (data_length != 4 * width * height) {
445 NOTREACHED() << "Invalid argument to setIcon. Expecting ImageData.";
[email protected]8b8e7c92010-08-19 18:05:56446 return false;
[email protected]5c21a2e2010-08-17 00:37:53447 }
448
449 SkBitmap bitmap;
450 bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height);
451 bitmap.allocPixels();
452 bitmap.eraseARGB(0, 0, 0, 0);
453
454 uint32_t* pixels = bitmap.getAddr32(0, 0);
455 for (int t = 0; t < width*height; t++) {
456 // |data| is RGBA, pixels is ARGB.
457 pixels[t] = SkPreMultiplyColor(
458 ((data->Get(v8::Integer::New(4*t + 3))->Int32Value() & 0xFF) << 24) |
459 ((data->Get(v8::Integer::New(4*t + 0))->Int32Value() & 0xFF) << 16) |
460 ((data->Get(v8::Integer::New(4*t + 1))->Int32Value() & 0xFF) << 8) |
461 ((data->Get(v8::Integer::New(4*t + 2))->Int32Value() & 0xFF) << 0));
462 }
463
464 // Construct the Value object.
465 IPC::Message bitmap_pickle;
466 IPC::WriteParam(&bitmap_pickle, bitmap);
[email protected]8b8e7c92010-08-19 18:05:56467 *bitmap_value = BinaryValue::CreateWithCopiedBuffer(
[email protected]5c21a2e2010-08-17 00:37:53468 static_cast<const char*>(bitmap_pickle.data()), bitmap_pickle.size());
469
[email protected]8b8e7c92010-08-19 18:05:56470 return true;
471 }
472
473 // A special request for setting the extension action icon and the sidebar
474 // mini tab icon. This function accepts a canvas ImageData object, so it needs
475 // to do extra processing before sending the request to the browser.
476 static v8::Handle<v8::Value> SetIconCommon(
477 const v8::Arguments& args) {
478 Value* bitmap_value = NULL;
479 if (!ConvertImageDataToBitmapValue(args, &bitmap_value))
480 return v8::Undefined();
481
482 v8::Local<v8::Object> extension_args = args[1]->ToObject();
483 v8::Local<v8::Object> details =
484 extension_args->Get(v8::String::New("0"))->ToObject();
485
[email protected]5c21a2e2010-08-17 00:37:53486 DictionaryValue* dict = new DictionaryValue();
487 dict->Set("imageData", bitmap_value);
488
489 if (details->Has(v8::String::New("tabId"))) {
490 dict->SetInteger("tabId",
491 details->Get(v8::String::New("tabId"))->Int32Value());
492 }
493
494 ListValue list_value;
495 list_value.Append(dict);
496
[email protected]8b8e7c92010-08-19 18:05:56497 return StartRequestCommon(args, &list_value);
[email protected]5c21a2e2010-08-17 00:37:53498 }
499
500 static v8::Handle<v8::Value> GetRenderViewId(const v8::Arguments& args) {
501 RenderView* renderview = bindings_utils::GetRenderViewForCurrentContext();
502 if (!renderview)
503 return v8::Undefined();
504 return v8::Integer::New(renderview->routing_id());
505 }
506
507 static v8::Handle<v8::Value> IsExtensionProcess(const v8::Arguments& args) {
508 bool retval = false;
509 if (EventBindings::GetRenderThread())
510 retval = EventBindings::GetRenderThread()->IsExtensionProcess();
511 return v8::Boolean::New(retval);
512 }
[email protected]bc535ee52010-08-31 18:40:32513
514 static v8::Handle<v8::Value> IsIncognitoProcess(const v8::Arguments& args) {
515 bool retval = false;
516 if (EventBindings::GetRenderThread())
517 retval = EventBindings::GetRenderThread()->IsIncognitoProcess();
518 return v8::Boolean::New(retval);
519 }
[email protected]5c21a2e2010-08-17 00:37:53520};
521
522} // namespace
523
524v8::Extension* ExtensionProcessBindings::Get() {
525 static v8::Extension* extension = new ExtensionImpl();
526 return extension;
527}
528
529void ExtensionProcessBindings::GetActiveExtensions(
530 std::set<std::string>* extension_ids) {
531 GetActiveExtensionIDs(extension_ids);
532}
533
534void ExtensionProcessBindings::SetFunctionNames(
535 const std::vector<std::string>& names) {
536 ExtensionImpl::SetFunctionNames(names);
537}
538
[email protected]5c21a2e2010-08-17 00:37:53539// static
540void ExtensionProcessBindings::HandleResponse(int request_id, bool success,
541 const std::string& response,
542 const std::string& error) {
543 PendingRequestMap& pending_requests = GetPendingRequestMap();
544 PendingRequestMap::iterator request = pending_requests.find(request_id);
545 if (request == pending_requests.end())
546 return; // The frame went away.
547
548 v8::HandleScope handle_scope;
549 v8::Handle<v8::Value> argv[5];
550 argv[0] = v8::Integer::New(request_id);
551 argv[1] = v8::String::New(request->second->name.c_str());
552 argv[2] = v8::Boolean::New(success);
553 argv[3] = v8::String::New(response.c_str());
554 argv[4] = v8::String::New(error.c_str());
555 v8::Handle<v8::Value> retval = bindings_utils::CallFunctionInContext(
556 request->second->context, "handleResponse", arraysize(argv), argv);
557 // In debug, the js will validate the callback parameters and return a
558 // string if a validation error has occured.
[email protected]42ff47b2011-01-10 23:01:20559#ifndef NDEBUG
[email protected]5c21a2e2010-08-17 00:37:53560 if (!retval.IsEmpty() && !retval->IsUndefined()) {
561 std::string error = *v8::String::AsciiValue(retval);
562 DCHECK(false) << error;
563 }
564#endif
565
566 request->second->context.Dispose();
567 request->second->context.Clear();
568 pending_requests.erase(request);
569}
570
571// static
572void ExtensionProcessBindings::SetPageActions(
573 const std::string& extension_id,
574 const std::vector<std::string>& page_actions) {
575 PageActionIdMap& page_action_map = *GetPageActionMap();
576 if (!page_actions.empty()) {
577 page_action_map[extension_id] = page_actions;
578 } else {
579 if (page_action_map.find(extension_id) != page_action_map.end())
580 page_action_map.erase(extension_id);
581 }
582}
583
584// static
585void ExtensionProcessBindings::SetAPIPermissions(
586 const std::string& extension_id,
[email protected]0df165f2010-09-28 16:49:40587 const std::set<std::string>& permissions) {
[email protected]583d45c12010-08-31 02:48:12588 PermissionsList& permissions_list = *GetPermissionsList(extension_id);
[email protected]0df165f2010-09-28 16:49:40589 permissions_list.clear();
590 permissions_list.insert(permissions.begin(), permissions.end());
[email protected]f83773f2011-03-02 19:15:21591
592 // The RenderViewTests set API permissions without an |extension_id|. If
593 // there's no ID, there will be no extension URL and no need to proceed.
594 if (extension_id.empty()) return;
595
596 // Grant access to chrome://extension-icon resources if they have the
597 // 'management' permission.
598 if (permissions_list.find(Extension::kManagementPermission) !=
599 permissions_list.end()) {
600 WebSecurityPolicy::addOriginAccessWhitelistEntry(
601 Extension::GetBaseURLFromExtensionId(extension_id),
602 WebKit::WebString::fromUTF8(chrome::kChromeUIScheme),
603 WebKit::WebString::fromUTF8(chrome::kChromeUIExtensionIconHost),
604 false);
605 }
[email protected]5c21a2e2010-08-17 00:37:53606}
607
608// static
609void ExtensionProcessBindings::SetHostPermissions(
610 const GURL& extension_url,
611 const std::vector<URLPattern>& permissions) {
612 for (size_t i = 0; i < permissions.size(); ++i) {
613 const char* schemes[] = {
614 chrome::kHttpScheme,
615 chrome::kHttpsScheme,
616 chrome::kFileScheme,
617 chrome::kChromeUIScheme,
618 };
619 for (size_t j = 0; j < arraysize(schemes); ++j) {
620 if (permissions[i].MatchesScheme(schemes[j])) {
621 WebSecurityPolicy::addOriginAccessWhitelistEntry(
622 extension_url,
623 WebKit::WebString::fromUTF8(schemes[j]),
624 WebKit::WebString::fromUTF8(permissions[i].host()),
625 permissions[i].match_subdomains());
626 }
627 }
628 }
629}
630
631// static
632bool ExtensionProcessBindings::CurrentContextHasPermission(
633 const std::string& function_name) {
634 std::string extension_id = ExtensionImpl::ExtensionIdForCurrentContext();
635 return HasPermission(extension_id, function_name);
636}
637
638// static
639bool ExtensionProcessBindings::HasPermission(const std::string& extension_id,
640 const std::string& permission) {
[email protected]583d45c12010-08-31 02:48:12641 PermissionsList& permissions_list = *GetPermissionsList(extension_id);
[email protected]246c05f2010-09-10 09:12:11642 return Extension::HasApiPermission(permissions_list, permission);
[email protected]5c21a2e2010-08-17 00:37:53643}
644
645// static
646v8::Handle<v8::Value>
647 ExtensionProcessBindings::ThrowPermissionDeniedException(
648 const std::string& function_name) {
649 static const char kMessage[] =
650 "You do not have permission to use '%s'. Be sure to declare"
651 " in your manifest what permissions you need.";
652 std::string error_msg = StringPrintf(kMessage, function_name.c_str());
653
654 return v8::ThrowException(v8::Exception::Error(
655 v8::String::New(error_msg.c_str())));
656}