Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(547)

Side by Side Diff: extensions/renderer/script_injection.cc

Issue 284153006: Introduce ScriptInjection in extensions/renderer to inject UserScripts (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 6 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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.
4
5 #include "extensions/renderer/script_injection.h"
6
7 #include <vector>
8
9 #include "base/lazy_instance.h"
10 #include "base/metrics/histogram.h"
11 #include "content/public/common/url_constants.h"
12 #include "extensions/common/extension.h"
13 #include "extensions/common/extension_messages.h"
14 #include "extensions/common/permissions/permissions_data.h"
15 #include "extensions/renderer/dom_activity_logger.h"
16 #include "extensions/renderer/extension_groups.h"
17 #include "extensions/renderer/script_context.h"
18 #include "extensions/renderer/user_script_slave.h"
19 #include "grit/renderer_resources.h"
20 #include "third_party/WebKit/public/web/WebDocument.h"
21 #include "third_party/WebKit/public/web/WebFrame.h"
22 #include "third_party/WebKit/public/web/WebScriptSource.h"
23 #include "ui/base/resource/resource_bundle.h"
24 #include "url/gurl.h"
25
26 namespace extensions {
27
28 namespace {
29
30 // These two strings are injected before and after the Greasemonkey API and
31 // user script to wrap it in an anonymous scope.
32 const char kUserScriptHead[] = "(function (unsafeWindow) {\n";
33 const char kUserScriptTail[] = "\n})(window);";
34
35 // Greasemonkey API source that is injected with the scripts.
36 struct GreasemonkeyApiJsString {
37 GreasemonkeyApiJsString();
38 blink::WebScriptSource source;
39 };
40
41 // The below constructor, monstrous as it is, just makes a WebScriptSource from
42 // the GreasemonkeyApiJs resource.
43 GreasemonkeyApiJsString::GreasemonkeyApiJsString()
44 : source(blink::WebScriptSource(blink::WebString::fromUTF8(
45 ResourceBundle::GetSharedInstance().GetRawDataResource(
46 IDR_GREASEMONKEY_API_JS).as_string()))) {
47 }
48
49 base::LazyInstance<GreasemonkeyApiJsString> g_greasemonkey_api =
50 LAZY_INSTANCE_INITIALIZER;
51
52 } // namespace
53
54 ScriptInjection::ScriptsRunInfo::ScriptsRunInfo() : num_css(0u), num_js(0u) {
55 }
56
57 ScriptInjection::ScriptsRunInfo::~ScriptsRunInfo() {
58 }
59
60 // static
61 GURL ScriptInjection::GetDocumentUrlForFrame(blink::WebFrame* frame) {
62 GURL data_source_url = ScriptContext::GetDataSourceURLForFrame(frame);
63 if (!data_source_url.is_empty() && frame->isViewSourceModeEnabled()) {
64 data_source_url = GURL(content::kViewSourceScheme + std::string(":") +
65 data_source_url.spec());
66 }
67
68 return data_source_url;
69 }
70
71 ScriptInjection::ScriptInjection(
72 scoped_ptr<UserScript> script,
73 UserScriptSlave* user_script_slave)
74 : script_(script.Pass()),
75 extension_id_(script_->extension_id()),
76 user_script_slave_(user_script_slave),
77 is_standalone_or_emulate_greasemonkey_(
78 script_->is_standalone() || script_->emulate_greasemonkey()) {
79 }
80
81 ScriptInjection::~ScriptInjection() {
82 }
83
84 bool ScriptInjection::WantsToRun(blink::WebFrame* frame,
85 UserScript::RunLocation run_location,
86 const GURL& document_url) const {
87 if (frame->parent() && !script_->match_all_frames())
88 return false; // Only match subframes if the script declared it wanted to.
89
90
not at google - send to devlin 2014/05/15 23:23:21 dd
Devlin 2014/05/16 22:32:20 Done.
91 const Extension* extension = user_script_slave_->GetExtension(extension_id_);
92 // Since extension info is sent separately from user script info, they can
93 // be out of sync. We just ignore this situation.
94 if (!extension)
95 return false;
96
97 // Content scripts are not tab-specific.
98 static const int kNoTabId = -1;
99 // We don't have a process id in this context.
100 static const int kNoProcessId = -1;
101
102 if (!PermissionsData::CanExecuteScriptOnPage(extension,
103 document_url,
104 frame->top()->document().url(),
105 kNoTabId,
106 script_.get(),
107 kNoProcessId,
108 NULL /* ignore error */)) {
109 return false;
110 }
111
112 return ShouldInjectCSS(run_location) || ShouldInjectJS(run_location);
113 }
114
115 void ScriptInjection::Inject(blink::WebFrame* frame,
116 UserScript::RunLocation run_location,
117 ScriptsRunInfo* scripts_run_info) const {
118 DCHECK(frame);
119 DCHECK(scripts_run_info);
120 DCHECK(WantsToRun(frame, run_location, GetDocumentUrlForFrame(frame)));
121 DCHECK(user_script_slave_->GetExtension(extension_id_));
122
123 if (ShouldInjectCSS(run_location))
124 InjectCSS(frame, scripts_run_info);
125 if (ShouldInjectJS(run_location))
126 InjectJS(frame, scripts_run_info);
127 }
128
129 bool ScriptInjection::ShouldInjectJS(UserScript::RunLocation run_location)
130 const {
131 return !script_->js_scripts().empty() &&
132 script_->run_location() == run_location;
133 }
134
135 bool ScriptInjection::ShouldInjectCSS(UserScript::RunLocation run_location)
136 const {
137 return !script_->css_scripts().empty() &&
138 script_->run_location() == UserScript::DOCUMENT_START;
not at google - send to devlin 2014/05/15 23:23:21 I think you want |run_location| == DOCUMENT_START
Devlin 2014/05/16 22:32:20 Whoops, good catch - yes, meant |run_location|.
139 }
140
141 void ScriptInjection::InjectJS(blink::WebFrame* frame,
142 ScriptsRunInfo* scripts_run_info) const {
143 const UserScript::FileList& js_scripts = script_->js_scripts();
144 std::vector<blink::WebScriptSource> sources;
145 scripts_run_info->num_js += js_scripts.size();
146 for (UserScript::FileList::const_iterator iter = js_scripts.begin();
147 iter != js_scripts.end();
148 ++iter) {
149 std::string content = iter->GetContent().as_string();
150
151 // We add this dumb function wrapper for standalone user script to
152 // emulate what Greasemonkey does.
153 // TODO(aa): I think that maybe "is_standalone" scripts don't exist
154 // anymore. Investigate.
155 if (is_standalone_or_emulate_greasemonkey_) {
156 content.insert(0, kUserScriptHead);
157 content += kUserScriptTail;
158 }
159 sources.push_back(blink::WebScriptSource(
160 blink::WebString::fromUTF8(content), iter->url()));
161 }
162
163 // Emulate Greasemonkey API for scripts that were converted to extensions
164 // and "standalone" user scripts.
165 if (is_standalone_or_emulate_greasemonkey_)
166 sources.insert(sources.begin(), g_greasemonkey_api.Get().source);
167
168 int isolated_world_id =
169 user_script_slave_->GetIsolatedWorldIdForExtension(
170 user_script_slave_->GetExtension(extension_id_), frame);
171 base::ElapsedTimer exec_timer;
172 DOMActivityLogger::AttachToWorld(isolated_world_id, extension_id_);
173 frame->executeScriptInIsolatedWorld(isolated_world_id,
174 &sources.front(),
175 sources.size(),
176 EXTENSION_GROUP_CONTENT_SCRIPTS);
177 UMA_HISTOGRAM_TIMES("Extensions.InjectScriptTime", exec_timer.Elapsed());
178
179 for (std::vector<blink::WebScriptSource>::const_iterator iter =
180 sources.begin();
181 iter != sources.end();
182 ++iter) {
183 scripts_run_info->executing_scripts[extension_id_].insert(
184 GURL(iter->url).path());
185 }
186 }
187
188 void ScriptInjection::InjectCSS(blink::WebFrame* frame,
189 ScriptsRunInfo* scripts_run_info) const {
190 const UserScript::FileList& css_scripts = script_->css_scripts();
191 scripts_run_info->num_css += css_scripts.size();
192 for (UserScript::FileList::const_iterator iter = css_scripts.begin();
193 iter != css_scripts.end();
194 ++iter) {
195 frame->document().insertStyleSheet(
196 blink::WebString::fromUTF8(iter->GetContent().as_string()));
197 }
198 }
199
200 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698