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

Side by Side Diff: chrome/common/extensions/api/content_scripts/content_scripts_handler.cc

Issue 11724002: Move ContentScripts out of Extension (Closed) Base URL: http://git.chromium.org/chromium/src.git@dc_unref_browser_action
Patch Set: Created 7 years, 11 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
OLDNEW
(Empty)
1 // Copyright (c) 2012 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 "chrome/common/extensions/api/content_scripts/content_scripts_handler.h "
6
7 #include "base/lazy_instance.h"
8 #include "base/memory/scoped_ptr.h"
9 #include "base/string_number_conversions.h"
10 #include "base/utf_string_conversions.h"
11 #include "base/values.h"
12 #include "chrome/common/extensions/extension.h"
13 #include "chrome/common/extensions/extension_manifest_constants.h"
14 #include "chrome/common/extensions/extension_resource.h"
15 #include "content/public/common/url_constants.h"
16 #include "extensions/common/error_utils.h"
17 #include "extensions/common/url_pattern.h"
18 #include "googleurl/src/gurl.h"
19
20 namespace extensions {
21
22 namespace keys = extension_manifest_keys;
23 namespace values = extension_manifest_values;
24 namespace errors = extension_manifest_errors;
25
26 namespace {
27
28 // Helper method that loads either the include_globs or exclude_globs list
29 // from an entry in the content_script lists of the manifest.
30 bool LoadGlobsHelper(const DictionaryValue* content_script,
31 int content_script_index,
32 const char* globs_property_name,
33 string16* error,
34 void(UserScript::*add_method)(const std::string& glob),
35 UserScript* instance) {
36 if (!content_script->HasKey(globs_property_name))
37 return true; // they are optional
38
39 const ListValue* list = NULL;
40 if (!content_script->GetList(globs_property_name, &list)) {
41 *error = ErrorUtils::FormatErrorMessageUTF16(
42 errors::kInvalidGlobList,
43 base::IntToString(content_script_index),
44 globs_property_name);
45 return false;
46 }
47
48 for (size_t i = 0; i < list->GetSize(); ++i) {
49 std::string glob;
50 if (!list->GetString(i, &glob)) {
51 *error = ErrorUtils::FormatErrorMessageUTF16(
52 errors::kInvalidGlob,
53 base::IntToString(content_script_index),
54 globs_property_name,
55 base::IntToString(i));
56 return false;
57 }
58
59 (instance->*add_method)(glob);
60 }
61
62 return true;
63 }
64
65 // Helper method that loads a UserScript object from a dictionary in the
66 // content_script list of the manifest.
67 bool LoadUserScriptFromDictionary(const DictionaryValue* content_script,
68 int definition_index,
69 Extension* extension,
70 string16* error,
71 UserScript* result) {
72 // run_at
73 if (content_script->HasKey(keys::kRunAt)) {
74 std::string run_location;
75 if (!content_script->GetString(keys::kRunAt, &run_location)) {
76 *error = ErrorUtils::FormatErrorMessageUTF16(
77 errors::kInvalidRunAt,
78 base::IntToString(definition_index));
79 return false;
80 }
81
82 if (run_location == values::kRunAtDocumentStart) {
83 result->set_run_location(UserScript::DOCUMENT_START);
84 } else if (run_location == values::kRunAtDocumentEnd) {
85 result->set_run_location(UserScript::DOCUMENT_END);
86 } else if (run_location == values::kRunAtDocumentIdle) {
87 result->set_run_location(UserScript::DOCUMENT_IDLE);
88 } else {
89 *error = ErrorUtils::FormatErrorMessageUTF16(
90 errors::kInvalidRunAt,
91 base::IntToString(definition_index));
92 return false;
93 }
94 }
95
96 // all frames
97 if (content_script->HasKey(keys::kAllFrames)) {
98 bool all_frames = false;
99 if (!content_script->GetBoolean(keys::kAllFrames, &all_frames)) {
100 *error = ErrorUtils::FormatErrorMessageUTF16(
101 errors::kInvalidAllFrames, base::IntToString(definition_index));
102 return false;
103 }
104 result->set_match_all_frames(all_frames);
105 }
106
107 // matches (required)
108 const ListValue* matches = NULL;
109 if (!content_script->GetList(keys::kMatches, &matches)) {
110 *error = ErrorUtils::FormatErrorMessageUTF16(
111 errors::kInvalidMatches,
112 base::IntToString(definition_index));
113 return false;
114 }
115
116 if (matches->GetSize() == 0) {
117 *error = ErrorUtils::FormatErrorMessageUTF16(
118 errors::kInvalidMatchCount,
119 base::IntToString(definition_index));
120 return false;
121 }
122 for (size_t j = 0; j < matches->GetSize(); ++j) {
123 std::string match_str;
124 if (!matches->GetString(j, &match_str)) {
125 *error = ErrorUtils::FormatErrorMessageUTF16(
126 errors::kInvalidMatch,
127 base::IntToString(definition_index),
128 base::IntToString(j),
129 errors::kExpectString);
130 return false;
131 }
132
133 URLPattern pattern(UserScript::kValidUserScriptSchemes);
134 if (extension->CanExecuteScriptEverywhere())
135 pattern.SetValidSchemes(URLPattern::SCHEME_ALL);
136
137 URLPattern::ParseResult parse_result = pattern.Parse(match_str);
138 if (parse_result != URLPattern::PARSE_SUCCESS) {
139 *error = ErrorUtils::FormatErrorMessageUTF16(
140 errors::kInvalidMatch,
141 base::IntToString(definition_index),
142 base::IntToString(j),
143 URLPattern::GetParseResultString(parse_result));
144 return false;
145 }
146
147 if (pattern.MatchesScheme(chrome::kFileScheme) &&
148 !extension->CanExecuteScriptEverywhere()) {
149 extension->set_wants_file_access(true);
Devlin 2012/12/29 21:18:38 This is bad. Do we know how we want to handle thin
Yoyo Zhou 2013/01/04 00:13:30 I'd put a TODO saying what's wrong, at least until
Devlin 2013/01/11 20:30:02 Done (in Extension.h, with the method).
150 if (!(extension->creation_flags() & Extension::ALLOW_FILE_ACCESS)) {
151 pattern.SetValidSchemes(
152 pattern.valid_schemes() & ~URLPattern::SCHEME_FILE);
153 }
154 }
155
156 result->add_url_pattern(pattern);
157 }
158
159 // exclude_matches
160 if (content_script->HasKey(keys::kExcludeMatches)) { // optional
161 const ListValue* exclude_matches = NULL;
162 if (!content_script->GetList(keys::kExcludeMatches, &exclude_matches)) {
163 *error = ErrorUtils::FormatErrorMessageUTF16(
164 errors::kInvalidExcludeMatches,
165 base::IntToString(definition_index));
166 return false;
167 }
168
169 for (size_t j = 0; j < exclude_matches->GetSize(); ++j) {
170 std::string match_str;
171 if (!exclude_matches->GetString(j, &match_str)) {
172 *error = ErrorUtils::FormatErrorMessageUTF16(
173 errors::kInvalidExcludeMatch,
174 base::IntToString(definition_index),
175 base::IntToString(j),
176 errors::kExpectString);
177 return false;
178 }
179
180 URLPattern pattern(UserScript::kValidUserScriptSchemes);
181 if (extension->CanExecuteScriptEverywhere())
182 pattern.SetValidSchemes(URLPattern::SCHEME_ALL);
183
184 URLPattern::ParseResult parse_result = pattern.Parse(match_str);
185 if (parse_result != URLPattern::PARSE_SUCCESS) {
186 *error = ErrorUtils::FormatErrorMessageUTF16(
187 errors::kInvalidExcludeMatch,
188 base::IntToString(definition_index), base::IntToString(j),
189 URLPattern::GetParseResultString(parse_result));
190 return false;
191 }
192
193 result->add_exclude_url_pattern(pattern);
194 }
195 }
196
197 // include/exclude globs (mostly for Greasemonkey compatibility)
198 if (!LoadGlobsHelper(content_script, definition_index, keys::kIncludeGlobs,
199 error, &UserScript::add_glob, result)) {
200 return false;
201 }
202
203 if (!LoadGlobsHelper(content_script, definition_index, keys::kExcludeGlobs,
204 error, &UserScript::add_exclude_glob, result)) {
205 return false;
206 }
207
208 // js and css keys
209 const ListValue* js = NULL;
210 if (content_script->HasKey(keys::kJs) &&
211 !content_script->GetList(keys::kJs, &js)) {
212 *error = ErrorUtils::FormatErrorMessageUTF16(
213 errors::kInvalidJsList,
214 base::IntToString(definition_index));
215 return false;
216 }
217
218 const ListValue* css = NULL;
219 if (content_script->HasKey(keys::kCss) &&
220 !content_script->GetList(keys::kCss, &css)) {
221 *error = ErrorUtils::
222 FormatErrorMessageUTF16(errors::kInvalidCssList,
223 base::IntToString(definition_index));
224 return false;
225 }
226
227 // The manifest needs to have at least one js or css user script definition.
228 if (((js ? js->GetSize() : 0) + (css ? css->GetSize() : 0)) == 0) {
229 *error = ErrorUtils::FormatErrorMessageUTF16(
230 errors::kMissingFile,
231 base::IntToString(definition_index));
232 return false;
233 }
234
235 if (js) {
236 for (size_t script_index = 0; script_index < js->GetSize();
237 ++script_index) {
238 const Value* value;
239 std::string relative;
240 if (!js->Get(script_index, &value) || !value->GetAsString(&relative)) {
241 *error = ErrorUtils::FormatErrorMessageUTF16(
242 errors::kInvalidJs,
243 base::IntToString(definition_index),
244 base::IntToString(script_index));
245 return false;
246 }
247 GURL url = extension->GetResourceURL(relative);
248 ExtensionResource resource = extension->GetResource(relative);
249 result->js_scripts().push_back(UserScript::File(
250 resource.extension_root(), resource.relative_path(), url));
251 }
252 }
253
254 if (css) {
255 for (size_t script_index = 0; script_index < css->GetSize();
256 ++script_index) {
257 const Value* value;
258 std::string relative;
259 if (!css->Get(script_index, &value) || !value->GetAsString(&relative)) {
260 *error = ErrorUtils::FormatErrorMessageUTF16(
261 errors::kInvalidCss,
262 base::IntToString(definition_index),
263 base::IntToString(script_index));
264 return false;
265 }
266 GURL url = extension->GetResourceURL(relative);
267 ExtensionResource resource = extension->GetResource(relative);
268 result->css_scripts().push_back(UserScript::File(
269 resource.extension_root(), resource.relative_path(), url));
270 }
271 }
272
273 return true;
274 }
275
276 struct EmptyUserScriptList {
277 UserScriptList user_script_list;
278 };
279
280 static base::LazyInstance<EmptyUserScriptList> g_empty_script_list =
281 LAZY_INSTANCE_INITIALIZER;
282
283 } // namespace
284
285 // static
286 const UserScriptList& ContentScriptsInfo::GetContentScripts(
287 const Extension* extension) {
288 ContentScriptsInfo* info = static_cast<ContentScriptsInfo*>(
289 extension->GetManifestData(keys::kContentScripts));
290 return info ? info->content_scripts
291 : g_empty_script_list.Get().user_script_list;
292 }
293
294 ContentScriptsHandler::ContentScriptsHandler() {
295 }
296
297 ContentScriptsHandler::~ContentScriptsHandler() {
298 }
299
300 bool ContentScriptsHandler::Parse(const base::Value* value,
301 Extension* extension,
302 string16* error) {
303 scoped_ptr<ContentScriptsInfo> content_scripts_info(new ContentScriptsInfo);
304 const ListValue* scripts_list = NULL;
305 if (!value->GetAsList(&scripts_list)) {
306 *error = ASCIIToUTF16(errors::kInvalidContentScriptsList);
307 return false;
308 }
309
310 for (size_t i = 0; i < scripts_list->GetSize(); ++i) {
311 const DictionaryValue* script_dict = NULL;
312 if (!scripts_list->GetDictionary(i, &script_dict)) {
313 *error = ErrorUtils::FormatErrorMessageUTF16(
314 extension_manifest_errors::kInvalidContentScript,
315 base::IntToString(i));
316 return false;
317 }
318
319 UserScript user_script;
320 if (!LoadUserScriptFromDictionary(script_dict,
321 i,
322 extension,
323 error,
324 &user_script)) {
325 return false; // Failed to parse script context definition.
326 }
327 user_script.set_extension_id(extension->id());
328 if (extension->converted_from_user_script()) {
329 user_script.set_emulate_greasemonkey(true);
330 // Greasemonkey matches all frames.
331 user_script.set_match_all_frames(true);
332 }
333 content_scripts_info->content_scripts.push_back(user_script);
334 }
335 extension->SetManifestData(keys::kContentScripts,
336 content_scripts_info.release());
337 return true;
338 }
339
340 } // namespace extensions
341
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698