Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(377)

Side by Side Diff: chrome/renderer/extensions/extension_dispatcher.cc

Issue 10821133: Move c/r/extensions/* into extensions namespace (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Latest master for cq Created 8 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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/extension_dispatcher.h"
6
7 #include "base/callback.h"
8 #include "base/command_line.h"
9 #include "base/memory/scoped_ptr.h"
10 #include "base/string_piece.h"
11 #include "chrome/common/child_process_logging.h"
12 #include "chrome/common/chrome_switches.h"
13 #include "chrome/common/chrome_version_info.h"
14 #include "chrome/common/extensions/api/extension_api.h"
15 #include "chrome/common/extensions/extension.h"
16 #include "chrome/common/extensions/extension_messages.h"
17 #include "chrome/common/extensions/permissions/permission_set.h"
18 #include "chrome/common/url_constants.h"
19 #include "chrome/common/view_type.h"
20 #include "chrome/renderer/chrome_render_process_observer.h"
21 #include "chrome/renderer/extensions/api_definitions_natives.h"
22 #include "chrome/renderer/extensions/app_bindings.h"
23 #include "chrome/renderer/extensions/app_window_custom_bindings.h"
24 #include "chrome/renderer/extensions/chrome_v8_context.h"
25 #include "chrome/renderer/extensions/chrome_v8_extension.h"
26 #include "chrome/renderer/extensions/context_menus_custom_bindings.h"
27 #include "chrome/renderer/extensions/event_bindings.h"
28 #include "chrome/renderer/extensions/experimental.app_custom_bindings.h"
29 #include "chrome/renderer/extensions/experimental.usb_custom_bindings.h"
30 #include "chrome/renderer/extensions/extension_custom_bindings.h"
31 #include "chrome/renderer/extensions/extension_groups.h"
32 #include "chrome/renderer/extensions/extension_helper.h"
33 #include "chrome/renderer/extensions/extension_request_sender.h"
34 #include "chrome/renderer/extensions/file_browser_handler_custom_bindings.h"
35 #include "chrome/renderer/extensions/file_browser_private_custom_bindings.h"
36 #include "chrome/renderer/extensions/file_system_natives.h"
37 #include "chrome/renderer/extensions/i18n_custom_bindings.h"
38 #include "chrome/renderer/extensions/media_gallery_custom_bindings.h"
39 #include "chrome/renderer/extensions/miscellaneous_bindings.h"
40 #include "chrome/renderer/extensions/page_actions_custom_bindings.h"
41 #include "chrome/renderer/extensions/page_capture_custom_bindings.h"
42 #include "chrome/renderer/extensions/runtime_custom_bindings.h"
43 #include "chrome/renderer/extensions/send_request_natives.h"
44 #include "chrome/renderer/extensions/set_icon_natives.h"
45 #include "chrome/renderer/extensions/tab_finder.h"
46 #include "chrome/renderer/extensions/tabs_custom_bindings.h"
47 #include "chrome/renderer/extensions/tts_custom_bindings.h"
48 #include "chrome/renderer/extensions/user_script_slave.h"
49 #include "chrome/renderer/extensions/web_request_custom_bindings.h"
50 #include "chrome/renderer/extensions/webstore_bindings.h"
51 #include "chrome/renderer/module_system.h"
52 #include "chrome/renderer/native_handler.h"
53 #include "chrome/renderer/resource_bundle_source_map.h"
54 #include "content/public/renderer/render_thread.h"
55 #include "content/public/renderer/render_view.h"
56 #include "grit/renderer_resources.h"
57 #include "third_party/WebKit/Source/WebKit/chromium/public/WebDataSource.h"
58 #include "third_party/WebKit/Source/WebKit/chromium/public/WebDocument.h"
59 #include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h"
60 #include "third_party/WebKit/Source/WebKit/chromium/public/WebScopedUserGesture. h"
61 #include "third_party/WebKit/Source/WebKit/chromium/public/WebSecurityPolicy.h"
62 #include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h"
63 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebString.h"
64 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebURLReques t.h"
65 #include "ui/base/layout.h"
66 #include "ui/base/resource/resource_bundle.h"
67 #include "v8/include/v8.h"
68
69 using WebKit::WebDataSource;
70 using WebKit::WebDocument;
71 using WebKit::WebFrame;
72 using WebKit::WebScopedUserGesture;
73 using WebKit::WebSecurityPolicy;
74 using WebKit::WebString;
75 using WebKit::WebVector;
76 using WebKit::WebView;
77 using content::RenderThread;
78 using content::RenderView;
79 using extensions::APIPermission;
80 using extensions::APIPermissionSet;
81 using extensions::ApiDefinitionsNatives;
82 using extensions::AppWindowCustomBindings;
83 using extensions::ContextMenusCustomBindings;
84 using extensions::Extension;
85 using extensions::ExperimentalAppCustomBindings;
86 using extensions::ExperimentalUsbCustomBindings;
87 using extensions::ExtensionAPI;
88 using extensions::ExtensionCustomBindings;
89 using extensions::Feature;
90 using extensions::FileBrowserHandlerCustomBindings;
91 using extensions::FileBrowserPrivateCustomBindings;
92 using extensions::FileSystemNatives;
93 using extensions::I18NCustomBindings;
94 using extensions::MiscellaneousBindings;
95 using extensions::MediaGalleryCustomBindings;
96 using extensions::PageActionsCustomBindings;
97 using extensions::PageCaptureCustomBindings;
98 using extensions::PermissionSet;
99 using extensions::RuntimeCustomBindings;
100 using extensions::SendRequestNatives;
101 using extensions::SetIconNatives;
102 using extensions::TTSCustomBindings;
103 using extensions::TabFinder;
104 using extensions::TabsCustomBindings;
105 using extensions::UpdatedExtensionPermissionsInfo;
106 using extensions::WebRequestCustomBindings;
107
108 namespace {
109
110 static const int64 kInitialExtensionIdleHandlerDelayMs = 5*1000;
111 static const int64 kMaxExtensionIdleHandlerDelayMs = 5*60*1000;
112 static const char kEventDispatchFunction[] = "Event.dispatchJSON";
113 static const char kOnUnloadEvent[] = "runtime.onSuspend";
114 static const char kOnSuspendCanceledEvent[] = "runtime.onSuspendCanceled";
115
116 class ChromeHiddenNativeHandler : public NativeHandler {
117 public:
118 ChromeHiddenNativeHandler() {
119 RouteFunction("GetChromeHidden",
120 base::Bind(&ChromeHiddenNativeHandler::GetChromeHidden,
121 base::Unretained(this)));
122 }
123
124 v8::Handle<v8::Value> GetChromeHidden(const v8::Arguments& args) {
125 return ChromeV8Context::GetOrCreateChromeHidden(v8::Context::GetCurrent());
126 }
127 };
128
129 class PrintNativeHandler : public NativeHandler {
130 public:
131 PrintNativeHandler() {
132 RouteFunction("Print",
133 base::Bind(&PrintNativeHandler::Print,
134 base::Unretained(this)));
135 }
136
137 v8::Handle<v8::Value> Print(const v8::Arguments& args) {
138 if (args.Length() < 1)
139 return v8::Undefined();
140
141 std::vector<std::string> components;
142 for (int i = 0; i < args.Length(); ++i)
143 components.push_back(*v8::String::Utf8Value(args[i]->ToString()));
144
145 LOG(ERROR) << JoinString(components, ',');
146 return v8::Undefined();
147 }
148 };
149
150 class LazyBackgroundPageNativeHandler : public ChromeV8Extension {
151 public:
152 explicit LazyBackgroundPageNativeHandler(ExtensionDispatcher* dispatcher)
153 : ChromeV8Extension(dispatcher) {
154 RouteFunction("IncrementKeepaliveCount",
155 base::Bind(&LazyBackgroundPageNativeHandler::IncrementKeepaliveCount,
156 base::Unretained(this)));
157 RouteFunction("DecrementKeepaliveCount",
158 base::Bind(&LazyBackgroundPageNativeHandler::DecrementKeepaliveCount,
159 base::Unretained(this)));
160 }
161
162 v8::Handle<v8::Value> IncrementKeepaliveCount(const v8::Arguments& args) {
163 ChromeV8Context* context =
164 extension_dispatcher()->v8_context_set().GetCurrent();
165 if (!context)
166 return v8::Undefined();
167 RenderView* render_view = context->GetRenderView();
168 if (IsContextLazyBackgroundPage(render_view, context->extension())) {
169 render_view->Send(new ExtensionHostMsg_IncrementLazyKeepaliveCount(
170 render_view->GetRoutingID()));
171 }
172 return v8::Undefined();
173 }
174
175 v8::Handle<v8::Value> DecrementKeepaliveCount(const v8::Arguments& args) {
176 ChromeV8Context* context =
177 extension_dispatcher()->v8_context_set().GetCurrent();
178 if (!context)
179 return v8::Undefined();
180 RenderView* render_view = context->GetRenderView();
181 if (IsContextLazyBackgroundPage(render_view, context->extension())) {
182 render_view->Send(new ExtensionHostMsg_DecrementLazyKeepaliveCount(
183 render_view->GetRoutingID()));
184 }
185 return v8::Undefined();
186 }
187
188 private:
189 bool IsContextLazyBackgroundPage(RenderView* render_view,
190 const Extension* extension) {
191 if (!render_view)
192 return false;
193
194 ExtensionHelper* helper = ExtensionHelper::Get(render_view);
195 return (extension && extension->has_lazy_background_page() &&
196 helper->view_type() == chrome::VIEW_TYPE_EXTENSION_BACKGROUND_PAGE);
197 }
198 };
199
200 class ProcessInfoNativeHandler : public ChromeV8Extension {
201 public:
202 explicit ProcessInfoNativeHandler(
203 ExtensionDispatcher* dispatcher,
204 const std::string& extension_id,
205 const std::string& context_type,
206 bool is_incognito_context,
207 int manifest_version)
208 : ChromeV8Extension(dispatcher),
209 extension_id_(extension_id),
210 context_type_(context_type),
211 is_incognito_context_(is_incognito_context),
212 manifest_version_(manifest_version) {
213 RouteFunction("GetExtensionId",
214 base::Bind(&ProcessInfoNativeHandler::GetExtensionId,
215 base::Unretained(this)));
216 RouteFunction("GetContextType",
217 base::Bind(&ProcessInfoNativeHandler::GetContextType,
218 base::Unretained(this)));
219 RouteFunction("InIncognitoContext",
220 base::Bind(&ProcessInfoNativeHandler::InIncognitoContext,
221 base::Unretained(this)));
222 RouteFunction("GetManifestVersion",
223 base::Bind(&ProcessInfoNativeHandler::GetManifestVersion,
224 base::Unretained(this)));
225 }
226
227 v8::Handle<v8::Value> GetExtensionId(const v8::Arguments& args) {
228 return v8::String::New(extension_id_.c_str());
229 }
230
231 v8::Handle<v8::Value> GetContextType(const v8::Arguments& args) {
232 return v8::String::New(context_type_.c_str());
233 }
234
235 v8::Handle<v8::Value> InIncognitoContext(const v8::Arguments& args) {
236 return v8::Boolean::New(is_incognito_context_);
237 }
238
239 v8::Handle<v8::Value> GetManifestVersion(const v8::Arguments& args) {
240 return v8::Integer::New(manifest_version_);
241 }
242
243 private:
244 std::string extension_id_;
245 std::string context_type_;
246 bool is_incognito_context_;
247 int manifest_version_;
248 };
249
250 class ChannelNativeHandler : public NativeHandler {
251 public:
252 explicit ChannelNativeHandler(chrome::VersionInfo::Channel channel)
253 : channel_(channel) {
254 RouteFunction("IsDevChannel",
255 base::Bind(&ChannelNativeHandler::IsDevChannel,
256 base::Unretained(this)));
257 }
258
259 v8::Handle<v8::Value> IsDevChannel(const v8::Arguments& args) {
260 return v8::Boolean::New(channel_ <= chrome::VersionInfo::CHANNEL_DEV);
261 }
262
263 chrome::VersionInfo::Channel channel_;
264 };
265
266 class LoggingNativeHandler : public NativeHandler {
267 public:
268 LoggingNativeHandler() {
269 RouteFunction("DCHECK",
270 base::Bind(&LoggingNativeHandler::Dcheck,
271 base::Unretained(this)));
272 }
273
274 v8::Handle<v8::Value> Dcheck(const v8::Arguments& args) {
275 CHECK_LE(args.Length(), 2);
276 bool check_value = args[0]->BooleanValue();
277 std::string error_message;
278 if (args.Length() == 2)
279 error_message += "Error: " + std::string(*v8::String::AsciiValue(args[1]))
280 + "\n";
281
282 v8::Handle<v8::Array> stack_trace(
283 v8::StackTrace::CurrentStackTrace(10)->AsArray());
284 error_message += "Stack trace: {\n";
285 for (size_t i = 0; i < stack_trace->Length(); i++) {
286 error_message += " "
287 + std::string(*v8::String::AsciiValue(stack_trace->Get(i))) + "\n";
288 }
289 error_message += "}";
290 DCHECK(check_value) << error_message;
291 return v8::Undefined();
292 }
293 };
294
295 void InstallAppBindings(ModuleSystem* module_system,
296 v8::Handle<v8::Object> chrome,
297 v8::Handle<v8::Object> chrome_hidden) {
298 module_system->SetLazyField(chrome, "app", "app", "chromeApp");
299 module_system->SetLazyField(chrome, "appNotifications", "app",
300 "chromeAppNotifications");
301 module_system->SetLazyField(chrome_hidden, "app", "app",
302 "chromeHiddenApp");
303 }
304
305 void InstallWebstoreBindings(ModuleSystem* module_system,
306 v8::Handle<v8::Object> chrome,
307 v8::Handle<v8::Object> chrome_hidden) {
308 module_system->SetLazyField(chrome, "webstore", "webstore", "chromeWebstore");
309 module_system->SetLazyField(chrome_hidden, "webstore", "webstore",
310 "chromeHiddenWebstore");
311 }
312
313 static v8::Handle<v8::Object> GetOrCreateChrome(
314 v8::Handle<v8::Context> context) {
315 v8::Handle<v8::String> chrome_string(v8::String::New("chrome"));
316 v8::Handle<v8::Object> global(context->Global());
317 v8::Handle<v8::Value> chrome(global->Get(chrome_string));
318 if (chrome.IsEmpty() || chrome->IsUndefined()) {
319 v8::Handle<v8::Object> chrome_object(v8::Object::New());
320 global->Set(chrome_string, chrome_object);
321 return chrome_object;
322 }
323 CHECK(chrome->IsObject());
324 return chrome->ToObject();
325 }
326
327 } // namespace
328
329 ExtensionDispatcher::ExtensionDispatcher()
330 : is_webkit_initialized_(false),
331 webrequest_adblock_(false),
332 webrequest_adblock_plus_(false),
333 webrequest_other_(false),
334 source_map_(&ResourceBundle::GetSharedInstance()),
335 chrome_channel_(chrome::VersionInfo::CHANNEL_UNKNOWN) {
336 const CommandLine& command_line = *(CommandLine::ForCurrentProcess());
337 is_extension_process_ =
338 command_line.HasSwitch(switches::kExtensionProcess) ||
339 command_line.HasSwitch(switches::kSingleProcess);
340
341 if (is_extension_process_) {
342 RenderThread::Get()->SetIdleNotificationDelayInMs(
343 kInitialExtensionIdleHandlerDelayMs);
344 }
345
346 user_script_slave_.reset(new extensions::UserScriptSlave(&extensions_));
347 request_sender_.reset(new ExtensionRequestSender(this, &v8_context_set_));
348 PopulateSourceMap();
349 PopulateLazyBindingsMap();
350 }
351
352 ExtensionDispatcher::~ExtensionDispatcher() {
353 }
354
355 bool ExtensionDispatcher::OnControlMessageReceived(
356 const IPC::Message& message) {
357 bool handled = true;
358 IPC_BEGIN_MESSAGE_MAP(ExtensionDispatcher, message)
359 IPC_MESSAGE_HANDLER(ExtensionMsg_SetChannel, OnSetChannel)
360 IPC_MESSAGE_HANDLER(ExtensionMsg_MessageInvoke, OnMessageInvoke)
361 IPC_MESSAGE_HANDLER(ExtensionMsg_DispatchOnConnect, OnDispatchOnConnect)
362 IPC_MESSAGE_HANDLER(ExtensionMsg_DeliverMessage, OnDeliverMessage)
363 IPC_MESSAGE_HANDLER(ExtensionMsg_DispatchOnDisconnect,
364 OnDispatchOnDisconnect)
365 IPC_MESSAGE_HANDLER(ExtensionMsg_SetFunctionNames, OnSetFunctionNames)
366 IPC_MESSAGE_HANDLER(ExtensionMsg_Loaded, OnLoaded)
367 IPC_MESSAGE_HANDLER(ExtensionMsg_Unloaded, OnUnloaded)
368 IPC_MESSAGE_HANDLER(ExtensionMsg_SetScriptingWhitelist,
369 OnSetScriptingWhitelist)
370 IPC_MESSAGE_HANDLER(ExtensionMsg_ActivateExtension, OnActivateExtension)
371 IPC_MESSAGE_HANDLER(ExtensionMsg_UpdatePermissions, OnUpdatePermissions)
372 IPC_MESSAGE_HANDLER(ExtensionMsg_UpdateTabSpecificPermissions,
373 OnUpdateTabSpecificPermissions)
374 IPC_MESSAGE_HANDLER(ExtensionMsg_ClearTabSpecificPermissions,
375 OnClearTabSpecificPermissions)
376 IPC_MESSAGE_HANDLER(ExtensionMsg_UpdateUserScripts, OnUpdateUserScripts)
377 IPC_MESSAGE_HANDLER(ExtensionMsg_UsingWebRequestAPI, OnUsingWebRequestAPI)
378 IPC_MESSAGE_HANDLER(ExtensionMsg_ShouldUnload, OnShouldUnload)
379 IPC_MESSAGE_HANDLER(ExtensionMsg_Unload, OnUnload)
380 IPC_MESSAGE_HANDLER(ExtensionMsg_CancelUnload, OnCancelUnload)
381 IPC_MESSAGE_UNHANDLED(handled = false)
382 IPC_END_MESSAGE_MAP()
383
384 return handled;
385 }
386
387 void ExtensionDispatcher::WebKitInitialized() {
388 // For extensions, we want to ensure we call the IdleHandler every so often,
389 // even if the extension keeps up activity.
390 if (is_extension_process_) {
391 forced_idle_timer_.Start(FROM_HERE,
392 base::TimeDelta::FromMilliseconds(kMaxExtensionIdleHandlerDelayMs),
393 RenderThread::Get(), &RenderThread::IdleHandler);
394 }
395
396 // Initialize host permissions for any extensions that were activated before
397 // WebKit was initialized.
398 for (std::set<std::string>::iterator iter = active_extension_ids_.begin();
399 iter != active_extension_ids_.end(); ++iter) {
400 const Extension* extension = extensions_.GetByID(*iter);
401 CHECK(extension);
402 InitOriginPermissions(extension);
403 }
404
405 is_webkit_initialized_ = true;
406 }
407
408 void ExtensionDispatcher::IdleNotification() {
409 if (is_extension_process_) {
410 // Dampen the forced delay as well if the extension stays idle for long
411 // periods of time.
412 int64 forced_delay_ms = std::max(
413 RenderThread::Get()->GetIdleNotificationDelayInMs(),
414 kMaxExtensionIdleHandlerDelayMs);
415 forced_idle_timer_.Stop();
416 forced_idle_timer_.Start(FROM_HERE,
417 base::TimeDelta::FromMilliseconds(forced_delay_ms),
418 RenderThread::Get(), &RenderThread::IdleHandler);
419 }
420 }
421
422 void ExtensionDispatcher::OnSetFunctionNames(
423 const std::vector<std::string>& names) {
424 function_names_.clear();
425 for (size_t i = 0; i < names.size(); ++i)
426 function_names_.insert(names[i]);
427 }
428
429 void ExtensionDispatcher::OnSetChannel(int channel) {
430 chrome_channel_ = channel;
431 }
432
433 void ExtensionDispatcher::OnMessageInvoke(const std::string& extension_id,
434 const std::string& function_name,
435 const ListValue& args,
436 const GURL& event_url,
437 bool user_gesture) {
438 scoped_ptr<WebScopedUserGesture> web_user_gesture;
439 if (user_gesture) {
440 web_user_gesture.reset(new WebScopedUserGesture);
441 }
442
443 v8_context_set_.DispatchChromeHiddenMethod(
444 extension_id, function_name, args, NULL, event_url);
445
446 // Reset the idle handler each time there's any activity like event or message
447 // dispatch, for which Invoke is the chokepoint.
448 if (is_extension_process_) {
449 RenderThread::Get()->ScheduleIdleHandler(
450 kInitialExtensionIdleHandlerDelayMs);
451 }
452
453 // Tell the browser process when an event has been dispatched with a lazy
454 // background page active.
455 const Extension* extension = extensions_.GetByID(extension_id);
456 if (extension && extension->has_lazy_background_page() &&
457 function_name == kEventDispatchFunction) {
458 RenderView* background_view =
459 ExtensionHelper::GetBackgroundPage(extension_id);
460 if (background_view) {
461 background_view->Send(new ExtensionHostMsg_EventAck(
462 background_view->GetRoutingID()));
463 }
464 }
465 }
466
467 void ExtensionDispatcher::OnDispatchOnConnect(
468 int target_port_id,
469 const std::string& channel_name,
470 const std::string& tab_json,
471 const std::string& source_extension_id,
472 const std::string& target_extension_id) {
473 MiscellaneousBindings::DispatchOnConnect(
474 v8_context_set_.GetAll(),
475 target_port_id, channel_name, tab_json,
476 source_extension_id, target_extension_id,
477 NULL); // All render views.
478 }
479
480 void ExtensionDispatcher::OnDeliverMessage(int target_port_id,
481 const std::string& message) {
482 MiscellaneousBindings::DeliverMessage(
483 v8_context_set_.GetAll(),
484 target_port_id,
485 message,
486 NULL); // All render views.
487 }
488
489 void ExtensionDispatcher::OnDispatchOnDisconnect(int port_id,
490 bool connection_error) {
491 MiscellaneousBindings::DispatchOnDisconnect(
492 v8_context_set_.GetAll(),
493 port_id, connection_error,
494 NULL); // All render views.
495 }
496
497 void ExtensionDispatcher::OnLoaded(
498 const std::vector<ExtensionMsg_Loaded_Params>& loaded_extensions) {
499 std::vector<WebString> platform_app_patterns;
500
501 std::vector<ExtensionMsg_Loaded_Params>::const_iterator i;
502 for (i = loaded_extensions.begin(); i != loaded_extensions.end(); ++i) {
503 scoped_refptr<const Extension> extension(i->ConvertToExtension());
504 if (!extension) {
505 // This can happen if extension parsing fails for any reason. One reason
506 // this can legitimately happen is if the
507 // --enable-experimental-extension-apis changes at runtime, which happens
508 // during browser tests. Existing renderers won't know about the change.
509 continue;
510 }
511
512 extensions_.Insert(extension);
513
514 if (extension->is_platform_app()) {
515 platform_app_patterns.push_back(
516 WebString::fromUTF8(extension->url().spec() + "*"));
517 }
518 }
519
520 if (!platform_app_patterns.empty()) {
521 // We have collected a set of platform-app extensions, so let's tell WebKit
522 // about them so that it can provide a default stylesheet for them.
523 //
524 // TODO(miket): consider enhancing WebView to allow removing
525 // single stylesheets, or else to edit the pattern set associated
526 // with one.
527 WebVector<WebString> patterns;
528 patterns.assign(platform_app_patterns);
529 WebView::addUserStyleSheet(
530 WebString::fromUTF8(ResourceBundle::GetSharedInstance().
531 GetRawDataResource(IDR_PLATFORM_APP_CSS,
532 ui::SCALE_FACTOR_NONE)),
533 patterns,
534 WebView::UserContentInjectInAllFrames,
535 WebView::UserStyleInjectInExistingDocuments);
536 }
537 }
538
539 void ExtensionDispatcher::OnUnloaded(const std::string& id) {
540 extensions_.Remove(id);
541 active_extension_ids_.erase(id);
542
543 // If the extension is later reloaded with a different set of permissions,
544 // we'd like it to get a new isolated world ID, so that it can pick up the
545 // changed origin whitelist.
546 user_script_slave_->RemoveIsolatedWorld(id);
547
548 // We don't do anything with existing platform-app stylesheets. They will
549 // stay resident, but the URL pattern corresponding to the unloaded
550 // extension's URL just won't match anything anymore.
551 }
552
553 void ExtensionDispatcher::OnSetScriptingWhitelist(
554 const Extension::ScriptingWhitelist& extension_ids) {
555 Extension::SetScriptingWhitelist(extension_ids);
556 }
557
558 bool ExtensionDispatcher::IsExtensionActive(
559 const std::string& extension_id) const {
560 bool is_active =
561 active_extension_ids_.find(extension_id) != active_extension_ids_.end();
562 if (is_active)
563 CHECK(extensions_.Contains(extension_id));
564 return is_active;
565 }
566
567 bool ExtensionDispatcher::AllowScriptExtension(
568 WebFrame* frame,
569 const std::string& v8_extension_name,
570 int extension_group) {
571 return AllowScriptExtension(frame, v8_extension_name, extension_group, 0);
572 }
573
574 namespace {
575
576 // This is what the extension_group variable will be when DidCreateScriptContext
577 // is called. We know because it's the same as what AllowScriptExtension gets
578 // passed, and the two functions are called sequentially from WebKit.
579 //
580 // TODO(koz): Plumb extension_group through to AllowScriptExtension() from
581 // WebKit.
582 static int g_hack_extension_group = 0;
583
584 }
585
586 bool ExtensionDispatcher::AllowScriptExtension(
587 WebFrame* frame,
588 const std::string& v8_extension_name,
589 int extension_group,
590 int world_id) {
591 g_hack_extension_group = extension_group;
592 return true;
593 }
594
595 void ExtensionDispatcher::RegisterNativeHandlers(ModuleSystem* module_system,
596 ChromeV8Context* context) {
597 module_system->RegisterNativeHandler("event_bindings",
598 scoped_ptr<NativeHandler>(EventBindings::Get(this)));
599 module_system->RegisterNativeHandler("miscellaneous_bindings",
600 scoped_ptr<NativeHandler>(MiscellaneousBindings::Get(this)));
601 module_system->RegisterNativeHandler("apiDefinitions",
602 scoped_ptr<NativeHandler>(new ApiDefinitionsNatives(this)));
603 module_system->RegisterNativeHandler("sendRequest",
604 scoped_ptr<NativeHandler>(
605 new SendRequestNatives(this, request_sender_.get())));
606 module_system->RegisterNativeHandler("setIcon",
607 scoped_ptr<NativeHandler>(
608 new SetIconNatives(this, request_sender_.get())));
609
610 // Natives used by multiple APIs.
611 module_system->RegisterNativeHandler("file_system_natives",
612 scoped_ptr<NativeHandler>(new FileSystemNatives()));
613
614 // Custom bindings.
615 module_system->RegisterNativeHandler("app",
616 scoped_ptr<NativeHandler>(new AppBindings(this, context)));
617 module_system->RegisterNativeHandler("app_window",
618 scoped_ptr<NativeHandler>(new AppWindowCustomBindings(this)));
619 module_system->RegisterNativeHandler("context_menus",
620 scoped_ptr<NativeHandler>(new ContextMenusCustomBindings()));
621 module_system->RegisterNativeHandler("extension",
622 scoped_ptr<NativeHandler>(
623 new ExtensionCustomBindings(this)));
624 module_system->RegisterNativeHandler("experimental_app",
625 scoped_ptr<NativeHandler>(new ExperimentalAppCustomBindings()));
626 module_system->RegisterNativeHandler("experimental_mediaGalleries",
627 scoped_ptr<NativeHandler>(new MediaGalleryCustomBindings()));
628 module_system->RegisterNativeHandler("experimental_usb",
629 scoped_ptr<NativeHandler>(new ExperimentalUsbCustomBindings()));
630 module_system->RegisterNativeHandler("file_browser_handler",
631 scoped_ptr<NativeHandler>(new FileBrowserHandlerCustomBindings()));
632 module_system->RegisterNativeHandler("file_browser_private",
633 scoped_ptr<NativeHandler>(new FileBrowserPrivateCustomBindings()));
634 module_system->RegisterNativeHandler("i18n",
635 scoped_ptr<NativeHandler>(new I18NCustomBindings()));
636 module_system->RegisterNativeHandler("page_actions",
637 scoped_ptr<NativeHandler>(
638 new PageActionsCustomBindings(this)));
639 module_system->RegisterNativeHandler("page_capture",
640 scoped_ptr<NativeHandler>(new PageCaptureCustomBindings()));
641 module_system->RegisterNativeHandler("runtime",
642 scoped_ptr<NativeHandler>(new RuntimeCustomBindings(context)));
643 module_system->RegisterNativeHandler("tabs",
644 scoped_ptr<NativeHandler>(new TabsCustomBindings()));
645 module_system->RegisterNativeHandler("tts",
646 scoped_ptr<NativeHandler>(new TTSCustomBindings()));
647 module_system->RegisterNativeHandler("web_request",
648 scoped_ptr<NativeHandler>(new WebRequestCustomBindings()));
649 module_system->RegisterNativeHandler("webstore",
650 scoped_ptr<NativeHandler>(new WebstoreBindings(this, context)));
651 }
652
653 void ExtensionDispatcher::PopulateSourceMap() {
654 source_map_.RegisterSource("event_bindings", IDR_EVENT_BINDINGS_JS);
655 source_map_.RegisterSource("miscellaneous_bindings",
656 IDR_MISCELLANEOUS_BINDINGS_JS);
657 source_map_.RegisterSource("schema_generated_bindings",
658 IDR_SCHEMA_GENERATED_BINDINGS_JS);
659 source_map_.RegisterSource("json_schema", IDR_JSON_SCHEMA_JS);
660 source_map_.RegisterSource("apitest", IDR_EXTENSION_APITEST_JS);
661
662 // Libraries.
663 source_map_.RegisterSource("lastError", IDR_LAST_ERROR_JS);
664 source_map_.RegisterSource("schemaUtils", IDR_SCHEMA_UTILS_JS);
665 source_map_.RegisterSource("sendRequest", IDR_SEND_REQUEST_JS);
666 source_map_.RegisterSource("setIcon", IDR_SET_ICON_JS);
667 source_map_.RegisterSource("utils", IDR_UTILS_JS);
668
669 // Custom bindings.
670 source_map_.RegisterSource("app", IDR_APP_CUSTOM_BINDINGS_JS);
671 source_map_.RegisterSource("app.window", IDR_APP_WINDOW_CUSTOM_BINDINGS_JS);
672 source_map_.RegisterSource("browserAction",
673 IDR_BROWSER_ACTION_CUSTOM_BINDINGS_JS);
674 source_map_.RegisterSource("contentSettings",
675 IDR_CONTENT_SETTINGS_CUSTOM_BINDINGS_JS);
676 source_map_.RegisterSource("contextMenus",
677 IDR_CONTEXT_MENUS_CUSTOM_BINDINGS_JS);
678 source_map_.RegisterSource("declarativeWebRequest",
679 IDR_DECLARATIVE_WEBREQUEST_CUSTOM_BINDINGS_JS);
680 source_map_.RegisterSource("devtools", IDR_DEVTOOLS_CUSTOM_BINDINGS_JS);
681 source_map_.RegisterSource("experimental.app",
682 IDR_EXPERIMENTAL_APP_CUSTOM_BINDINGS_JS);
683 source_map_.RegisterSource("experimental.bluetooth",
684 IDR_EXPERIMENTAL_BLUETOOTH_CUSTOM_BINDINGS_JS);
685 source_map_.RegisterSource("experimental.mediaGalleries",
686 IDR_EXPERIMENTAL_MEDIA_GALLERY_CUSTOM_BINDINGS_JS);
687 source_map_.RegisterSource("experimental.offscreen",
688 IDR_EXPERIMENTAL_OFFSCREENTABS_CUSTOM_BINDINGS_JS);
689 source_map_.RegisterSource("experimental.usb",
690 IDR_EXPERIMENTAL_USB_CUSTOM_BINDINGS_JS);
691 source_map_.RegisterSource("extension", IDR_EXTENSION_CUSTOM_BINDINGS_JS);
692 source_map_.RegisterSource("fileBrowserHandler",
693 IDR_FILE_BROWSER_HANDLER_CUSTOM_BINDINGS_JS);
694 source_map_.RegisterSource("fileBrowserPrivate",
695 IDR_FILE_BROWSER_PRIVATE_CUSTOM_BINDINGS_JS);
696 source_map_.RegisterSource("fileSystem",
697 IDR_FILE_SYSTEM_CUSTOM_BINDINGS_JS);
698 source_map_.RegisterSource("i18n", IDR_I18N_CUSTOM_BINDINGS_JS);
699 source_map_.RegisterSource("input.ime", IDR_INPUT_IME_CUSTOM_BINDINGS_JS);
700 source_map_.RegisterSource("omnibox", IDR_OMNIBOX_CUSTOM_BINDINGS_JS);
701 source_map_.RegisterSource("pageActions",
702 IDR_PAGE_ACTIONS_CUSTOM_BINDINGS_JS);
703 source_map_.RegisterSource("pageAction", IDR_PAGE_ACTION_CUSTOM_BINDINGS_JS);
704 source_map_.RegisterSource("pageCapture",
705 IDR_PAGE_CAPTURE_CUSTOM_BINDINGS_JS);
706 source_map_.RegisterSource("runtime", IDR_RUNTIME_CUSTOM_BINDINGS_JS);
707 source_map_.RegisterSource("storage", IDR_STORAGE_CUSTOM_BINDINGS_JS);
708 source_map_.RegisterSource("tabs", IDR_TABS_CUSTOM_BINDINGS_JS);
709 source_map_.RegisterSource("tts", IDR_TTS_CUSTOM_BINDINGS_JS);
710 source_map_.RegisterSource("ttsEngine", IDR_TTS_ENGINE_CUSTOM_BINDINGS_JS);
711 source_map_.RegisterSource("types", IDR_TYPES_CUSTOM_BINDINGS_JS);
712 source_map_.RegisterSource("webRequest", IDR_WEB_REQUEST_CUSTOM_BINDINGS_JS);
713 source_map_.RegisterSource("webRequestInternal",
714 IDR_WEB_REQUEST_INTERNAL_CUSTOM_BINDINGS_JS);
715 source_map_.RegisterSource("webstore", IDR_WEBSTORE_CUSTOM_BINDINGS_JS);
716
717 // Platform app sources that are not API-specific..
718 source_map_.RegisterSource("browserTag", IDR_BROWSER_TAG_JS);
719 source_map_.RegisterSource("platformApp", IDR_PLATFORM_APP_JS);
720 }
721
722 void ExtensionDispatcher::PopulateLazyBindingsMap() {
723 lazy_bindings_map_["app"] = InstallAppBindings;
724 lazy_bindings_map_["webstore"] = InstallWebstoreBindings;
725 }
726
727 void ExtensionDispatcher::InstallBindings(ModuleSystem* module_system,
728 v8::Handle<v8::Context> v8_context,
729 const std::string& api) {
730 std::map<std::string, BindingInstaller>::const_iterator lazy_binding =
731 lazy_bindings_map_.find(api);
732 if (lazy_binding != lazy_bindings_map_.end()) {
733 v8::Handle<v8::Object> global(v8_context->Global());
734 v8::Handle<v8::Object> chrome =
735 global->Get(v8::String::New("chrome"))->ToObject();
736 v8::Handle<v8::Object> chrome_hidden =
737 ChromeV8Context::GetOrCreateChromeHidden(v8_context)->ToObject();
738 (*lazy_binding->second)(module_system, chrome, chrome_hidden);
739 } else {
740 module_system->Require(api);
741 }
742 }
743
744 void ExtensionDispatcher::DidCreateScriptContext(
745 WebFrame* frame, v8::Handle<v8::Context> v8_context, int extension_group,
746 int world_id) {
747 // TODO(koz): If the caller didn't pass extension_group, use the last value.
748 if (extension_group == -1)
749 extension_group = g_hack_extension_group;
750
751 std::string extension_id = GetExtensionID(frame, world_id);
752
753 const Extension* extension = extensions_.GetByID(extension_id);
754 if (!extension && !extension_id.empty()) {
755 // There are conditions where despite a context being associated with an
756 // extension, no extension actually gets found. Ignore "invalid" because
757 // CSP blocks extension page loading by switching the extension ID to
758 // "invalid". This isn't interesting.
759 if (extension_id != "invalid") {
760 LOG(ERROR) << "Extension \"" << extension_id << "\" not found";
761 RenderThread::Get()->RecordUserMetrics("ExtensionNotFound_ED");
762 }
763
764 extension_id = "";
765 }
766
767 ExtensionURLInfo url_info(frame->document().securityOrigin(),
768 extensions::UserScriptSlave::GetDataSourceURLForFrame(frame));
769
770 Feature::Context context_type =
771 ClassifyJavaScriptContext(extension_id, extension_group, url_info);
772
773 ChromeV8Context* context =
774 new ChromeV8Context(v8_context, frame, extension, context_type);
775 v8_context_set_.Add(context);
776
777 scoped_ptr<ModuleSystem> module_system(new ModuleSystem(v8_context,
778 &source_map_));
779 // Enable natives in startup.
780 ModuleSystem::NativesEnabledScope natives_enabled_scope(module_system.get());
781
782 RegisterNativeHandlers(module_system.get(), context);
783
784 module_system->RegisterNativeHandler("chrome_hidden",
785 scoped_ptr<NativeHandler>(new ChromeHiddenNativeHandler()));
786 module_system->RegisterNativeHandler("print",
787 scoped_ptr<NativeHandler>(new PrintNativeHandler()));
788 module_system->RegisterNativeHandler("lazy_background_page",
789 scoped_ptr<NativeHandler>(new LazyBackgroundPageNativeHandler(this)));
790 module_system->RegisterNativeHandler("channel",
791 scoped_ptr<NativeHandler>(new ChannelNativeHandler(
792 static_cast<chrome::VersionInfo::Channel>(chrome_channel_))));
793 module_system->RegisterNativeHandler("logging",
794 scoped_ptr<NativeHandler>(new LoggingNativeHandler()));
795
796
797 int manifest_version = extension ? extension->manifest_version() : 1;
798 module_system->RegisterNativeHandler("process",
799 scoped_ptr<NativeHandler>(new ProcessInfoNativeHandler(
800 this, context->GetExtensionID(),
801 context->GetContextTypeDescription(),
802 ChromeRenderProcessObserver::is_incognito_process(),
803 manifest_version)));
804
805 GetOrCreateChrome(v8_context);
806
807 // Loading JavaScript is expensive, so only run the full API bindings
808 // generation mechanisms in extension pages (NOT all web pages).
809 switch (context_type) {
810 case Feature::UNSPECIFIED_CONTEXT:
811 case Feature::WEB_PAGE_CONTEXT:
812 // TODO(kalman): see comment below about ExtensionAPI.
813 InstallBindings(module_system.get(), v8_context, "app");
814 InstallBindings(module_system.get(), v8_context, "webstore");
815 break;
816
817 case Feature::BLESSED_EXTENSION_CONTEXT:
818 case Feature::UNBLESSED_EXTENSION_CONTEXT:
819 case Feature::CONTENT_SCRIPT_CONTEXT: {
820 CHECK(extension);
821 if (!extension->is_platform_app())
822 module_system->Require("miscellaneous_bindings");
823 module_system->Require("schema_generated_bindings");
824 module_system->Require("apitest");
825
826 // TODO(kalman): move this code back out of the switch and execute it
827 // regardless of |context_type|. ExtensionAPI knows how to return the
828 // correct APIs, however, until it doesn't have a 2MB overhead we can't
829 // load it in every process.
830 const std::set<std::string>& apis = context->GetAvailableExtensionAPIs();
831 for (std::set<std::string>::const_iterator i = apis.begin();
832 i != apis.end(); ++i) {
833 InstallBindings(module_system.get(), v8_context, *i);
834 }
835
836 break;
837 }
838 }
839
840 // Inject custom JS into the platform app context.
841 if (IsWithinPlatformApp(frame))
842 module_system->Require("platformApp");
843
844 if (context_type == Feature::BLESSED_EXTENSION_CONTEXT &&
845 extension->HasAPIPermission(APIPermission::kBrowserTag)) {
846 module_system->Require("browserTag");
847 }
848
849 context->set_module_system(module_system.Pass());
850
851 context->DispatchOnLoadEvent(
852 ChromeRenderProcessObserver::is_incognito_process(),
853 manifest_version);
854
855 VLOG(1) << "Num tracked contexts: " << v8_context_set_.size();
856 }
857
858 std::string ExtensionDispatcher::GetExtensionID(const WebFrame* frame,
859 int world_id) {
860 if (world_id != 0) {
861 // Isolated worlds (content script).
862 return user_script_slave_->GetExtensionIdForIsolatedWorld(world_id);
863 }
864
865 // Extension pages (chrome-extension:// URLs).
866 GURL frame_url = extensions::UserScriptSlave::GetDataSourceURLForFrame(frame);
867 return extensions_.GetExtensionOrAppIDByURL(
868 ExtensionURLInfo(frame->document().securityOrigin(), frame_url));
869 }
870
871 bool ExtensionDispatcher::IsWithinPlatformApp(const WebFrame* frame) {
872 const Extension* extension =
873 extensions_.GetByID(GetExtensionID(frame->top(), 0));
874 return extension && extension->is_platform_app();
875 }
876
877 void ExtensionDispatcher::WillReleaseScriptContext(
878 WebFrame* frame, v8::Handle<v8::Context> v8_context, int world_id) {
879 ChromeV8Context* context = v8_context_set_.GetByV8Context(v8_context);
880 if (!context)
881 return;
882
883 context->DispatchOnUnloadEvent();
884
885 v8_context_set_.Remove(context);
886 VLOG(1) << "Num tracked contexts: " << v8_context_set_.size();
887 }
888
889 void ExtensionDispatcher::OnActivateExtension(
890 const std::string& extension_id) {
891 active_extension_ids_.insert(extension_id);
892 const Extension* extension = extensions_.GetByID(extension_id);
893 CHECK(extension);
894
895 // This is called when starting a new extension page, so start the idle
896 // handler ticking.
897 RenderThread::Get()->ScheduleIdleHandler(kInitialExtensionIdleHandlerDelayMs);
898
899 UpdateActiveExtensions();
900
901 if (is_webkit_initialized_)
902 InitOriginPermissions(extension);
903 }
904
905 void ExtensionDispatcher::InitOriginPermissions(const Extension* extension) {
906 // TODO(jstritar): We should try to remove this special case. Also, these
907 // whitelist entries need to be updated when the kManagement permission
908 // changes.
909 if (extension->HasAPIPermission(APIPermission::kManagement)) {
910 WebSecurityPolicy::addOriginAccessWhitelistEntry(
911 extension->url(),
912 WebString::fromUTF8(chrome::kChromeUIScheme),
913 WebString::fromUTF8(chrome::kChromeUIExtensionIconHost),
914 false);
915 }
916
917 AddOrRemoveOriginPermissions(
918 UpdatedExtensionPermissionsInfo::ADDED,
919 extension,
920 extension->GetActivePermissions()->explicit_hosts());
921 }
922
923 void ExtensionDispatcher::AddOrRemoveOriginPermissions(
924 UpdatedExtensionPermissionsInfo::Reason reason,
925 const Extension* extension,
926 const URLPatternSet& origins) {
927 for (URLPatternSet::const_iterator i = origins.begin();
928 i != origins.end(); ++i) {
929 const char* schemes[] = {
930 chrome::kHttpScheme,
931 chrome::kHttpsScheme,
932 chrome::kFileScheme,
933 chrome::kChromeUIScheme,
934 };
935 for (size_t j = 0; j < arraysize(schemes); ++j) {
936 if (i->MatchesScheme(schemes[j])) {
937 ((reason == UpdatedExtensionPermissionsInfo::REMOVED) ?
938 WebSecurityPolicy::removeOriginAccessWhitelistEntry :
939 WebSecurityPolicy::addOriginAccessWhitelistEntry)(
940 extension->url(),
941 WebString::fromUTF8(schemes[j]),
942 WebString::fromUTF8(i->host()),
943 i->match_subdomains());
944 }
945 }
946 }
947 }
948
949 void ExtensionDispatcher::OnUpdatePermissions(
950 int reason_id,
951 const std::string& extension_id,
952 const extensions::APIPermissionSet& apis,
953 const URLPatternSet& explicit_hosts,
954 const URLPatternSet& scriptable_hosts) {
955 const Extension* extension = extensions_.GetByID(extension_id);
956 if (!extension)
957 return;
958
959 scoped_refptr<const PermissionSet> delta =
960 new PermissionSet(apis, explicit_hosts, scriptable_hosts);
961 scoped_refptr<const PermissionSet> old_active =
962 extension->GetActivePermissions();
963 UpdatedExtensionPermissionsInfo::Reason reason =
964 static_cast<UpdatedExtensionPermissionsInfo::Reason>(reason_id);
965
966 const PermissionSet* new_active = NULL;
967 switch (reason) {
968 case UpdatedExtensionPermissionsInfo::ADDED:
969 new_active = PermissionSet::CreateUnion(old_active, delta);
970 break;
971 case UpdatedExtensionPermissionsInfo::REMOVED:
972 new_active = PermissionSet::CreateDifference(old_active, delta);
973 break;
974 }
975
976 extension->SetActivePermissions(new_active);
977 AddOrRemoveOriginPermissions(reason, extension, explicit_hosts);
978 }
979
980 void ExtensionDispatcher::OnUpdateTabSpecificPermissions(
981 int page_id,
982 int tab_id,
983 const std::string& extension_id,
984 const URLPatternSet& origin_set) {
985 RenderView* view = TabFinder::Find(tab_id);
986
987 // For now, the message should only be sent to the render view that contains
988 // the target tab. This may change. Either way, if this is the target tab it
989 // gives us the chance to check against the page ID to avoid races.
990 DCHECK(view);
991 if (view && view->GetPageId() != page_id)
992 return;
993
994 const Extension* extension = extensions_.GetByID(extension_id);
995 if (!extension)
996 return;
997
998 extension->UpdateTabSpecificPermissions(
999 tab_id,
1000 new PermissionSet(APIPermissionSet(), origin_set, URLPatternSet()));
1001 }
1002
1003 void ExtensionDispatcher::OnClearTabSpecificPermissions(
1004 int tab_id,
1005 const std::vector<std::string>& extension_ids) {
1006 for (std::vector<std::string>::const_iterator it = extension_ids.begin();
1007 it != extension_ids.end(); ++it) {
1008 const Extension* extension = extensions_.GetByID(*it);
1009 if (extension)
1010 extension->ClearTabSpecificPermissions(tab_id);
1011 }
1012 }
1013
1014 void ExtensionDispatcher::OnUpdateUserScripts(
1015 base::SharedMemoryHandle scripts) {
1016 DCHECK(base::SharedMemory::IsHandleValid(scripts)) << "Bad scripts handle";
1017 user_script_slave_->UpdateScripts(scripts);
1018 UpdateActiveExtensions();
1019 }
1020
1021 void ExtensionDispatcher::UpdateActiveExtensions() {
1022 // In single-process mode, the browser process reports the active extensions.
1023 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kSingleProcess))
1024 return;
1025
1026 std::set<std::string> active_extensions = active_extension_ids_;
1027 user_script_slave_->GetActiveExtensions(&active_extensions);
1028 child_process_logging::SetActiveExtensions(active_extensions);
1029 }
1030
1031 void ExtensionDispatcher::RegisterExtension(v8::Extension* extension,
1032 bool restrict_to_extensions) {
1033 if (restrict_to_extensions)
1034 restricted_v8_extensions_.insert(extension->name());
1035
1036 RenderThread::Get()->RegisterExtension(extension);
1037 }
1038
1039 void ExtensionDispatcher::OnUsingWebRequestAPI(
1040 bool adblock, bool adblock_plus, bool other) {
1041 webrequest_adblock_ = adblock;
1042 webrequest_adblock_plus_ = adblock_plus;
1043 webrequest_other_ = other;
1044 }
1045
1046 void ExtensionDispatcher::OnShouldUnload(const std::string& extension_id,
1047 int sequence_id) {
1048 RenderThread::Get()->Send(
1049 new ExtensionHostMsg_ShouldUnloadAck(extension_id, sequence_id));
1050 }
1051
1052 void ExtensionDispatcher::OnUnload(const std::string& extension_id) {
1053 // Dispatch the unload event. This doesn't go through the standard event
1054 // dispatch machinery because it requires special handling. We need to let
1055 // the browser know when we are starting and stopping the event dispatch, so
1056 // that it still considers the extension idle despite any activity the unload
1057 // event creates.
1058 ListValue args;
1059 args.Set(0, Value::CreateStringValue(kOnUnloadEvent));
1060 args.Set(1, Value::CreateStringValue("[]"));
1061 v8_context_set_.DispatchChromeHiddenMethod(
1062 extension_id, kEventDispatchFunction, args, NULL, GURL());
1063
1064 RenderThread::Get()->Send(new ExtensionHostMsg_UnloadAck(extension_id));
1065 }
1066
1067 void ExtensionDispatcher::OnCancelUnload(const std::string& extension_id) {
1068 ListValue args;
1069 args.Set(0, Value::CreateStringValue(kOnSuspendCanceledEvent));
1070 args.Set(1, Value::CreateStringValue("[]"));
1071 v8_context_set_.DispatchChromeHiddenMethod(
1072 extension_id, kEventDispatchFunction, args, NULL, GURL());
1073 }
1074
1075 Feature::Context ExtensionDispatcher::ClassifyJavaScriptContext(
1076 const std::string& extension_id,
1077 int extension_group,
1078 const ExtensionURLInfo& url_info) {
1079 if (extension_group == EXTENSION_GROUP_CONTENT_SCRIPTS) {
1080 return extensions_.Contains(extension_id) ?
1081 Feature::CONTENT_SCRIPT_CONTEXT : Feature::UNSPECIFIED_CONTEXT;
1082 }
1083
1084 // We have an explicit check for sandboxed pages first since:
1085 // 1. Sandboxed pages run in the same process as regular extension pages, so
1086 // the extension is considered active.
1087 // 2. ScriptContext creation (which triggers bindings injection) happens
1088 // before the SecurityContext is updated with the sandbox flags (after
1089 // reading the CSP header), so url_info.url().securityOrigin() is not
1090 // unique yet.
1091 if (extensions_.IsSandboxedPage(url_info))
1092 return Feature::WEB_PAGE_CONTEXT;
1093
1094 if (IsExtensionActive(extension_id))
1095 return Feature::BLESSED_EXTENSION_CONTEXT;
1096
1097 if (extensions_.ExtensionBindingsAllowed(url_info))
1098 return Feature::UNBLESSED_EXTENSION_CONTEXT;
1099
1100 if (url_info.url().is_valid())
1101 return Feature::WEB_PAGE_CONTEXT;
1102
1103 return Feature::UNSPECIFIED_CONTEXT;
1104 }
1105
1106 void ExtensionDispatcher::OnExtensionResponse(int request_id,
1107 bool success,
1108 const base::ListValue& response,
1109 const std::string& error) {
1110 request_sender_->HandleResponse(request_id, success, response, error);
1111 }
1112
1113 bool ExtensionDispatcher::CheckCurrentContextAccessToExtensionAPI(
1114 const std::string& function_name) const {
1115 ChromeV8Context* context = v8_context_set().GetCurrent();
1116 if (!context) {
1117 DLOG(ERROR) << "Not in a v8::Context";
1118 return false;
1119 }
1120
1121 if (!context->extension()) {
1122 v8::ThrowException(
1123 v8::Exception::Error(v8::String::New("Not in an extension.")));
1124 return false;
1125 }
1126
1127 // We need to whitelist tabs.executeScript and tabs.insertCSS because they
1128 // are granted under special circumstances with the activeTab permission
1129 // (note that the browser checks too, so this isn't a security problem).
1130 //
1131 // Only the browser knows which tab this call will be sent to... sometimes we
1132 // *could* figure it out (if the extension gives an explicit tab ID in the
1133 // call), but the expected case will be the extension passing through -1,
1134 // meaning the active tab, and only the browser safely knows what this is.
1135 bool skip_permission_check = (function_name == "tabs.executeScript") ||
1136 (function_name == "tabs.insertCSS");
1137
1138 if (!skip_permission_check &&
1139 !context->extension()->HasAPIPermission(function_name)) {
1140 static const char kMessage[] =
1141 "You do not have permission to use '%s'. Be sure to declare"
1142 " in your manifest what permissions you need.";
1143 std::string error_msg = base::StringPrintf(kMessage, function_name.c_str());
1144 v8::ThrowException(
1145 v8::Exception::Error(v8::String::New(error_msg.c_str())));
1146 return false;
1147 }
1148
1149 if (ExtensionAPI::GetSharedInstance()->IsPrivileged(function_name) &&
1150 context->context_type() != Feature::BLESSED_EXTENSION_CONTEXT) {
1151 static const char kMessage[] =
1152 "%s can only be used in an extension process.";
1153 std::string error_msg = base::StringPrintf(kMessage, function_name.c_str());
1154 v8::ThrowException(
1155 v8::Exception::Error(v8::String::New(error_msg.c_str())));
1156 return false;
1157 }
1158
1159 // We should never end up with sandboxed contexts trying to invoke extension
1160 // APIs, they don't get extension bindings injected. If we end up here it
1161 // means that a sandboxed page somehow managed to invoke an API anyway, so
1162 // we should abort.
1163 WebKit::WebFrame* frame = context->web_frame();
1164 ExtensionURLInfo url_info(frame->document().securityOrigin(),
1165 extensions::UserScriptSlave::GetDataSourceURLForFrame(frame));
1166 CHECK(!extensions_.IsSandboxedPage(url_info));
1167
1168 return true;
1169 }
OLDNEW
« no previous file with comments | « chrome/renderer/extensions/extension_dispatcher.h ('k') | chrome/renderer/extensions/extension_groups.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698