Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / extensions / renderer / user_script_injector.cc
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_injector.h"
6
7 #include <vector>
8
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"
21
22 namespace extensions {
23
24 namespace {
25
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);";
30
31 // Greasemonkey API source that is injected with the scripts.
32 struct GreasemonkeyApiJsString {
33   GreasemonkeyApiJsString();
34   blink::WebScriptSource GetSource() const;
35
36  private:
37   std::string 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_(ResourceBundle::GetSharedInstance()
44                   .GetRawDataResource(IDR_GREASEMONKEY_API_JS)
45                   .as_string()) {
46 }
47
48 blink::WebScriptSource GreasemonkeyApiJsString::GetSource() const {
49   return blink::WebScriptSource(blink::WebString::fromUTF8(source_));
50 }
51
52 base::LazyInstance<GreasemonkeyApiJsString> g_greasemonkey_api =
53     LAZY_INSTANCE_INITIALIZER;
54
55 }  // namespace
56
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);
67 }
68
69 UserScriptInjector::~UserScriptInjector() {
70 }
71
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;
79
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;
88     }
89   }
90 }
91
92 UserScript::InjectionType UserScriptInjector::script_type() const {
93   return UserScript::CONTENT_SCRIPT;
94 }
95
96 bool UserScriptInjector::ShouldExecuteInChildFrames() const {
97   return false;
98 }
99
100 bool UserScriptInjector::ShouldExecuteInMainWorld() const {
101   return false;
102 }
103
104 bool UserScriptInjector::IsUserGesture() const {
105   return false;
106 }
107
108 bool UserScriptInjector::ExpectsResults() const {
109   return false;
110 }
111
112 bool UserScriptInjector::ShouldInjectJs(
113     UserScript::RunLocation run_location) const {
114   return script_->run_location() == run_location &&
115          !script_->js_scripts().empty();
116 }
117
118 bool UserScriptInjector::ShouldInjectCss(
119     UserScript::RunLocation run_location) const {
120   return run_location == UserScript::DOCUMENT_START &&
121          !script_->css_scripts().empty();
122 }
123
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;
133
134   GURL effective_document_url = ScriptContext::GetEffectiveDocumentURL(
135       web_frame, web_frame->document().url(), script_->match_about_blank());
136
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 */);
156   }
157 }
158
159 std::vector<blink::WebScriptSource> UserScriptInjector::GetJsSources(
160     UserScript::RunLocation run_location) const {
161   DCHECK_EQ(script_->run_location(), run_location);
162
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();
167
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();
172
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;
180     }
181     sources.push_back(blink::WebScriptSource(
182         blink::WebString::fromUTF8(content), iter->url()));
183   }
184
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());
189
190   return sources;
191 }
192
193 std::vector<std::string> UserScriptInjector::GetCssSources(
194     UserScript::RunLocation run_location) const {
195   DCHECK_EQ(UserScript::DOCUMENT_START, run_location);
196
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());
203   }
204   return sources;
205 }
206
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());
219     }
220   }
221
222   if (ShouldInjectCss(run_location))
223     scripts_run_info->num_css += script_->css_scripts().size();
224 }
225
226 void UserScriptInjector::OnWillNotInject(InjectFailureReason reason) {
227 }
228
229 }  // namespace extensions