1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
|
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/renderer/extensions/chrome_v8_context_set.h"
#include "base/logging.h"
#include "base/message_loop.h"
#include "base/tracked_objects.h"
#include "base/values.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/url_constants.h"
#include "chrome/renderer/extensions/chrome_v8_context.h"
#include "content/public/renderer/render_thread.h"
#include "content/public/renderer/render_view.h"
#include "content/public/renderer/v8_value_converter.h"
#include "extensions/common/constants.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebURL.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebURLRequest.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebDocument.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h"
#include "v8/include/v8.h"
using content::RenderThread;
using content::V8ValueConverter;
namespace extensions {
namespace {
// Returns true if the extension running in the given |render_view| has
// sufficient permissions to access the data.
//
// TODO(aa): This looks super suspicious. Is it correct? Can we use something
// else already in the system? Should it be moved elsewhere?
bool HasSufficientPermissions(content::RenderView* render_view,
const GURL& event_url) {
// During unit tests, we might be invoked without a v8 context. In these
// cases, we only allow empty event_urls and short-circuit before retrieving
// the render view from the current context.
if (!event_url.is_valid())
return true;
WebKit::WebDocument document =
render_view->GetWebView()->mainFrame()->document();
return GURL(document.url()).SchemeIs(extensions::kExtensionScheme) &&
document.securityOrigin().canRequest(event_url);
}
}
ChromeV8ContextSet::ChromeV8ContextSet() {
}
ChromeV8ContextSet::~ChromeV8ContextSet() {
}
int ChromeV8ContextSet::size() const {
return static_cast<int>(contexts_.size());
}
void ChromeV8ContextSet::Add(ChromeV8Context* context) {
#ifndef NDEBUG
// It's OK to insert the same context twice, but we should only ever have one
// ChromeV8Context per v8::Context.
for (ContextSet::iterator iter = contexts_.begin(); iter != contexts_.end();
++iter) {
ChromeV8Context* candidate = *iter;
if (candidate != context)
DCHECK(candidate->v8_context() != context->v8_context());
}
#endif
contexts_.insert(context);
}
void ChromeV8ContextSet::Remove(ChromeV8Context* context) {
if (contexts_.erase(context)) {
context->clear_web_frame();
MessageLoop::current()->DeleteSoon(FROM_HERE, context);
}
}
ChromeV8ContextSet::ContextSet ChromeV8ContextSet::GetAll()
const {
return contexts_;
}
ChromeV8Context* ChromeV8ContextSet::GetCurrent() const {
if (!v8::Context::InContext())
return NULL;
else
return GetByV8Context(v8::Context::GetCurrent());
}
ChromeV8Context* ChromeV8ContextSet::GetByV8Context(
v8::Handle<v8::Context> v8_context) const {
for (ContextSet::const_iterator iter = contexts_.begin();
iter != contexts_.end(); ++iter) {
if ((*iter)->v8_context() == v8_context)
return *iter;
}
return NULL;
}
void ChromeV8ContextSet::DispatchChromeHiddenMethod(
const std::string& extension_id,
const std::string& method_name,
const base::ListValue& arguments,
content::RenderView* render_view,
const GURL& event_url) const {
v8::HandleScope handle_scope;
// We copy the context list, because calling into javascript may modify it
// out from under us.
ContextSet contexts = GetAll();
scoped_ptr<V8ValueConverter> converter(V8ValueConverter::create());
for (ContextSet::iterator it = contexts.begin(); it != contexts.end();
++it) {
if ((*it)->v8_context().IsEmpty())
continue;
if (!extension_id.empty()) {
const Extension* extension = (*it)->extension();
if (!extension || (extension_id != extension->id()))
continue;
}
content::RenderView* context_render_view = (*it)->GetRenderView();
if (!context_render_view)
continue;
if (render_view && render_view != context_render_view)
continue;
if (!HasSufficientPermissions(context_render_view, event_url))
continue;
v8::Local<v8::Context> context(*((*it)->v8_context()));
std::vector<v8::Handle<v8::Value> > v8_arguments;
for (size_t i = 0; i < arguments.GetSize(); ++i) {
const base::Value* item = NULL;
CHECK(arguments.Get(i, &item));
v8_arguments.push_back(converter->ToV8Value(item, context));
}
v8::Handle<v8::Value> retval;
(*it)->CallChromeHiddenMethod(
method_name, v8_arguments.size(), &v8_arguments[0], &retval);
}
}
} // namespace extensions
|