summaryrefslogtreecommitdiffstats
path: root/chrome/browser/extensions/extension.cc
diff options
context:
space:
mode:
authoraa@chromium.org <aa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-01-22 19:27:56 +0000
committeraa@chromium.org <aa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-01-22 19:27:56 +0000
commit91c394a8ab7a4a3acd1721ccc314498f0f726c8f (patch)
tree5b6fb9aa84bb2654b2655b528d3887699d30fb9a /chrome/browser/extensions/extension.cc
parentf1cbc4644f1c41954e5f3562d723a471139ff465 (diff)
downloadchromium_src-91c394a8ab7a4a3acd1721ccc314498f0f726c8f.zip
chromium_src-91c394a8ab7a4a3acd1721ccc314498f0f726c8f.tar.gz
chromium_src-91c394a8ab7a4a3acd1721ccc314498f0f726c8f.tar.bz2
Parse more user script info out of the manifest and expose
it on the Extension class. Removed Extension::CopyToValue() because it was only being used in unit tests. Centralize functions for creation of absolute URLs and paths to extension resources in Extension class and move corresponding unit tests. Various other minor nitpickery. Review URL: http://codereview.chromium.org/18352 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@8486 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/extensions/extension.cc')
-rw-r--r--chrome/browser/extensions/extension.cc228
1 files changed, 176 insertions, 52 deletions
diff --git a/chrome/browser/extensions/extension.cc b/chrome/browser/extensions/extension.cc
index e8d6513..4dfac73 100644
--- a/chrome/browser/extensions/extension.cc
+++ b/chrome/browser/extensions/extension.cc
@@ -6,32 +6,140 @@
#include "base/logging.h"
#include "base/string_util.h"
+#include "net/base/net_util.h"
const char Extension::kManifestFilename[] = "manifest";
+const wchar_t* Extension::kDescriptionKey = L"description";
+const wchar_t* Extension::kFilesKey = L"files";
const wchar_t* Extension::kFormatVersionKey = L"format_version";
const wchar_t* Extension::kIdKey = L"id";
+const wchar_t* Extension::kMatchesKey = L"matches";
const wchar_t* Extension::kNameKey = L"name";
-const wchar_t* Extension::kDescriptionKey = L"description";
-const wchar_t* Extension::kContentScriptsKey = L"content_scripts";
+const wchar_t* Extension::kUserScriptsKey = L"user_scripts";
const wchar_t* Extension::kVersionKey = L"version";
-const char* Extension::kInvalidManifestError =
- "Manifest is missing or invalid.";
+// Extension-related error messages. Some of these are simple patterns, where a
+// '*' is replaced at runtime with a specific value. This is used instead of
+// printf because we want to unit test them and scanf is hard to make
+// cross-platform.
+const char* Extension::kInvalidDescriptionError =
+ "Invalid value for 'description'.";
+const char* Extension::kInvalidFileCountError =
+ "Invalid value for 'user_scripts[*].files. Only one file is currently "
+ "supported per-user script.";
+const char* Extension::kInvalidFileError =
+ "Invalid value for 'user_scripts[*].files[*]'.";
+const char* Extension::kInvalidFilesError =
+ "Required value 'user_scripts[*].files is missing or invalid.";
const char* Extension::kInvalidFormatVersionError =
- "Required key 'format_version' is missing or invalid.";
+ "Required value 'format_version' is missing or invalid.";
const char* Extension::kInvalidIdError =
- "Required key 'id' is missing or invalid.";
+ "Required value 'id' is missing or invalid.";
+const char* Extension::kInvalidManifestError =
+ "Manifest is missing or invalid.";
+const char* Extension::kInvalidMatchCountError =
+ "Invalid value for 'user_scripts[*].matches. There must be at least one "
+ "match specified.";
+const char* Extension::kInvalidMatchError =
+ "Invalid value for 'user_scripts[*].matches[*]'.";
+const char* Extension::kInvalidMatchesError =
+ "Required value 'user_scripts[*].matches' is missing or invalid.";
const char* Extension::kInvalidNameError =
- "Required key 'name' is missing or has invalid type.";
-const char* Extension::kInvalidDescriptionError =
- "Invalid type for 'description' key.";
-const char* Extension::kInvalidContentScriptsListError =
- "Invalid type for 'content_scripts' key.";
-const char* Extension::kInvalidContentScriptError =
- "Invalid type for content_scripts at index ";
+ "Required value 'name' is missing or invalid.";
+const char* Extension::kInvalidUserScriptError =
+ "Invalid value for 'user_scripts[*]'.";
+const char* Extension::kInvalidUserScriptsListError =
+ "Invalid value for 'user_scripts'.";
const char* Extension::kInvalidVersionError =
- "Required key 'version' is missing or invalid.";
+ "Required value 'version' is missing or invalid.";
+
+// Defined in extension_protocols.h.
+extern const char kExtensionURLScheme[];
+
+// static
+GURL Extension::GetResourceURL(const GURL& extension_url,
+ const std::string& relative_path) {
+ DCHECK(extension_url.SchemeIs(kExtensionURLScheme));
+ DCHECK(extension_url.path() == "/");
+
+ GURL ret_val = GURL(extension_url.spec() + relative_path);
+ DCHECK(StartsWithASCII(ret_val.spec(), extension_url.spec(), false));
+
+ return ret_val;
+}
+
+// static
+FilePath Extension::GetResourcePath(const FilePath& extension_path,
+ const std::string& relative_path) {
+ // Build up a file:// URL and convert that back to a FilePath. This avoids
+ // URL encoding and path separator issues.
+
+ // Convert the extension's root to a file:// URL.
+ GURL extension_url = net::FilePathToFileURL(extension_path);
+ if (!extension_url.is_valid())
+ return FilePath();
+
+ // Append the requested path.
+ GURL::Replacements replacements;
+ std::string new_path(extension_url.path());
+ new_path += "/";
+ new_path += relative_path;
+ replacements.SetPathStr(new_path);
+ GURL file_url = extension_url.ReplaceComponents(replacements);
+ if (!file_url.is_valid())
+ return FilePath();
+
+ // Convert the result back to a FilePath.
+ FilePath ret_val;
+ if (!net::FileURLToFilePath(file_url, &ret_val))
+ return FilePath();
+
+ // Double-check that the path we ended up with is actually inside the
+ // extension root. We can do this with a simple prefix match because:
+ // a) We control the prefix on both sides, and they should match.
+ // b) GURL normalizes things like "../" and "//" before it gets to us.
+ if (ret_val.value().find(extension_path.value() +
+ FilePath::kSeparators[0]) != 0)
+ return FilePath();
+
+ return ret_val;
+}
+
+// Creates an error messages from a pattern.
+static std::string FormatErrorMessage(const std::string& format,
+ const std::string s1) {
+ std::string ret_val = format;
+ ReplaceFirstSubstringAfterOffset(&ret_val, 0, "*", s1);
+ return ret_val;
+}
+
+static std::string FormatErrorMessage(const std::string& format,
+ const std::string s1,
+ const std::string s2) {
+ std::string ret_val = format;
+ ReplaceFirstSubstringAfterOffset(&ret_val, 0, "*", s1);
+ ReplaceFirstSubstringAfterOffset(&ret_val, 0, "*", s2);
+ return ret_val;
+}
+
+Extension::Extension(const FilePath& path) {
+ DCHECK(path.IsAbsolute());
+
+#if defined(OS_WIN)
+ // Normalize any drive letter to upper-case. We do this for consistency with
+ // net_utils::FilePathToFileURL(), which does the same thing, to make string
+ // comparisons simpler.
+ std::wstring path_str = path.value();
+ if (path_str.size() >= 2 && path_str[0] >= L'a' && path_str[0] <= L'z' &&
+ path_str[1] == ':')
+ path_str[0] += ('A' - 'a');
+
+ path_ = FilePath(path_str);
+#else
+ path_ = path;
+#endif
+}
bool Extension::InitFromValue(const DictionaryValue& source,
std::string* error) {
@@ -49,6 +157,9 @@ bool Extension::InitFromValue(const DictionaryValue& source,
return false;
}
+ // Initialize URL.
+ extension_url_ = GURL(std::string(kExtensionURLScheme) + "://" + id_ + "/");
+
// Initialize version.
if (!source.GetString(kVersionKey, &version_)) {
*error = kInvalidVersionError;
@@ -62,64 +173,77 @@ bool Extension::InitFromValue(const DictionaryValue& source,
}
// Initialize description (optional).
- Value* value = NULL;
- if (source.Get(kDescriptionKey, &value)) {
- if (!value->GetAsString(&description_)) {
+ if (source.HasKey(kDescriptionKey)) {
+ if (!source.GetString(kDescriptionKey, &description_)) {
*error = kInvalidDescriptionError;
return false;
}
}
- // Initialize content scripts (optional).
- if (source.Get(kContentScriptsKey, &value)) {
- ListValue* list_value = NULL;
- if (value->GetType() != Value::TYPE_LIST) {
- *error = kInvalidContentScriptsListError;
+ // Initialize user scripts (optional).
+ if (source.HasKey(kUserScriptsKey)) {
+ ListValue* list_value;
+ if (!source.GetList(kUserScriptsKey, &list_value)) {
+ *error = kInvalidUserScriptsListError;
return false;
- } else {
- list_value = static_cast<ListValue*>(value);
}
for (size_t i = 0; i < list_value->GetSize(); ++i) {
- std::string content_script;
- if (!list_value->Get(i, &value) || !value->GetAsString(&content_script)) {
- *error = kInvalidContentScriptError;
- *error += IntToString(i);
+ DictionaryValue* user_script;
+ if (!list_value->GetDictionary(i, &user_script)) {
+ *error = FormatErrorMessage(kInvalidUserScriptError, IntToString(i));
return false;
}
- content_scripts_.push_back(content_script);
- }
- }
+ ListValue* matches;
+ ListValue* files;
- return true;
-}
+ if (!user_script->GetList(kMatchesKey, &matches)) {
+ *error = FormatErrorMessage(kInvalidMatchesError, IntToString(i));
+ return false;
+ }
-void Extension::CopyToValue(DictionaryValue* destination) {
- // Set format version
- destination->SetInteger(kFormatVersionKey,
- kExpectedFormatVersion);
+ if (!user_script->GetList(kFilesKey, &files)) {
+ *error = FormatErrorMessage(kInvalidFilesError, IntToString(i));
+ return false;
+ }
- // Copy id.
- destination->SetString(kIdKey, id_);
+ if (matches->GetSize() == 0) {
+ *error = FormatErrorMessage(kInvalidMatchCountError, IntToString(i));
+ return false;
+ }
- // Copy version.
- destination->SetString(kVersionKey, version_);
+ // NOTE: Only one file is supported right now.
+ if (files->GetSize() != 1) {
+ *error = FormatErrorMessage(kInvalidFileCountError, IntToString(i));
+ return false;
+ }
- // Copy name.
- destination->SetString(kNameKey, name_);
+ UserScriptInfo script_info;
+ for (size_t j = 0; j < matches->GetSize(); ++j) {
+ std::string match;
+ if (!matches->GetString(j, &match)) {
+ *error = FormatErrorMessage(kInvalidMatchError, IntToString(i),
+ IntToString(j));
+ return false;
+ }
- // Copy description (optional).
- if (description_.size() > 0)
- destination->SetString(kDescriptionKey, description_);
+ script_info.matches.push_back(match);
+ }
- // Copy content scripts (optional).
- if (content_scripts_.size() > 0) {
- ListValue* list_value = new ListValue();
- destination->Set(kContentScriptsKey, list_value);
+ // TODO(aa): Support multiple files.
+ std::string file;
+ if (!files->GetString(0, &file)) {
+ *error = FormatErrorMessage(kInvalidFileError, IntToString(i),
+ IntToString(0));
+ return false;
+ }
+ script_info.path = Extension::GetResourcePath(path(), file);
+ script_info.url = Extension::GetResourceURL(url(), file);
- for (size_t i = 0; i < content_scripts_.size(); ++i) {
- list_value->Set(i, Value::CreateStringValue(content_scripts_[i]));
+ user_scripts_.push_back(script_info);
}
}
+
+ return true;
}