Note that promise is settled on reject. Add test coverage for Resolver.
[chromium-blink-merge.git] / extensions / renderer / user_script_injector.cc
blob73ac9f60a839a44787e079db87d84a7847e8bf24
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 "extensions/common/extension.h"
12 #include "extensions/common/permissions/permissions_data.h"
13 #include "extensions/renderer/script_context.h"
14 #include "extensions/renderer/scripts_run_info.h"
15 #include "grit/extensions_renderer_resources.h"
16 #include "third_party/WebKit/public/web/WebDocument.h"
17 #include "third_party/WebKit/public/web/WebFrame.h"
18 #include "third_party/WebKit/public/web/WebScriptSource.h"
19 #include "ui/base/resource/resource_bundle.h"
20 #include "url/gurl.h"
22 namespace extensions {
24 namespace {
26 // These two strings are injected before and after the Greasemonkey API and
27 // user script to wrap it in an anonymous scope.
28 const char kUserScriptHead[] = "(function (unsafeWindow) {\n";
29 const char kUserScriptTail[] = "\n})(window);";
31 // Greasemonkey API source that is injected with the scripts.
32 struct GreasemonkeyApiJsString {
33 GreasemonkeyApiJsString();
34 blink::WebScriptSource GetSource() const;
36 private:
37 std::string source_;
40 // The below constructor, monstrous as it is, just makes a WebScriptSource from
41 // the GreasemonkeyApiJs resource.
42 GreasemonkeyApiJsString::GreasemonkeyApiJsString()
43 : source_(ResourceBundle::GetSharedInstance()
44 .GetRawDataResource(IDR_GREASEMONKEY_API_JS)
45 .as_string()) {
48 blink::WebScriptSource GreasemonkeyApiJsString::GetSource() const {
49 return blink::WebScriptSource(blink::WebString::fromUTF8(source_));
52 base::LazyInstance<GreasemonkeyApiJsString> g_greasemonkey_api =
53 LAZY_INSTANCE_INITIALIZER;
55 } // namespace
57 UserScriptInjector::UserScriptInjector(
58 const UserScript* script,
59 UserScriptSet* script_list,
60 bool is_declarative)
61 : script_(script),
62 script_id_(script_->id()),
63 extension_id_(script_->extension_id()),
64 is_declarative_(is_declarative),
65 user_script_set_observer_(this) {
66 user_script_set_observer_.Add(script_list);
69 UserScriptInjector::~UserScriptInjector() {
72 void UserScriptInjector::OnUserScriptsUpdated(
73 const std::set<std::string>& changed_extensions,
74 const std::vector<UserScript*>& scripts) {
75 // If the extension causing this injection changed, then this injection
76 // will be removed, and there's no guarantee the backing script still exists.
77 if (changed_extensions.count(extension_id_) > 0)
78 return;
80 for (std::vector<UserScript*>::const_iterator iter = scripts.begin();
81 iter != scripts.end();
82 ++iter) {
83 // We need to compare to |script_id_| (and not to script_->id()) because the
84 // old |script_| may be deleted by now.
85 if ((*iter)->id() == script_id_) {
86 script_ = *iter;
87 break;
92 UserScript::InjectionType UserScriptInjector::script_type() const {
93 return UserScript::CONTENT_SCRIPT;
96 bool UserScriptInjector::ShouldExecuteInChildFrames() const {
97 return false;
100 bool UserScriptInjector::ShouldExecuteInMainWorld() const {
101 return false;
104 bool UserScriptInjector::IsUserGesture() const {
105 return false;
108 bool UserScriptInjector::ExpectsResults() const {
109 return false;
112 bool UserScriptInjector::ShouldInjectJs(
113 UserScript::RunLocation run_location) const {
114 return script_->run_location() == run_location &&
115 !script_->js_scripts().empty();
118 bool UserScriptInjector::ShouldInjectCss(
119 UserScript::RunLocation run_location) const {
120 return run_location == UserScript::DOCUMENT_START &&
121 !script_->css_scripts().empty();
124 PermissionsData::AccessType UserScriptInjector::CanExecuteOnFrame(
125 const Extension* extension,
126 blink::WebFrame* web_frame,
127 int tab_id,
128 const GURL& top_url) const {
129 // If we don't have a tab id, we have no UI surface to ask for user consent.
130 // For now, we treat this as an automatic allow.
131 if (tab_id == -1)
132 return PermissionsData::ACCESS_ALLOWED;
134 GURL effective_document_url = ScriptContext::GetEffectiveDocumentURL(
135 web_frame, web_frame->document().url(), script_->match_about_blank());
137 // Declarative user scripts use "page access" (from "permissions" section in
138 // manifest) whereas non-declarative user scripts use custom
139 // "content script access" logic.
140 if (is_declarative_) {
141 return extension->permissions_data()->GetPageAccess(
142 extension,
143 effective_document_url,
144 top_url,
145 tab_id,
146 -1, // no process id
147 NULL /* ignore error */);
148 } else {
149 return extension->permissions_data()->GetContentScriptAccess(
150 extension,
151 effective_document_url,
152 top_url,
153 tab_id,
154 -1, // no process id
155 NULL /* ignore error */);
159 std::vector<blink::WebScriptSource> UserScriptInjector::GetJsSources(
160 UserScript::RunLocation run_location) const {
161 DCHECK_EQ(script_->run_location(), run_location);
163 std::vector<blink::WebScriptSource> sources;
164 const UserScript::FileList& js_scripts = script_->js_scripts();
165 bool is_standalone_or_emulate_greasemonkey =
166 script_->is_standalone() || script_->emulate_greasemonkey();
168 for (UserScript::FileList::const_iterator iter = js_scripts.begin();
169 iter != js_scripts.end();
170 ++iter) {
171 std::string content = iter->GetContent().as_string();
173 // We add this dumb function wrapper for standalone user script to
174 // emulate what Greasemonkey does.
175 // TODO(aa): I think that maybe "is_standalone" scripts don't exist
176 // anymore. Investigate.
177 if (is_standalone_or_emulate_greasemonkey) {
178 content.insert(0, kUserScriptHead);
179 content += kUserScriptTail;
181 sources.push_back(blink::WebScriptSource(
182 blink::WebString::fromUTF8(content), iter->url()));
185 // Emulate Greasemonkey API for scripts that were converted to extensions
186 // and "standalone" user scripts.
187 if (is_standalone_or_emulate_greasemonkey)
188 sources.insert(sources.begin(), g_greasemonkey_api.Get().GetSource());
190 return sources;
193 std::vector<std::string> UserScriptInjector::GetCssSources(
194 UserScript::RunLocation run_location) const {
195 DCHECK_EQ(UserScript::DOCUMENT_START, run_location);
197 std::vector<std::string> sources;
198 const UserScript::FileList& css_scripts = script_->css_scripts();
199 for (UserScript::FileList::const_iterator iter = css_scripts.begin();
200 iter != css_scripts.end();
201 ++iter) {
202 sources.push_back(iter->GetContent().as_string());
204 return sources;
207 void UserScriptInjector::OnInjectionComplete(
208 scoped_ptr<base::ListValue> execution_results,
209 ScriptsRunInfo* scripts_run_info,
210 UserScript::RunLocation run_location) {
211 if (ShouldInjectJs(run_location)) {
212 const UserScript::FileList& js_scripts = script_->js_scripts();
213 scripts_run_info->num_js += js_scripts.size();
214 for (UserScript::FileList::const_iterator iter = js_scripts.begin();
215 iter != js_scripts.end();
216 ++iter) {
217 scripts_run_info->executing_scripts[extension_id_].insert(
218 iter->url().path());
222 if (ShouldInjectCss(run_location))
223 scripts_run_info->num_css += script_->css_scripts().size();
226 void UserScriptInjector::OnWillNotInject(InjectFailureReason reason) {
229 } // namespace extensions