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

Side by Side Diff: chrome/browser/extensions/extension.cc

Issue 18352: Miscellaneous changes to Extension class in prep for user scripts (Closed)
Patch Set: be more paranoid about accessing string indexes than is probably warranted Created 11 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
« no previous file with comments | « chrome/browser/extensions/extension.h ('k') | chrome/browser/extensions/extension_protocols.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/extensions/extension.h" 5 #include "chrome/browser/extensions/extension.h"
6 6
7 #include "base/logging.h" 7 #include "base/logging.h"
8 #include "base/string_util.h" 8 #include "base/string_util.h"
9 #include "net/base/net_util.h"
9 10
10 const FilePath::CharType* Extension::kManifestFilename = 11 const FilePath::CharType* Extension::kManifestFilename =
11 FILE_PATH_LITERAL("manifest"); 12 FILE_PATH_LITERAL("manifest");
12 13
14 const wchar_t* Extension::kDescriptionKey = L"description";
15 const wchar_t* Extension::kFilesKey = L"files";
13 const wchar_t* Extension::kFormatVersionKey = L"format_version"; 16 const wchar_t* Extension::kFormatVersionKey = L"format_version";
14 const wchar_t* Extension::kIdKey = L"id"; 17 const wchar_t* Extension::kIdKey = L"id";
18 const wchar_t* Extension::kMatchesKey = L"matches";
15 const wchar_t* Extension::kNameKey = L"name"; 19 const wchar_t* Extension::kNameKey = L"name";
16 const wchar_t* Extension::kDescriptionKey = L"description"; 20 const wchar_t* Extension::kUserScriptsKey = L"user_scripts";
17 const wchar_t* Extension::kContentScriptsKey = L"content_scripts";
18 const wchar_t* Extension::kVersionKey = L"version"; 21 const wchar_t* Extension::kVersionKey = L"version";
19 22
20 const char* Extension::kInvalidManifestError = 23 // Extension-related error messages. Some of these are simple patterns, where a
24 // '*' is replaced at runtime with a specific value. This is used instead of
25 // printf because we want to unit test them and scanf is hard to make
26 // cross-platform.
27 const char* Extension::kInvalidDescriptionError
28 "Invalid value for 'description'.";
29 const char* Extension::kInvalidFileCountError
30 "Invalid value for 'user_scripts[*].files. Only one file is currently "
31 "supported per-user script.";
32 const char* Extension::kInvalidFileError
33 "Invalid value for 'user_scripts[*].files[*]'.";
34 const char* Extension::kInvalidFilesError
35 "Required value 'user_scripts[*].files is missing or invalid.";
36 const char* Extension::kInvalidFormatVersionError
37 "Required value 'format_version' is missing or invalid.";
38 const char* Extension::kInvalidIdError
39 "Required value 'id' is missing or invalid.";
40 const char* Extension::kInvalidManifestError
21 "Manifest is missing or invalid."; 41 "Manifest is missing or invalid.";
22 const char* Extension::kInvalidFormatVersionError = 42 const char* Extension::kInvalidMatchCountError
23 "Required key 'format_version' is missing or invalid."; 43 "Invalid value for 'user_scripts[*].matches. There must be at least one "
24 const char* Extension::kInvalidIdError = 44 "match specified.";
25 "Required key 'id' is missing or invalid."; 45 const char* Extension::kInvalidMatchError
26 const char* Extension::kInvalidNameError = 46 "Invalid value for 'user_scripts[*].matches[*]'.";
27 "Required key 'name' is missing or has invalid type."; 47 const char* Extension::kInvalidMatchesError
28 const char* Extension::kInvalidDescriptionError = 48 "Required value 'user_scripts[*].matches' is missing or invalid.";
29 "Invalid type for 'description' key."; 49 const char* Extension::kInvalidNameError
30 const char* Extension::kInvalidContentScriptsListError = 50 "Required value 'name' is missing or invalid.";
31 "Invalid type for 'content_scripts' key."; 51 const char* Extension::kInvalidUserScriptError
32 const char* Extension::kInvalidContentScriptError = 52 "Invalid value for 'user_scripts[*]'.";
33 "Invalid type for content_scripts at index "; 53 const char* Extension::kInvalidUserScriptsListError
34 const char* Extension::kInvalidVersionError = 54 "Invalid value for 'user_scripts'.";
35 "Required key 'version' is missing or invalid."; 55 const char* Extension::kInvalidVersionError
56 "Required value 'version' is missing or invalid.";
57
58 // Defined in extension_protocols.h.
59 extern const char kExtensionURLScheme[];
60
61 // static
62 GURL Extension::GetResourceURL(const GURL& extension_url,
63 const std::string& relative_path) {
64 DCHECK(extension_url.SchemeIs(kExtensionURLScheme));
65 DCHECK(extension_url.path() == "/");
66
67 GURL ret_val = GURL(extension_url.spec() + relative_path);
68 DCHECK(StartsWithASCII(ret_val.spec(), extension_url.spec(), false));
69
70 return ret_val;
71 }
72
73 // static
74 FilePath Extension::GetResourcePath(const FilePath& extension_path,
75 const std::string& relative_path) {
76 // Build up a file:// URL and convert that back to a FilePath. This avoids
77 // URL encoding and path separator issues.
78
79 // Convert the extension's root to a file:// URL.
80 GURL extension_url = net::FilePathToFileURL(extension_path);
81 if (!extension_url.is_valid())
82 return FilePath();
83
84 // Append the requested path.
85 GURL::Replacements replacements;
86 std::string new_path(extension_url.path());
87 new_path += "/";
88 new_path += relative_path;
89 replacements.SetPathStr(new_path);
90 GURL file_url = extension_url.ReplaceComponents(replacements);
91 if (!file_url.is_valid())
92 return FilePath();
93
94 // Convert the result back to a FilePath.
95 FilePath ret_val;
96 if (!net::FileURLToFilePath(file_url, &ret_val))
97 return FilePath();
98
99 // Double-check that the path we ended up with is actually inside the
100 // extension root. We can do this with a simple prefix match because:
101 // a) We control the prefix on both sides, and they should match.
102 // b) GURL normalizes things like "../" and "//" before it gets to us.
103 if (ret_val.value().find(extension_path.value() +
104 FilePath::kSeparators[0]) != 0)
105 return FilePath();
106
107 return ret_val;
108 }
109
110 // Creates an error messages from a pattern.
111 static std::string FormatErrorMessage(const std::string& format,
112 const std::string s1) {
113 std::string ret_val = format;
114 ReplaceSubstringsAfterOffset(&ret_val, 0, "*", s1);
115 return ret_val;
116 }
117
118 static std::string FormatErrorMessage(const std::string& format,
119 const std::string s1,
120 const std::string s2) {
121 std::string ret_val = format;
122 ReplaceSubstringsAfterOffset(&ret_val, 0, "*", s1);
123 ReplaceSubstringsAfterOffset(&ret_val, 0, "*", s2);
124 return ret_val;
125 }
126
127 Extension::Extension(const FilePath& path) {
128 DCHECK(path.IsAbsolute());
129
130 #if defined(OS_WIN)
131 // Normalize any drive letter to upper-case. We do this for consistency with
132 // net_utils::FilePathToFileURL(), which does the same thing, to make string
133 // comparisons simpler.
134 std::wstring path_str = path.value();
135 if (path_str.size() >= 2 && path_str[0] >= L'a' && path_str[0] <= L'z' &&
136 path_str[1] == ':')
137 path_str[0] += ('A' - 'a');
138
139 path_ = FilePath(path_str);
140 #else
141 path_ = path;
142 #endif
143 }
36 144
37 bool Extension::InitFromValue(const DictionaryValue& source, 145 bool Extension::InitFromValue(const DictionaryValue& source,
38 std::string* error) { 146 std::string* error) {
39 // Check format version. 147 // Check format version.
40 int format_version = 0; 148 int format_version = 0;
41 if (!source.GetInteger(kFormatVersionKey, &format_version) || 149 if (!source.GetInteger(kFormatVersionKey, &format_version) ||
42 format_version != kExpectedFormatVersion) { 150 format_version != kExpectedFormatVersion) {
43 *error = kInvalidFormatVersionError; 151 *error = kInvalidFormatVersionError;
44 return false; 152 return false;
45 } 153 }
46 154
47 // Initialize id. 155 // Initialize id.
48 if (!source.GetString(kIdKey, &id_)) { 156 if (!source.GetString(kIdKey, &id_)) {
49 *error = kInvalidIdError; 157 *error = kInvalidIdError;
50 return false; 158 return false;
51 } 159 }
52 160
161 // Initialize URL.
162 extension_url_ = GURL(std::string(kExtensionURLScheme) + "://" + id_ + "/");
163
53 // Initialize version. 164 // Initialize version.
54 if (!source.GetString(kVersionKey, &version_)) { 165 if (!source.GetString(kVersionKey, &version_)) {
55 *error = kInvalidVersionError; 166 *error = kInvalidVersionError;
56 return false; 167 return false;
57 } 168 }
58 169
59 // Initialize name. 170 // Initialize name.
60 if (!source.GetString(kNameKey, &name_)) { 171 if (!source.GetString(kNameKey, &name_)) {
61 *error = kInvalidNameError; 172 *error = kInvalidNameError;
62 return false; 173 return false;
63 } 174 }
64 175
65 // Initialize description (optional). 176 // Initialize description (optional).
66 Value* value = NULL; 177 if (source.HasKey(kDescriptionKey)) {
67 if (source.Get(kDescriptionKey, &value)) { 178 if (!source.GetString(kDescriptionKey, &description_)) {
68 if (!value->GetAsString(&description_)) {
69 *error = kInvalidDescriptionError; 179 *error = kInvalidDescriptionError;
70 return false; 180 return false;
71 } 181 }
72 } 182 }
73 183
74 // Initialize content scripts (optional). 184 // Initialize user scripts (optional).
75 if (source.Get(kContentScriptsKey, &value)) { 185 if (source.HasKey(kUserScriptsKey)) {
76 ListValue* list_value = NULL; 186 ListValue* list_value;
77 if (value->GetType() != Value::TYPE_LIST) { 187 if (!source.GetList(kUserScriptsKey, &list_value)) {
78 *error = kInvalidContentScriptsListError; 188 *error = kInvalidUserScriptsListError;
79 return false; 189 return false;
80 } else {
81 list_value = static_cast<ListValue*>(value);
82 } 190 }
83 191
84 for (size_t i = 0; i < list_value->GetSize(); ++i) { 192 for (size_t i = 0; i < list_value->GetSize(); ++i) {
85 std::string content_script; 193 DictionaryValue* user_script;
86 if (!list_value->Get(i, &value) || !value->GetAsString(&content_script)) { 194 if (!list_value->GetDictionary(i, &user_script)) {
87 *error = kInvalidContentScriptError; 195 *error = FormatErrorMessage(kInvalidUserScriptError, IntToString(i));
88 *error += IntToString(i);
89 return false; 196 return false;
90 } 197 }
91 198
92 content_scripts_.push_back(content_script); 199 ListValue* matches;
200 ListValue* files;
201
202 if (!user_script->GetList(kMatchesKey, &matches)) {
203 *error = FormatErrorMessage(kInvalidMatchesError, IntToString(i));
204 return false;
205 }
206
207 if (!user_script->GetList(kFilesKey, &files)) {
208 *error = FormatErrorMessage(kInvalidFilesError, IntToString(i));
209 return false;
210 }
211
212 if (matches->GetSize() == 0) {
213 *error = FormatErrorMessage(kInvalidMatchCountError, IntToString(i));
214 return false;
215 }
216
217 // NOTE: Only one file is supported right now.
218 if (files->GetSize() != 1) {
219 *error = FormatErrorMessage(kInvalidFileCountError, IntToString(i));
220 return false;
221 }
222
223 UserScriptInfo script_info;
224 for (size_t j = 0; j < matches->GetSize(); ++j) {
225 std::string match;
226 if (!matches->GetString(j, &match)) {
227 *error = FormatErrorMessage(kInvalidMatchError, IntToString(i),
228 IntToString(j));
229 return false;
230 }
231
232 script_info.matches.push_back(match);
233 }
234
235 // TODO(aa): Support multiple files.
236 std::string file;
237 if (!files->GetString(0, &file)) {
238 *error = FormatErrorMessage(kInvalidFileError, IntToString(i),
239 IntToString(0));
240 return false;
241 }
242 script_info.path = Extension::GetResourcePath(path(), file);
243 script_info.url = Extension::GetResourceURL(url(), file);
244
245 user_scripts_.push_back(script_info);
93 } 246 }
94 } 247 }
95 248
96 return true; 249 return true;
97 } 250 }
98
99 void Extension::CopyToValue(DictionaryValue* destination) {
100 // Set format version
101 destination->SetInteger(kFormatVersionKey,
102 kExpectedFormatVersion);
103
104 // Copy id.
105 destination->SetString(kIdKey, id_);
106
107 // Copy version.
108 destination->SetString(kVersionKey, version_);
109
110 // Copy name.
111 destination->SetString(kNameKey, name_);
112
113 // Copy description (optional).
114 if (description_.size() > 0)
115 destination->SetString(kDescriptionKey, description_);
116
117 // Copy content scripts (optional).
118 if (content_scripts_.size() > 0) {
119 ListValue* list_value = new ListValue();
120 destination->Set(kContentScriptsKey, list_value);
121
122 for (size_t i = 0; i < content_scripts_.size(); ++i) {
123 list_value->Set(i, Value::CreateStringValue(content_scripts_[i]));
124 }
125 }
126 }
OLDNEW
« no previous file with comments | « chrome/browser/extensions/extension.h ('k') | chrome/browser/extensions/extension_protocols.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698