blob: 97465f822a750880c090d2d9138905bd669f37fd [file] [log] [blame]
[email protected]2ee1e3a2011-10-04 15:04:041// Copyright (c) 2011 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
[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]2a80aee2011-10-07 16:06:0311#include "chrome/common/url_constants.h"
[email protected]27131e72011-10-06 03:34:5612#include "chrome/renderer/extensions/chrome_v8_context.h"
[email protected]526476902011-10-06 20:34:0613#include "content/public/renderer/render_thread.h"
[email protected]8d86f13d2011-10-04 17:01:1914#include "content/public/renderer/v8_value_converter.h"
[email protected]a2ef54c2011-10-10 16:20:3115#include "content/public/renderer/render_view.h"
[email protected]2ee1e3a2011-10-04 15:04:0416#include "v8/include/v8.h"
17#include "third_party/WebKit/Source/WebKit/chromium/public/WebDocument.h"
18#include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h"
19#include "third_party/WebKit/Source/WebKit/chromium/public/WebURL.h"
20#include "third_party/WebKit/Source/WebKit/chromium/public/WebURLRequest.h"
21#include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h"
22
[email protected]526476902011-10-06 20:34:0623using content::RenderThread;
[email protected]8d86f13d2011-10-04 17:01:1924using content::V8ValueConverter;
25
[email protected]2ee1e3a2011-10-04 15:04:0426namespace {
27
28// Returns true if the extension running in the given |render_view| has
29// sufficient permissions to access the data.
30//
31// TODO(aa): This looks super suspicious. Is it correct? Can we use something
32// else already in the system? Should it be moved elsewhere?
[email protected]a2ef54c2011-10-10 16:20:3133 bool HasSufficientPermissions(content::RenderView* render_view,
34 const GURL& event_url) {
[email protected]2ee1e3a2011-10-04 15:04:0435 // During unit tests, we might be invoked without a v8 context. In these
36 // cases, we only allow empty event_urls and short-circuit before retrieving
37 // the render view from the current context.
38 if (!event_url.is_valid())
39 return true;
40
41 WebKit::WebDocument document =
[email protected]a2ef54c2011-10-10 16:20:3142 render_view->GetWebView()->mainFrame()->document();
[email protected]2ee1e3a2011-10-04 15:04:0443 return GURL(document.url()).SchemeIs(chrome::kExtensionScheme) &&
44 document.securityOrigin().canRequest(event_url);
45}
46
47}
48
[email protected]27131e72011-10-06 03:34:5649ChromeV8ContextSet::ChromeV8ContextSet() {
[email protected]2ee1e3a2011-10-04 15:04:0450}
[email protected]27131e72011-10-06 03:34:5651ChromeV8ContextSet::~ChromeV8ContextSet() {
[email protected]2ee1e3a2011-10-04 15:04:0452}
53
[email protected]27131e72011-10-06 03:34:5654int ChromeV8ContextSet::size() const {
[email protected]2ee1e3a2011-10-04 15:04:0455 return static_cast<int>(contexts_.size());
56}
57
[email protected]27131e72011-10-06 03:34:5658void ChromeV8ContextSet::Add(ChromeV8Context* context) {
[email protected]2ee1e3a2011-10-04 15:04:0459#ifndef NDEBUG
60 // It's OK to insert the same context twice, but we should only ever have one
[email protected]27131e72011-10-06 03:34:5661 // ChromeV8Context per v8::Context.
[email protected]2ee1e3a2011-10-04 15:04:0462 for (ContextSet::iterator iter = contexts_.begin(); iter != contexts_.end();
63 ++iter) {
[email protected]27131e72011-10-06 03:34:5664 ChromeV8Context* candidate = *iter;
[email protected]2ee1e3a2011-10-04 15:04:0465 if (candidate != context)
66 DCHECK(candidate->v8_context() != context->v8_context());
67 }
68#endif
69 contexts_.insert(context);
70}
71
[email protected]27131e72011-10-06 03:34:5672void ChromeV8ContextSet::Remove(ChromeV8Context* context) {
[email protected]2ee1e3a2011-10-04 15:04:0473 if (contexts_.erase(context)) {
74 context->clear_web_frame();
[email protected]380244092011-10-07 17:26:2775 MessageLoop::current()->DeleteSoon(FROM_HERE, context);
[email protected]2ee1e3a2011-10-04 15:04:0476 }
77}
78
[email protected]27131e72011-10-06 03:34:5679ChromeV8ContextSet::ContextSet ChromeV8ContextSet::GetAll()
[email protected]2ee1e3a2011-10-04 15:04:0480 const {
81 return contexts_;
82}
83
[email protected]27131e72011-10-06 03:34:5684ChromeV8Context* ChromeV8ContextSet::GetCurrent() const {
[email protected]2ee1e3a2011-10-04 15:04:0485 if (!v8::Context::InContext())
86 return NULL;
87 else
88 return GetByV8Context(v8::Context::GetCurrent());
89}
90
[email protected]27131e72011-10-06 03:34:5691ChromeV8Context* ChromeV8ContextSet::GetByV8Context(
[email protected]2ee1e3a2011-10-04 15:04:0492 v8::Handle<v8::Context> v8_context) const {
93 for (ContextSet::const_iterator iter = contexts_.begin();
94 iter != contexts_.end(); ++iter) {
95 if ((*iter)->v8_context() == v8_context)
96 return *iter;
97 }
98
99 return NULL;
100}
101
[email protected]27131e72011-10-06 03:34:56102void ChromeV8ContextSet::DispatchChromeHiddenMethod(
[email protected]2ee1e3a2011-10-04 15:04:04103 const std::string& extension_id,
104 const std::string& method_name,
105 const base::ListValue& arguments,
[email protected]a2ef54c2011-10-10 16:20:31106 content::RenderView* render_view,
[email protected]2ee1e3a2011-10-04 15:04:04107 const GURL& event_url) const {
108 v8::HandleScope handle_scope;
109
110 // We copy the context list, because calling into javascript may modify it
111 // out from under us.
112 ContextSet contexts = GetAll();
113
[email protected]8d86f13d2011-10-04 17:01:19114 scoped_ptr<V8ValueConverter> converter(V8ValueConverter::create());
[email protected]2ee1e3a2011-10-04 15:04:04115 for (ContextSet::iterator it = contexts.begin(); it != contexts.end();
116 ++it) {
117 if ((*it)->v8_context().IsEmpty())
118 continue;
119
120 if (!extension_id.empty() && extension_id != (*it)->extension_id())
121 continue;
122
[email protected]a2ef54c2011-10-10 16:20:31123 content::RenderView* context_render_view = (*it)->GetRenderView();
[email protected]2ee1e3a2011-10-04 15:04:04124 if (!context_render_view)
125 continue;
126
127 if (render_view && render_view != context_render_view)
128 continue;
129
130 if (!HasSufficientPermissions(context_render_view, event_url))
131 continue;
132
133 v8::Local<v8::Context> context(*((*it)->v8_context()));
134 std::vector<v8::Handle<v8::Value> > v8_arguments;
135 for (size_t i = 0; i < arguments.GetSize(); ++i) {
136 base::Value* item = NULL;
137 CHECK(arguments.Get(i, &item));
[email protected]8d86f13d2011-10-04 17:01:19138 v8_arguments.push_back(converter->ToV8Value(item, context));
[email protected]2ee1e3a2011-10-04 15:04:04139 }
140
[email protected]2df5db742011-10-12 01:37:22141 v8::Handle<v8::Value> retval;
142 (*it)->CallChromeHiddenMethod(
143 method_name, v8_arguments.size(), &v8_arguments[0], &retval);
[email protected]2ee1e3a2011-10-04 15:04:04144 // In debug, the js will validate the event parameters and return a
145 // string if a validation error has occured.
146 // TODO(rafaelw): Consider only doing this check if function_name ==
147 // "Event.dispatchJSON".
148#ifndef NDEBUG
149 if (!retval.IsEmpty() && !retval->IsUndefined()) {
150 std::string error = *v8::String::AsciiValue(retval);
151 DCHECK(false) << error;
152 }
153#endif
154 }
155}