Adding Peter Thatcher to the owners file.
[chromium-blink-merge.git] / extensions / renderer / user_script_injector.cc
blob5a42ffa71b03f1a26c0d1fda54ff0427c341471c
1 // Copyright 2014 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.
5 #include "extensions/renderer/user_script_injector.h"
7 #include <vector>
9 #include "base/lazy_instance.h"
10 #include "content/public/common/url_constants.h"
11 #include "content/public/renderer/render_view.h"
12 #include "extensions/common/extension.h"
13 #include "extensions/common/permissions/permissions_data.h"
14 #include "extensions/renderer/injection_host.h"
15 #include "extensions/renderer/script_context.h"
16 #include "extensions/renderer/scripts_run_info.h"
17 #include "grit/extensions_renderer_resources.h"
18 #include "third_party/WebKit/public/web/WebDocument.h"
19 #include "third_party/WebKit/public/web/WebFrame.h"
20 #include "third_party/WebKit/public/web/WebScriptSource.h"
21 #include "ui/base/resource/resource_bundle.h"
22 #include "url/gurl.h"
24 namespace extensions {
26 namespace {
28 // These two strings are injected before and after the Greasemonkey API and
29 // user script to wrap it in an anonymous scope.
30 const char kUserScriptHead[] = "(function (unsafeWindow) {\n";
31 const char kUserScriptTail[] = "\n})(window);";
33 // Greasemonkey API source that is injected with the scripts.
34 struct GreasemonkeyApiJsString {
35 GreasemonkeyApiJsString();
36 blink::WebScriptSource GetSource() const;
38 private:
39 std::string source_;
42 // The below constructor, monstrous as it is, just makes a WebScriptSource from
43 // the GreasemonkeyApiJs resource.
44 GreasemonkeyApiJsString::GreasemonkeyApiJsString()
45 : source_(ResourceBundle::GetSharedInstance()
46 .GetRawDataResource(IDR_GREASEMONKEY_API_JS)
47 .as_string()) {
50 blink::WebScriptSource GreasemonkeyApiJsString::GetSource() const {
51 return blink::WebScriptSource(blink::WebString::fromUTF8(source_));
54 base::LazyInstance<GreasemonkeyApiJsString> g_greasemonkey_api =
55 LAZY_INSTANCE_INITIALIZER;
57 } // namespace
59 UserScriptInjector::UserScriptInjector(const UserScript* script,
60 UserScriptSet* script_list,
61 bool is_declarative)
62 : script_(script),
63 script_id_(script_->id()),
64 host_id_(script_->host_id()),
65 is_declarative_(is_declarative),
66 user_script_set_observer_(this) {
67 user_script_set_observer_.Add(script_list);
70 UserScriptInjector::~UserScriptInjector() {
73 void UserScriptInjector::OnUserScriptsUpdated(
74 const std::set<HostID>& changed_hosts,
75 const std::vector<UserScript*>& scripts) {
76 // If the host causing this injection changed, then this injection
77 // will be removed, and there's no guarantee the backing script still exists.
78 if (changed_hosts.count(host_id_) > 0)
79 return;
81 for (std::vector<UserScript*>::const_iterator iter = scripts.begin();
82 iter != scripts.end();
83 ++iter) {
84 // We need to compare to |script_id_| (and not to script_->id()) because the
85 // old |script_| may be deleted by now.
86 if ((*iter)->id() == script_id_) {
87 script_ = *iter;
88 break;
93 UserScript::InjectionType UserScriptInjector::script_type() const {
94 return UserScript::CONTENT_SCRIPT;
97 bool UserScriptInjector::ShouldExecuteInChildFrames() const {
98 return false;
101 bool UserScriptInjector::ShouldExecuteInMainWorld() const {
102 return false;
105 bool UserScriptInjector::IsUserGesture() const {
106 return false;
109 bool UserScriptInjector::ExpectsResults() const {
110 return false;
113 bool UserScriptInjector::ShouldInjectJs(
114 UserScript::RunLocation run_location) const {
115 return script_->run_location() == run_location &&
116 !script_->js_scripts().empty();
119 bool UserScriptInjector::ShouldInjectCss(
120 UserScript::RunLocation run_location) const {
121 return run_location == UserScript::DOCUMENT_START &&
122 !script_->css_scripts().empty();
125 PermissionsData::AccessType UserScriptInjector::CanExecuteOnFrame(
126 const InjectionHost* injection_host,
127 blink::WebFrame* web_frame,
128 int tab_id,
129 const GURL& top_url) const {
130 GURL effective_document_url = ScriptContext::GetEffectiveDocumentURL(
131 web_frame, web_frame->document().url(), script_->match_about_blank());
132 PermissionsData::AccessType can_execute = injection_host->CanExecuteOnFrame(
133 effective_document_url, top_url, tab_id, is_declarative_);
135 if (script_->consumer_instance_type() !=
136 UserScript::ConsumerInstanceType::WEBVIEW ||
137 can_execute == PermissionsData::ACCESS_DENIED)
138 return can_execute;
140 int routing_id = content::RenderView::FromWebView(web_frame->top()->view())
141 ->GetRoutingID();
142 return script_->routing_info().render_view_id == routing_id
143 ? PermissionsData::ACCESS_ALLOWED
144 : PermissionsData::ACCESS_DENIED;
147 std::vector<blink::WebScriptSource> UserScriptInjector::GetJsSources(
148 UserScript::RunLocation run_location) const {
149 DCHECK_EQ(script_->run_location(), run_location);
151 std::vector<blink::WebScriptSource> sources;
152 const UserScript::FileList& js_scripts = script_->js_scripts();
153 bool is_standalone_or_emulate_greasemonkey =
154 script_->is_standalone() || script_->emulate_greasemonkey();
156 for (UserScript::FileList::const_iterator iter = js_scripts.begin();
157 iter != js_scripts.end();
158 ++iter) {
159 std::string content = iter->GetContent().as_string();
161 // We add this dumb function wrapper for standalone user script to
162 // emulate what Greasemonkey does.
163 // TODO(aa): I think that maybe "is_standalone" scripts don't exist
164 // anymore. Investigate.
165 if (is_standalone_or_emulate_greasemonkey) {
166 content.insert(0, kUserScriptHead);
167 content += kUserScriptTail;
169 sources.push_back(blink::WebScriptSource(
170 blink::WebString::fromUTF8(content), iter->url()));
173 // Emulate Greasemonkey API for scripts that were converted to extensions
174 // and "standalone" user scripts.
175 if (is_standalone_or_emulate_greasemonkey)
176 sources.insert(sources.begin(), g_greasemonkey_api.Get().GetSource());
178 return sources;
181 std::vector<std::string> UserScriptInjector::GetCssSources(
182 UserScript::RunLocation run_location) const {
183 DCHECK_EQ(UserScript::DOCUMENT_START, run_location);
185 std::vector<std::string> sources;
186 const UserScript::FileList& css_scripts = script_->css_scripts();
187 for (UserScript::FileList::const_iterator iter = css_scripts.begin();
188 iter != css_scripts.end();
189 ++iter) {
190 sources.push_back(iter->GetContent().as_string());
192 return sources;
195 void UserScriptInjector::GetRunInfo(
196 ScriptsRunInfo* scripts_run_info,
197 UserScript::RunLocation run_location) const {
198 if (ShouldInjectJs(run_location)) {
199 const UserScript::FileList& js_scripts = script_->js_scripts();
200 scripts_run_info->num_js += js_scripts.size();
201 for (UserScript::FileList::const_iterator iter = js_scripts.begin();
202 iter != js_scripts.end();
203 ++iter) {
204 scripts_run_info->executing_scripts[host_id_.id()].insert(
205 iter->url().path());
209 if (ShouldInjectCss(run_location))
210 scripts_run_info->num_css += script_->css_scripts().size();
213 void UserScriptInjector::OnInjectionComplete(
214 scoped_ptr<base::ListValue> execution_results,
215 UserScript::RunLocation run_location) {
218 void UserScriptInjector::OnWillNotInject(InjectFailureReason reason) {
221 } // namespace extensions