blob: 88f7f98e76137174256b879757fd233a815fb3a9 [file] [log] [blame]
[email protected]a76226d2012-04-11 07:58:291// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]2ee1e3a2011-10-04 15:04:042// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
[email protected]27131e72011-10-06 03:34:565#include "chrome/renderer/extensions/chrome_v8_context_set.h"
[email protected]2ee1e3a2011-10-04 15:04:046
7#include "base/logging.h"
8#include "base/message_loop.h"
9#include "base/tracked_objects.h"
[email protected]526476902011-10-06 20:34:0610#include "base/values.h"
[email protected]1c321ee2012-05-21 03:02:3411#include "chrome/common/extensions/extension.h"
[email protected]2a80aee2011-10-07 16:06:0312#include "chrome/common/url_constants.h"
[email protected]27131e72011-10-06 03:34:5613#include "chrome/renderer/extensions/chrome_v8_context.h"
[email protected]526476902011-10-06 20:34:0614#include "content/public/renderer/render_thread.h"
[email protected]a2ef54c2011-10-10 16:20:3115#include "content/public/renderer/render_view.h"
[email protected]885c0e92012-11-13 20:27:4216#include "content/public/renderer/v8_value_converter.h"
17#include "extensions/common/constants.h"
[email protected]61abbb72d2013-01-10 05:59:0818#include "third_party/WebKit/Source/Platform/chromium/public/WebURL.h"
19#include "third_party/WebKit/Source/Platform/chromium/public/WebURLRequest.h"
[email protected]885c0e92012-11-13 20:27:4220#include "third_party/WebKit/Source/WebKit/chromium/public/WebDocument.h"
21#include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h"
[email protected]2ee1e3a2011-10-04 15:04:0422#include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h"
[email protected]885c0e92012-11-13 20:27:4223#include "v8/include/v8.h"
[email protected]2ee1e3a2011-10-04 15:04:0424
[email protected]526476902011-10-06 20:34:0625using content::RenderThread;
[email protected]8d86f13d2011-10-04 17:01:1926using content::V8ValueConverter;
27
[email protected]8fe74bf2012-08-07 21:08:4228namespace extensions {
29
[email protected]2ee1e3a2011-10-04 15:04:0430namespace {
31
32// Returns true if the extension running in the given |render_view| has
33// sufficient permissions to access the data.
34//
35// TODO(aa): This looks super suspicious. Is it correct? Can we use something
36// else already in the system? Should it be moved elsewhere?
[email protected]a2ef54c2011-10-10 16:20:3137 bool HasSufficientPermissions(content::RenderView* render_view,
38 const GURL& event_url) {
[email protected]2ee1e3a2011-10-04 15:04:0439 // During unit tests, we might be invoked without a v8 context. In these
40 // cases, we only allow empty event_urls and short-circuit before retrieving
41 // the render view from the current context.
42 if (!event_url.is_valid())
43 return true;
44
45 WebKit::WebDocument document =
[email protected]a2ef54c2011-10-10 16:20:3146 render_view->GetWebView()->mainFrame()->document();
[email protected]885c0e92012-11-13 20:27:4247 return GURL(document.url()).SchemeIs(extensions::kExtensionScheme) &&
[email protected]2ee1e3a2011-10-04 15:04:0448 document.securityOrigin().canRequest(event_url);
49}
50
[email protected]303aaaa2013-01-04 22:59:5851} // namespace
[email protected]2ee1e3a2011-10-04 15:04:0452
[email protected]27131e72011-10-06 03:34:5653ChromeV8ContextSet::ChromeV8ContextSet() {
[email protected]2ee1e3a2011-10-04 15:04:0454}
[email protected]27131e72011-10-06 03:34:5655ChromeV8ContextSet::~ChromeV8ContextSet() {
[email protected]2ee1e3a2011-10-04 15:04:0456}
57
[email protected]27131e72011-10-06 03:34:5658int ChromeV8ContextSet::size() const {
[email protected]2ee1e3a2011-10-04 15:04:0459 return static_cast<int>(contexts_.size());
60}
61
[email protected]27131e72011-10-06 03:34:5662void ChromeV8ContextSet::Add(ChromeV8Context* context) {
[email protected]bd82ccea2013-02-20 09:56:2063 if (DCHECK_IS_ON()) {
64 // It's OK to insert the same context twice, but we should only ever have
65 // one ChromeV8Context per v8::Context.
66 for (ContextSet::iterator iter = contexts_.begin(); iter != contexts_.end();
67 ++iter) {
68 ChromeV8Context* candidate = *iter;
69 if (candidate != context)
70 DCHECK(candidate->v8_context() != context->v8_context());
71 }
[email protected]2ee1e3a2011-10-04 15:04:0472 }
[email protected]2ee1e3a2011-10-04 15:04:0473 contexts_.insert(context);
74}
75
[email protected]27131e72011-10-06 03:34:5676void ChromeV8ContextSet::Remove(ChromeV8Context* context) {
[email protected]2ee1e3a2011-10-04 15:04:0477 if (contexts_.erase(context)) {
[email protected]4f1633f2013-03-09 14:26:2478 context->Invalidate();
[email protected]380244092011-10-07 17:26:2779 MessageLoop::current()->DeleteSoon(FROM_HERE, context);
[email protected]2ee1e3a2011-10-04 15:04:0480 }
81}
82
[email protected]8c9311c2013-01-16 03:28:4783ChromeV8ContextSet::ContextSet ChromeV8ContextSet::GetAll() const {
[email protected]2ee1e3a2011-10-04 15:04:0484 return contexts_;
85}
86
[email protected]27131e72011-10-06 03:34:5687ChromeV8Context* ChromeV8ContextSet::GetCurrent() const {
[email protected]2ee1e3a2011-10-04 15:04:0488 if (!v8::Context::InContext())
89 return NULL;
90 else
91 return GetByV8Context(v8::Context::GetCurrent());
92}
93
[email protected]27131e72011-10-06 03:34:5694ChromeV8Context* ChromeV8ContextSet::GetByV8Context(
[email protected]2ee1e3a2011-10-04 15:04:0495 v8::Handle<v8::Context> v8_context) const {
96 for (ContextSet::const_iterator iter = contexts_.begin();
97 iter != contexts_.end(); ++iter) {
98 if ((*iter)->v8_context() == v8_context)
99 return *iter;
100 }
101
102 return NULL;
103}
104
[email protected]27131e72011-10-06 03:34:56105void ChromeV8ContextSet::DispatchChromeHiddenMethod(
[email protected]2ee1e3a2011-10-04 15:04:04106 const std::string& extension_id,
107 const std::string& method_name,
108 const base::ListValue& arguments,
[email protected]a2ef54c2011-10-10 16:20:31109 content::RenderView* render_view,
[email protected]2ee1e3a2011-10-04 15:04:04110 const GURL& event_url) const {
111 v8::HandleScope handle_scope;
112
113 // We copy the context list, because calling into javascript may modify it
114 // out from under us.
115 ContextSet contexts = GetAll();
116
[email protected]8d86f13d2011-10-04 17:01:19117 scoped_ptr<V8ValueConverter> converter(V8ValueConverter::create());
[email protected]2ee1e3a2011-10-04 15:04:04118 for (ContextSet::iterator it = contexts.begin(); it != contexts.end();
119 ++it) {
120 if ((*it)->v8_context().IsEmpty())
121 continue;
122
[email protected]a76226d2012-04-11 07:58:29123 if (!extension_id.empty()) {
[email protected]8fe74bf2012-08-07 21:08:42124 const Extension* extension = (*it)->extension();
[email protected]a76226d2012-04-11 07:58:29125 if (!extension || (extension_id != extension->id()))
126 continue;
127 }
[email protected]2ee1e3a2011-10-04 15:04:04128
[email protected]a2ef54c2011-10-10 16:20:31129 content::RenderView* context_render_view = (*it)->GetRenderView();
[email protected]2ee1e3a2011-10-04 15:04:04130 if (!context_render_view)
131 continue;
132
133 if (render_view && render_view != context_render_view)
134 continue;
135
136 if (!HasSufficientPermissions(context_render_view, event_url))
137 continue;
138
139 v8::Local<v8::Context> context(*((*it)->v8_context()));
140 std::vector<v8::Handle<v8::Value> > v8_arguments;
141 for (size_t i = 0; i < arguments.GetSize(); ++i) {
[email protected]5d30f92bf2012-08-03 08:43:37142 const base::Value* item = NULL;
[email protected]2ee1e3a2011-10-04 15:04:04143 CHECK(arguments.Get(i, &item));
[email protected]8d86f13d2011-10-04 17:01:19144 v8_arguments.push_back(converter->ToV8Value(item, context));
[email protected]2ee1e3a2011-10-04 15:04:04145 }
146
[email protected]2df5db742011-10-12 01:37:22147 v8::Handle<v8::Value> retval;
148 (*it)->CallChromeHiddenMethod(
149 method_name, v8_arguments.size(), &v8_arguments[0], &retval);
[email protected]2ee1e3a2011-10-04 15:04:04150 }
151}
[email protected]8fe74bf2012-08-07 21:08:42152
[email protected]8c9311c2013-01-16 03:28:47153void ChromeV8ContextSet::OnExtensionUnloaded(const std::string& extension_id) {
154 ContextSet contexts = GetAll();
155
156 // Clean up contexts belonging to the unloaded extension. This is done so
157 // that content scripts (which remain injected into the page) don't continue
158 // receiving events and sending messages.
159 for (ContextSet::iterator it = contexts.begin(); it != contexts.end();
160 ++it) {
161 if ((*it)->extension() && (*it)->extension()->id() == extension_id) {
162 (*it)->DispatchOnUnloadEvent();
163 Remove(*it);
164 }
165 }
166}
167
[email protected]8fe74bf2012-08-07 21:08:42168} // namespace extensions