summaryrefslogtreecommitdiffstats
path: root/chrome/common/extensions
diff options
context:
space:
mode:
authorcira@chromium.org <cira@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-10-07 22:49:10 +0000
committercira@chromium.org <cira@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-10-07 22:49:10 +0000
commitecabe6eed156a36238888bfd2fdb96ec4906f0a4 (patch)
tree9419d9a349fc940d45fa450b3a75169fdf48b39f /chrome/common/extensions
parent7050861ff094fd74d155264b6da3ca3795543870 (diff)
downloadchromium_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.cc52
-rw-r--r--chrome/common/extensions/extension.h18
-rw-r--r--chrome/common/extensions/extension_resource.cc100
-rw-r--r--chrome/common/extensions/extension_resource.h49
-rw-r--r--chrome/common/extensions/extension_resource_unittest.cc74
-rw-r--r--chrome/common/extensions/extension_unittest.cc9
-rw-r--r--chrome/common/extensions/user_script.h17
-rw-r--r--chrome/common/extensions/user_script_unittest.cc9
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);