OLD | NEW |
---|---|
(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/user_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 "content/public/renderer/render_view.h" | |
13 #include "extensions/common/extension.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 "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 "third_party/WebKit/public/web/WebView.h" | |
22 #include "ui/base/resource/resource_bundle.h" | |
23 #include "url/gurl.h" | |
24 | |
25 namespace extensions { | |
26 | |
27 namespace { | |
28 | |
29 // These two strings are injected before and after the Greasemonkey API and | |
30 // user script to wrap it in an anonymous scope. | |
31 const char kUserScriptHead[] = "(function (unsafeWindow) {\n"; | |
32 const char kUserScriptTail[] = "\n})(window);"; | |
33 | |
34 // Greasemonkey API source that is injected with the scripts. | |
35 struct GreasemonkeyApiJsString { | |
36 GreasemonkeyApiJsString(); | |
37 blink::WebScriptSource source; | |
38 }; | |
39 | |
40 // The below constructor, monstrous as it is, just makes a WebScriptSource from | |
41 // the GreasemonkeyApiJs resource. | |
42 GreasemonkeyApiJsString::GreasemonkeyApiJsString() | |
43 : source(blink::WebScriptSource(blink::WebString::fromUTF8( | |
44 ResourceBundle::GetSharedInstance() | |
45 .GetRawDataResource(IDR_GREASEMONKEY_API_JS) | |
46 .as_string()))) { | |
47 } | |
48 | |
49 base::LazyInstance<GreasemonkeyApiJsString> g_greasemonkey_api = | |
50 LAZY_INSTANCE_INITIALIZER; | |
51 | |
52 } // namespace | |
53 | |
54 UserScriptInjection::UserScriptInjection( | |
55 blink::WebFrame* web_frame, | |
56 const std::string& extension_id, | |
57 UserScript::RunLocation run_location, | |
58 int tab_id, | |
59 UserScriptInjectionList* script_list, | |
60 const UserScript* script, | |
61 bool inject_js, | |
62 bool inject_css) | |
63 : ScriptInjection(web_frame, | |
64 extension_id, | |
65 run_location, | |
66 tab_id), | |
67 script_(script), | |
68 script_id_(script_->id()), | |
69 inject_js_(inject_js), | |
70 inject_css_(inject_css), | |
not at google - send to devlin
2014/06/15 23:53:38
see comment in user_script_injection_list; I'd ski
Devlin
2014/06/16 18:11:16
Done.
| |
71 user_script_injection_list_observer_(this) { | |
72 user_script_injection_list_observer_.Add(script_list); | |
73 } | |
74 | |
75 UserScriptInjection::~UserScriptInjection() { | |
76 } | |
77 | |
78 void UserScriptInjection::InjectJS(const Extension* extension, | |
79 ScriptsRunInfo* scripts_run_info) { | |
80 const UserScript::FileList& js_scripts = script_->js_scripts(); | |
81 std::vector<blink::WebScriptSource> sources; | |
82 scripts_run_info->num_js += js_scripts.size(); | |
83 | |
84 bool is_standalone_or_emulate_greasemonkey = | |
85 script_->is_standalone() || script_->emulate_greasemonkey(); | |
86 for (UserScript::FileList::const_iterator iter = js_scripts.begin(); | |
87 iter != js_scripts.end(); | |
88 ++iter) { | |
89 std::string content = iter->GetContent().as_string(); | |
90 | |
91 // We add this dumb function wrapper for standalone user script to | |
92 // emulate what Greasemonkey does. | |
93 // TODO(aa): I think that maybe "is_standalone" scripts don't exist | |
94 // anymore. Investigate. | |
95 if (is_standalone_or_emulate_greasemonkey) { | |
96 content.insert(0, kUserScriptHead); | |
97 content += kUserScriptTail; | |
98 } | |
99 sources.push_back(blink::WebScriptSource( | |
100 blink::WebString::fromUTF8(content), iter->url())); | |
101 } | |
102 | |
103 // Emulate Greasemonkey API for scripts that were converted to extensions | |
104 // and "standalone" user scripts. | |
105 if (is_standalone_or_emulate_greasemonkey) | |
106 sources.insert(sources.begin(), g_greasemonkey_api.Get().source); | |
107 | |
108 int isolated_world_id = | |
109 GetIsolatedWorldIdForExtension(extension, web_frame()); | |
110 base::ElapsedTimer exec_timer; | |
111 DOMActivityLogger::AttachToWorld(isolated_world_id, script_->extension_id()); | |
112 web_frame()->executeScriptInIsolatedWorld(isolated_world_id, | |
113 &sources.front(), | |
114 sources.size(), | |
115 EXTENSION_GROUP_CONTENT_SCRIPTS); | |
116 UMA_HISTOGRAM_TIMES("Extensions.InjectScriptTime", exec_timer.Elapsed()); | |
117 | |
118 for (std::vector<blink::WebScriptSource>::const_iterator iter = | |
119 sources.begin(); | |
120 iter != sources.end(); | |
121 ++iter) { | |
122 scripts_run_info->executing_scripts[script_->extension_id()].insert( | |
123 GURL(iter->url).path()); | |
124 } | |
125 } | |
126 | |
127 void UserScriptInjection::InjectCSS(ScriptsRunInfo* scripts_run_info) { | |
128 const UserScript::FileList& css_scripts = script_->css_scripts(); | |
129 scripts_run_info->num_css += css_scripts.size(); | |
130 for (UserScript::FileList::const_iterator iter = css_scripts.begin(); | |
131 iter != css_scripts.end(); | |
132 ++iter) { | |
133 web_frame()->document().insertStyleSheet( | |
134 blink::WebString::fromUTF8(iter->GetContent().as_string())); | |
135 } | |
136 } | |
137 | |
138 bool UserScriptInjection::Allowed(const Extension* extension) { | |
139 // If we don't have a tab id, we have no UI surface to ask for user consent. | |
140 // For now, we treat this as an automatic allow. | |
141 if (tab_id() == -1) | |
142 return true; | |
143 | |
144 return !extension->permissions_data()->RequiresActionForScriptExecution( | |
145 extension, tab_id(), web_frame()->top()->document().url()); | |
146 } | |
147 | |
148 void UserScriptInjection::Inject(ScriptsRunInfo* scripts_run_info, | |
149 const Extension* extension) { | |
150 if (inject_js_) | |
151 InjectJS(extension, scripts_run_info); | |
152 if (inject_css_) | |
153 InjectCSS(scripts_run_info); | |
154 } | |
155 | |
156 void UserScriptInjection::OnUserScriptsUpdated( | |
157 const std::set<std::string>& changed_extensions, | |
158 const std::vector<UserScript*>& scripts) { | |
159 // If the extension causing this injection changed, then this injection | |
160 // will be removed, and there's no guarantee the backing script still even | |
not at google - send to devlin
2014/06/15 23:53:38
s/even //
Devlin
2014/06/16 18:11:16
Done.
| |
161 // exists. | |
162 if (changed_extensions.count(extension_id()) > 0) | |
163 return; | |
164 | |
165 for (std::vector<UserScript*>::const_iterator iter = scripts.begin(); | |
166 iter != scripts.end(); | |
167 ++iter) { | |
168 if ((*iter)->id() == script_id_) { | |
169 script_ = *iter; | |
170 break; | |
171 } | |
172 } | |
173 } | |
174 | |
175 } // namespace extensions | |
OLD | NEW |