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/dispatcher.h"
6
7#include "base/callback.h"
8#include "base/command_line.h"
9#include "base/debug/alias.h"
10#include "base/json/json_reader.h"
11#include "base/memory/scoped_ptr.h"
12#include "base/sha1.h"
13#include "base/strings/string_number_conversions.h"
14#include "base/strings/string_piece.h"
15#include "base/strings/string_split.h"
16#include "base/strings/string_util.h"
17#include "chrome/common/chrome_switches.h"
18#include "chrome/common/chrome_version_info.h"
19#include "chrome/common/crash_keys.h"
20#include "chrome/common/extensions/api/messaging/message.h"
21#include "chrome/common/extensions/extension_messages.h"
22#include "chrome/common/extensions/features/feature_channel.h"
23#include "chrome/common/extensions/manifest_handlers/externally_connectable.h"
24#include "chrome/common/extensions/message_bundle.h"
25#include "chrome/common/url_constants.h"
26#include "chrome/renderer/chrome_render_process_observer.h"
27#include "chrome/renderer/extensions/api_activity_logger.h"
28#include "chrome/renderer/extensions/api_definitions_natives.h"
29#include "chrome/renderer/extensions/app_bindings.h"
30#include "chrome/renderer/extensions/app_runtime_custom_bindings.h"
31#include "chrome/renderer/extensions/app_window_custom_bindings.h"
32#include "chrome/renderer/extensions/binding_generating_native_handler.h"
33#include "chrome/renderer/extensions/blob_native_handler.h"
34#include "chrome/renderer/extensions/chrome_v8_context.h"
35#include "chrome/renderer/extensions/chrome_v8_extension.h"
36#include "chrome/renderer/extensions/content_watcher.h"
37#include "chrome/renderer/extensions/context_menus_custom_bindings.h"
38#include "chrome/renderer/extensions/css_native_handler.h"
39#include "chrome/renderer/extensions/document_custom_bindings.h"
40#include "chrome/renderer/extensions/dom_activity_logger.h"
41#include "chrome/renderer/extensions/event_bindings.h"
42#include "chrome/renderer/extensions/extension_groups.h"
43#include "chrome/renderer/extensions/extension_helper.h"
44#include "chrome/renderer/extensions/file_browser_handler_custom_bindings.h"
45#include "chrome/renderer/extensions/file_browser_private_custom_bindings.h"
46#include "chrome/renderer/extensions/file_system_natives.h"
47#include "chrome/renderer/extensions/i18n_custom_bindings.h"
48#include "chrome/renderer/extensions/id_generator_custom_bindings.h"
49#include "chrome/renderer/extensions/logging_native_handler.h"
50#include "chrome/renderer/extensions/media_galleries_custom_bindings.h"
51#include "chrome/renderer/extensions/messaging_bindings.h"
52#include "chrome/renderer/extensions/module_system.h"
53#include "chrome/renderer/extensions/object_backed_native_handler.h"
54#include "chrome/renderer/extensions/page_actions_custom_bindings.h"
55#include "chrome/renderer/extensions/page_capture_custom_bindings.h"
56#include "chrome/renderer/extensions/pepper_request_natives.h"
57#include "chrome/renderer/extensions/render_view_observer_natives.h"
58#include "chrome/renderer/extensions/request_sender.h"
59#include "chrome/renderer/extensions/runtime_custom_bindings.h"
60#include "chrome/renderer/extensions/safe_builtins.h"
61#include "chrome/renderer/extensions/send_request_natives.h"
62#include "chrome/renderer/extensions/set_icon_natives.h"
63#include "chrome/renderer/extensions/sync_file_system_custom_bindings.h"
64#include "chrome/renderer/extensions/tab_finder.h"
65#include "chrome/renderer/extensions/tabs_custom_bindings.h"
66#include "chrome/renderer/extensions/user_script_slave.h"
67#include "chrome/renderer/extensions/webstore_bindings.h"
68#include "chrome/renderer/resource_bundle_source_map.h"
69#include "content/public/renderer/render_thread.h"
70#include "content/public/renderer/render_view.h"
71#include "content/public/renderer/v8_value_converter.h"
72#include "extensions/common/constants.h"
73#include "extensions/common/extension.h"
74#include "extensions/common/extension_api.h"
75#include "extensions/common/extension_urls.h"
76#include "extensions/common/features/feature.h"
77#include "extensions/common/features/feature_provider.h"
78#include "extensions/common/manifest.h"
79#include "extensions/common/manifest_constants.h"
80#include "extensions/common/manifest_handlers/background_info.h"
81#include "extensions/common/manifest_handlers/sandboxed_page_info.h"
82#include "extensions/common/permissions/permission_set.h"
83#include "extensions/common/permissions/permissions_data.h"
84#include "extensions/common/view_type.h"
85#include "grit/common_resources.h"
86#include "grit/renderer_resources.h"
87#include "third_party/WebKit/public/platform/WebString.h"
88#include "third_party/WebKit/public/platform/WebURLRequest.h"
89#include "third_party/WebKit/public/web/WebCustomElement.h"
90#include "third_party/WebKit/public/web/WebDataSource.h"
91#include "third_party/WebKit/public/web/WebDocument.h"
92#include "third_party/WebKit/public/web/WebFrame.h"
93#include "third_party/WebKit/public/web/WebRuntimeFeatures.h"
94#include "third_party/WebKit/public/web/WebScopedUserGesture.h"
95#include "third_party/WebKit/public/web/WebSecurityPolicy.h"
96#include "third_party/WebKit/public/web/WebUserGestureIndicator.h"
97#include "third_party/WebKit/public/web/WebView.h"
98#include "ui/base/layout.h"
99#include "ui/base/resource/resource_bundle.h"
100#include "v8/include/v8.h"
101
102#if defined(ENABLE_WEBRTC)
103#include "chrome/renderer/extensions/cast_streaming_native_handler.h"
104#endif
105
106using blink::WebDataSource;
107using blink::WebDocument;
108using blink::WebFrame;
109using blink::WebScopedUserGesture;
110using blink::WebSecurityPolicy;
111using blink::WebString;
112using blink::WebVector;
113using blink::WebView;
114using content::RenderThread;
115using content::RenderView;
116using content::UserMetricsAction;
117
118namespace extensions {
119
120namespace {
121
122static const int64 kInitialExtensionIdleHandlerDelayMs = 5*1000;
123static const int64 kMaxExtensionIdleHandlerDelayMs = 5*60*1000;
124static const char kEventDispatchFunction[] = "dispatchEvent";
125static const char kOnSuspendEvent[] = "runtime.onSuspend";
126static const char kOnSuspendCanceledEvent[] = "runtime.onSuspendCanceled";
127
128// Returns the global value for "chrome" from |context|. If one doesn't exist
129// creates a new object for it.
130//
131// Note that this isn't necessarily an object, since webpages can write, for
132// example, "window.chrome = true".
133v8::Handle<v8::Value> GetOrCreateChrome(ChromeV8Context* context) {
134  v8::Handle<v8::String> chrome_string(
135      v8::String::NewFromUtf8(context->isolate(), "chrome"));
136  v8::Handle<v8::Object> global(context->v8_context()->Global());
137  v8::Handle<v8::Value> chrome(global->Get(chrome_string));
138  if (chrome->IsUndefined()) {
139    chrome = v8::Object::New();
140    global->Set(chrome_string, chrome);
141  }
142  return chrome;
143}
144
145// Returns |value| cast to an object if possible, else an empty handle.
146v8::Handle<v8::Object> AsObjectOrEmpty(v8::Handle<v8::Value> value) {
147  return value->IsObject() ? value.As<v8::Object>() : v8::Handle<v8::Object>();
148}
149
150class TestFeaturesNativeHandler : public ObjectBackedNativeHandler {
151 public:
152  explicit TestFeaturesNativeHandler(ChromeV8Context* context)
153      : ObjectBackedNativeHandler(context) {
154    RouteFunction("GetAPIFeatures",
155        base::Bind(&TestFeaturesNativeHandler::GetAPIFeatures,
156                   base::Unretained(this)));
157  }
158
159 private:
160  void GetAPIFeatures(const v8::FunctionCallbackInfo<v8::Value>& args) {
161    base::Value* value = base::JSONReader::Read(
162        ResourceBundle::GetSharedInstance().GetRawDataResource(
163            IDR_EXTENSION_API_FEATURES).as_string());
164    scoped_ptr<content::V8ValueConverter> converter(
165        content::V8ValueConverter::create());
166    args.GetReturnValue().Set(
167        converter->ToV8Value(value, context()->v8_context()));
168  }
169};
170
171class UserGesturesNativeHandler : public ObjectBackedNativeHandler {
172 public:
173  explicit UserGesturesNativeHandler(ChromeV8Context* context)
174      : ObjectBackedNativeHandler(context) {
175    RouteFunction("IsProcessingUserGesture",
176        base::Bind(&UserGesturesNativeHandler::IsProcessingUserGesture,
177                   base::Unretained(this)));
178    RouteFunction("RunWithUserGesture",
179        base::Bind(&UserGesturesNativeHandler::RunWithUserGesture,
180                   base::Unretained(this)));
181    RouteFunction("RunWithoutUserGesture",
182        base::Bind(&UserGesturesNativeHandler::RunWithoutUserGesture,
183                   base::Unretained(this)));
184  }
185
186 private:
187  void IsProcessingUserGesture(
188      const v8::FunctionCallbackInfo<v8::Value>& args) {
189    args.GetReturnValue().Set(v8::Boolean::New(
190        args.GetIsolate(),
191        blink::WebUserGestureIndicator::isProcessingUserGesture()));
192  }
193
194  void RunWithUserGesture(
195      const v8::FunctionCallbackInfo<v8::Value>& args) {
196    blink::WebScopedUserGesture user_gesture;
197    CHECK_EQ(args.Length(), 1);
198    CHECK(args[0]->IsFunction());
199    v8::Handle<v8::Value> no_args;
200    context()->CallFunction(v8::Handle<v8::Function>::Cast(args[0]),
201                            0, &no_args);
202  }
203
204  void RunWithoutUserGesture(
205      const v8::FunctionCallbackInfo<v8::Value>& args) {
206    blink::WebUserGestureIndicator::consumeUserGesture();
207    CHECK_EQ(args.Length(), 1);
208    CHECK(args[0]->IsFunction());
209    v8::Handle<v8::Value> no_args;
210    context()->CallFunction(v8::Handle<v8::Function>::Cast(args[0]),
211                            0, &no_args);
212  }
213};
214
215class V8ContextNativeHandler : public ObjectBackedNativeHandler {
216 public:
217  V8ContextNativeHandler(ChromeV8Context* context, Dispatcher* dispatcher)
218      : ObjectBackedNativeHandler(context),
219        context_(context),
220        dispatcher_(dispatcher) {
221    RouteFunction("GetAvailability",
222        base::Bind(&V8ContextNativeHandler::GetAvailability,
223                   base::Unretained(this)));
224    RouteFunction("GetModuleSystem",
225        base::Bind(&V8ContextNativeHandler::GetModuleSystem,
226                   base::Unretained(this)));
227  }
228
229 private:
230  void GetAvailability(const v8::FunctionCallbackInfo<v8::Value>& args) {
231    CHECK_EQ(args.Length(), 1);
232    v8::Isolate* isolate = args.GetIsolate();
233    std::string api_name = *v8::String::Utf8Value(args[0]->ToString());
234    Feature::Availability availability = context_->GetAvailability(api_name);
235
236    v8::Handle<v8::Object> ret = v8::Object::New();
237    ret->Set(v8::String::NewFromUtf8(isolate, "is_available"),
238             v8::Boolean::New(isolate, availability.is_available()));
239    ret->Set(v8::String::NewFromUtf8(isolate, "message"),
240             v8::String::NewFromUtf8(isolate, availability.message().c_str()));
241    ret->Set(v8::String::NewFromUtf8(isolate, "result"),
242             v8::Integer::New(availability.result()));
243    args.GetReturnValue().Set(ret);
244  }
245
246  void GetModuleSystem(const v8::FunctionCallbackInfo<v8::Value>& args) {
247    CHECK_EQ(args.Length(), 1);
248    CHECK(args[0]->IsObject());
249    v8::Handle<v8::Context> v8_context =
250        v8::Handle<v8::Object>::Cast(args[0])->CreationContext();
251    ChromeV8Context* context = dispatcher_->v8_context_set().GetByV8Context(
252        v8_context);
253    args.GetReturnValue().Set(context->module_system()->NewInstance());
254  }
255
256  ChromeV8Context* context_;
257  Dispatcher* dispatcher_;
258};
259
260class ChromeNativeHandler : public ObjectBackedNativeHandler {
261 public:
262  explicit ChromeNativeHandler(ChromeV8Context* context)
263      : ObjectBackedNativeHandler(context) {
264    RouteFunction("GetChrome",
265        base::Bind(&ChromeNativeHandler::GetChrome, base::Unretained(this)));
266  }
267
268  void GetChrome(const v8::FunctionCallbackInfo<v8::Value>& args) {
269    args.GetReturnValue().Set(GetOrCreateChrome(context()));
270  }
271};
272
273class PrintNativeHandler : public ObjectBackedNativeHandler {
274 public:
275  explicit PrintNativeHandler(ChromeV8Context* context)
276      : ObjectBackedNativeHandler(context) {
277    RouteFunction("Print",
278        base::Bind(&PrintNativeHandler::Print,
279                   base::Unretained(this)));
280  }
281
282  void Print(const v8::FunctionCallbackInfo<v8::Value>& args) {
283    if (args.Length() < 1)
284      return;
285
286    std::vector<std::string> components;
287    for (int i = 0; i < args.Length(); ++i)
288      components.push_back(*v8::String::Utf8Value(args[i]->ToString()));
289
290    LOG(ERROR) << JoinString(components, ',');
291  }
292};
293
294class LazyBackgroundPageNativeHandler : public ChromeV8Extension {
295 public:
296  LazyBackgroundPageNativeHandler(Dispatcher* dispatcher,
297                                  ChromeV8Context* context)
298      : ChromeV8Extension(dispatcher, context) {
299    RouteFunction("IncrementKeepaliveCount",
300        base::Bind(&LazyBackgroundPageNativeHandler::IncrementKeepaliveCount,
301                   base::Unretained(this)));
302    RouteFunction("DecrementKeepaliveCount",
303        base::Bind(&LazyBackgroundPageNativeHandler::DecrementKeepaliveCount,
304                   base::Unretained(this)));
305  }
306
307  void IncrementKeepaliveCount(
308      const v8::FunctionCallbackInfo<v8::Value>& args) {
309    if (!context())
310      return;
311    RenderView* render_view = context()->GetRenderView();
312    if (IsContextLazyBackgroundPage(render_view, context()->extension())) {
313      render_view->Send(new ExtensionHostMsg_IncrementLazyKeepaliveCount(
314          render_view->GetRoutingID()));
315    }
316  }
317
318  void DecrementKeepaliveCount(
319      const v8::FunctionCallbackInfo<v8::Value>& args) {
320    if (!context())
321      return;
322    RenderView* render_view = context()->GetRenderView();
323    if (IsContextLazyBackgroundPage(render_view, context()->extension())) {
324      render_view->Send(new ExtensionHostMsg_DecrementLazyKeepaliveCount(
325          render_view->GetRoutingID()));
326    }
327  }
328
329 private:
330  bool IsContextLazyBackgroundPage(RenderView* render_view,
331                                   const Extension* extension) {
332    if (!render_view)
333      return false;
334
335    ExtensionHelper* helper = ExtensionHelper::Get(render_view);
336    return (extension && BackgroundInfo::HasLazyBackgroundPage(extension) &&
337            helper->view_type() == VIEW_TYPE_EXTENSION_BACKGROUND_PAGE);
338  }
339};
340
341class ProcessInfoNativeHandler : public ChromeV8Extension {
342 public:
343  ProcessInfoNativeHandler(Dispatcher* dispatcher,
344                           ChromeV8Context* context,
345                           const std::string& extension_id,
346                           const std::string& context_type,
347                           bool is_incognito_context,
348                           int manifest_version,
349                           bool send_request_disabled)
350      : ChromeV8Extension(dispatcher, context),
351        extension_id_(extension_id),
352        context_type_(context_type),
353        is_incognito_context_(is_incognito_context),
354        manifest_version_(manifest_version),
355        send_request_disabled_(send_request_disabled) {
356    RouteFunction("GetExtensionId",
357        base::Bind(&ProcessInfoNativeHandler::GetExtensionId,
358                   base::Unretained(this)));
359    RouteFunction("GetContextType",
360        base::Bind(&ProcessInfoNativeHandler::GetContextType,
361                   base::Unretained(this)));
362    RouteFunction("InIncognitoContext",
363        base::Bind(&ProcessInfoNativeHandler::InIncognitoContext,
364                   base::Unretained(this)));
365    RouteFunction("GetManifestVersion",
366        base::Bind(&ProcessInfoNativeHandler::GetManifestVersion,
367                   base::Unretained(this)));
368    RouteFunction("IsSendRequestDisabled",
369        base::Bind(&ProcessInfoNativeHandler::IsSendRequestDisabled,
370                   base::Unretained(this)));
371    RouteFunction("HasSwitch",
372        base::Bind(&ProcessInfoNativeHandler::HasSwitch,
373                   base::Unretained(this)));
374  }
375
376 private:
377  void GetExtensionId(const v8::FunctionCallbackInfo<v8::Value>& args) {
378    args.GetReturnValue()
379        .Set(v8::String::NewFromUtf8(args.GetIsolate(), extension_id_.c_str()));
380  }
381
382  void GetContextType(const v8::FunctionCallbackInfo<v8::Value>& args) {
383    args.GetReturnValue()
384        .Set(v8::String::NewFromUtf8(args.GetIsolate(), context_type_.c_str()));
385  }
386
387  void InIncognitoContext(const v8::FunctionCallbackInfo<v8::Value>& args) {
388    args.GetReturnValue().Set(is_incognito_context_);
389  }
390
391  void GetManifestVersion(const v8::FunctionCallbackInfo<v8::Value>& args) {
392    args.GetReturnValue().Set(static_cast<int32_t>(manifest_version_));
393  }
394
395  void IsSendRequestDisabled(const v8::FunctionCallbackInfo<v8::Value>& args) {
396    if (send_request_disabled_) {
397      args.GetReturnValue().Set(v8::String::NewFromUtf8(args.GetIsolate(),
398          "sendRequest and onRequest are obsolete."
399          " Please use sendMessage and onMessage instead."));
400    }
401  }
402
403  void HasSwitch(const v8::FunctionCallbackInfo<v8::Value>& args) {
404    CHECK(args.Length() == 1 && args[0]->IsString());
405    bool has_switch = CommandLine::ForCurrentProcess()->HasSwitch(
406        *v8::String::Utf8Value(args[0]));
407    args.GetReturnValue().Set(v8::Boolean::New(args.GetIsolate(), has_switch));
408  }
409
410  std::string extension_id_;
411  std::string context_type_;
412  bool is_incognito_context_;
413  int manifest_version_;
414  bool send_request_disabled_;
415};
416
417void InstallAppBindings(ModuleSystem* module_system,
418                        v8::Handle<v8::Object> chrome) {
419  module_system->SetLazyField(chrome, "app", "app", "chromeApp");
420}
421
422void InstallWebstoreBindings(ModuleSystem* module_system,
423                             v8::Handle<v8::Object> chrome) {
424  module_system->SetLazyField(chrome, "webstore", "webstore", "chromeWebstore");
425}
426
427// Calls a method |method_name| in a module |module_name| belonging to the
428// module system from |context|. Intended as a callback target from
429// ChromeV8ContextSet::ForEach.
430void CallModuleMethod(const std::string& module_name,
431                      const std::string& method_name,
432                      const base::ListValue* args,
433                      ChromeV8Context* context) {
434  v8::HandleScope handle_scope(context->isolate());
435  v8::Context::Scope context_scope(context->v8_context());
436
437  scoped_ptr<content::V8ValueConverter> converter(
438      content::V8ValueConverter::create());
439
440  std::vector<v8::Handle<v8::Value> > arguments;
441  for (base::ListValue::const_iterator it = args->begin(); it != args->end();
442       ++it) {
443    arguments.push_back(converter->ToV8Value(*it, context->v8_context()));
444  }
445
446  context->module_system()->CallModuleMethod(
447      module_name, method_name, &arguments);
448}
449
450}  // namespace
451
452Dispatcher::Dispatcher()
453    : content_watcher_(new ContentWatcher()),
454      is_webkit_initialized_(false),
455      webrequest_adblock_(false),
456      webrequest_adblock_plus_(false),
457      webrequest_other_(false),
458      source_map_(&ResourceBundle::GetSharedInstance()),
459      v8_schema_registry_(new V8SchemaRegistry) {
460  const CommandLine& command_line = *(CommandLine::ForCurrentProcess());
461  is_extension_process_ =
462      command_line.HasSwitch(switches::kExtensionProcess) ||
463      command_line.HasSwitch(switches::kSingleProcess);
464
465  if (is_extension_process_) {
466    RenderThread::Get()->SetIdleNotificationDelayInMs(
467        kInitialExtensionIdleHandlerDelayMs);
468  }
469
470  RenderThread::Get()->RegisterExtension(SafeBuiltins::CreateV8Extension());
471
472  user_script_slave_.reset(new UserScriptSlave(&extensions_));
473  request_sender_.reset(new RequestSender(this));
474  PopulateSourceMap();
475  PopulateLazyBindingsMap();
476}
477
478Dispatcher::~Dispatcher() {
479}
480
481bool Dispatcher::OnControlMessageReceived(const IPC::Message& message) {
482  bool handled = true;
483  IPC_BEGIN_MESSAGE_MAP(Dispatcher, message)
484    IPC_MESSAGE_HANDLER(ExtensionMsg_SetChannel, OnSetChannel)
485    IPC_MESSAGE_HANDLER(ExtensionMsg_MessageInvoke, OnMessageInvoke)
486    IPC_MESSAGE_HANDLER(ExtensionMsg_DispatchOnConnect, OnDispatchOnConnect)
487    IPC_MESSAGE_HANDLER(ExtensionMsg_DeliverMessage, OnDeliverMessage)
488    IPC_MESSAGE_HANDLER(ExtensionMsg_DispatchOnDisconnect,
489                        OnDispatchOnDisconnect)
490    IPC_MESSAGE_HANDLER(ExtensionMsg_SetFunctionNames, OnSetFunctionNames)
491    IPC_MESSAGE_HANDLER(ExtensionMsg_SetSystemFont, OnSetSystemFont)
492    IPC_MESSAGE_HANDLER(ExtensionMsg_Loaded, OnLoaded)
493    IPC_MESSAGE_HANDLER(ExtensionMsg_Unloaded, OnUnloaded)
494    IPC_MESSAGE_HANDLER(ExtensionMsg_SetScriptingWhitelist,
495                        OnSetScriptingWhitelist)
496    IPC_MESSAGE_HANDLER(ExtensionMsg_ActivateExtension, OnActivateExtension)
497    IPC_MESSAGE_HANDLER(ExtensionMsg_UpdatePermissions, OnUpdatePermissions)
498    IPC_MESSAGE_HANDLER(ExtensionMsg_UpdateTabSpecificPermissions,
499                        OnUpdateTabSpecificPermissions)
500    IPC_MESSAGE_HANDLER(ExtensionMsg_ClearTabSpecificPermissions,
501                        OnClearTabSpecificPermissions)
502    IPC_MESSAGE_HANDLER(ExtensionMsg_UpdateUserScripts, OnUpdateUserScripts)
503    IPC_MESSAGE_HANDLER(ExtensionMsg_UsingWebRequestAPI, OnUsingWebRequestAPI)
504    IPC_MESSAGE_HANDLER(ExtensionMsg_ShouldSuspend, OnShouldSuspend)
505    IPC_MESSAGE_HANDLER(ExtensionMsg_Suspend, OnSuspend)
506    IPC_MESSAGE_HANDLER(ExtensionMsg_CancelSuspend, OnCancelSuspend)
507    IPC_MESSAGE_FORWARD(ExtensionMsg_WatchPages,
508                        content_watcher_.get(), ContentWatcher::OnWatchPages)
509    IPC_MESSAGE_UNHANDLED(handled = false)
510  IPC_END_MESSAGE_MAP()
511
512  return handled;
513}
514
515void Dispatcher::WebKitInitialized() {
516  // For extensions, we want to ensure we call the IdleHandler every so often,
517  // even if the extension keeps up activity.
518  if (is_extension_process_) {
519    forced_idle_timer_.Start(FROM_HERE,
520        base::TimeDelta::FromMilliseconds(kMaxExtensionIdleHandlerDelayMs),
521        RenderThread::Get(), &RenderThread::IdleHandler);
522  }
523
524  // Initialize host permissions for any extensions that were activated before
525  // WebKit was initialized.
526  for (std::set<std::string>::iterator iter = active_extension_ids_.begin();
527       iter != active_extension_ids_.end(); ++iter) {
528    const Extension* extension = extensions_.GetByID(*iter);
529    CHECK(extension);
530    InitOriginPermissions(extension);
531  }
532
533  EnableCustomElementWhiteList();
534
535  is_webkit_initialized_ = true;
536}
537
538void Dispatcher::IdleNotification() {
539  if (is_extension_process_) {
540    // Dampen the forced delay as well if the extension stays idle for long
541    // periods of time.
542    int64 forced_delay_ms = std::max(
543        RenderThread::Get()->GetIdleNotificationDelayInMs(),
544        kMaxExtensionIdleHandlerDelayMs);
545    forced_idle_timer_.Stop();
546    forced_idle_timer_.Start(FROM_HERE,
547        base::TimeDelta::FromMilliseconds(forced_delay_ms),
548        RenderThread::Get(), &RenderThread::IdleHandler);
549  }
550}
551
552void Dispatcher::OnRenderProcessShutdown() {
553  v8_schema_registry_.reset();
554}
555
556void Dispatcher::OnSetFunctionNames(
557    const std::vector<std::string>& names) {
558  function_names_.clear();
559  for (size_t i = 0; i < names.size(); ++i)
560    function_names_.insert(names[i]);
561}
562
563void Dispatcher::OnSetSystemFont(const std::string& font_family,
564                                 const std::string& font_size) {
565  system_font_family_ = font_family;
566  system_font_size_ = font_size;
567}
568
569void Dispatcher::OnSetChannel(int channel) {
570  SetCurrentChannel(static_cast<chrome::VersionInfo::Channel>(channel));
571}
572
573void Dispatcher::OnMessageInvoke(const std::string& extension_id,
574                                 const std::string& module_name,
575                                 const std::string& function_name,
576                                 const base::ListValue& args,
577                                 bool user_gesture) {
578  InvokeModuleSystemMethod(
579      NULL, extension_id, module_name, function_name, args, user_gesture);
580}
581
582void Dispatcher::OnDispatchOnConnect(
583    int target_port_id,
584    const std::string& channel_name,
585    const base::DictionaryValue& source_tab,
586    const ExtensionMsg_ExternalConnectionInfo& info,
587    const std::string& tls_channel_id) {
588  MessagingBindings::DispatchOnConnect(
589      v8_context_set_.GetAll(),
590      target_port_id, channel_name, source_tab,
591      info.source_id, info.target_id, info.source_url,
592      tls_channel_id,
593      NULL);  // All render views.
594}
595
596void Dispatcher::OnDeliverMessage(int target_port_id,
597                                  const Message& message) {
598  MessagingBindings::DeliverMessage(
599      v8_context_set_.GetAll(),
600      target_port_id,
601      message,
602      NULL);  // All render views.
603}
604
605void Dispatcher::OnDispatchOnDisconnect(int port_id,
606                                        const std::string& error_message) {
607  MessagingBindings::DispatchOnDisconnect(
608      v8_context_set_.GetAll(),
609      port_id, error_message,
610      NULL);  // All render views.
611}
612
613void Dispatcher::OnLoaded(
614    const std::vector<ExtensionMsg_Loaded_Params>& loaded_extensions) {
615  std::vector<ExtensionMsg_Loaded_Params>::const_iterator i;
616  for (i = loaded_extensions.begin(); i != loaded_extensions.end(); ++i) {
617    std::string error;
618    scoped_refptr<const Extension> extension = i->ConvertToExtension(&error);
619    if (!extension.get()) {
620      extension_load_errors_[i->id] = error;
621      continue;
622    }
623    OnLoadedInternal(extension);
624  }
625  // Update the available bindings for all contexts. These may have changed if
626  // an externally_connectable extension was loaded that can connect to an
627  // open webpage.
628  AddOrRemoveBindings("");
629}
630
631void Dispatcher::OnLoadedInternal(scoped_refptr<const Extension> extension) {
632  extensions_.Insert(extension);
633}
634
635void Dispatcher::OnUnloaded(const std::string& id) {
636  extensions_.Remove(id);
637  active_extension_ids_.erase(id);
638
639  // If the extension is later reloaded with a different set of permissions,
640  // we'd like it to get a new isolated world ID, so that it can pick up the
641  // changed origin whitelist.
642  user_script_slave_->RemoveIsolatedWorld(id);
643
644  // Invalidate all of the contexts that were removed.
645  // TODO(kalman): add an invalidation observer interface to ChromeV8Context.
646  ChromeV8ContextSet::ContextSet removed_contexts =
647      v8_context_set_.OnExtensionUnloaded(id);
648  for (ChromeV8ContextSet::ContextSet::iterator it = removed_contexts.begin();
649       it != removed_contexts.end(); ++it) {
650    request_sender_->InvalidateSource(*it);
651  }
652
653  // Update the available bindings for the remaining contexts. These may have
654  // changed if an externally_connectable extension is unloaded and a webpage
655  // is no longer accessible.
656  AddOrRemoveBindings("");
657
658  // Invalidates the messages map for the extension in case the extension is
659  // reloaded with a new messages map.
660  EraseL10nMessagesMap(id);
661
662  // We don't do anything with existing platform-app stylesheets. They will
663  // stay resident, but the URL pattern corresponding to the unloaded
664  // extension's URL just won't match anything anymore.
665}
666
667void Dispatcher::OnSetScriptingWhitelist(
668    const ExtensionsClient::ScriptingWhitelist& extension_ids) {
669  ExtensionsClient::Get()->SetScriptingWhitelist(extension_ids);
670}
671
672bool Dispatcher::IsExtensionActive(
673    const std::string& extension_id) const {
674  bool is_active =
675      active_extension_ids_.find(extension_id) != active_extension_ids_.end();
676  if (is_active)
677    CHECK(extensions_.Contains(extension_id));
678  return is_active;
679}
680
681v8::Handle<v8::Object> Dispatcher::GetOrCreateObject(
682    v8::Handle<v8::Object> object,
683    const std::string& field,
684    v8::Isolate* isolate) {
685  v8::Handle<v8::String> key = v8::String::NewFromUtf8(isolate, field.c_str());
686  // If the object has a callback property, it is assumed it is an unavailable
687  // API, so it is safe to delete. This is checked before GetOrCreateObject is
688  // called.
689  if (object->HasRealNamedCallbackProperty(key)) {
690    object->Delete(key);
691  } else if (object->HasRealNamedProperty(key)) {
692    v8::Handle<v8::Value> value = object->Get(key);
693    CHECK(value->IsObject());
694    return v8::Handle<v8::Object>::Cast(value);
695  }
696
697  v8::Handle<v8::Object> new_object = v8::Object::New();
698  object->Set(key, new_object);
699  return new_object;
700}
701
702void Dispatcher::AddOrRemoveBindingsForContext(ChromeV8Context* context) {
703  v8::HandleScope handle_scope(context->isolate());
704  v8::Context::Scope context_scope(context->v8_context());
705
706  // TODO(kalman): Make the bindings registration have zero overhead then run
707  // the same code regardless of context type.
708  switch (context->context_type()) {
709    case Feature::UNSPECIFIED_CONTEXT:
710    case Feature::WEB_PAGE_CONTEXT:
711    case Feature::BLESSED_WEB_PAGE_CONTEXT: {
712      // Web page context; it's too expensive to run the full bindings code.
713      // Hard-code that the app and webstore APIs are available...
714      RegisterBinding("app", context);
715      RegisterBinding("webstore", context);
716
717      // ... and that the runtime API might be available if any extension can
718      // connect to it.
719      bool runtime_is_available = false;
720      for (ExtensionSet::const_iterator it = extensions_.begin();
721           it != extensions_.end(); ++it) {
722        ExternallyConnectableInfo* info =
723            static_cast<ExternallyConnectableInfo*>((*it)->GetManifestData(
724                manifest_keys::kExternallyConnectable));
725        if (info && info->matches.MatchesURL(context->GetURL())) {
726          runtime_is_available = true;
727          break;
728        }
729      }
730      if (runtime_is_available)
731        RegisterBinding("runtime", context);
732      break;
733    }
734
735    case Feature::BLESSED_EXTENSION_CONTEXT:
736    case Feature::UNBLESSED_EXTENSION_CONTEXT:
737    case Feature::CONTENT_SCRIPT_CONTEXT: {
738      // Extension context; iterate through all the APIs and bind the available
739      // ones.
740      FeatureProvider* api_feature_provider = FeatureProvider::GetAPIFeatures();
741      const std::vector<std::string>& apis =
742          api_feature_provider->GetAllFeatureNames();
743      for (std::vector<std::string>::const_iterator it = apis.begin();
744          it != apis.end(); ++it) {
745        const std::string& api_name = *it;
746        Feature* feature = api_feature_provider->GetFeature(api_name);
747        DCHECK(feature);
748
749        // Internal APIs are included via require(api_name) from internal code
750        // rather than chrome[api_name].
751        if (feature->IsInternal())
752          continue;
753
754        // If this API name has parent features, then this must be a function or
755        // event, so we should not register.
756        bool parent_feature_available = false;
757        for (Feature* parent = api_feature_provider->GetParent(feature);
758             parent != NULL; parent = api_feature_provider->GetParent(parent)) {
759          if (context->IsAnyFeatureAvailableToContext(parent->name())) {
760            parent_feature_available = true;
761            break;
762          }
763        }
764        if (parent_feature_available)
765          continue;
766
767        if (context->IsAnyFeatureAvailableToContext(api_name))
768          RegisterBinding(api_name, context);
769      }
770      break;
771    }
772  }
773}
774
775v8::Handle<v8::Object> Dispatcher::GetOrCreateBindObjectIfAvailable(
776    const std::string& api_name,
777    std::string* bind_name,
778    ChromeV8Context* context) {
779  std::vector<std::string> split;
780  base::SplitString(api_name, '.', &split);
781
782  v8::Handle<v8::Object> bind_object;
783
784  // Check if this API has an ancestor. If the API's ancestor is available and
785  // the API is not available, don't install the bindings for this API. If
786  // the API is available and its ancestor is not, delete the ancestor and
787  // install the bindings for the API. This is to prevent loading the ancestor
788  // API schema if it will not be needed.
789  //
790  // For example:
791  //  If app is available and app.window is not, just install app.
792  //  If app.window is available and app is not, delete app and install
793  //  app.window on a new object so app does not have to be loaded.
794  FeatureProvider* api_feature_provider = FeatureProvider::GetAPIFeatures();
795  std::string ancestor_name;
796  bool only_ancestor_available = false;
797
798  for (size_t i = 0; i < split.size() - 1; ++i) {
799    ancestor_name += (i ? ".": "") + split[i];
800    if (api_feature_provider->GetFeature(ancestor_name) &&
801        context->GetAvailability(ancestor_name).is_available() &&
802        !context->GetAvailability(api_name).is_available()) {
803      only_ancestor_available = true;
804      break;
805    }
806
807    if (bind_object.IsEmpty()) {
808      bind_object = AsObjectOrEmpty(GetOrCreateChrome(context));
809      if (bind_object.IsEmpty())
810        return v8::Handle<v8::Object>();
811    }
812    bind_object = GetOrCreateObject(bind_object, split[i], context->isolate());
813  }
814
815  if (only_ancestor_available)
816    return v8::Handle<v8::Object>();
817
818  if (bind_name)
819    *bind_name = split.back();
820
821  return bind_object.IsEmpty() ?
822      AsObjectOrEmpty(GetOrCreateChrome(context)) : bind_object;
823}
824
825void Dispatcher::RegisterBinding(const std::string& api_name,
826                                 ChromeV8Context* context) {
827  std::string bind_name;
828  v8::Handle<v8::Object> bind_object =
829      GetOrCreateBindObjectIfAvailable(api_name, &bind_name, context);
830
831  // Empty if the bind object failed to be created, probably because the
832  // extension overrode chrome with a non-object, e.g. window.chrome = true.
833  if (bind_object.IsEmpty())
834    return;
835
836  v8::Local<v8::String> v8_api_name =
837      v8::String::NewFromUtf8(context->isolate(), api_name.c_str());
838  if (bind_object->HasRealNamedProperty(v8_api_name)) {
839    // The bind object may already have the property if the API has been
840    // registered before (or if the extension has put something there already,
841    // but, whatevs).
842    //
843    // In the former case, we need to re-register the bindings for the APIs
844    // which the extension now has permissions for (if any), but not touch any
845    // others so that we don't destroy state such as event listeners.
846    //
847    // TODO(kalman): Only register available APIs to make this all moot.
848    if (bind_object->HasRealNamedCallbackProperty(v8_api_name))
849      return;  // lazy binding still there, nothing to do
850    if (bind_object->Get(v8_api_name)->IsObject())
851      return;  // binding has already been fully installed
852  }
853
854  ModuleSystem* module_system = context->module_system();
855  if (lazy_bindings_map_.find(api_name) != lazy_bindings_map_.end()) {
856    InstallBindings(module_system, context->v8_context(), api_name);
857  } else if (!source_map_.Contains(api_name)) {
858    module_system->RegisterNativeHandler(
859        api_name,
860        scoped_ptr<NativeHandler>(new BindingGeneratingNativeHandler(
861            module_system,
862            api_name,
863            "binding")));
864    module_system->SetNativeLazyField(bind_object,
865                                      bind_name,
866                                      api_name,
867                                      "binding");
868  } else {
869    module_system->SetLazyField(bind_object,
870                                bind_name,
871                                api_name,
872                                "binding");
873  }
874}
875
876// NOTE: please use the naming convention "foo_natives" for these.
877void Dispatcher::RegisterNativeHandlers(ModuleSystem* module_system,
878                                        ChromeV8Context* context) {
879  module_system->RegisterNativeHandler("event_natives",
880      scoped_ptr<NativeHandler>(EventBindings::Create(this, context)));
881  module_system->RegisterNativeHandler("messaging_natives",
882      scoped_ptr<NativeHandler>(MessagingBindings::Get(this, context)));
883  module_system->RegisterNativeHandler("apiDefinitions",
884      scoped_ptr<NativeHandler>(new ApiDefinitionsNatives(this, context)));
885  module_system->RegisterNativeHandler("sendRequest",
886      scoped_ptr<NativeHandler>(
887          new SendRequestNatives(this, request_sender_.get(), context)));
888  module_system->RegisterNativeHandler("setIcon",
889      scoped_ptr<NativeHandler>(
890          new SetIconNatives(this, request_sender_.get(), context)));
891  module_system->RegisterNativeHandler("activityLogger",
892      scoped_ptr<NativeHandler>(new APIActivityLogger(this, context)));
893  module_system->RegisterNativeHandler("renderViewObserverNatives",
894      scoped_ptr<NativeHandler>(new RenderViewObserverNatives(this, context)));
895
896  // Natives used by multiple APIs.
897  module_system->RegisterNativeHandler("file_system_natives",
898      scoped_ptr<NativeHandler>(new FileSystemNatives(context)));
899
900  // Custom bindings.
901  module_system->RegisterNativeHandler("app",
902      scoped_ptr<NativeHandler>(new AppBindings(this, context)));
903  module_system->RegisterNativeHandler("app_runtime",
904      scoped_ptr<NativeHandler>(
905          new AppRuntimeCustomBindings(this, context)));
906  module_system->RegisterNativeHandler("app_window_natives",
907      scoped_ptr<NativeHandler>(
908          new AppWindowCustomBindings(this, context)));
909  module_system->RegisterNativeHandler("blob_natives",
910      scoped_ptr<NativeHandler>(new BlobNativeHandler(context)));
911  module_system->RegisterNativeHandler("context_menus",
912      scoped_ptr<NativeHandler>(
913          new ContextMenusCustomBindings(this, context)));
914  module_system->RegisterNativeHandler(
915      "css_natives", scoped_ptr<NativeHandler>(new CssNativeHandler(context)));
916  module_system->RegisterNativeHandler("document_natives",
917      scoped_ptr<NativeHandler>(
918          new DocumentCustomBindings(this, context)));
919  module_system->RegisterNativeHandler("sync_file_system",
920      scoped_ptr<NativeHandler>(
921          new SyncFileSystemCustomBindings(this, context)));
922  module_system->RegisterNativeHandler("file_browser_handler",
923      scoped_ptr<NativeHandler>(new FileBrowserHandlerCustomBindings(
924          this, context)));
925  module_system->RegisterNativeHandler("file_browser_private",
926      scoped_ptr<NativeHandler>(new FileBrowserPrivateCustomBindings(
927          this, context)));
928  module_system->RegisterNativeHandler("i18n",
929      scoped_ptr<NativeHandler>(
930          new I18NCustomBindings(this, context)));
931  module_system->RegisterNativeHandler(
932      "id_generator",
933      scoped_ptr<NativeHandler>(new IdGeneratorCustomBindings(this, context)));
934  module_system->RegisterNativeHandler("mediaGalleries",
935      scoped_ptr<NativeHandler>(
936          new MediaGalleriesCustomBindings(this, context)));
937  module_system->RegisterNativeHandler("page_actions",
938      scoped_ptr<NativeHandler>(
939          new PageActionsCustomBindings(this, context)));
940  module_system->RegisterNativeHandler("page_capture",
941      scoped_ptr<NativeHandler>(
942          new PageCaptureCustomBindings(this, context)));
943  module_system->RegisterNativeHandler(
944      "pepper_request_natives",
945      scoped_ptr<NativeHandler>(new PepperRequestNatives(context)));
946  module_system->RegisterNativeHandler("runtime",
947      scoped_ptr<NativeHandler>(new RuntimeCustomBindings(this, context)));
948  module_system->RegisterNativeHandler("tabs",
949      scoped_ptr<NativeHandler>(new TabsCustomBindings(this, context)));
950  module_system->RegisterNativeHandler("webstore",
951      scoped_ptr<NativeHandler>(new WebstoreBindings(this, context)));
952#if defined(ENABLE_WEBRTC)
953  module_system->RegisterNativeHandler("cast_streaming_natives",
954      scoped_ptr<NativeHandler>(new CastStreamingNativeHandler(context)));
955#endif
956}
957
958void Dispatcher::PopulateSourceMap() {
959  // Libraries.
960  source_map_.RegisterSource("entryIdManager", IDR_ENTRY_ID_MANAGER);
961  source_map_.RegisterSource(kEventBindings, IDR_EVENT_BINDINGS_JS);
962  source_map_.RegisterSource("imageUtil", IDR_IMAGE_UTIL_JS);
963  source_map_.RegisterSource("json_schema", IDR_JSON_SCHEMA_JS);
964  source_map_.RegisterSource("lastError", IDR_LAST_ERROR_JS);
965  source_map_.RegisterSource("messaging", IDR_MESSAGING_JS);
966  source_map_.RegisterSource("messaging_utils", IDR_MESSAGING_UTILS_JS);
967  source_map_.RegisterSource("pepper_request", IDR_PEPPER_REQUEST_JS);
968  source_map_.RegisterSource(kSchemaUtils, IDR_SCHEMA_UTILS_JS);
969  source_map_.RegisterSource("sendRequest", IDR_SEND_REQUEST_JS);
970  source_map_.RegisterSource("setIcon", IDR_SET_ICON_JS);
971  source_map_.RegisterSource("test", IDR_TEST_CUSTOM_BINDINGS_JS);
972  source_map_.RegisterSource("unload_event", IDR_UNLOAD_EVENT_JS);
973  source_map_.RegisterSource("utils", IDR_UTILS_JS);
974
975  // Custom bindings.
976  source_map_.RegisterSource("app", IDR_APP_CUSTOM_BINDINGS_JS);
977  source_map_.RegisterSource("app.runtime", IDR_APP_RUNTIME_CUSTOM_BINDINGS_JS);
978  source_map_.RegisterSource("app.window", IDR_APP_WINDOW_CUSTOM_BINDINGS_JS);
979  source_map_.RegisterSource("bluetooth", IDR_BLUETOOTH_CUSTOM_BINDINGS_JS);
980  source_map_.RegisterSource("browserAction",
981                             IDR_BROWSER_ACTION_CUSTOM_BINDINGS_JS);
982  source_map_.RegisterSource("contextMenus",
983                             IDR_CONTEXT_MENUS_CUSTOM_BINDINGS_JS);
984  source_map_.RegisterSource("declarativeContent",
985                             IDR_DECLARATIVE_CONTENT_CUSTOM_BINDINGS_JS);
986  source_map_.RegisterSource("declarativeWebRequest",
987                             IDR_DECLARATIVE_WEBREQUEST_CUSTOM_BINDINGS_JS);
988  source_map_.RegisterSource("desktopCapture",
989                             IDR_DESKTOP_CAPTURE_CUSTOM_BINDINGS_JS);
990  source_map_.RegisterSource("downloads",
991                             IDR_DOWNLOADS_CUSTOM_BINDINGS_JS);
992  source_map_.RegisterSource("experimental.offscreen",
993                             IDR_EXPERIMENTAL_OFFSCREENTABS_CUSTOM_BINDINGS_JS);
994  source_map_.RegisterSource("extension", IDR_EXTENSION_CUSTOM_BINDINGS_JS);
995  source_map_.RegisterSource("feedbackPrivate",
996                             IDR_FEEDBACK_PRIVATE_CUSTOM_BINDINGS_JS);
997  source_map_.RegisterSource("fileBrowserHandler",
998                             IDR_FILE_BROWSER_HANDLER_CUSTOM_BINDINGS_JS);
999  source_map_.RegisterSource("fileBrowserPrivate",
1000                             IDR_FILE_BROWSER_PRIVATE_CUSTOM_BINDINGS_JS);
1001  source_map_.RegisterSource("fileSystem",
1002                             IDR_FILE_SYSTEM_CUSTOM_BINDINGS_JS);
1003  source_map_.RegisterSource("fileSystemProvider",
1004                             IDR_FILE_SYSTEM_PROVIDER_CUSTOM_BINDINGS_JS);
1005  source_map_.RegisterSource("gcm",
1006                             IDR_GCM_CUSTOM_BINDINGS_JS);
1007  source_map_.RegisterSource("i18n", IDR_I18N_CUSTOM_BINDINGS_JS);
1008  source_map_.RegisterSource("identity", IDR_IDENTITY_CUSTOM_BINDINGS_JS);
1009  source_map_.RegisterSource("imageWriterPrivate",
1010                             IDR_IMAGE_WRITER_PRIVATE_CUSTOM_BINDINGS_JS);
1011  source_map_.RegisterSource("input.ime", IDR_INPUT_IME_CUSTOM_BINDINGS_JS);
1012  source_map_.RegisterSource("mediaGalleries",
1013                             IDR_MEDIA_GALLERIES_CUSTOM_BINDINGS_JS);
1014  source_map_.RegisterSource("notifications",
1015                             IDR_NOTIFICATIONS_CUSTOM_BINDINGS_JS);
1016  source_map_.RegisterSource("omnibox", IDR_OMNIBOX_CUSTOM_BINDINGS_JS);
1017  source_map_.RegisterSource("pageActions",
1018                             IDR_PAGE_ACTIONS_CUSTOM_BINDINGS_JS);
1019  source_map_.RegisterSource("pageAction", IDR_PAGE_ACTION_CUSTOM_BINDINGS_JS);
1020  source_map_.RegisterSource("pageCapture",
1021                             IDR_PAGE_CAPTURE_CUSTOM_BINDINGS_JS);
1022  source_map_.RegisterSource("permissions", IDR_PERMISSIONS_CUSTOM_BINDINGS_JS);
1023  source_map_.RegisterSource("runtime", IDR_RUNTIME_CUSTOM_BINDINGS_JS);
1024  source_map_.RegisterSource("syncFileSystem",
1025                             IDR_SYNC_FILE_SYSTEM_CUSTOM_BINDINGS_JS);
1026  source_map_.RegisterSource("systemIndicator",
1027                             IDR_SYSTEM_INDICATOR_CUSTOM_BINDINGS_JS);
1028  source_map_.RegisterSource("tabCapture", IDR_TAB_CAPTURE_CUSTOM_BINDINGS_JS);
1029  source_map_.RegisterSource("tabs", IDR_TABS_CUSTOM_BINDINGS_JS);
1030  source_map_.RegisterSource("tts", IDR_TTS_CUSTOM_BINDINGS_JS);
1031  source_map_.RegisterSource("ttsEngine", IDR_TTS_ENGINE_CUSTOM_BINDINGS_JS);
1032  source_map_.RegisterSource("webRequest", IDR_WEB_REQUEST_CUSTOM_BINDINGS_JS);
1033  source_map_.RegisterSource("webRequestInternal",
1034                             IDR_WEB_REQUEST_INTERNAL_CUSTOM_BINDINGS_JS);
1035#if defined(ENABLE_WEBRTC)
1036  source_map_.RegisterSource("cast.streaming.rtpStream",
1037                             IDR_CAST_STREAMING_RTP_STREAM_CUSTOM_BINDINGS_JS);
1038  source_map_.RegisterSource("cast.streaming.session",
1039                             IDR_CAST_STREAMING_SESSION_CUSTOM_BINDINGS_JS);
1040  source_map_.RegisterSource(
1041      "cast.streaming.udpTransport",
1042      IDR_CAST_STREAMING_UDP_TRANSPORT_CUSTOM_BINDINGS_JS);
1043#endif
1044  source_map_.RegisterSource("webstore", IDR_WEBSTORE_CUSTOM_BINDINGS_JS);
1045  source_map_.RegisterSource("windowControls", IDR_WINDOW_CONTROLS_JS);
1046  source_map_.RegisterSource("binding", IDR_BINDING_JS);
1047
1048  // Custom types sources.
1049  source_map_.RegisterSource("ChromeSetting", IDR_CHROME_SETTING_JS);
1050  source_map_.RegisterSource("StorageArea", IDR_STORAGE_AREA_JS);
1051  source_map_.RegisterSource("ContentSetting", IDR_CONTENT_SETTING_JS);
1052  source_map_.RegisterSource("ChromeDirectSetting",
1053                             IDR_CHROME_DIRECT_SETTING_JS);
1054
1055  // Platform app sources that are not API-specific..
1056  source_map_.RegisterSource("tagWatcher", IDR_TAG_WATCHER_JS);
1057  // Note: webView not webview so that this doesn't interfere with the
1058  // chrome.webview API bindings.
1059  source_map_.RegisterSource("webView", IDR_WEB_VIEW_JS);
1060  source_map_.RegisterSource("webViewExperimental",
1061                             IDR_WEB_VIEW_EXPERIMENTAL_JS);
1062  source_map_.RegisterSource("webViewRequest",
1063                             IDR_WEB_VIEW_REQUEST_CUSTOM_BINDINGS_JS);
1064  source_map_.RegisterSource("denyWebView", IDR_WEB_VIEW_DENY_JS);
1065  source_map_.RegisterSource("adView", IDR_AD_VIEW_JS);
1066  source_map_.RegisterSource("denyAdView", IDR_AD_VIEW_DENY_JS);
1067  source_map_.RegisterSource("platformApp", IDR_PLATFORM_APP_JS);
1068  source_map_.RegisterSource("injectAppTitlebar", IDR_INJECT_APP_TITLEBAR_JS);
1069}
1070
1071void Dispatcher::PopulateLazyBindingsMap() {
1072  lazy_bindings_map_["app"] = InstallAppBindings;
1073  lazy_bindings_map_["webstore"] = InstallWebstoreBindings;
1074}
1075
1076void Dispatcher::InstallBindings(ModuleSystem* module_system,
1077                                 v8::Handle<v8::Context> v8_context,
1078                                 const std::string& api) {
1079  std::map<std::string, BindingInstaller>::const_iterator lazy_binding =
1080      lazy_bindings_map_.find(api);
1081  if (lazy_binding != lazy_bindings_map_.end()) {
1082    v8::Handle<v8::Object> global(v8_context->Global());
1083    v8::Handle<v8::Object> chrome =
1084        global->Get(v8::String::NewFromUtf8(v8_context->GetIsolate(), "chrome"))
1085            ->ToObject();
1086    (*lazy_binding->second)(module_system, chrome);
1087  } else {
1088    module_system->Require(api);
1089  }
1090}
1091
1092void Dispatcher::DidCreateScriptContext(
1093    WebFrame* frame, v8::Handle<v8::Context> v8_context, int extension_group,
1094    int world_id) {
1095#if !defined(ENABLE_EXTENSIONS)
1096  return;
1097#endif
1098
1099  std::string extension_id = GetExtensionID(frame, world_id);
1100
1101  const Extension* extension = extensions_.GetByID(extension_id);
1102  if (!extension && !extension_id.empty()) {
1103    // There are conditions where despite a context being associated with an
1104    // extension, no extension actually gets found.  Ignore "invalid" because
1105    // CSP blocks extension page loading by switching the extension ID to
1106    // "invalid". This isn't interesting.
1107    if (extension_id != "invalid") {
1108      LOG(ERROR) << "Extension \"" << extension_id << "\" not found";
1109      RenderThread::Get()->RecordAction(
1110          UserMetricsAction("ExtensionNotFound_ED"));
1111    }
1112
1113    extension_id = "";
1114  }
1115
1116  Feature::Context context_type = ClassifyJavaScriptContext(
1117      extension,
1118      extension_group,
1119      UserScriptSlave::GetDataSourceURLForFrame(frame),
1120      frame->document().securityOrigin());
1121
1122  ChromeV8Context* context =
1123      new ChromeV8Context(v8_context, frame, extension, context_type);
1124  v8_context_set_.Add(context);
1125
1126  {
1127    scoped_ptr<ModuleSystem> module_system(new ModuleSystem(context,
1128                                                            &source_map_));
1129    context->set_module_system(module_system.Pass());
1130  }
1131  ModuleSystem* module_system = context->module_system();
1132
1133  // Enable natives in startup.
1134  ModuleSystem::NativesEnabledScope natives_enabled_scope(
1135      module_system);
1136
1137  RegisterNativeHandlers(module_system, context);
1138
1139  module_system->RegisterNativeHandler("chrome",
1140      scoped_ptr<NativeHandler>(new ChromeNativeHandler(context)));
1141  module_system->RegisterNativeHandler("print",
1142      scoped_ptr<NativeHandler>(new PrintNativeHandler(context)));
1143  module_system->RegisterNativeHandler("lazy_background_page",
1144      scoped_ptr<NativeHandler>(
1145          new LazyBackgroundPageNativeHandler(this, context)));
1146  module_system->RegisterNativeHandler("logging",
1147      scoped_ptr<NativeHandler>(new LoggingNativeHandler(context)));
1148  module_system->RegisterNativeHandler("schema_registry",
1149      v8_schema_registry_->AsNativeHandler());
1150  module_system->RegisterNativeHandler("v8_context",
1151      scoped_ptr<NativeHandler>(new V8ContextNativeHandler(context, this)));
1152  module_system->RegisterNativeHandler("test_features",
1153      scoped_ptr<NativeHandler>(new TestFeaturesNativeHandler(context)));
1154  module_system->RegisterNativeHandler("user_gestures",
1155      scoped_ptr<NativeHandler>(new UserGesturesNativeHandler(context)));
1156
1157  int manifest_version = extension ? extension->manifest_version() : 1;
1158  bool send_request_disabled =
1159      (extension && Manifest::IsUnpackedLocation(extension->location()) &&
1160       BackgroundInfo::HasLazyBackgroundPage(extension));
1161  module_system->RegisterNativeHandler("process",
1162      scoped_ptr<NativeHandler>(new ProcessInfoNativeHandler(
1163          this, context, context->GetExtensionID(),
1164          context->GetContextTypeDescription(),
1165          ChromeRenderProcessObserver::is_incognito_process(),
1166          manifest_version, send_request_disabled)));
1167
1168  // chrome.Event is part of the public API (although undocumented). Make it
1169  // lazily evalulate to Event from event_bindings.js. For extensions only
1170  // though, not all webpages!
1171  if (context->extension()) {
1172    v8::Handle<v8::Object> chrome = AsObjectOrEmpty(GetOrCreateChrome(context));
1173    if (!chrome.IsEmpty())
1174      module_system->SetLazyField(chrome, "Event", kEventBindings, "Event");
1175  }
1176
1177  AddOrRemoveBindingsForContext(context);
1178
1179  bool is_within_platform_app = IsWithinPlatformApp();
1180  // Inject custom JS into the platform app context.
1181  if (is_within_platform_app) {
1182    module_system->Require("platformApp");
1183  }
1184
1185  if (context_type == Feature::BLESSED_EXTENSION_CONTEXT &&
1186      is_within_platform_app &&
1187      GetCurrentChannel() <= chrome::VersionInfo::CHANNEL_DEV &&
1188      CommandLine::ForCurrentProcess()->HasSwitch(
1189          switches::kEnableAppWindowControls)) {
1190    module_system->Require("windowControls");
1191  }
1192
1193  // Currently only platform apps and whitelisted component extensions support
1194  // the <webview> tag, because the "denyWebView" module will affect the
1195  // performance of DOM modifications (http://crbug.com/196453).
1196  // We used to limit WebView to |BLESSED_EXTENSION_CONTEXT| within platform
1197  // apps. An ext/app runs in a blessed extension context, if it is the active
1198  // extension in the current process, in other words, if it is loaded in a top
1199  // frame. To support webview in a non-frame extension, we have to allow
1200  // unblessed extension context as well.
1201  if (context_type == Feature::BLESSED_EXTENSION_CONTEXT ||
1202      context_type == Feature::UNBLESSED_EXTENSION_CONTEXT) {
1203    // Note: setting up the WebView class here, not the chrome.webview API.
1204    // The API will be automatically set up when first used.
1205    if (extension->HasAPIPermission(APIPermission::kWebView)) {
1206      module_system->Require("webView");
1207      bool includeExperimental =
1208          GetCurrentChannel() <= chrome::VersionInfo::CHANNEL_DEV;
1209      if (!includeExperimental) {
1210        // TODO(asargent) We need a whitelist for webview experimental.
1211        // crbug.com/264852
1212        std::string id_hash = base::SHA1HashString(extension->id());
1213        std::string hexencoded_id_hash = base::HexEncode(id_hash.c_str(),
1214                                                         id_hash.length());
1215        if (hexencoded_id_hash == "8C3741E3AF0B93B6E8E0DDD499BB0B74839EA578" ||
1216            hexencoded_id_hash == "E703483CEF33DEC18B4B6DD84B5C776FB9182BDB" ||
1217            hexencoded_id_hash == "1A26E32DE447A17CBE5E9750CDBA78F58539B39C" ||
1218            hexencoded_id_hash == "59048028102D7B4C681DBC7BC6CD980C3DC66DA3")
1219          includeExperimental = true;
1220      }
1221      if (includeExperimental)
1222        module_system->Require("webViewExperimental");
1223    } else {
1224      module_system->Require("denyWebView");
1225    }
1226  }
1227
1228  // Same comment as above for <adview> tag.
1229  if (context_type == Feature::BLESSED_EXTENSION_CONTEXT &&
1230      is_within_platform_app) {
1231    if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnableAdview)) {
1232      if (extension->HasAPIPermission(APIPermission::kAdView)) {
1233        module_system->Require("adView");
1234      } else {
1235        module_system->Require("denyAdView");
1236      }
1237    }
1238  }
1239
1240  VLOG(1) << "Num tracked contexts: " << v8_context_set_.size();
1241}
1242
1243std::string Dispatcher::GetExtensionID(const WebFrame* frame, int world_id) {
1244  if (world_id != 0) {
1245    // Isolated worlds (content script).
1246    return user_script_slave_->GetExtensionIdForIsolatedWorld(world_id);
1247  }
1248
1249  // TODO(kalman): Delete this check.
1250  if (frame->document().securityOrigin().isUnique())
1251    return std::string();
1252
1253  // Extension pages (chrome-extension:// URLs).
1254  GURL frame_url = UserScriptSlave::GetDataSourceURLForFrame(frame);
1255  return extensions_.GetExtensionOrAppIDByURL(frame_url);
1256}
1257
1258bool Dispatcher::IsWithinPlatformApp() {
1259  for (std::set<std::string>::iterator iter = active_extension_ids_.begin();
1260       iter != active_extension_ids_.end(); ++iter) {
1261    const Extension* extension = extensions_.GetByID(*iter);
1262    if (extension && extension->is_platform_app())
1263      return true;
1264  }
1265  return false;
1266}
1267
1268void Dispatcher::WillReleaseScriptContext(
1269    WebFrame* frame, v8::Handle<v8::Context> v8_context, int world_id) {
1270  ChromeV8Context* context = v8_context_set_.GetByV8Context(v8_context);
1271  if (!context)
1272    return;
1273
1274  // If the V8 context has an OOM exception, javascript execution has been
1275  // stopped, so dispatching an onUnload event is pointless.
1276  if (!v8_context->HasOutOfMemoryException())
1277    context->DispatchOnUnloadEvent();
1278  // TODO(kalman): add an invalidation observer interface to ChromeV8Context.
1279  request_sender_->InvalidateSource(context);
1280
1281  v8_context_set_.Remove(context);
1282  VLOG(1) << "Num tracked contexts: " << v8_context_set_.size();
1283}
1284
1285void Dispatcher::DidCreateDocumentElement(blink::WebFrame* frame) {
1286  if (IsWithinPlatformApp()) {
1287    // WebKit doesn't let us define an additional user agent stylesheet, so we
1288    // insert the default platform app stylesheet into all documents that are
1289    // loaded in each app.
1290    std::string stylesheet =
1291        ResourceBundle::GetSharedInstance().
1292            GetRawDataResource(IDR_PLATFORM_APP_CSS).as_string();
1293    ReplaceFirstSubstringAfterOffset(&stylesheet, 0,
1294                                     "$FONTFAMILY", system_font_family_);
1295    ReplaceFirstSubstringAfterOffset(&stylesheet, 0,
1296                                     "$FONTSIZE", system_font_size_);
1297    frame->document().insertUserStyleSheet(
1298        WebString::fromUTF8(stylesheet), WebDocument::UserStyleAuthorLevel);
1299  }
1300
1301  content_watcher_->DidCreateDocumentElement(frame);
1302}
1303
1304void Dispatcher::DidMatchCSS(
1305    blink::WebFrame* frame,
1306    const blink::WebVector<blink::WebString>& newly_matching_selectors,
1307    const blink::WebVector<blink::WebString>& stopped_matching_selectors) {
1308  content_watcher_->DidMatchCSS(
1309      frame, newly_matching_selectors, stopped_matching_selectors);
1310}
1311
1312
1313void Dispatcher::OnActivateExtension(const std::string& extension_id) {
1314  const Extension* extension = extensions_.GetByID(extension_id);
1315  if (!extension) {
1316    // Extension was activated but was never loaded. This probably means that
1317    // the renderer failed to load it (or the browser failed to tell us when it
1318    // did). Failures shouldn't happen, but instead of crashing there (which
1319    // executes on all renderers) be conservative and only crash in the renderer
1320    // of the extension which failed to load; this one.
1321    std::string& error = extension_load_errors_[extension_id];
1322    char minidump[256];
1323    base::debug::Alias(&minidump);
1324    base::snprintf(minidump, arraysize(minidump),
1325        "e::dispatcher:%s:%s", extension_id.c_str(), error.c_str());
1326    CHECK(extension) << extension_id << " was never loaded: " << error;
1327  }
1328
1329  active_extension_ids_.insert(extension_id);
1330
1331  // This is called when starting a new extension page, so start the idle
1332  // handler ticking.
1333  RenderThread::Get()->ScheduleIdleHandler(kInitialExtensionIdleHandlerDelayMs);
1334
1335  UpdateActiveExtensions();
1336
1337  if (is_webkit_initialized_) {
1338    InitOriginPermissions(extension);
1339    DOMActivityLogger::AttachToWorld(DOMActivityLogger::kMainWorldId,
1340                                     extension_id);
1341  }
1342}
1343
1344void Dispatcher::InitOriginPermissions(const Extension* extension) {
1345  // TODO(jstritar): We should try to remove this special case. Also, these
1346  // whitelist entries need to be updated when the kManagement permission
1347  // changes.
1348  if (extension->HasAPIPermission(APIPermission::kManagement)) {
1349    WebSecurityPolicy::addOriginAccessWhitelistEntry(
1350        extension->url(),
1351        WebString::fromUTF8(chrome::kChromeUIScheme),
1352        WebString::fromUTF8(chrome::kChromeUIExtensionIconHost),
1353        false);
1354  }
1355
1356  AddOrRemoveOriginPermissions(
1357      UpdatedExtensionPermissionsInfo::ADDED,
1358      extension,
1359      extension->GetActivePermissions()->explicit_hosts());
1360}
1361
1362void Dispatcher::AddOrRemoveOriginPermissions(
1363    UpdatedExtensionPermissionsInfo::Reason reason,
1364    const Extension* extension,
1365    const URLPatternSet& origins) {
1366  for (URLPatternSet::const_iterator i = origins.begin();
1367       i != origins.end(); ++i) {
1368    const char* schemes[] = {
1369      content::kHttpScheme,
1370      content::kHttpsScheme,
1371      chrome::kFileScheme,
1372      chrome::kChromeUIScheme,
1373    };
1374    for (size_t j = 0; j < arraysize(schemes); ++j) {
1375      if (i->MatchesScheme(schemes[j])) {
1376        ((reason == UpdatedExtensionPermissionsInfo::REMOVED) ?
1377         WebSecurityPolicy::removeOriginAccessWhitelistEntry :
1378         WebSecurityPolicy::addOriginAccessWhitelistEntry)(
1379              extension->url(),
1380              WebString::fromUTF8(schemes[j]),
1381              WebString::fromUTF8(i->host()),
1382              i->match_subdomains());
1383      }
1384    }
1385  }
1386}
1387
1388void Dispatcher::EnableCustomElementWhiteList() {
1389  blink::WebRuntimeFeatures::enableEmbedderCustomElements(true);
1390  blink::WebCustomElement::addEmbedderCustomElementName("webview");
1391  // TODO(fsamuel): Add <adview> to the whitelist once it has been converted
1392  // into a custom element.
1393  blink::WebCustomElement::addEmbedderCustomElementName("browser-plugin");
1394}
1395
1396void Dispatcher::AddOrRemoveBindings(const std::string& extension_id) {
1397  v8_context_set().ForEach(
1398      extension_id,
1399      NULL,  // all render views
1400      base::Bind(&Dispatcher::AddOrRemoveBindingsForContext,
1401                 base::Unretained(this)));
1402}
1403
1404void Dispatcher::OnUpdatePermissions(
1405  const ExtensionMsg_UpdatePermissions_Params& params) {
1406  int reason_id = params.reason_id;
1407  const std::string& extension_id = params.extension_id;
1408  const APIPermissionSet& apis = params.apis;
1409  const ManifestPermissionSet& manifest_permissions =
1410      params.manifest_permissions;
1411  const URLPatternSet& explicit_hosts = params.explicit_hosts;
1412  const URLPatternSet& scriptable_hosts = params.scriptable_hosts;
1413
1414  const Extension* extension = extensions_.GetByID(extension_id);
1415  if (!extension)
1416    return;
1417
1418  scoped_refptr<const PermissionSet> delta =
1419      new PermissionSet(apis, manifest_permissions,
1420                        explicit_hosts, scriptable_hosts);
1421  scoped_refptr<const PermissionSet> old_active =
1422      extension->GetActivePermissions();
1423  UpdatedExtensionPermissionsInfo::Reason reason =
1424      static_cast<UpdatedExtensionPermissionsInfo::Reason>(reason_id);
1425
1426  const PermissionSet* new_active = NULL;
1427  switch (reason) {
1428    case UpdatedExtensionPermissionsInfo::ADDED:
1429      new_active = PermissionSet::CreateUnion(old_active.get(), delta.get());
1430      break;
1431    case UpdatedExtensionPermissionsInfo::REMOVED:
1432      new_active =
1433          PermissionSet::CreateDifference(old_active.get(), delta.get());
1434      break;
1435  }
1436
1437  PermissionsData::SetActivePermissions(extension, new_active);
1438  AddOrRemoveOriginPermissions(reason, extension, explicit_hosts);
1439  AddOrRemoveBindings(extension->id());
1440}
1441
1442void Dispatcher::OnUpdateTabSpecificPermissions(
1443    int page_id,
1444    int tab_id,
1445    const std::string& extension_id,
1446    const URLPatternSet& origin_set) {
1447  RenderView* view = TabFinder::Find(tab_id);
1448
1449  // For now, the message should only be sent to the render view that contains
1450  // the target tab. This may change. Either way, if this is the target tab it
1451  // gives us the chance to check against the page ID to avoid races.
1452  DCHECK(view);
1453  if (view && view->GetPageId() != page_id)
1454    return;
1455
1456  const Extension* extension = extensions_.GetByID(extension_id);
1457  if (!extension)
1458    return;
1459
1460  PermissionsData::UpdateTabSpecificPermissions(
1461      extension,
1462      tab_id,
1463      new PermissionSet(APIPermissionSet(), ManifestPermissionSet(),
1464                        origin_set, URLPatternSet()));
1465}
1466
1467void Dispatcher::OnClearTabSpecificPermissions(
1468    int tab_id,
1469    const std::vector<std::string>& extension_ids) {
1470  for (std::vector<std::string>::const_iterator it = extension_ids.begin();
1471       it != extension_ids.end(); ++it) {
1472    const Extension* extension = extensions_.GetByID(*it);
1473    if (extension)
1474      PermissionsData::ClearTabSpecificPermissions(extension, tab_id);
1475  }
1476}
1477
1478void Dispatcher::OnUpdateUserScripts(
1479    base::SharedMemoryHandle scripts) {
1480  DCHECK(base::SharedMemory::IsHandleValid(scripts)) << "Bad scripts handle";
1481  user_script_slave_->UpdateScripts(scripts);
1482  UpdateActiveExtensions();
1483}
1484
1485void Dispatcher::UpdateActiveExtensions() {
1486  // In single-process mode, the browser process reports the active extensions.
1487  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kSingleProcess))
1488    return;
1489
1490  std::set<std::string> active_extensions = active_extension_ids_;
1491  user_script_slave_->GetActiveExtensions(&active_extensions);
1492  crash_keys::SetActiveExtensions(active_extensions);
1493}
1494
1495void Dispatcher::OnUsingWebRequestAPI(
1496    bool adblock, bool adblock_plus, bool other) {
1497  webrequest_adblock_ = adblock;
1498  webrequest_adblock_plus_ = adblock_plus;
1499  webrequest_other_ = other;
1500}
1501
1502void Dispatcher::OnShouldSuspend(const std::string& extension_id,
1503                                 int sequence_id) {
1504  RenderThread::Get()->Send(
1505      new ExtensionHostMsg_ShouldSuspendAck(extension_id, sequence_id));
1506}
1507
1508void Dispatcher::OnSuspend(const std::string& extension_id) {
1509  // Dispatch the suspend event. This doesn't go through the standard event
1510  // dispatch machinery because it requires special handling. We need to let
1511  // the browser know when we are starting and stopping the event dispatch, so
1512  // that it still considers the extension idle despite any activity the suspend
1513  // event creates.
1514  DispatchEvent(extension_id, kOnSuspendEvent);
1515  RenderThread::Get()->Send(new ExtensionHostMsg_SuspendAck(extension_id));
1516}
1517
1518void Dispatcher::OnCancelSuspend(const std::string& extension_id) {
1519  DispatchEvent(extension_id, kOnSuspendCanceledEvent);
1520}
1521
1522// TODO(kalman): This is checking for the wrong thing, it should be checking if
1523// the frame's security origin is unique. The extension sandbox directive is
1524// checked for in extensions/common/manifest_handlers/csp_info.cc.
1525bool Dispatcher::IsSandboxedPage(const GURL& url) const {
1526  if (url.SchemeIs(kExtensionScheme)) {
1527    const Extension* extension = extensions_.GetByID(url.host());
1528    if (extension) {
1529      return SandboxedPageInfo::IsSandboxedPage(extension, url.path());
1530    }
1531  }
1532  return false;
1533}
1534
1535Feature::Context Dispatcher::ClassifyJavaScriptContext(
1536    const Extension* extension,
1537    int extension_group,
1538    const GURL& url,
1539    const blink::WebSecurityOrigin& origin) {
1540  DCHECK_GE(extension_group, 0);
1541  if (extension_group == EXTENSION_GROUP_CONTENT_SCRIPTS) {
1542    return extension ?  // TODO(kalman): when does this happen?
1543        Feature::CONTENT_SCRIPT_CONTEXT : Feature::UNSPECIFIED_CONTEXT;
1544  }
1545
1546  // We have an explicit check for sandboxed pages before checking whether the
1547  // extension is active in this process because:
1548  // 1. Sandboxed pages run in the same process as regular extension pages, so
1549  //    the extension is considered active.
1550  // 2. ScriptContext creation (which triggers bindings injection) happens
1551  //    before the SecurityContext is updated with the sandbox flags (after
1552  //    reading the CSP header), so the caller can't check if the context's
1553  //    security origin is unique yet.
1554  if (IsSandboxedPage(url))
1555    return Feature::WEB_PAGE_CONTEXT;
1556
1557  if (extension && IsExtensionActive(extension->id())) {
1558    // |extension| is active in this process, but it could be either a true
1559    // extension process or within the extent of a hosted app. In the latter
1560    // case this would usually be considered a (blessed) web page context,
1561    // unless the extension in question is a component extension, in which case
1562    // we cheat and call it blessed.
1563    return (extension->is_hosted_app() &&
1564            extension->location() != Manifest::COMPONENT) ?
1565        Feature::BLESSED_WEB_PAGE_CONTEXT : Feature::BLESSED_EXTENSION_CONTEXT;
1566  }
1567
1568  // TODO(kalman): This isUnique() check is wrong, it should be performed as
1569  // part of IsSandboxedPage().
1570  if (!origin.isUnique() && extensions_.ExtensionBindingsAllowed(url)) {
1571    if (!extension)  // TODO(kalman): when does this happen?
1572      return Feature::UNSPECIFIED_CONTEXT;
1573    return extension->is_hosted_app() ?
1574        Feature::BLESSED_WEB_PAGE_CONTEXT :
1575        Feature::UNBLESSED_EXTENSION_CONTEXT;
1576  }
1577
1578  if (url.is_valid())
1579    return Feature::WEB_PAGE_CONTEXT;
1580
1581  return Feature::UNSPECIFIED_CONTEXT;
1582}
1583
1584void Dispatcher::OnExtensionResponse(int request_id,
1585                                     bool success,
1586                                     const base::ListValue& response,
1587                                     const std::string& error) {
1588  request_sender_->HandleResponse(request_id, success, response, error);
1589}
1590
1591bool Dispatcher::CheckContextAccessToExtensionAPI(
1592    const std::string& function_name, ChromeV8Context* context) const {
1593  if (!context) {
1594    DLOG(ERROR) << "Not in a v8::Context";
1595    return false;
1596  }
1597
1598  if (!context->extension()) {
1599    context->isolate()->ThrowException(v8::Exception::Error(
1600        v8::String::NewFromUtf8(context->isolate(), "Not in an extension.")));
1601    return false;
1602  }
1603
1604  // Theoretically we could end up with bindings being injected into sandboxed
1605  // frames, for example content scripts. Don't let them execute API functions.
1606  blink::WebFrame* frame = context->web_frame();
1607  if (IsSandboxedPage(UserScriptSlave::GetDataSourceURLForFrame(frame))) {
1608    static const char kMessage[] =
1609        "%s cannot be used within a sandboxed frame.";
1610    std::string error_msg = base::StringPrintf(kMessage, function_name.c_str());
1611    context->isolate()->ThrowException(v8::Exception::Error(
1612        v8::String::NewFromUtf8(context->isolate(), error_msg.c_str())));
1613    return false;
1614  }
1615
1616  Feature::Availability availability = context->GetAvailability(function_name);
1617  if (!availability.is_available()) {
1618    context->isolate()->ThrowException(
1619        v8::Exception::Error(v8::String::NewFromUtf8(
1620            context->isolate(), availability.message().c_str())));
1621  }
1622
1623  return availability.is_available();
1624}
1625
1626void Dispatcher::DispatchEvent(const std::string& extension_id,
1627                               const std::string& event_name) const {
1628  base::ListValue args;
1629  args.Set(0, new base::StringValue(event_name));
1630  args.Set(1, new base::ListValue());
1631
1632  // Needed for Windows compilation, since kEventBindings is declared extern.
1633  const char* local_event_bindings = kEventBindings;
1634  v8_context_set_.ForEach(
1635      extension_id,
1636      NULL,  // all render views
1637      base::Bind(&CallModuleMethod,
1638                 local_event_bindings,
1639                 kEventDispatchFunction,
1640                 &args));
1641}
1642
1643void Dispatcher::InvokeModuleSystemMethod(
1644      content::RenderView* render_view,
1645      const std::string& extension_id,
1646      const std::string& module_name,
1647      const std::string& function_name,
1648      const base::ListValue& args,
1649      bool user_gesture) {
1650  scoped_ptr<WebScopedUserGesture> web_user_gesture;
1651  if (user_gesture)
1652    web_user_gesture.reset(new WebScopedUserGesture);
1653
1654  v8_context_set_.ForEach(
1655      extension_id,
1656      render_view,
1657      base::Bind(&CallModuleMethod, module_name, function_name, &args));
1658
1659  // Reset the idle handler each time there's any activity like event or message
1660  // dispatch, for which Invoke is the chokepoint.
1661  if (is_extension_process_) {
1662    RenderThread::Get()->ScheduleIdleHandler(
1663        kInitialExtensionIdleHandlerDelayMs);
1664  }
1665
1666  // Tell the browser process when an event has been dispatched with a lazy
1667  // background page active.
1668  const Extension* extension = extensions_.GetByID(extension_id);
1669  if (extension && BackgroundInfo::HasLazyBackgroundPage(extension) &&
1670      module_name == kEventBindings &&
1671      function_name == kEventDispatchFunction) {
1672    RenderView* background_view =
1673        ExtensionHelper::GetBackgroundPage(extension_id);
1674    if (background_view) {
1675      background_view->Send(new ExtensionHostMsg_EventAck(
1676          background_view->GetRoutingID()));
1677    }
1678  }
1679}
1680
1681}  // namespace extensions
1682