summaryrefslogtreecommitdiffstats
path: root/chrome/browser
diff options
context:
space:
mode:
authorcira@chromium.org <cira@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-08-19 20:45:14 +0000
committercira@chromium.org <cira@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-08-19 20:45:14 +0000
commit300cc58db6bc8d78e279dc07c46f15d9702148c6 (patch)
tree01eb9d8585bc43b01850c226bc4d5f2a3ec00cea /chrome/browser
parentcceaf1fbf3f4963c59a49268217f1e3edfb372ef (diff)
downloadchromium_src-300cc58db6bc8d78e279dc07c46f15d9702148c6.zip
chromium_src-300cc58db6bc8d78e279dc07c46f15d9702148c6.tar.gz
chromium_src-300cc58db6bc8d78e279dc07c46f15d9702148c6.tar.bz2
This change enables Chrome to load locale information for the extension. It detects default locale, and filters out all locales not supported
by Chrome or with invalid names/missing messages. It also checks for folders that start with _ and are not in the reserved list. We don't validate messages file with this CL. Added support for loading supplied locale information to the extension_file_util, and detecting default locale. Added new constants to extension class (_locales directory name, messages filename). Added new error messages to _constants. Added new unittests. BUG=12131 TEST=There should be no visible changes, except in case of error when loading extension (e.g. create empty _locales folder and try loading). Review URL: http://codereview.chromium.org/170015 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@23739 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser')
-rw-r--r--chrome/browser/extensions/extension_file_util.cc60
-rw-r--r--chrome/browser/extensions/extension_file_util.h7
-rw-r--r--chrome/browser/extensions/extension_file_util_unittest.cc109
-rw-r--r--chrome/browser/extensions/extension_l10n_util.cc90
-rw-r--r--chrome/browser/extensions/extension_l10n_util.h46
-rw-r--r--chrome/browser/extensions/extension_l10n_util_unittest.cc135
6 files changed, 447 insertions, 0 deletions
diff --git a/chrome/browser/extensions/extension_file_util.cc b/chrome/browser/extensions/extension_file_util.cc
index 07ef77f..bf6cd9c 100644
--- a/chrome/browser/extensions/extension_file_util.cc
+++ b/chrome/browser/extensions/extension_file_util.cc
@@ -8,6 +8,7 @@
#include "base/logging.h"
#include "base/scoped_temp_dir.h"
#include "base/string_util.h"
+#include "chrome/browser/extensions/extension_l10n_util.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/extensions/extension_constants.h"
#include "chrome/common/json_value_serializer.h"
@@ -276,6 +277,27 @@ Extension* LoadExtension(const FilePath& extension_path, bool require_key,
}
}
+ // Load locale information if available.
+ FilePath locale_path = extension_path.AppendASCII(Extension::kLocaleFolder);
+ if (file_util::PathExists(locale_path)) {
+ if (!extension_l10n_util::AddValidLocales(locale_path,
+ extension.get(),
+ error)) {
+ return NULL;
+ }
+
+ if (!extension_l10n_util::ValidateDefaultLocale(extension.get())) {
+ *error = extension_manifest_errors::kLocalesNoDefaultLocaleSpecified;
+ return NULL;
+ }
+ }
+
+ // Check children of extension root to see if any of them start with _ and is
+ // not on the reserved list.
+ if (!CheckForIllegalFilenames(extension_path, error)) {
+ return NULL;
+ }
+
return extension.release();
}
@@ -349,4 +371,42 @@ void GarbageCollectExtensions(const FilePath& install_directory) {
}
}
+bool CheckForIllegalFilenames(const FilePath& extension_path,
+ std::string* error) {
+ // Reserved underscore names.
+ static const char* reserved_names[] = {
+ Extension::kLocaleFolder
+ };
+ static std::set<std::string> reserved_underscore_names(
+ reserved_names, reserved_names + arraysize(reserved_names));
+
+ // Enumerate all files and directories in the extension root.
+ // There is a problem when using pattern "_*" with FileEnumerator, so we have
+ // to cheat with find_first_of and match all.
+ file_util::FileEnumerator all_files(
+ extension_path,
+ false,
+ static_cast<file_util::FileEnumerator::FILE_TYPE>(
+ file_util::FileEnumerator::DIRECTORIES |
+ file_util::FileEnumerator::FILES));
+
+ FilePath files;
+ while (!(files = all_files.Next()).empty()) {
+ std::string filename =
+ WideToASCII(files.BaseName().ToWStringHack());
+ // Skip all that don't start with "_".
+ if (filename.find_first_of("_") != 0) continue;
+ if (reserved_underscore_names.find(filename) ==
+ reserved_underscore_names.end()) {
+ *error = StringPrintf(
+ "Cannot load extension with file or directory name %s."
+ "Filenames starting with \"_\" are reserved for use by the system",
+ filename.c_str());
+ return false;
+ }
+ }
+
+ return true;
+}
+
} // extensionfile_util
diff --git a/chrome/browser/extensions/extension_file_util.h b/chrome/browser/extensions/extension_file_util.h
index 45d0b30..c2eb5c9 100644
--- a/chrome/browser/extensions/extension_file_util.h
+++ b/chrome/browser/extensions/extension_file_util.h
@@ -78,6 +78,13 @@ void UninstallExtension(const std::string& id, const FilePath& extensions_dir);
// removing others?
void GarbageCollectExtensions(const FilePath& extensions_dir);
+// We need to reserve the namespace of entries that start with "_" for future
+// use by Chrome.
+// If any files or directories are found using "_" prefix and are not on
+// reserved list we return false, and set error message.
+bool CheckForIllegalFilenames(const FilePath& extension_path,
+ std::string* error);
+
} // extension_file_util
#endif // CHROME_BROWSER_EXTENSIONS_EXTENSION_FILE_UTIL_H_
diff --git a/chrome/browser/extensions/extension_file_util_unittest.cc b/chrome/browser/extensions/extension_file_util_unittest.cc
index 6e9b2dc..73dfb46 100644
--- a/chrome/browser/extensions/extension_file_util_unittest.cc
+++ b/chrome/browser/extensions/extension_file_util_unittest.cc
@@ -8,8 +8,13 @@
#include "base/scoped_temp_dir.h"
#include "base/path_service.h"
#include "chrome/common/chrome_paths.h"
+#include "chrome/common/extensions/extension.h"
+#include "chrome/common/extensions/extension_constants.h"
+#include "chrome/common/json_value_serializer.h"
#include "testing/gtest/include/gtest/gtest.h"
+namespace keys = extension_manifest_keys;
+
TEST(ExtensionFileUtil, MoveDirSafely) {
// Create a test directory structure with some data in it.
ScopedTempDir temp;
@@ -162,6 +167,110 @@ TEST(ExtensionFileUtil, CompareToInstalledVersion) {
ASSERT_EQ("", version_out);
}
+// Creates minimal manifest, with or without default_locale section.
+bool CreateMinimalManifest(const std::string& locale,
+ const FilePath& manifest_path) {
+ DictionaryValue manifest;
+
+ manifest.SetString(keys::kVersion, "1.0.0.0");
+ manifest.SetString(keys::kName, "my extension");
+ if (!locale.empty()) {
+ manifest.SetString(keys::kDefaultLocale, locale);
+ }
+
+ JSONFileValueSerializer serializer(manifest_path);
+ return serializer.Serialize(manifest);
+}
+
+TEST(ExtensionFileUtil, LoadExtensionWithValidLocales) {
+ ScopedTempDir temp;
+ ASSERT_TRUE(temp.CreateUniqueTempDir());
+ ASSERT_TRUE(CreateMinimalManifest(
+ "en_US", temp.path().AppendASCII(Extension::kManifestFilename)));
+
+ FilePath src_path = temp.path().AppendASCII(Extension::kLocaleFolder);
+ ASSERT_TRUE(file_util::CreateDirectory(src_path));
+
+ FilePath locale_1 = src_path.AppendASCII("sr");
+ ASSERT_TRUE(file_util::CreateDirectory(locale_1));
+
+ std::string data = "foobar";
+ ASSERT_TRUE(
+ file_util::WriteFile(locale_1.AppendASCII(Extension::kMessagesFilename),
+ data.c_str(), data.length()));
+
+ FilePath locale_2 = src_path.AppendASCII("en_US");
+ ASSERT_TRUE(file_util::CreateDirectory(locale_2));
+
+ ASSERT_TRUE(
+ file_util::WriteFile(locale_2.AppendASCII(Extension::kMessagesFilename),
+ data.c_str(), data.length()));
+
+ std::string error;
+ scoped_ptr<Extension> extension(
+ extension_file_util::LoadExtension(temp.path(), false, &error));
+ ASSERT_FALSE(extension == NULL);
+ EXPECT_EQ(static_cast<unsigned int>(2),
+ extension->supported_locales().size());
+ EXPECT_EQ("en-US", extension->default_locale());
+}
+
+TEST(ExtensionFileUtil, LoadExtensionWithoutLocalesFolder) {
+ ScopedTempDir temp;
+ ASSERT_TRUE(temp.CreateUniqueTempDir());
+ ASSERT_TRUE(CreateMinimalManifest(
+ "", temp.path().AppendASCII(Extension::kManifestFilename)));
+
+ std::string error;
+ scoped_ptr<Extension> extension(
+ extension_file_util::LoadExtension(temp.path(), false, &error));
+ ASSERT_FALSE(extension == NULL);
+ EXPECT_TRUE(extension->supported_locales().empty());
+ EXPECT_TRUE(extension->default_locale().empty());
+}
+
+TEST(ExtensionFileUtil, CheckIllegalFilenamesNoUnderscores) {
+ ScopedTempDir temp;
+ ASSERT_TRUE(temp.CreateUniqueTempDir());
+
+ FilePath src_path = temp.path().AppendASCII("some_dir");
+ ASSERT_TRUE(file_util::CreateDirectory(src_path));
+
+ std::string data = "foobar";
+ ASSERT_TRUE(file_util::WriteFile(src_path.AppendASCII("some_file.txt"),
+ data.c_str(), data.length()));
+ std::string error;
+ EXPECT_TRUE(extension_file_util::CheckForIllegalFilenames(temp.path(),
+ &error));
+}
+
+TEST(ExtensionFileUtil, CheckIllegalFilenamesOnlyReserved) {
+ ScopedTempDir temp;
+ ASSERT_TRUE(temp.CreateUniqueTempDir());
+
+ FilePath src_path = temp.path().AppendASCII(Extension::kLocaleFolder);
+ ASSERT_TRUE(file_util::CreateDirectory(src_path));
+
+ std::string error;
+ EXPECT_TRUE(extension_file_util::CheckForIllegalFilenames(temp.path(),
+ &error));
+}
+
+TEST(ExtensionFileUtil, CheckIllegalFilenamesReservedAndIllegal) {
+ ScopedTempDir temp;
+ ASSERT_TRUE(temp.CreateUniqueTempDir());
+
+ FilePath src_path = temp.path().AppendASCII(Extension::kLocaleFolder);
+ ASSERT_TRUE(file_util::CreateDirectory(src_path));
+
+ src_path = temp.path().AppendASCII("_some_dir");
+ ASSERT_TRUE(file_util::CreateDirectory(src_path));
+
+ std::string error;
+ EXPECT_FALSE(extension_file_util::CheckForIllegalFilenames(temp.path(),
+ &error));
+}
+
// TODO(aa): More tests as motivation allows. Maybe steal some from
// ExtensionsService? Many of them could probably be tested here without the
// MessageLoop shenanigans.
diff --git a/chrome/browser/extensions/extension_l10n_util.cc b/chrome/browser/extensions/extension_l10n_util.cc
new file mode 100644
index 0000000..77fddba
--- /dev/null
+++ b/chrome/browser/extensions/extension_l10n_util.cc
@@ -0,0 +1,90 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/extensions/extension_l10n_util.h"
+
+#include <set>
+#include <string>
+#include <vector>
+
+#include "app/l10n_util.h"
+#include "base/file_util.h"
+#include "base/string_util.h"
+#include "base/values.h"
+#include "chrome/common/extensions/extension.h"
+#include "chrome/common/extensions/extension_constants.h"
+
+namespace keys = extension_manifest_keys;
+
+namespace extension_l10n_util {
+
+bool ValidateDefaultLocale(const Extension* extension) {
+ std::string default_locale = extension->default_locale();
+
+ if (extension->supported_locales().find(default_locale) !=
+ extension->supported_locales().end()) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+
+bool AddLocale(const std::set<std::string>& chrome_locales,
+ const FilePath& locale_folder,
+ Extension* extension,
+ std::string* locale_name,
+ std::string* error) {
+ // Normalize underscores to hyphens because that's what our locale files use.
+ std::replace(locale_name->begin(), locale_name->end(), '_', '-');
+ if (chrome_locales.find(*locale_name) == chrome_locales.end()) {
+ // Fail if there is an extension locale that's not in the Chrome list.
+ *error = StringPrintf("Supplied locale %s is not supported.",
+ locale_name->c_str());
+ return false;
+ }
+ // Check if messages file is actually present (but don't check content).
+ if (file_util::PathExists(
+ locale_folder.AppendASCII(Extension::kMessagesFilename))) {
+ extension->AddSupportedLocale(*locale_name);
+ } else {
+ *error = StringPrintf("Catalog file is missing for locale %s.",
+ locale_name->c_str());
+ return false;
+ }
+
+ return true;
+}
+
+bool AddValidLocales(const FilePath& locale_path,
+ Extension* extension,
+ std::string* error) {
+ // Get available chrome locales as a set.
+ const std::vector<std::string>& available_locales =
+ l10n_util::GetAvailableLocales();
+ static std::set<std::string> chrome_locales(available_locales.begin(),
+ available_locales.end());
+ // Enumerate all supplied locales in the extension.
+ file_util::FileEnumerator locales(locale_path,
+ false,
+ file_util::FileEnumerator::DIRECTORIES);
+ FilePath locale_folder;
+ while (!(locale_folder = locales.Next()).empty()) {
+ std::string locale_name =
+ WideToASCII(locale_folder.BaseName().ToWStringHack());
+ if (!AddLocale(chrome_locales, locale_folder,
+ extension, &locale_name, error)) {
+ return false;
+ }
+ }
+
+ if (extension->supported_locales().empty()) {
+ *error = extension_manifest_errors::kLocalesNoValidLocaleNamesListed;
+ return false;
+ }
+
+ return true;
+}
+
+} // namespace extension_l10n_util
diff --git a/chrome/browser/extensions/extension_l10n_util.h b/chrome/browser/extensions/extension_l10n_util.h
new file mode 100644
index 0000000..d964566
--- /dev/null
+++ b/chrome/browser/extensions/extension_l10n_util.h
@@ -0,0 +1,46 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// This file declares extension specific l10n utils.
+
+#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_L10N_UTIL_H_
+#define CHROME_BROWSER_EXTENSIONS_EXTENSION_L10N_UTIL_H_
+
+#include <set>
+#include <string>
+
+class DictionaryValue;
+class Extension;
+class FilePath;
+
+namespace extension_l10n_util {
+
+// Returns true if default_locale was set to valid locale
+// (supported by the extension).
+bool ValidateDefaultLocale(const Extension* extension);
+
+// Adds locale_name to the extension if it's in chrome_locales, and
+// if messages file is present (we don't check content of messages file here).
+// Returns false if locale_name was not found in chrome_locales, and sets
+// error with locale_name.
+bool AddLocale(const std::set<std::string>& chrome_locales,
+ const FilePath& locale_folder,
+ Extension* extension,
+ std::string* locale_name,
+ std::string* error);
+
+// Adds valid locales to the extension.
+// 1. Do nothing if _locales directory is missing (not an error).
+// 2. Get list of Chrome locales.
+// 3. Enumerate all subdirectories of _locales directory.
+// 4. Intersect both lists, and add intersection to the extension.
+// Returns false if any of supplied locales don't match chrome list of locales.
+// Fills out error with offending locale name.
+bool AddValidLocales(const FilePath& locale_path,
+ Extension* extension,
+ std::string* error);
+
+} // namespace extension_l10n_util
+
+#endif // CHROME_BROWSER_EXTENSIONS_EXTENSION_L10N_UTIL_H_
diff --git a/chrome/browser/extensions/extension_l10n_util_unittest.cc b/chrome/browser/extensions/extension_l10n_util_unittest.cc
new file mode 100644
index 0000000..04f1ac0
--- /dev/null
+++ b/chrome/browser/extensions/extension_l10n_util_unittest.cc
@@ -0,0 +1,135 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/extensions/extension_l10n_util.h"
+
+#include "base/file_path.h"
+#include "base/file_util.h"
+#include "base/scoped_ptr.h"
+#include "base/scoped_temp_dir.h"
+#include "base/values.h"
+#include "chrome/common/extensions/extension.h"
+#include "chrome/common/extensions/extension_constants.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace keys = extension_manifest_keys;
+
+namespace {
+
+ Extension* CreateMinimalExtension(const std::string& default_locale) {
+#if defined(OS_WIN)
+ FilePath path(FILE_PATH_LITERAL("C:\\foo"));
+#elif defined(OS_POSIX)
+ FilePath path(FILE_PATH_LITERAL("/foo"));
+#endif
+ Extension* extension = new Extension(path);
+ std::string error;
+ DictionaryValue input_value;
+
+ // Test minimal extension
+ input_value.SetString(keys::kVersion, "1.0.0.0");
+ input_value.SetString(keys::kName, "my extension");
+ if (!default_locale.empty()) {
+ input_value.SetString(keys::kDefaultLocale, default_locale);
+ }
+ EXPECT_TRUE(extension->InitFromValue(input_value, false, &error));
+
+ return extension;
+}
+
+TEST(ExtensionL10nUtil, AddValidLocalesEmptyLocaleFolder) {
+ ScopedTempDir temp;
+ ASSERT_TRUE(temp.CreateUniqueTempDir());
+
+ FilePath src_path = temp.path().AppendASCII(Extension::kLocaleFolder);
+ ASSERT_TRUE(file_util::CreateDirectory(src_path));
+
+ scoped_ptr<Extension> extension(CreateMinimalExtension(""));
+
+ std::string error;
+ EXPECT_FALSE(extension_l10n_util::AddValidLocales(src_path,
+ extension.get(),
+ &error));
+
+ EXPECT_TRUE(extension->supported_locales().empty());
+}
+
+TEST(ExtensionL10nUtil, AddValidLocalesWithValidLocaleNoMessagesFile) {
+ ScopedTempDir temp;
+ ASSERT_TRUE(temp.CreateUniqueTempDir());
+
+ FilePath src_path = temp.path().AppendASCII(Extension::kLocaleFolder);
+ ASSERT_TRUE(file_util::CreateDirectory(src_path));
+
+ ASSERT_TRUE(file_util::CreateDirectory(src_path.AppendASCII("sr")));
+
+ scoped_ptr<Extension> extension(CreateMinimalExtension(""));
+
+ std::string error;
+ EXPECT_FALSE(extension_l10n_util::AddValidLocales(src_path,
+ extension.get(),
+ &error));
+
+ EXPECT_TRUE(extension->supported_locales().empty());
+}
+
+TEST(ExtensionL10nUtil, AddValidLocalesWithValidLocalesAndMessagesFile) {
+ ScopedTempDir temp;
+ ASSERT_TRUE(temp.CreateUniqueTempDir());
+
+ FilePath src_path = temp.path().AppendASCII(Extension::kLocaleFolder);
+ ASSERT_TRUE(file_util::CreateDirectory(src_path));
+
+ FilePath locale_1 = src_path.AppendASCII("sr");
+ ASSERT_TRUE(file_util::CreateDirectory(locale_1));
+
+ std::string data = "foobar";
+ ASSERT_TRUE(
+ file_util::WriteFile(locale_1.AppendASCII(Extension::kMessagesFilename),
+ data.c_str(), data.length()));
+
+ FilePath locale_2 = src_path.AppendASCII("en_US");
+ ASSERT_TRUE(file_util::CreateDirectory(locale_2));
+
+ ASSERT_TRUE(
+ file_util::WriteFile(locale_2.AppendASCII(Extension::kMessagesFilename),
+ data.c_str(), data.length()));
+
+ scoped_ptr<Extension> extension(CreateMinimalExtension(""));
+
+ std::string error;
+ EXPECT_TRUE(extension_l10n_util::AddValidLocales(src_path,
+ extension.get(),
+ &error));
+
+ EXPECT_EQ(static_cast<unsigned int>(2),
+ extension->supported_locales().size());
+}
+
+TEST(ExtensionL10nUtil, SetDefaultLocaleGoodDefaultLocaleInManifest) {
+ scoped_ptr<Extension> extension(CreateMinimalExtension("sr"));
+ extension->AddSupportedLocale("sr");
+ extension->AddSupportedLocale("en-US");
+
+ EXPECT_TRUE(extension_l10n_util::ValidateDefaultLocale(extension.get()));
+ EXPECT_EQ("sr", extension->default_locale());
+}
+
+TEST(ExtensionL10nUtil, SetDefaultLocaleNoDefaultLocaleInManifest) {
+ scoped_ptr<Extension> extension(CreateMinimalExtension(""));
+ extension->AddSupportedLocale("sr");
+ extension->AddSupportedLocale("en-US");
+
+ EXPECT_FALSE(extension_l10n_util::ValidateDefaultLocale(extension.get()));
+}
+
+TEST(ExtensionL10nUtil, SetDefaultLocaleWrongDefaultLocaleInManifest) {
+ scoped_ptr<Extension> extension(CreateMinimalExtension("ko"));
+ extension->AddSupportedLocale("sr");
+ extension->AddSupportedLocale("en-US");
+
+ EXPECT_FALSE(extension_l10n_util::ValidateDefaultLocale(extension.get()));
+}
+
+} // namespace