blob: dfe3d85fa532b03c1ffa89f8a1609598f7e8104a [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]8d86f13d2011-10-04 17:01:1915#include "content/public/renderer/v8_value_converter.h"
[email protected]a2ef54c2011-10-10 16:20:3116#include "content/public/renderer/render_view.h"
[email protected]2ee1e3a2011-10-04 15:04:0417#include "v8/include/v8.h"
18#include "third_party/WebKit/Source/WebKit/chromium/public/WebDocument.h"
19#include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h"
[email protected]75bff522011-12-03 00:04:2020#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebURL.h"
21#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebURLRequest.h"
[email protected]2ee1e3a2011-10-04 15:04:0422#include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h"
23
[email protected]526476902011-10-06 20:34:0624using content::RenderThread;
[email protected]8d86f13d2011-10-04 17:01:1925using content::V8ValueConverter;
26
[email protected]2ee1e3a2011-10-04 15:04:0427namespace {
28
29// Returns true if the extension running in the given |render_view| has
30// sufficient permissions to access the data.
31//
32// TODO(aa): This looks super suspicious. Is it correct? Can we use something
33// else already in the system? Should it be moved elsewhere?
[email protected]a2ef54c2011-10-10 16:20:3134 bool HasSufficientPermissions(content::RenderView* render_view,
35 const GURL& event_url) {
[email protected]2ee1e3a2011-10-04 15:04:0436 // During unit tests, we might be invoked without a v8 context. In these
37 // cases, we only allow empty event_urls and short-circuit before retrieving
38 // the render view from the current context.
39 if (!event_url.is_valid())
40 return true;
41
42 WebKit::WebDocument document =
[email protected]a2ef54c2011-10-10 16:20:3143 render_view->GetWebView()->mainFrame()->document();
[email protected]2ee1e3a2011-10-04 15:04:0444 return GURL(document.url()).SchemeIs(chrome::kExtensionScheme) &&
45 document.securityOrigin().canRequest(event_url);
46}
47
48}
49
[email protected]27131e72011-10-06 03:34:5650ChromeV8ContextSet::ChromeV8ContextSet() {
[email protected]2ee1e3a2011-10-04 15:04:0451}
[email protected]27131e72011-10-06 03:34:5652ChromeV8ContextSet::~ChromeV8ContextSet() {
[email protected]2ee1e3a2011-10-04 15:04:0453}
54
[email protected]27131e72011-10-06 03:34:5655int ChromeV8ContextSet::size() const {
[email protected]2ee1e3a2011-10-04 15:04:0456 return static_cast<int>(contexts_.size());
57}
58
[email protected]27131e72011-10-06 03:34:5659void ChromeV8ContextSet::Add(ChromeV8Context* context) {
[email protected]2ee1e3a2011-10-04 15:04:0460#ifndef NDEBUG
61 // It's OK to insert the same context twice, but we should only ever have one
[email protected]27131e72011-10-06 03:34:5662 // ChromeV8Context per v8::Context.
[email protected]2ee1e3a2011-10-04 15:04:0463 for (ContextSet::iterator iter = contexts_.begin(); iter != contexts_.end();
64 ++iter) {
[email protected]27131e72011-10-06 03:34:5665 ChromeV8Context* candidate = *iter;
[email protected]2ee1e3a2011-10-04 15:04:0466 if (candidate != context)
67 DCHECK(candidate->v8_context() != context->v8_context());
68 }
69#endif
70 contexts_.insert(context);
71}
72
[email protected]27131e72011-10-06 03:34:5673void ChromeV8ContextSet::Remove(ChromeV8Context* context) {
[email protected]2ee1e3a2011-10-04 15:04:0474 if (contexts_.erase(context)) {
75 context->clear_web_frame();
[email protected]380244092011-10-07 17:26:2776 MessageLoop::current()->DeleteSoon(FROM_HERE, context);
[email protected]2ee1e3a2011-10-04 15:04:0477 }
78}
79
[email protected]27131e72011-10-06 03:34:5680ChromeV8ContextSet::ContextSet ChromeV8ContextSet::GetAll()
[email protected]2ee1e3a2011-10-04 15:04:0481 const {
82 return contexts_;
83}
84
[email protected]27131e72011-10-06 03:34:5685ChromeV8Context* ChromeV8ContextSet::GetCurrent() const {
[email protected]2ee1e3a2011-10-04 15:04:0486 if (!v8::Context::InContext())
87 return NULL;
88 else
89 return GetByV8Context(v8::Context::GetCurrent());
90}
91
[email protected]27131e72011-10-06 03:34:5692ChromeV8Context* ChromeV8ContextSet::GetByV8Context(
[email protected]2ee1e3a2011-10-04 15:04:0493 v8::Handle<v8::Context> v8_context) const {
94 for (ContextSet::const_iterator iter = contexts_.begin();
95 iter != contexts_.end(); ++iter) {
96 if ((*iter)->v8_context() == v8_context)
97 return *iter;
98 }
99
100 return NULL;
101}
102
[email protected]27131e72011-10-06 03:34:56103void ChromeV8ContextSet::DispatchChromeHiddenMethod(
[email protected]2ee1e3a2011-10-04 15:04:04104 const std::string& extension_id,
105 const std::string& method_name,
106 const base::ListValue& arguments,
[email protected]a2ef54c2011-10-10 16:20:31107 content::RenderView* render_view,
[email protected]2ee1e3a2011-10-04 15:04:04108 const GURL& event_url) const {
109 v8::HandleScope handle_scope;
110
111 // We copy the context list, because calling into javascript may modify it
112 // out from under us.
113 ContextSet contexts = GetAll();
114
[email protected]8d86f13d2011-10-04 17:01:19115 scoped_ptr<V8ValueConverter> converter(V8ValueConverter::create());
[email protected]2ee1e3a2011-10-04 15:04:04116 for (ContextSet::iterator it = contexts.begin(); it != contexts.end();
117 ++it) {
118 if ((*it)->v8_context().IsEmpty())
119 continue;
120
[email protected]a76226d2012-04-11 07:58:29121 if (!extension_id.empty()) {
[email protected]1c321ee2012-05-21 03:02:34122 const extensions::Extension* extension = (*it)->extension();
[email protected]a76226d2012-04-11 07:58:29123 if (!extension || (extension_id != extension->id()))
124 continue;
125 }
[email protected]2ee1e3a2011-10-04 15:04:04126
[email protected]a2ef54c2011-10-10 16:20:31127 content::RenderView* context_render_view = (*it)->GetRenderView();
[email protected]2ee1e3a2011-10-04 15:04:04128 if (!context_render_view)
129 continue;
130
131 if (render_view && render_view != context_render_view)
132 continue;
133
134 if (!HasSufficientPermissions(context_render_view, event_url))
135 continue;
136
137 v8::Local<v8::Context> context(*((*it)->v8_context()));
138 std::vector<v8::Handle<v8::Value> > v8_arguments;
139 for (size_t i = 0; i < arguments.GetSize(); ++i) {
140 base::Value* item = NULL;
141 CHECK(arguments.Get(i, &item));
[email protected]8d86f13d2011-10-04 17:01:19142 v8_arguments.push_back(converter->ToV8Value(item, context));
[email protected]2ee1e3a2011-10-04 15:04:04143 }
144
[email protected]2df5db742011-10-12 01:37:22145 v8::Handle<v8::Value> retval;
146 (*it)->CallChromeHiddenMethod(
147 method_name, v8_arguments.size(), &v8_arguments[0], &retval);
[email protected]2ee1e3a2011-10-04 15:04:04148 // In debug, the js will validate the event parameters and return a
149 // string if a validation error has occured.
150 // TODO(rafaelw): Consider only doing this check if function_name ==
151 // "Event.dispatchJSON".
152#ifndef NDEBUG
153 if (!retval.IsEmpty() && !retval->IsUndefined()) {
154 std::string error = *v8::String::AsciiValue(retval);
155 DCHECK(false) << error;
156 }
157#endif
158 }
159}