summaryrefslogtreecommitdiffstats
path: root/chrome/common
diff options
context:
space:
mode:
authorphajdan.jr@chromium.org <phajdan.jr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-02-24 09:54:13 +0000
committerphajdan.jr@chromium.org <phajdan.jr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-02-24 09:54:13 +0000
commit7c927b60bffa117129ba9214fcb6174d753351d9 (patch)
tree785de404571d36e57c8c9b916426805fc43ee476 /chrome/common
parentaf2ae52b8f5ec53e1ba1b4593368cd66f59c3a4d (diff)
downloadchromium_src-7c927b60bffa117129ba9214fcb6174d753351d9.zip
chromium_src-7c927b60bffa117129ba9214fcb6174d753351d9.tar.gz
chromium_src-7c927b60bffa117129ba9214fcb6174d753351d9.tar.bz2
Further reduce the bad dependency of chrome/common on chrome/browser.
TEST=none BUG=none Review URL: http://codereview.chromium.org/656011 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@39877 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/common')
-rw-r--r--chrome/common/chrome_constants.cc2
-rw-r--r--chrome/common/chrome_constants.h2
-rw-r--r--chrome/common/extensions/extension_file_util.cc521
-rw-r--r--chrome/common/extensions/extension_file_util.h108
-rw-r--r--chrome/common/extensions/extension_file_util_unittest.cc258
-rw-r--r--chrome/common/extensions/extension_l10n_util.cc2
-rw-r--r--chrome/common/extensions/extension_unpacker.cc2
-rw-r--r--chrome/common/histogram_synchronizer.cc273
-rw-r--r--chrome/common/histogram_synchronizer.h147
-rw-r--r--chrome/common/render_messages.h2
-rw-r--r--chrome/common/resource_response.h50
11 files changed, 944 insertions, 423 deletions
diff --git a/chrome/common/chrome_constants.cc b/chrome/common/chrome_constants.cc
index 8226cd8..ed5947a 100644
--- a/chrome/common/chrome_constants.cc
+++ b/chrome/common/chrome_constants.cc
@@ -129,6 +129,8 @@ const bool kRecordModeEnabled = true;
const bool kRecordModeEnabled = false;
#endif
+const int kHistogramSynchronizerReservedSequenceNumber = 0;
+
} // namespace chrome
#undef FPL
diff --git a/chrome/common/chrome_constants.h b/chrome/common/chrome_constants.h
index fc271e0..cd85a14 100644
--- a/chrome/common/chrome_constants.h
+++ b/chrome/common/chrome_constants.h
@@ -77,6 +77,8 @@ extern const size_t kMaxURLChars;
extern const bool kRecordModeEnabled;
+extern const int kHistogramSynchronizerReservedSequenceNumber;
+
} // namespace chrome
#endif // CHROME_COMMON_CHROME_CONSTANTS_H_
diff --git a/chrome/common/extensions/extension_file_util.cc b/chrome/common/extensions/extension_file_util.cc
new file mode 100644
index 0000000..0192b67
--- /dev/null
+++ b/chrome/common/extensions/extension_file_util.cc
@@ -0,0 +1,521 @@
+// 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_file_util.h"
+
+#include "app/l10n_util.h"
+#include "base/file_util.h"
+#include "base/logging.h"
+#include "base/scoped_temp_dir.h"
+#include "base/string_util.h"
+#include "chrome/common/extensions/extension.h"
+#include "chrome/common/extensions/extension_l10n_util.h"
+#include "chrome/common/extensions/extension_constants.h"
+#include "chrome/common/json_value_serializer.h"
+#include "net/base/escape.h"
+#include "net/base/file_stream.h"
+
+namespace errors = extension_manifest_errors;
+namespace keys = extension_manifest_keys;
+
+namespace extension_file_util {
+
+// Validates locale info. Doesn't check if messages.json files are valid.
+static bool ValidateLocaleInfo(const Extension& extension, std::string* error);
+
+const char kInstallDirectoryName[] = "Extensions";
+// TODO(mpcomplete): obsolete. remove after migration period.
+// http://code.google.com/p/chromium/issues/detail?id=19733
+const char kCurrentVersionFileName[] = "Current Version";
+
+bool MoveDirSafely(const FilePath& source_dir, const FilePath& dest_dir) {
+ if (file_util::PathExists(dest_dir)) {
+ if (!file_util::Delete(dest_dir, true))
+ return false;
+ } else {
+ FilePath parent = dest_dir.DirName();
+ if (!file_util::DirectoryExists(parent)) {
+ if (!file_util::CreateDirectory(parent))
+ return false;
+ }
+ }
+
+ if (!file_util::Move(source_dir, dest_dir))
+ return false;
+
+ return true;
+}
+
+Extension::InstallType CompareToInstalledVersion(
+ const FilePath& extensions_dir,
+ const std::string& extension_id,
+ const std::string& current_version_str,
+ const std::string& new_version_str,
+ FilePath* version_dir) {
+ FilePath dest_dir = extensions_dir.AppendASCII(extension_id);
+ FilePath current_version_dir = dest_dir.AppendASCII(current_version_str);
+ *version_dir = dest_dir.AppendASCII(new_version_str);
+
+ if (current_version_str.empty())
+ return Extension::NEW_INSTALL;
+
+ scoped_ptr<Version> current_version(
+ Version::GetVersionFromString(current_version_str));
+ scoped_ptr<Version> new_version(
+ Version::GetVersionFromString(new_version_str));
+ int comp = new_version->CompareTo(*current_version);
+ if (comp > 0)
+ return Extension::UPGRADE;
+ if (comp < 0)
+ return Extension::DOWNGRADE;
+
+ // Same version. Treat corrupted existing installation as new install case.
+ if (!SanityCheckExtension(current_version_dir))
+ return Extension::NEW_INSTALL;
+
+ return Extension::REINSTALL;
+}
+
+bool SanityCheckExtension(const FilePath& dir) {
+ // Verify that the directory actually exists.
+ // TODO(erikkay): A further step would be to verify that the extension
+ // has actually loaded successfully.
+ FilePath manifest_file(dir.Append(Extension::kManifestFilename));
+ return file_util::PathExists(dir) && file_util::PathExists(manifest_file);
+}
+
+bool InstallExtension(const FilePath& src_dir,
+ const FilePath& version_dir,
+ std::string* error) {
+ // If anything fails after this, we want to delete the extension dir.
+ ScopedTempDir scoped_version_dir;
+ scoped_version_dir.Set(version_dir);
+
+ if (!MoveDirSafely(src_dir, version_dir)) {
+ *error = "Could not move extension directory into profile.";
+ return false;
+ }
+
+ scoped_version_dir.Take();
+ return true;
+}
+
+Extension* LoadExtension(const FilePath& extension_path,
+ bool require_key,
+ std::string* error) {
+ FilePath manifest_path =
+ extension_path.Append(Extension::kManifestFilename);
+ if (!file_util::PathExists(manifest_path)) {
+ *error = extension_manifest_errors::kManifestUnreadable;
+ return NULL;
+ }
+
+ JSONFileValueSerializer serializer(manifest_path);
+ scoped_ptr<Value> root(serializer.Deserialize(error));
+ if (!root.get()) {
+ if (error->empty()) {
+ // If |error| is empty, than the file could not be read.
+ // It would be cleaner to have the JSON reader give a specific error
+ // in this case, but other code tests for a file error with
+ // error->empty(). For now, be consistent.
+ *error = extension_manifest_errors::kManifestUnreadable;
+ } else {
+ *error = StringPrintf("%s %s",
+ extension_manifest_errors::kManifestParseError,
+ error->c_str());
+ }
+ return NULL;
+ }
+
+ if (!root->IsType(Value::TYPE_DICTIONARY)) {
+ *error = extension_manifest_errors::kInvalidManifest;
+ return NULL;
+ }
+
+ DictionaryValue* manifest = static_cast<DictionaryValue*>(root.get());
+
+ scoped_ptr<Extension> extension(new Extension(extension_path));
+
+ if (!extension_l10n_util::LocalizeExtension(extension.get(), manifest, error))
+ return NULL;
+
+ if (!extension->InitFromValue(*manifest, require_key, error))
+ return NULL;
+
+ if (!ValidateExtension(extension.get(), error))
+ return NULL;
+
+ return extension.release();
+}
+
+bool ValidateExtension(Extension* extension, std::string* error) {
+ // Validate icons exist.
+ for (std::map<int, std::string>::const_iterator iter =
+ extension->icons().begin(); iter != extension->icons().end(); ++iter) {
+ const FilePath path = extension->GetResource(iter->second).GetFilePath();
+ if (!file_util::PathExists(path)) {
+ *error = StringPrintf("Could not load extension icon '%s'.",
+ iter->second.c_str());
+ return false;
+ }
+ }
+
+ // Theme resource validation.
+ if (extension->IsTheme()) {
+ DictionaryValue* images_value = extension->GetThemeImages();
+ if (images_value) {
+ for (DictionaryValue::key_iterator iter = images_value->begin_keys();
+ iter != images_value->end_keys(); ++iter) {
+ std::string val;
+ if (images_value->GetStringWithoutPathExpansion(*iter, &val)) {
+ FilePath image_path = extension->path().AppendASCII(val);
+ if (!file_util::PathExists(image_path)) {
+ *error = StringPrintf(
+ "Could not load '%s' for theme.",
+ WideToUTF8(image_path.ToWStringHack()).c_str());
+ return false;
+ }
+ }
+ }
+ }
+
+ // Themes cannot contain other extension types.
+ return true;
+ }
+
+ // Validate that claimed script resources actually exist.
+ for (size_t i = 0; i < extension->content_scripts().size(); ++i) {
+ const UserScript& script = extension->content_scripts()[i];
+
+ for (size_t j = 0; j < script.js_scripts().size(); j++) {
+ const UserScript::File& js_script = script.js_scripts()[j];
+ const FilePath& path = ExtensionResource::GetFilePath(
+ js_script.extension_root(), js_script.relative_path());
+ if (!file_util::PathExists(path)) {
+ *error = StringPrintf(
+ "Could not load javascript '%s' for content script.",
+ WideToUTF8(js_script.relative_path().ToWStringHack()).c_str());
+ return false;
+ }
+ }
+
+ for (size_t j = 0; j < script.css_scripts().size(); j++) {
+ const UserScript::File& css_script = script.css_scripts()[j];
+ const FilePath& path = ExtensionResource::GetFilePath(
+ css_script.extension_root(), css_script.relative_path());
+ if (!file_util::PathExists(path)) {
+ *error = StringPrintf(
+ "Could not load css '%s' for content script.",
+ WideToUTF8(css_script.relative_path().ToWStringHack()).c_str());
+ return false;
+ }
+ }
+ }
+
+ // Validate claimed plugin paths.
+ for (size_t i = 0; i < extension->plugins().size(); ++i) {
+ const Extension::PluginInfo& plugin = extension->plugins()[i];
+ if (!file_util::PathExists(plugin.path)) {
+ *error = StringPrintf("Could not load '%s' for plugin.",
+ WideToUTF8(plugin.path.ToWStringHack()).c_str());
+ return false;
+ }
+ }
+
+ // Validate icon location for page actions.
+ ExtensionAction* page_action = extension->page_action();
+ if (page_action) {
+ std::vector<std::string> icon_paths(*page_action->icon_paths());
+ if (!page_action->default_icon_path().empty())
+ icon_paths.push_back(page_action->default_icon_path());
+ for (std::vector<std::string>::iterator iter = icon_paths.begin();
+ iter != icon_paths.end(); ++iter) {
+ if (!file_util::PathExists(extension->GetResource(*iter).GetFilePath())) {
+ *error = StringPrintf("Could not load icon '%s' for page action.",
+ iter->c_str());
+ return false;
+ }
+ }
+ }
+
+ // Validate icon location for browser actions.
+ // Note: browser actions don't use the icon_paths().
+ ExtensionAction* browser_action = extension->browser_action();
+ if (browser_action) {
+ std::string path = browser_action->default_icon_path();
+ if (!path.empty() &&
+ !file_util::PathExists(extension->GetResource(path).GetFilePath())) {
+ *error = StringPrintf("Could not load icon '%s' for browser action.",
+ path.c_str());
+ return false;
+ }
+ }
+
+ // Validate background page location.
+ if (!extension->background_url().is_empty()) {
+ FilePath page_path = ExtensionURLToRelativeFilePath(
+ extension->background_url());
+ const FilePath path = extension->GetResource(page_path).GetFilePath();
+ if (!file_util::PathExists(path)) {
+ *error = StringPrintf("Could not load background page '%s'.",
+ WideToUTF8(path.ToWStringHack()).c_str());
+ return false;
+ }
+ }
+
+ // Validate locale info.
+ if (!ValidateLocaleInfo(*extension, error))
+ return false;
+
+ // 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 false;
+ }
+
+ return true;
+}
+
+void UninstallExtension(const std::string& id, const FilePath& extensions_dir) {
+ // First, delete the Current Version file. If the directory delete fails, then
+ // at least the extension won't be loaded again.
+ FilePath extension_root = extensions_dir.AppendASCII(id);
+
+ if (!file_util::PathExists(extension_root)) {
+ LOG(WARNING) << "Asked to remove a non-existent extension " << id;
+ return;
+ }
+
+ FilePath current_version_file = extension_root.AppendASCII(
+ kCurrentVersionFileName);
+ if (!file_util::PathExists(current_version_file)) {
+ // This is OK, since we're phasing out the current version file.
+ } else {
+ if (!file_util::Delete(current_version_file, false)) {
+ LOG(WARNING) << "Could not delete Current Version file for extension "
+ << id;
+ return;
+ }
+ }
+
+ // OK, now try and delete the entire rest of the directory. One major place
+ // this can fail is if the extension contains a plugin (stupid plugins). It's
+ // not a big deal though, because we'll notice next time we startup that the
+ // Current Version file is gone and finish the delete then.
+ if (!file_util::Delete(extension_root, true))
+ LOG(WARNING) << "Could not delete directory for extension " << id;
+}
+
+void GarbageCollectExtensions(
+ const FilePath& install_directory,
+ const std::set<std::string>& installed_ids,
+ const std::map<std::string, std::string>& installed_versions) {
+ // Nothing to clean up if it doesn't exist.
+ if (!file_util::DirectoryExists(install_directory))
+ return;
+
+ LOG(INFO) << "Loading installed extensions...";
+ file_util::FileEnumerator enumerator(install_directory,
+ false, // Not recursive.
+ file_util::FileEnumerator::DIRECTORIES);
+ FilePath extension_path;
+ for (extension_path = enumerator.Next(); !extension_path.value().empty();
+ extension_path = enumerator.Next()) {
+ std::string extension_id = WideToASCII(
+ extension_path.BaseName().ToWStringHack());
+
+ // If there is no entry in the prefs file, just delete the directory and
+ // move on. This can legitimately happen when an uninstall does not
+ // complete, for example, when a plugin is in use at uninstall time.
+ if (installed_ids.count(extension_id) == 0) {
+ LOG(INFO) << "Deleting unreferenced install for directory "
+ << WideToASCII(extension_path.ToWStringHack()) << ".";
+ file_util::Delete(extension_path, true); // Recursive.
+ continue;
+ }
+
+ // Delete directories that aren't valid IDs.
+ if (!Extension::IdIsValid(extension_id)) {
+ LOG(WARNING) << "Invalid extension ID encountered in extensions "
+ "directory: " << extension_id;
+ LOG(INFO) << "Deleting invalid extension directory "
+ << WideToASCII(extension_path.ToWStringHack()) << ".";
+ file_util::Delete(extension_path, true); // Recursive.
+ continue;
+ }
+
+ // Clean up old version directories.
+ file_util::FileEnumerator versions_enumerator(
+ extension_path,
+ false, // Not recursive.
+ file_util::FileEnumerator::DIRECTORIES);
+ for (FilePath version_dir = versions_enumerator.Next();
+ !version_dir.value().empty();
+ version_dir = versions_enumerator.Next()) {
+ std::map<std::string, std::string>::const_iterator installed_version =
+ installed_versions.find(extension_id);
+ if (installed_version == installed_versions.end()) {
+ NOTREACHED() << "No installed version found for " << extension_id;
+ continue;
+ }
+
+ std::string version = WideToASCII(version_dir.BaseName().ToWStringHack());
+ if (version != installed_version->second) {
+ LOG(INFO) << "Deleting old version for directory "
+ << WideToASCII(version_dir.ToWStringHack()) << ".";
+ file_util::Delete(version_dir, true); // Recursive.
+ }
+ }
+ }
+}
+
+ExtensionMessageBundle* LoadExtensionMessageBundle(
+ const FilePath& extension_path,
+ const std::string& default_locale,
+ std::string* error) {
+ error->clear();
+ // Load locale information if available.
+ FilePath locale_path = extension_path.Append(Extension::kLocaleFolder);
+ if (!file_util::PathExists(locale_path))
+ return NULL;
+
+ std::set<std::string> locales;
+ if (!extension_l10n_util::GetValidLocales(locale_path, &locales, error))
+ return NULL;
+
+ if (default_locale.empty() ||
+ locales.find(default_locale) == locales.end()) {
+ *error = extension_manifest_errors::kLocalesNoDefaultLocaleSpecified;
+ return NULL;
+ }
+
+ ExtensionMessageBundle* message_bundle =
+ extension_l10n_util::LoadMessageCatalogs(
+ locale_path,
+ default_locale,
+ extension_l10n_util::CurrentLocaleOrDefault(),
+ locales,
+ error);
+
+ return message_bundle;
+}
+
+static bool ValidateLocaleInfo(const Extension& extension, std::string* error) {
+ // default_locale and _locales have to be both present or both missing.
+ const FilePath path = extension.path().Append(Extension::kLocaleFolder);
+ bool path_exists = file_util::PathExists(path);
+ std::string default_locale = extension.default_locale();
+
+ // If both default locale and _locales folder are empty, skip verification.
+ if (!default_locale.empty() || path_exists) {
+ if (default_locale.empty() && path_exists) {
+ *error = errors::kLocalesNoDefaultLocaleSpecified;
+ return false;
+ } else if (!default_locale.empty() && !path_exists) {
+ *error = errors::kLocalesTreeMissing;
+ return false;
+ }
+
+ // Treat all folders under _locales as valid locales.
+ file_util::FileEnumerator locales(path,
+ false,
+ file_util::FileEnumerator::DIRECTORIES);
+
+ FilePath locale_path = locales.Next();
+ if (locale_path.empty()) {
+ *error = errors::kLocalesTreeMissing;
+ return false;
+ }
+
+ const FilePath default_locale_path = path.AppendASCII(default_locale);
+ bool has_default_locale_message_file = false;
+ do {
+ // Skip any strings with '.'. This happens sometimes, for example with
+ // '.svn' directories.
+ FilePath relative_path;
+ if (!extension.path().AppendRelativePath(locale_path, &relative_path))
+ NOTREACHED();
+ std::wstring subdir(relative_path.ToWStringHack());
+ if (std::find(subdir.begin(), subdir.end(), L'.') != subdir.end())
+ continue;
+
+ FilePath messages_path =
+ locale_path.Append(Extension::kMessagesFilename);
+
+ if (!file_util::PathExists(messages_path)) {
+ *error = StringPrintf(
+ "%s %s", errors::kLocalesMessagesFileMissing,
+ WideToUTF8(messages_path.ToWStringHack()).c_str());
+ return false;
+ }
+
+ if (locale_path == default_locale_path)
+ has_default_locale_message_file = true;
+ } while (!(locale_path = locales.Next()).empty());
+
+ // Only message file for default locale has to exist.
+ if (!has_default_locale_message_file) {
+ *error = errors::kLocalesNoDefaultMessages;
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool CheckForIllegalFilenames(const FilePath& extension_path,
+ std::string* error) {
+ // Reserved underscore names.
+ static const FilePath::CharType* reserved_names[] = {
+ Extension::kLocaleFolder,
+ FILE_PATH_LITERAL("__MACOSX"),
+ };
+ static std::set<FilePath::StringType> 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 file;
+ while (!(file = all_files.Next()).empty()) {
+ FilePath::StringType filename = file.BaseName().value();
+ // Skip all that don't start with "_".
+ if (filename.find_first_of(FILE_PATH_LITERAL("_")) != 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;
+}
+
+FilePath ExtensionURLToRelativeFilePath(const GURL& url) {
+ std::string url_path = url.path();
+ if (url_path.empty() || url_path[0] != '/')
+ return FilePath();
+
+ // Drop the leading slash and convert %-encoded UTF8 to regular UTF8.
+ std::string file_path = UnescapeURLComponent(url_path.substr(1),
+ UnescapeRule::SPACES | UnescapeRule::URL_SPECIAL_CHARS);
+
+#if defined(OS_POSIX)
+ return FilePath(file_path);
+#elif defined(OS_WIN)
+ return FilePath(UTF8ToWide(file_path));
+#endif
+}
+
+} // namespace extension_file_util
diff --git a/chrome/common/extensions/extension_file_util.h b/chrome/common/extensions/extension_file_util.h
new file mode 100644
index 0000000..b711df0
--- /dev/null
+++ b/chrome/common/extensions/extension_file_util.h
@@ -0,0 +1,108 @@
+// 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_FILE_UTIL_H_
+#define CHROME_COMMON_EXTENSIONS_EXTENSION_FILE_UTIL_H_
+
+#include <set>
+#include <string>
+
+#include "base/file_path.h"
+#include "chrome/common/extensions/extension.h"
+
+class ExtensionMessageBundle;
+
+// Utilties for manipulating the on-disk storage of extensions.
+namespace extension_file_util {
+
+// The name of the directory inside the profile that we store installed
+// extension in.
+extern const char kInstallDirectoryName[];
+
+// The name of the file that contains the current version of an installed
+// extension.
+extern const char kCurrentVersionFileName[];
+
+// Move source_dir to dest_dir (it will actually be named dest_dir, not inside
+// dest_dir). If the parent path doesn't exixt, create it. If something else is
+// already there, remove it.
+bool MoveDirSafely(const FilePath& source_dir, const FilePath& dest_dir);
+
+// Updates the Current Version file inside the installed extension.
+bool SetCurrentVersion(const FilePath& dest_dir,
+ const std::string& version,
+ std::string* error);
+
+// Reads the Current Version file.
+bool ReadCurrentVersion(const FilePath& dir, std::string* version_string);
+
+// Determine what type of install it is (new, upgrade, overinstall, downgrade)
+// given the current version and a newly installing version. |extensions_dir| is
+// the root directory containing all extensions in the user profile.
+// |extension_id| and |current_version_str| are the id and version of the
+// extension contained in |src_dir|, if any.
+//
+// Returns the full path to the destination version directory and the type of
+// install that was attempted.
+Extension::InstallType CompareToInstalledVersion(
+ const FilePath& extensions_dir,
+ const std::string& extension_id,
+ const std::string& current_version_str,
+ const std::string& new_version_str,
+ FilePath* version_dir);
+
+// Sanity check that the directory has the minimum files to be a working
+// extension.
+bool SanityCheckExtension(const FilePath& extension_root);
+
+// Installs an extension unpacked in |src_dir|.
+//
+// On failure, also returns an error message.
+//
+// NOTE: |src_dir| is not actually copied in the case of downgrades or
+// overinstall of previous verisons of the extension. In that case, the function
+// returns true and install_type is populated.
+bool InstallExtension(const FilePath& src_dir,
+ const FilePath& version_dir,
+ std::string* error);
+
+// Loads and validates an extension from the specified directory. Returns NULL
+// on failure, with a description of the error in |error|.
+Extension* LoadExtension(const FilePath& extension_root,
+ bool require_key,
+ std::string* error);
+
+// Returns true if the given extension object is valid and consistent.
+// Otherwise, a description of the error is returned in |error|.
+bool ValidateExtension(Extension* extension, std::string* error);
+
+// Uninstalls the extension |id| from the install directory |extensions_dir|.
+void UninstallExtension(const std::string& id, const FilePath& extensions_dir);
+
+// Clean up directories that aren't valid extensions from the install directory.
+void GarbageCollectExtensions(
+ const FilePath& extensions_dir,
+ const std::set<std::string>& installed_ids,
+ const std::map<std::string, std::string>& installed_versions);
+
+// Loads extension message catalogs and returns message bundle.
+// Returns NULL on error, or if extension is not localized.
+ExtensionMessageBundle* LoadExtensionMessageBundle(
+ const FilePath& extension_path,
+ const std::string& default_locale,
+ std::string* error);
+
+// 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);
+
+// Get a relative file path from a chrome-extension:// URL.
+FilePath ExtensionURLToRelativeFilePath(const GURL& url);
+
+} // extension_file_util
+
+#endif // CHROME_COMMON_EXTENSIONS_EXTENSION_FILE_UTIL_H_
diff --git a/chrome/common/extensions/extension_file_util_unittest.cc b/chrome/common/extensions/extension_file_util_unittest.cc
new file mode 100644
index 0000000..9856e42
--- /dev/null
+++ b/chrome/common/extensions/extension_file_util_unittest.cc
@@ -0,0 +1,258 @@
+// 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_file_util.h"
+
+#include "base/file_util.h"
+#include "base/scoped_temp_dir.h"
+#include "base/string_util.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 "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;
+ ASSERT_TRUE(temp.CreateUniqueTempDir());
+
+ FilePath src_path = temp.path().AppendASCII("src");
+ ASSERT_TRUE(file_util::CreateDirectory(src_path));
+
+ std::string data = "foobar";
+ ASSERT_TRUE(file_util::WriteFile(src_path.AppendASCII("data"),
+ data.c_str(), data.length()));
+
+ // Move it to a path that doesn't exist yet.
+ FilePath dest_path = temp.path().AppendASCII("dest").AppendASCII("dest");
+ ASSERT_TRUE(extension_file_util::MoveDirSafely(src_path, dest_path));
+
+ // The path should get created.
+ ASSERT_TRUE(file_util::DirectoryExists(dest_path));
+
+ // The data should match.
+ std::string data_out;
+ ASSERT_TRUE(file_util::ReadFileToString(dest_path.AppendASCII("data"),
+ &data_out));
+ ASSERT_EQ(data, data_out);
+
+ // The src path should be gone.
+ ASSERT_FALSE(file_util::PathExists(src_path));
+
+ // Create some new test data.
+ ASSERT_TRUE(file_util::CopyDirectory(dest_path, src_path,
+ true)); // recursive
+ data = "hotdog";
+ ASSERT_TRUE(file_util::WriteFile(src_path.AppendASCII("data"),
+ data.c_str(), data.length()));
+
+ // Test again, overwriting the old path.
+ ASSERT_TRUE(extension_file_util::MoveDirSafely(src_path, dest_path));
+ ASSERT_TRUE(file_util::DirectoryExists(dest_path));
+
+ data_out.clear();
+ ASSERT_TRUE(file_util::ReadFileToString(dest_path.AppendASCII("data"),
+ &data_out));
+ ASSERT_EQ(data, data_out);
+ ASSERT_FALSE(file_util::PathExists(src_path));
+}
+
+TEST(ExtensionFileUtil, CompareToInstalledVersion) {
+ // Compare to an existing extension.
+ FilePath install_dir;
+ ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &install_dir));
+ install_dir = install_dir.AppendASCII("extensions")
+ .AppendASCII("good")
+ .AppendASCII("Extensions");
+
+ const std::string kId = "behllobkkfkfnphdnhnkndlbkcpglgmj";
+ const std::string kCurrentVersion = "1.0.0.0";
+
+ FilePath version_dir;
+
+ ASSERT_EQ(Extension::UPGRADE,
+ extension_file_util::CompareToInstalledVersion(
+ install_dir, kId, kCurrentVersion, "1.0.0.1", &version_dir));
+
+ ASSERT_EQ(Extension::REINSTALL,
+ extension_file_util::CompareToInstalledVersion(
+ install_dir, kId, kCurrentVersion, "1.0.0.0", &version_dir));
+
+ ASSERT_EQ(Extension::REINSTALL,
+ extension_file_util::CompareToInstalledVersion(
+ install_dir, kId, kCurrentVersion, "1.0.0", &version_dir));
+
+ ASSERT_EQ(Extension::DOWNGRADE,
+ extension_file_util::CompareToInstalledVersion(
+ install_dir, kId, kCurrentVersion, "0.0.1.0", &version_dir));
+
+ // Compare to an extension that is missing its manifest file.
+ ScopedTempDir temp;
+ ASSERT_TRUE(temp.CreateUniqueTempDir());
+ FilePath src = install_dir.AppendASCII(kId).AppendASCII(kCurrentVersion);
+ FilePath dest = temp.path().AppendASCII(kId).AppendASCII(kCurrentVersion);
+ ASSERT_TRUE(file_util::CreateDirectory(dest.DirName()));
+ ASSERT_TRUE(file_util::CopyDirectory(src, dest, true));
+ ASSERT_TRUE(file_util::Delete(dest.AppendASCII("manifest.json"), false));
+
+ ASSERT_EQ(Extension::NEW_INSTALL,
+ extension_file_util::CompareToInstalledVersion(
+ temp.path(), kId, kCurrentVersion, "1.0.0", &version_dir));
+
+ // Compare to a non-existent extension.
+ const std::string kMissingVersion = "";
+ const std::string kBadId = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
+ ASSERT_EQ(Extension::NEW_INSTALL,
+ extension_file_util::CompareToInstalledVersion(
+ temp.path(), kBadId, kMissingVersion, "1.0.0", &version_dir));
+}
+
+TEST(ExtensionFileUtil, LoadExtensionWithValidLocales) {
+ FilePath install_dir;
+ ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &install_dir));
+ install_dir = install_dir.AppendASCII("extensions")
+ .AppendASCII("good")
+ .AppendASCII("Extensions")
+ .AppendASCII("behllobkkfkfnphdnhnkndlbkcpglgmj")
+ .AppendASCII("1.0.0.0");
+
+ std::string error;
+ scoped_ptr<Extension> extension(
+ extension_file_util::LoadExtension(install_dir, false, &error));
+ ASSERT_TRUE(extension != NULL);
+ EXPECT_EQ("The first extension that I made.", extension->description());
+}
+
+TEST(ExtensionFileUtil, LoadExtensionWithoutLocalesFolder) {
+ FilePath install_dir;
+ ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &install_dir));
+ install_dir = install_dir.AppendASCII("extensions")
+ .AppendASCII("good")
+ .AppendASCII("Extensions")
+ .AppendASCII("bjafgdebaacbbbecmhlhpofkepfkgcpa")
+ .AppendASCII("1.0");
+
+ std::string error;
+ scoped_ptr<Extension> extension(
+ extension_file_util::LoadExtension(install_dir, false, &error));
+ ASSERT_FALSE(extension == NULL);
+ EXPECT_TRUE(error.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 = "{ \"name\": { \"message\": \"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().Append(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().Append(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));
+}
+
+TEST(ExtensionFileUtil, LoadExtensionGivesHelpfullErrorOnMissingManifest) {
+ FilePath install_dir;
+ ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &install_dir));
+ install_dir = install_dir.AppendASCII("extensions")
+ .AppendASCII("bad")
+ .AppendASCII("Extensions")
+ .AppendASCII("dddddddddddddddddddddddddddddddd")
+ .AppendASCII("1.0");
+
+ std::string error;
+ scoped_ptr<Extension> extension(
+ extension_file_util::LoadExtension(install_dir, false, &error));
+ ASSERT_TRUE(extension == NULL);
+ ASSERT_FALSE(error.empty());
+ ASSERT_STREQ("Manifest file is missing or unreadable.", error.c_str());
+}
+
+TEST(ExtensionFileUtil, LoadExtensionGivesHelpfullErrorOnBadManifest) {
+ FilePath install_dir;
+ ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &install_dir));
+ install_dir = install_dir.AppendASCII("extensions")
+ .AppendASCII("bad")
+ .AppendASCII("Extensions")
+ .AppendASCII("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee")
+ .AppendASCII("1.0");
+
+ std::string error;
+ scoped_ptr<Extension> extension(
+ extension_file_util::LoadExtension(install_dir, false, &error));
+ ASSERT_TRUE(extension == NULL);
+ ASSERT_FALSE(error.empty());
+ ASSERT_STREQ("Manifest is not valid JSON. "
+ "Line: 2, column: 16, Syntax error.", error.c_str());
+}
+
+#define URL_PREFIX "chrome-extension://extension-id/"
+
+TEST(ExtensionFileUtil, ExtensionURLToRelativeFilePath) {
+ struct TestCase {
+ const char* url;
+ const char* expected_relative_path;
+ } test_cases[] = {
+ { URL_PREFIX "simple.html",
+ "simple.html" },
+ { URL_PREFIX "directory/to/file.html",
+ "directory/to/file.html" },
+ { URL_PREFIX "escape%20spaces.html",
+ "escape spaces.html" },
+ { URL_PREFIX "%C3%9Cber.html",
+ "\xC3\x9C" "ber.html" },
+ };
+
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) {
+ GURL url(test_cases[i].url);
+#if defined(OS_POSIX)
+ FilePath expected_path(test_cases[i].expected_relative_path);
+#elif defined(OS_WIN)
+ FilePath expected_path(UTF8ToWide(test_cases[i].expected_relative_path));
+#endif
+
+ FilePath actual_path =
+ extension_file_util::ExtensionURLToRelativeFilePath(url);
+ EXPECT_FALSE(actual_path.IsAbsolute()) <<
+ " For the path " << actual_path.value();
+ EXPECT_EQ(expected_path.value(), actual_path.value());
+ }
+}
+
+// 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/common/extensions/extension_l10n_util.cc b/chrome/common/extensions/extension_l10n_util.cc
index 2fd3f92..3f329fb 100644
--- a/chrome/common/extensions/extension_l10n_util.cc
+++ b/chrome/common/extensions/extension_l10n_util.cc
@@ -14,10 +14,10 @@
#include "base/string_util.h"
#include "base/values.h"
#include "chrome/browser/browser_process.h"
-#include "chrome/browser/extensions/extension_file_util.h"
#include "chrome/browser/renderer_host/resource_dispatcher_host_request_info.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/extensions/extension_constants.h"
+#include "chrome/common/extensions/extension_file_util.h"
#include "chrome/common/extensions/extension_message_bundle.h"
#include "chrome/common/json_value_serializer.h"
#include "chrome/common/url_constants.h"
diff --git a/chrome/common/extensions/extension_unpacker.cc b/chrome/common/extensions/extension_unpacker.cc
index 425105f..ac643df 100644
--- a/chrome/common/extensions/extension_unpacker.cc
+++ b/chrome/common/extensions/extension_unpacker.cc
@@ -11,10 +11,10 @@
#include "base/thread.h"
#include "base/values.h"
#include "net/base/file_stream.h"
-#include "chrome/browser/extensions/extension_file_util.h"
#include "chrome/common/common_param_traits.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/extensions/extension_constants.h"
+#include "chrome/common/extensions/extension_file_util.h"
#include "chrome/common/json_value_serializer.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/url_constants.h"
diff --git a/chrome/common/histogram_synchronizer.cc b/chrome/common/histogram_synchronizer.cc
deleted file mode 100644
index 9aeff5e..0000000
--- a/chrome/common/histogram_synchronizer.cc
+++ /dev/null
@@ -1,273 +0,0 @@
-// 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/histogram_synchronizer.h"
-
-#include "base/histogram.h"
-#include "base/logging.h"
-#include "base/thread.h"
-#include "chrome/browser/chrome_thread.h"
-#include "chrome/browser/renderer_host/render_process_host.h"
-#include "chrome/common/render_messages.h"
-
-using base::Time;
-using base::TimeDelta;
-using base::TimeTicks;
-
-HistogramSynchronizer::HistogramSynchronizer()
- : lock_(),
- received_all_renderer_historgrams_(&lock_),
- callback_task_(NULL),
- callback_thread_(NULL),
- io_message_loop_(NULL),
- next_available_sequence_number_(0),
- async_sequence_number_(0),
- async_renderers_pending_(0),
- async_callback_start_time_(TimeTicks::Now()),
- synchronous_sequence_number_(0),
- synchronous_renderers_pending_(0) {
- DCHECK(histogram_synchronizer_ == NULL);
- histogram_synchronizer_ = this;
-}
-
-HistogramSynchronizer::~HistogramSynchronizer() {
- // Clean up.
- delete callback_task_;
- callback_task_ = NULL;
- callback_thread_ = NULL;
- histogram_synchronizer_ = NULL;
-}
-
-// static
-HistogramSynchronizer* HistogramSynchronizer::CurrentSynchronizer() {
- DCHECK(histogram_synchronizer_ != NULL);
- return histogram_synchronizer_;
-}
-
-void HistogramSynchronizer::FetchRendererHistogramsSynchronously(
- TimeDelta wait_time) {
- DCHECK(MessageLoop::current()->type() == MessageLoop::TYPE_UI);
-
- int sequence_number = GetNextAvaibleSequenceNumber(SYNCHRONOUS_HISTOGRAMS);
- for (RenderProcessHost::iterator it(RenderProcessHost::AllHostsIterator());
- !it.IsAtEnd(); it.Advance()) {
- it.GetCurrentValue()->Send(
- new ViewMsg_GetRendererHistograms(sequence_number));
- IncrementPendingRenderers(SYNCHRONOUS_HISTOGRAMS);
- }
-
- TimeTicks start = TimeTicks::Now();
- TimeTicks end_time = start + wait_time;
- int unresponsive_renderer_count;
- {
- AutoLock auto_lock(lock_);
- while (synchronous_renderers_pending_ > 0 &&
- TimeTicks::Now() < end_time) {
- wait_time = end_time - TimeTicks::Now();
- received_all_renderer_historgrams_.TimedWait(wait_time);
- }
- unresponsive_renderer_count = synchronous_renderers_pending_;
- synchronous_renderers_pending_ = 0;
- synchronous_sequence_number_ = 0;
- }
- UMA_HISTOGRAM_COUNTS("Histogram.RendersNotRespondingSynchronous",
- unresponsive_renderer_count);
- if (!unresponsive_renderer_count)
- UMA_HISTOGRAM_TIMES("Histogram.FetchRendererHistogramsSynchronously",
- TimeTicks::Now() - start);
-}
-
-// static
-void HistogramSynchronizer::FetchRendererHistogramsAsynchronously(
- MessageLoop* callback_thread,
- Task* callback_task,
- int wait_time) {
- DCHECK(MessageLoop::current()->type() == MessageLoop::TYPE_UI);
- DCHECK(callback_thread != NULL);
- DCHECK(callback_task != NULL);
-
- HistogramSynchronizer* current_synchronizer =
- HistogramSynchronizer::CurrentSynchronizer();
-
- if (current_synchronizer == NULL) {
- // System teardown is happening.
- callback_thread->PostTask(FROM_HERE, callback_task);
- return;
- }
-
- // callback_task_ member can only be accessed on IO thread.
- ChromeThread::PostTask(
- ChromeThread::IO, FROM_HERE,
- NewRunnableMethod(
- current_synchronizer,
- &HistogramSynchronizer::SetCallbackTaskToCallAfterGettingHistograms,
- callback_thread,
- callback_task));
-
- // Tell all renderer processes to send their histograms.
- int sequence_number =
- current_synchronizer->GetNextAvaibleSequenceNumber(ASYNC_HISTOGRAMS);
- for (RenderProcessHost::iterator it(RenderProcessHost::AllHostsIterator());
- !it.IsAtEnd(); it.Advance()) {
- it.GetCurrentValue()->Send(
- new ViewMsg_GetRendererHistograms(sequence_number));
- current_synchronizer->IncrementPendingRenderers(ASYNC_HISTOGRAMS);
- }
-
- // Post a task that would be called after waiting for wait_time.
- ChromeThread::PostDelayedTask(
- ChromeThread::IO, FROM_HERE,
- NewRunnableMethod(
- current_synchronizer,
- &HistogramSynchronizer::ForceHistogramSynchronizationDoneCallback,
- sequence_number),
- wait_time);
-}
-
-// static
-void HistogramSynchronizer::DeserializeHistogramList(
- int sequence_number,
- const std::vector<std::string>& histograms) {
- HistogramSynchronizer* current_synchronizer =
- HistogramSynchronizer::CurrentSynchronizer();
- if (current_synchronizer == NULL)
- return;
-
- DCHECK(current_synchronizer->IsOnIoThread());
-
- for (std::vector<std::string>::const_iterator it = histograms.begin();
- it < histograms.end();
- ++it) {
- Histogram::DeserializeHistogramInfo(*it);
- }
-
- // Record that we have received a histogram from renderer process.
- current_synchronizer->RecordRendererHistogram(sequence_number);
-}
-
-bool HistogramSynchronizer::RecordRendererHistogram(int sequence_number) {
- DCHECK(IsOnIoThread());
-
- if (sequence_number == async_sequence_number_) {
- if ((async_renderers_pending_ == 0) ||
- (--async_renderers_pending_ > 0))
- return false;
- DCHECK(callback_task_ != NULL);
- CallCallbackTaskAndResetData();
- return true;
- }
-
- {
- AutoLock auto_lock(lock_);
- if (sequence_number != synchronous_sequence_number_) {
- // No need to do anything if the sequence_number does not match current
- // synchronous_sequence_number_ or async_sequence_number_.
- return true;
- }
- if ((synchronous_renderers_pending_ == 0) ||
- (--synchronous_renderers_pending_ > 0))
- return false;
- DCHECK_EQ(synchronous_renderers_pending_, 0);
- }
-
- // We could call Signal() without holding the lock.
- received_all_renderer_historgrams_.Signal();
- return true;
-}
-
-// This method is called on the IO thread.
-void HistogramSynchronizer::SetCallbackTaskToCallAfterGettingHistograms(
- MessageLoop* callback_thread,
- Task* callback_task) {
- DCHECK(IsOnIoThread());
-
- // Test for the existence of a previous task, and post call to post it if it
- // exists. We promised to post it after some timeout... and at this point, we
- // should just force the posting.
- if (callback_task_ != NULL) {
- CallCallbackTaskAndResetData();
- }
-
- // Assert there was no callback_task_ already.
- DCHECK(callback_task_ == NULL);
-
- // Save the thread and the callback_task.
- DCHECK(callback_thread != NULL);
- DCHECK(callback_task != NULL);
- callback_task_ = callback_task;
- callback_thread_ = callback_thread;
- async_callback_start_time_ = TimeTicks::Now();
-}
-
-void HistogramSynchronizer::ForceHistogramSynchronizationDoneCallback(
- int sequence_number) {
- DCHECK(IsOnIoThread());
-
- if (sequence_number == async_sequence_number_) {
- CallCallbackTaskAndResetData();
- }
-}
-
-// If wait time has elapsed or if we have received all the histograms from all
-// the renderers, call the callback_task if a callback_task exists. This is
-// called on IO Thread.
-void HistogramSynchronizer::CallCallbackTaskAndResetData() {
- DCHECK(IsOnIoThread());
-
- // callback_task_ would be set to NULL, if we have heard from all renderers
- // and we would have called the callback_task already.
- if (callback_task_ == NULL) {
- return;
- }
-
- UMA_HISTOGRAM_COUNTS("Histogram.RendersNotRespondingAsynchronous",
- async_renderers_pending_);
- if (!async_renderers_pending_)
- UMA_HISTOGRAM_TIMES("Histogram.FetchRendererHistogramsAsynchronously",
- TimeTicks::Now() - async_callback_start_time_);
-
- DCHECK(callback_thread_ != NULL);
- DCHECK(callback_task_ != NULL);
- callback_thread_->PostTask(FROM_HERE, callback_task_);
- async_renderers_pending_ = 0;
- async_callback_start_time_ = TimeTicks::Now();
- callback_task_ = NULL;
- callback_thread_ = NULL;
-}
-
-int HistogramSynchronizer::GetNextAvaibleSequenceNumber(
- RendererHistogramRequester requester) {
- AutoLock auto_lock(lock_);
- ++next_available_sequence_number_;
- if (0 > next_available_sequence_number_) // We wrapped around.
- next_available_sequence_number_ = kReservedSequenceNumber + 1;
- DCHECK(next_available_sequence_number_ != kReservedSequenceNumber);
- if (requester == ASYNC_HISTOGRAMS) {
- async_sequence_number_ = next_available_sequence_number_;
- async_renderers_pending_ = 0;
- } else if (requester == SYNCHRONOUS_HISTOGRAMS) {
- synchronous_sequence_number_ = next_available_sequence_number_;
- synchronous_renderers_pending_ = 0;
- }
- return next_available_sequence_number_;
-}
-
-void HistogramSynchronizer::IncrementPendingRenderers(
- RendererHistogramRequester requester) {
- if (requester == ASYNC_HISTOGRAMS) {
- async_renderers_pending_++;
- } else {
- synchronous_renderers_pending_++;
- }
-}
-
-bool HistogramSynchronizer::IsOnIoThread() {
- if (io_message_loop_ == NULL) {
- io_message_loop_ = MessageLoop::current();
- }
- return (MessageLoop::current() == io_message_loop_);
-}
-
-// static
-HistogramSynchronizer* HistogramSynchronizer::histogram_synchronizer_ = NULL;
diff --git a/chrome/common/histogram_synchronizer.h b/chrome/common/histogram_synchronizer.h
deleted file mode 100644
index 1190555..0000000
--- a/chrome/common/histogram_synchronizer.h
+++ /dev/null
@@ -1,147 +0,0 @@
-// Copyright (c) 2006-2008 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_HISTOGRAM_SYNCHRONIZER_H_
-#define CHROME_COMMON_HISTOGRAM_SYNCHRONIZER_H_
-
-#include <string>
-#include <vector>
-
-#include "base/basictypes.h"
-#include "base/condition_variable.h"
-#include "base/lock.h"
-#include "base/ref_counted.h"
-#include "base/time.h"
-
-class MessageLoop;
-class Task;
-
-class HistogramSynchronizer : public
- base::RefCountedThreadSafe<HistogramSynchronizer> {
- public:
-
- enum RendererHistogramRequester {
- ASYNC_HISTOGRAMS,
- SYNCHRONOUS_HISTOGRAMS
- };
-
- static const int kReservedSequenceNumber = 0;
-
- HistogramSynchronizer();
-
- ~HistogramSynchronizer();
-
- // Return pointer to the singleton instance, which is allocated and
- // deallocated on the main UI thread (during system startup and teardown).
- static HistogramSynchronizer* CurrentSynchronizer();
-
- // Contact all renderers, and get them to upload to the browser any/all
- // changes to histograms. Return when all changes have been acquired, or when
- // the wait time expires (whichever is sooner). This method is called on the
- // main UI thread from about:histograms.
- void FetchRendererHistogramsSynchronously(base::TimeDelta wait_time);
-
- // Contact all renderers, and get them to upload to the browser any/all
- // changes to histograms. When all changes have been acquired, or when the
- // wait time expires (whichever is sooner), post the callback_task to the UI
- // thread. Note the callback_task is posted exactly once. This method is
- // called on the IO thread from UMA via PostMessage.
- static void FetchRendererHistogramsAsynchronously(
- MessageLoop* callback_thread, Task* callback_task, int wait_time);
-
- // This method is called on the IO thread. Desrializes the histograms and
- // records that we have received histograms from a renderer process.
- static void DeserializeHistogramList(
- int sequence_number, const std::vector<std::string>& histograms);
-
- private:
- // Records that we have received the histograms from a renderer for the given
- // sequence number. If we have received a response from all histograms, either
- // signal the waiting process or call the callback function. Returns true when
- // we receive histograms from the last of N renderers that were contacted for
- // an update. This is called on IO Thread.
- bool RecordRendererHistogram(int sequence_number);
-
- void SetCallbackTaskToCallAfterGettingHistograms(
- MessageLoop* callback_thread, Task* callback_task);
-
- void ForceHistogramSynchronizationDoneCallback(int sequence_number);
-
- // Calls the callback task, if there is a callback_task.
- void CallCallbackTaskAndResetData();
-
- // Gets a new sequence number to be sent to renderers from broswer process.
- // This will also reset the current pending renderers for the given type.
- int GetNextAvaibleSequenceNumber(RendererHistogramRequester requster);
-
- // Increments the count of the renderers we're waiting for for the request
- // of the given type.
- void IncrementPendingRenderers(RendererHistogramRequester requester);
-
- // For use ONLY in a DCHECK. This method initializes io_message_loop_ in its
- // first call and then compares io_message_loop_ with MessageLoop::current()
- // in subsequent calls. This method guarantees we're consistently on the
- // singular IO thread and we don't need to worry about locks.
- bool IsOnIoThread();
-
- // This lock_ protects access to sequence number and
- // synchronous_renderers_pending_.
- Lock lock_;
-
- // This condition variable is used to block caller of the synchronous request
- // to update histograms, and to signal that thread when updates are completed.
- ConditionVariable received_all_renderer_historgrams_;
-
- // When a request is made to asynchronously update the histograms, we store
- // the task and thread we use to post a completion notification in
- // callback_task_ and callback_thread_.
- Task* callback_task_;
- MessageLoop* callback_thread_;
-
- // For use ONLY in a DCHECK and is used in IsOnIoThread(). io_message_loop_ is
- // initialized during the first call to IsOnIoThread(), and then compares
- // MessageLoop::current() against io_message_loop_ in subsequent calls for
- // consistency.
- MessageLoop* io_message_loop_;
-
- // We don't track the actual renderers that are contacted for an update, only
- // the count of the number of renderers, and we can sometimes time-out and
- // give up on a "slow to respond" renderer. We use a sequence_number to be
- // sure a response from a renderer is associated with the current round of
- // requests (and not merely a VERY belated prior response).
- // next_available_sequence_number_ is the next available number (used to
- // avoid reuse for a long time).
- int next_available_sequence_number_;
-
- // The sequence number used by the most recent asynchronous update request to
- // contact all renderers.
- int async_sequence_number_;
-
- // The number of renderers that have not yet responded to requests (as part of
- // an asynchronous update).
- int async_renderers_pending_;
-
- // The time when we were told to start the fetch histograms asynchronously
- // from renderers.
- base::TimeTicks async_callback_start_time_;
-
- // The sequence number used by the most recent synchronous update request to
- // contact all renderers.
- int synchronous_sequence_number_;
-
- // The number of renderers that have not yet responded to requests (as part of
- // a synchronous update).
- int synchronous_renderers_pending_;
-
- // This singleton instance should be started during the single threaded
- // portion of main(). It initializes globals to provide support for all future
- // calls. This object is created on the UI thread, and it is destroyed after
- // all the other threads have gone away. As a result, it is ok to call it
- // from the UI thread (for UMA uploads), or for about:histograms.
- static HistogramSynchronizer* histogram_synchronizer_;
-
- DISALLOW_COPY_AND_ASSIGN(HistogramSynchronizer);
-};
-
-#endif // CHROME_COMMON_HISTOGRAM_SYNCHRONIZER_H_
diff --git a/chrome/common/render_messages.h b/chrome/common/render_messages.h
index 7e05039..42b0313 100644
--- a/chrome/common/render_messages.h
+++ b/chrome/common/render_messages.h
@@ -16,7 +16,6 @@
#include "base/ref_counted.h"
#include "base/shared_memory.h"
#include "base/string16.h"
-#include "chrome/browser/renderer_host/resource_handler.h"
#include "chrome/common/common_param_traits.h"
#include "chrome/common/css_colors.h"
#include "chrome/common/dom_storage_common.h"
@@ -26,6 +25,7 @@
#include "chrome/common/navigation_gesture.h"
#include "chrome/common/page_transition_types.h"
#include "chrome/common/renderer_preferences.h"
+#include "chrome/common/resource_response.h"
#include "chrome/common/transport_dib.h"
#include "chrome/common/view_types.h"
#include "chrome/common/webkit_param_traits.h"
diff --git a/chrome/common/resource_response.h b/chrome/common/resource_response.h
new file mode 100644
index 0000000..840b864
--- /dev/null
+++ b/chrome/common/resource_response.h
@@ -0,0 +1,50 @@
+// Copyright (c) 2010 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.
+
+// See http://dev.chromium.org/developers/design-documents/multi-process-resource-loading
+
+#ifndef CHROME_COMMON_RESOURCE_RESPONSE_H_
+#define CHROME_COMMON_RESOURCE_RESPONSE_H_
+
+#include <string>
+
+#include "base/ref_counted.h"
+#include "chrome/common/filter_policy.h"
+#include "googleurl/src/gurl.h"
+#include "net/url_request/url_request_status.h"
+#include "webkit/glue/resource_loader_bridge.h"
+
+// Parameters for a resource response header.
+struct ResourceResponseHead
+ : webkit_glue::ResourceLoaderBridge::ResponseInfo {
+ ResourceResponseHead() : filter_policy(FilterPolicy::DONT_FILTER) {}
+
+ // The response status.
+ URLRequestStatus status;
+
+ // Specifies if the resource should be filtered before being displayed
+ // (insecure resources can be filtered to keep the page secure).
+ FilterPolicy::Type filter_policy;
+};
+
+// Parameters for a synchronous resource response.
+struct SyncLoadResult : ResourceResponseHead {
+ // The final URL after any redirects.
+ GURL final_url;
+
+ // The response data.
+ std::string data;
+};
+
+// Simple wrapper that refcounts ResourceResponseHead.
+struct ResourceResponse : public base::RefCounted<ResourceResponse> {
+ ResourceResponseHead response_head;
+
+ private:
+ friend class base::RefCounted<ResourceResponse>;
+
+ ~ResourceResponse() {}
+};
+
+#endif // CHROME_COMMON_RESOURCE_RESPONSE_H_