diff options
author | cira@chromium.org <cira@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-10-07 22:49:10 +0000 |
---|---|---|
committer | cira@chromium.org <cira@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-10-07 22:49:10 +0000 |
commit | ecabe6eed156a36238888bfd2fdb96ec4906f0a4 (patch) | |
tree | 9419d9a349fc940d45fa450b3a75169fdf48b39f /chrome/common/extensions | |
parent | 7050861ff094fd74d155264b6da3ca3795543870 (diff) | |
download | chromium_src-ecabe6eed156a36238888bfd2fdb96ec4906f0a4.zip chromium_src-ecabe6eed156a36238888bfd2fdb96ec4906f0a4.tar.gz chromium_src-ecabe6eed156a36238888bfd2fdb96ec4906f0a4.tar.bz2 |
Loads local resources from current locale subtree if available, if not it falls back to extension subtree.
We look for ext_root/foo/bar.js under ext_root/_locales/fr/foo/bar.js if current locale is fr. If there is no fr specific resource we load ext_root/foo/bar.js instead.
Lots of small refactoring to replace FilePath with ExtensionResource.
BUG=12131
TEST=See unittest for sample tree.
Review URL: http://codereview.chromium.org/256022
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@28333 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/common/extensions')
-rw-r--r-- | chrome/common/extensions/extension.cc | 52 | ||||
-rw-r--r-- | chrome/common/extensions/extension.h | 18 | ||||
-rw-r--r-- | chrome/common/extensions/extension_resource.cc | 100 | ||||
-rw-r--r-- | chrome/common/extensions/extension_resource.h | 49 | ||||
-rw-r--r-- | chrome/common/extensions/extension_resource_unittest.cc | 74 | ||||
-rw-r--r-- | chrome/common/extensions/extension_unittest.cc | 9 | ||||
-rw-r--r-- | chrome/common/extensions/user_script.h | 17 | ||||
-rw-r--r-- | chrome/common/extensions/user_script_unittest.cc | 9 |
8 files changed, 261 insertions, 67 deletions
diff --git a/chrome/common/extensions/extension.cc b/chrome/common/extensions/extension.cc index f00db65..ccfe787 100644 --- a/chrome/common/extensions/extension.cc +++ b/chrome/common/extensions/extension.cc @@ -13,6 +13,7 @@ #include "base/stl_util-inl.h" #include "base/third_party/nss/blapi.h" #include "base/third_party/nss/sha256.h" +#include "chrome/browser/extensions/extension_l10n_util.h" #include "chrome/common/chrome_constants.h" #include "chrome/common/extensions/extension_constants.h" #include "chrome/common/extensions/extension_error_reporter.h" @@ -21,7 +22,6 @@ #include "chrome/common/notification_service.h" #include "chrome/common/url_constants.h" #include "net/base/base64.h" -#include "net/base/net_util.h" #if defined(OS_WIN) #include "base/registry.h" @@ -282,8 +282,8 @@ bool Extension::LoadUserScriptHelper(const DictionaryValue* content_script, } // TODO(georged): Make GetResourceURL accept wstring too GURL url = GetResourceURL(WideToUTF8(relative)); - FilePath path = GetResourcePath(WideToUTF8(relative)); - result->js_scripts().push_back(UserScript::File(path, url)); + ExtensionResource resource = GetResource(WideToUTF8(relative)); + result->js_scripts().push_back(UserScript::File(resource, url)); } } @@ -299,8 +299,8 @@ bool Extension::LoadUserScriptHelper(const DictionaryValue* content_script, } // TODO(georged): Make GetResourceURL accept wstring too GURL url = GetResourceURL(WideToUTF8(relative)); - FilePath path = GetResourcePath(WideToUTF8(relative)); - result->css_scripts().push_back(UserScript::File(path, url)); + ExtensionResource resource = GetResource(WideToUTF8(relative)); + result->css_scripts().push_back(UserScript::File(resource, url)); } } @@ -427,37 +427,11 @@ bool Extension::ContainsNonThemeKeys(const DictionaryValue& source) { } // 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. - if (!extension_path.IsParent(ret_val)) - return FilePath(); - - return ret_val; +ExtensionResource Extension::GetResource(const FilePath& extension_path, + const std::string& relative_path) { + FilePath relative_resource_path; + return ExtensionResource(extension_path, + relative_resource_path.AppendASCII(relative_path)); } Extension::Extension(const FilePath& path) @@ -1119,12 +1093,12 @@ void Extension::SetBackgroundPageReady() { NotificationService::NoDetails()); } -FilePath Extension::GetIconPath(Icons icon) { +ExtensionResource Extension::GetIconPath(Icons icon) { std::map<int, std::string>::const_iterator iter = icons_.find(Extension::EXTENSION_ICON_LARGE); if (iter == icons_.end()) - return FilePath(); - return GetResourcePath(iter->second); + return ExtensionResource(); + return GetResource(iter->second); } bool Extension::CanAccessHost(const GURL& url) const { diff --git a/chrome/common/extensions/extension.h b/chrome/common/extensions/extension.h index c01d948..57337de 100644 --- a/chrome/common/extensions/extension.h +++ b/chrome/common/extensions/extension.h @@ -17,6 +17,7 @@ #include "chrome/browser/extensions/user_script_master.h" #include "chrome/common/extensions/extension_action.h" #include "chrome/common/extensions/extension_message_bundle.h" +#include "chrome/common/extensions/extension_resource.h" #include "chrome/common/extensions/user_script.h" #include "chrome/common/extensions/url_pattern.h" #include "googleurl/src/gurl.h" @@ -132,15 +133,14 @@ class Extension { return GetResourceURL(url(), relative_path); } - // Returns an absolute path to a resource inside of an extension. The - // |extension_path| argument should be the path() from an Extension object. - // The |relative_path| can be untrusted user input. The returned path will - // either be empty or a child of extension_path. + // Returns an extension resource object. The |extension_path| argument should + // be the path() from an Extension object. + // The |relative_path| can be untrusted user input. // NOTE: Static so that it can be used from multiple threads. - static FilePath GetResourcePath(const FilePath& extension_path, - const std::string& relative_path); - FilePath GetResourcePath(const std::string& relative_path) { - return GetResourcePath(path(), relative_path); + static ExtensionResource GetResource(const FilePath& extension_path, + const std::string& relative_path); + ExtensionResource GetResource(const std::string& relative_path) { + return GetResource(path(), relative_path); } // |input| is expected to be the text of an rsa public or private key. It @@ -243,7 +243,7 @@ class Extension { // Returns an absolute path to the given icon inside of the extension. Returns // an empty FilePath if the extension does not have that icon. - FilePath GetIconPath(Icons icon); + ExtensionResource GetIconPath(Icons icon); const DictionaryValue* manifest_value() const { return manifest_value_.get(); diff --git a/chrome/common/extensions/extension_resource.cc b/chrome/common/extensions/extension_resource.cc new file mode 100644 index 0000000..f64354f --- /dev/null +++ b/chrome/common/extensions/extension_resource.cc @@ -0,0 +1,100 @@ +// 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/common/extensions/extension_resource.h" + +#include "base/file_path.h" +#include "base/file_util.h" +#include "base/string_util.h" +#include "chrome/browser/extensions/extension_l10n_util.h" +#include "googleurl/src/gurl.h" +#include "net/base/net_util.h" + +ExtensionResource::ExtensionResource() { +} + +ExtensionResource::ExtensionResource(const FilePath& extension_root, + const FilePath& relative_path) + : extension_root_(extension_root), + relative_path_(relative_path) { +} + +const FilePath& ExtensionResource::GetFilePath() const { + if (extension_root_.empty() || relative_path_.empty()) + return full_resource_path_; + + // We've already checked, just return last value. + if (!full_resource_path_.empty()) + return full_resource_path_; + + // Stat l10n file, and return new path if it exists. + FilePath l10n_relative_path = + extension_l10n_util::GetL10nRelativePath(relative_path_); + full_resource_path_ = CombinePathsSafely(extension_root_, l10n_relative_path); + if (file_util::PathExists(full_resource_path_)) { + return full_resource_path_; + } + + // Fall back to root resource. + full_resource_path_ = CombinePathsSafely(extension_root_, relative_path_); + return full_resource_path_; +} + +FilePath ExtensionResource::CombinePathsSafely( + const FilePath& extension_path, + const FilePath& relative_resource_path) const { + // 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. + std::string relative_path = + WideToUTF8(relative_resource_path.ToWStringHack()); + 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. + if (!extension_path.IsParent(ret_val)) + return FilePath(); + + return ret_val; +} + +// Unittesting helpers. +FilePath::StringType ExtensionResource::NormalizeSeperators( + FilePath::StringType path) const { +#if defined(FILE_PATH_USES_WIN_SEPARATORS) + FilePath::StringType ret_val; + for (size_t i = 0; i < path.length(); i++) { + if (FilePath::IsSeparator(path[i])) + path[i] = FilePath::kSeparators[0]; + } +#endif // FILE_PATH_USES_WIN_SEPARATORS + return path; +} + +bool ExtensionResource::ComparePathWithDefault(const FilePath& path) const { + if (NormalizeSeperators(path.value()) == + NormalizeSeperators(full_resource_path_.value())) { + return true; + } else { + return false; + } +} diff --git a/chrome/common/extensions/extension_resource.h b/chrome/common/extensions/extension_resource.h new file mode 100644 index 0000000..7d6e70c6 --- /dev/null +++ b/chrome/common/extensions/extension_resource.h @@ -0,0 +1,49 @@ +// 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. + +#ifndef CHROME_COMMON_EXTENSIONS_EXTENSION_RESOURCE_H_ +#define CHROME_COMMON_EXTENSIONS_EXTENSION_RESOURCE_H_ + +#include "base/file_path.h" + +// Represents a resource inside an extension. For example, an image, or a +// JavaScript file. This is more complicated than just a simple FilePath +// because extension resources can come from multiple physical file locations +// depending on locale. +class ExtensionResource { + public: + ExtensionResource(); + + ExtensionResource(const FilePath& extension_root, + const FilePath& relative_path); + + // Returns actual path to the resource (default or locale specific). + // *** MIGHT HIT FILESYSTEM. Do not call on UI thread! *** + const FilePath& GetFilePath() const; + + // Getters + const FilePath& extension_root() const { return extension_root_; } + const FilePath& relative_path() const { return relative_path_; } + + // Unittest helpers. + FilePath::StringType NormalizeSeperators(FilePath::StringType path) const; + bool ComparePathWithDefault(const FilePath& path) const; + + private: + // Returns normalized full path to the resource. + // Resource doesn't have to exist. + FilePath CombinePathsSafely(const FilePath& extension_root, + const FilePath& relative_path) const; + + // Extension root. + FilePath extension_root_; + + // Relative path to resource. + FilePath relative_path_; + + // Full path to extension resource. Starts empty. + mutable FilePath full_resource_path_; +}; + +#endif // CHROME_COMMON_EXTENSIONS_EXTENSION_RESOURCE_H_ diff --git a/chrome/common/extensions/extension_resource_unittest.cc b/chrome/common/extensions/extension_resource_unittest.cc new file mode 100644 index 0000000..bd92bd9 --- /dev/null +++ b/chrome/common/extensions/extension_resource_unittest.cc @@ -0,0 +1,74 @@ +// 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 <algorithm> + +#include "app/l10n_util.h" +#include "base/file_util.h" +#include "base/path_service.h" +#include "base/scoped_temp_dir.h" +#include "chrome/common/chrome_paths.h" +#include "chrome/common/extensions/extension.h" +#include "chrome/common/extensions/extension_resource.h" +#include "testing/gtest/include/gtest/gtest.h" + +TEST(ExtensionResourceTest, CreateEmptyResource) { + ExtensionResource resource; + + EXPECT_TRUE(resource.extension_root().empty()); + EXPECT_TRUE(resource.relative_path().empty()); + EXPECT_TRUE(resource.GetFilePath().empty()); +} + +const FilePath::StringType ToLower(const FilePath::StringType& in_str) { + FilePath::StringType str(in_str); + std::transform(str.begin(), str.end(), str.begin(), tolower); + return str; +} + +TEST(ExtensionResourceTest, CreateWithMissingResourceOnDisk) { + FilePath root_path; + ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &root_path)); + FilePath relative_path; + relative_path = relative_path.AppendASCII("cira.js"); + ExtensionResource resource(root_path, relative_path); + + EXPECT_EQ(root_path.value(), resource.extension_root().value()); + EXPECT_EQ(relative_path.value(), resource.relative_path().value()); + EXPECT_EQ(root_path.Append(relative_path).value(), + ToLower(resource.GetFilePath().value())); + + EXPECT_FALSE(resource.GetFilePath().empty()); +} + +TEST(ExtensionResourceTest, CreateWithBothResourcesOnDisk) { + ScopedTempDir temp; + ASSERT_TRUE(temp.CreateUniqueTempDir()); + + const char* filename = "res.ico"; + FilePath root_resource = temp.path().AppendASCII(filename); + std::string data = "some foo"; + ASSERT_TRUE(file_util::WriteFile(root_resource.AppendASCII(filename), + data.c_str(), data.length())); + + FilePath l10n_path = temp.path().AppendASCII(Extension::kLocaleFolder); + ASSERT_TRUE(file_util::CreateDirectory(l10n_path)); + + static std::string current_locale = l10n_util::GetApplicationLocale(L""); + std::replace(current_locale.begin(), current_locale.end(), '-', '_'); + l10n_path = l10n_path.AppendASCII(current_locale); + ASSERT_TRUE(file_util::CreateDirectory(l10n_path)); + + ASSERT_TRUE(file_util::WriteFile(l10n_path.AppendASCII(filename), + data.c_str(), data.length())); + + FilePath path; + ExtensionResource resource(temp.path(), FilePath().AppendASCII(filename)); + FilePath resolved_path = resource.GetFilePath(); + + EXPECT_EQ(l10n_path.AppendASCII(filename).value(), resolved_path.value()); + EXPECT_EQ(temp.path().value(), resource.extension_root().value()); + EXPECT_EQ(FilePath().AppendASCII(filename).value(), + resource.relative_path().value()); +} diff --git a/chrome/common/extensions/extension_unittest.cc b/chrome/common/extensions/extension_unittest.cc index 466f27a..26cf648 100644 --- a/chrome/common/extensions/extension_unittest.cc +++ b/chrome/common/extensions/extension_unittest.cc @@ -262,15 +262,6 @@ TEST(ExtensionTest, GetResourceURLAndPath) { Extension::GetResourceURL(extension.url(), "bar/../baz.js").spec()); EXPECT_EQ(extension.url().spec() + "baz.js", Extension::GetResourceURL(extension.url(), "../baz.js").spec()); - - EXPECT_EQ(path.Append(FILE_PATH_LITERAL("bar")) - .Append(FILE_PATH_LITERAL("baz.js")).value(), - Extension::GetResourcePath(extension.path(), "bar/baz.js").value()); - EXPECT_EQ(path.Append(FILE_PATH_LITERAL("baz.js")).value(), - Extension::GetResourcePath(extension.path(), "bar/../baz.js") - .value()); - EXPECT_EQ(FilePath().value(), - Extension::GetResourcePath(extension.path(), "../baz.js").value()); } TEST(ExtensionTest, LoadPageActionHelper) { diff --git a/chrome/common/extensions/user_script.h b/chrome/common/extensions/user_script.h index 4b571799..30807e8 100644 --- a/chrome/common/extensions/user_script.h +++ b/chrome/common/extensions/user_script.h @@ -10,6 +10,7 @@ #include "base/file_path.h" #include "base/string_piece.h" +#include "chrome/common/extensions/extension_resource.h" #include "chrome/common/extensions/url_pattern.h" #include "googleurl/src/gurl.h" @@ -34,14 +35,16 @@ class UserScript { // Holds actual script file info. class File { public: - File(const FilePath& path, const GURL& url): - path_(path), + File(const ExtensionResource& resource, const GURL& url): + resource_(resource), url_(url) { } File() {} - const FilePath& path() const { return path_; } - void set_path(const FilePath& path) { path_ = path; } + const ExtensionResource& resource() const { return resource_; } + void set_resource(const ExtensionResource& resource) { + resource_ = resource; + } const GURL& url() const { return url_; } void set_url(const GURL& url) { url_ = url; } @@ -61,14 +64,14 @@ class UserScript { content_.assign(content.begin(), content.end()); } - // Serialization support. The content and path_ member will not be + // Serialization support. The content and resource_ member will not be // serialized! void Pickle(::Pickle* pickle) const; void Unpickle(const ::Pickle& pickle, void** iter); private: - // Where is the script file lives on the disk. - FilePath path_; + // Where the script file lives on the disk. + ExtensionResource resource_; // The url to this scipt file. GURL url_; diff --git a/chrome/common/extensions/user_script_unittest.cc b/chrome/common/extensions/user_script_unittest.cc index 62fa0a3..0c0bac9 100644 --- a/chrome/common/extensions/user_script_unittest.cc +++ b/chrome/common/extensions/user_script_unittest.cc @@ -78,13 +78,16 @@ TEST(UserScriptTest, Pickle) { UserScript script1; script1.js_scripts().push_back(UserScript::File( - FilePath(FILE_PATH_LITERAL("c:\\foo\\foo.user.js")), + ExtensionResource(FilePath(FILE_PATH_LITERAL("c:\\foo\\")), + FilePath(FILE_PATH_LITERAL("foo.user.js"))), GURL("chrome-user-script:/foo.user.js"))); script1.css_scripts().push_back(UserScript::File( - FilePath(FILE_PATH_LITERAL("c:\\foo\\foo.user.css")), + ExtensionResource(FilePath(FILE_PATH_LITERAL("c:\\foo\\")), + FilePath(FILE_PATH_LITERAL("foo.user.css"))), GURL("chrome-user-script:/foo.user.css"))); script1.css_scripts().push_back(UserScript::File( - FilePath(FILE_PATH_LITERAL("c:\\foo\\foo2.user.css")), + ExtensionResource(FilePath(FILE_PATH_LITERAL("c:\\foo\\")), + FilePath(FILE_PATH_LITERAL("foo2.user.css"))), GURL("chrome-user-script:/foo2.user.css"))); script1.set_run_location(UserScript::DOCUMENT_START); |