From 7c927b60bffa117129ba9214fcb6174d753351d9 Mon Sep 17 00:00:00 2001 From: "phajdan.jr@chromium.org" Date: Wed, 24 Feb 2010 09:54:13 +0000 Subject: 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 --- chrome/browser/browser_about_handler.cc | 2 +- chrome/browser/browser_main.cc | 2 +- chrome/browser/extensions/crx_installer.cc | 2 +- chrome/browser/extensions/extension_creator.cc | 2 +- .../extension_disabled_infobar_delegate.cc | 2 +- chrome/browser/extensions/extension_file_util.cc | 523 --------------------- chrome/browser/extensions/extension_file_util.h | 108 ----- .../extensions/extension_file_util_unittest.cc | 258 ---------- chrome/browser/extensions/extension_protocols.cc | 2 +- chrome/browser/extensions/extensions_service.cc | 2 +- .../extensions/sandboxed_extension_unpacker.cc | 4 +- .../extensions/user_script_listener_unittest.cc | 2 +- chrome/browser/metrics/histogram_synchronizer.cc | 278 +++++++++++ chrome/browser/metrics/histogram_synchronizer.h | 145 ++++++ chrome/browser/metrics/metrics_service.cc | 2 +- .../renderer_host/buffered_resource_handler.cc | 1 + .../renderer_host/cross_site_resource_handler.h | 1 + .../renderer_host/download_resource_handler.cc | 1 + .../download_throttling_resource_handler.cc | 1 + chrome/browser/renderer_host/resource_handler.h | 37 +- .../renderer_host/resource_message_filter.cc | 4 +- .../renderer_host/save_file_resource_handler.cc | 1 + .../renderer_host/save_file_resource_handler.h | 1 + .../browser/renderer_host/sync_resource_handler.h | 1 + .../x509_user_cert_resource_handler.cc | 1 + chrome/chrome_browser.gypi | 6 +- chrome/chrome_common.gypi | 11 +- chrome/chrome_tests.gypi | 6 +- chrome/common/chrome_constants.cc | 2 + chrome/common/chrome_constants.h | 2 + chrome/common/extensions/extension_file_util.cc | 521 ++++++++++++++++++++ chrome/common/extensions/extension_file_util.h | 108 +++++ .../extensions/extension_file_util_unittest.cc | 258 ++++++++++ chrome/common/extensions/extension_l10n_util.cc | 2 +- chrome/common/extensions/extension_unpacker.cc | 2 +- chrome/common/histogram_synchronizer.cc | 273 ----------- chrome/common/histogram_synchronizer.h | 147 ------ chrome/common/render_messages.h | 2 +- chrome/common/resource_response.h | 50 ++ chrome/renderer/render_view.cc | 3 +- 40 files changed, 1404 insertions(+), 1372 deletions(-) delete mode 100644 chrome/browser/extensions/extension_file_util.cc delete mode 100644 chrome/browser/extensions/extension_file_util.h delete mode 100644 chrome/browser/extensions/extension_file_util_unittest.cc create mode 100644 chrome/browser/metrics/histogram_synchronizer.cc create mode 100644 chrome/browser/metrics/histogram_synchronizer.h create mode 100644 chrome/common/extensions/extension_file_util.cc create mode 100644 chrome/common/extensions/extension_file_util.h create mode 100644 chrome/common/extensions/extension_file_util_unittest.cc delete mode 100644 chrome/common/histogram_synchronizer.cc delete mode 100644 chrome/common/histogram_synchronizer.h create mode 100644 chrome/common/resource_response.h diff --git a/chrome/browser/browser_about_handler.cc b/chrome/browser/browser_about_handler.cc index 88ee96f..a4126d1 100644 --- a/chrome/browser/browser_about_handler.cc +++ b/chrome/browser/browser_about_handler.cc @@ -27,6 +27,7 @@ #include "chrome/browser/dom_ui/chrome_url_data_manager.h" #include "chrome/browser/google_service_auth_error.h" #include "chrome/browser/memory_details.h" +#include "chrome/browser/metrics/histogram_synchronizer.h" #include "chrome/browser/net/dns_global.h" #include "chrome/browser/pref_service.h" #include "chrome/browser/profile.h" @@ -35,7 +36,6 @@ #include "chrome/browser/renderer_host/render_view_host.h" #include "chrome/browser/sync/profile_sync_service.h" #include "chrome/common/chrome_paths.h" -#include "chrome/common/histogram_synchronizer.h" #include "chrome/common/jstemplate_builder.h" #include "chrome/common/platform_util.h" #include "chrome/common/pref_names.h" diff --git a/chrome/browser/browser_main.cc b/chrome/browser/browser_main.cc index e462d1d..63a3e86 100644 --- a/chrome/browser/browser_main.cc +++ b/chrome/browser/browser_main.cc @@ -36,6 +36,7 @@ #include "chrome/browser/extensions/extension_protocols.h" #include "chrome/browser/first_run.h" #include "chrome/browser/jankometer.h" +#include "chrome/browser/metrics/histogram_synchronizer.h" #include "chrome/browser/metrics/metrics_service.h" #include "chrome/browser/net/dns_global.h" #include "chrome/browser/net/metadata_url_request.h" @@ -52,7 +53,6 @@ #include "chrome/common/chrome_constants.h" #include "chrome/common/chrome_paths.h" #include "chrome/common/chrome_switches.h" -#include "chrome/common/histogram_synchronizer.h" #include "chrome/common/jstemplate_builder.h" #include "chrome/common/main_function_params.h" #include "chrome/common/net/net_resource_provider.h" diff --git a/chrome/browser/extensions/crx_installer.cc b/chrome/browser/extensions/crx_installer.cc index e9874cd..fa466f3 100644 --- a/chrome/browser/extensions/crx_installer.cc +++ b/chrome/browser/extensions/crx_installer.cc @@ -13,11 +13,11 @@ #include "chrome/browser/browser_process.h" #include "chrome/browser/chrome_thread.h" #include "chrome/browser/extensions/convert_user_script.h" -#include "chrome/browser/extensions/extension_file_util.h" #include "chrome/browser/profile.h" #include "chrome/browser/shell_integration.h" #include "chrome/browser/web_applications/web_app.h" #include "chrome/common/extensions/extension_error_reporter.h" +#include "chrome/common/extensions/extension_file_util.h" #include "chrome/common/notification_service.h" #include "chrome/common/notification_type.h" #include "grit/browser_resources.h" diff --git a/chrome/browser/extensions/extension_creator.cc b/chrome/browser/extensions/extension_creator.cc index 3d1fc64..7c9ec15 100644 --- a/chrome/browser/extensions/extension_creator.cc +++ b/chrome/browser/extensions/extension_creator.cc @@ -13,9 +13,9 @@ #include "base/scoped_handle.h" #include "base/scoped_temp_dir.h" #include "base/string_util.h" -#include "chrome/browser/extensions/extension_file_util.h" #include "chrome/browser/extensions/sandboxed_extension_unpacker.h" #include "chrome/common/extensions/extension.h" +#include "chrome/common/extensions/extension_file_util.h" #include "chrome/common/zip.h" namespace { diff --git a/chrome/browser/extensions/extension_disabled_infobar_delegate.cc b/chrome/browser/extensions/extension_disabled_infobar_delegate.cc index dd12915..20acb53 100644 --- a/chrome/browser/extensions/extension_disabled_infobar_delegate.cc +++ b/chrome/browser/extensions/extension_disabled_infobar_delegate.cc @@ -6,12 +6,12 @@ #include "app/l10n_util.h" #include "chrome/browser/chrome_thread.h" -#include "chrome/browser/extensions/extension_file_util.h" #include "chrome/browser/extensions/extension_install_ui.h" #include "chrome/browser/extensions/extensions_service.h" #include "chrome/browser/tab_contents/infobar_delegate.h" #include "chrome/browser/tab_contents/tab_contents.h" #include "chrome/browser/browser_list.h" +#include "chrome/common/extensions/extension_file_util.h" #include "chrome/common/extensions/extension_resource.h" #include "chrome/common/notification_registrar.h" #include "chrome/common/notification_service.h" diff --git a/chrome/browser/extensions/extension_file_util.cc b/chrome/browser/extensions/extension_file_util.cc deleted file mode 100644 index 346bfab..0000000 --- a/chrome/browser/extensions/extension_file_util.cc +++ /dev/null @@ -1,523 +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/browser/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/browser/browser_process.h" -#include "chrome/browser/extensions/extension_prefs.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 current_version( - Version::GetVersionFromString(current_version_str)); - scoped_ptr 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 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(root.get()); - - scoped_ptr 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::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 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::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& installed_ids, - const std::map& 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::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 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 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::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/browser/extensions/extension_file_util.h b/chrome/browser/extensions/extension_file_util.h deleted file mode 100644 index d8bb448..0000000 --- a/chrome/browser/extensions/extension_file_util.h +++ /dev/null @@ -1,108 +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. - -#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_FILE_UTIL_H_ -#define CHROME_BROWSER_EXTENSIONS_EXTENSION_FILE_UTIL_H_ - -#include -#include - -#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& installed_ids, - const std::map& 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_BROWSER_EXTENSIONS_EXTENSION_FILE_UTIL_H_ diff --git a/chrome/browser/extensions/extension_file_util_unittest.cc b/chrome/browser/extensions/extension_file_util_unittest.cc deleted file mode 100644 index 31ed023..0000000 --- a/chrome/browser/extensions/extension_file_util_unittest.cc +++ /dev/null @@ -1,258 +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/browser/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_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_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_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_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/browser/extensions/extension_protocols.cc b/chrome/browser/extensions/extension_protocols.cc index 2141622..21dcd12 100644 --- a/chrome/browser/extensions/extension_protocols.cc +++ b/chrome/browser/extensions/extension_protocols.cc @@ -5,9 +5,9 @@ #include "chrome/browser/extensions/extension_protocols.h" #include "base/string_util.h" -#include "chrome/browser/extensions/extension_file_util.h" #include "chrome/browser/net/chrome_url_request_context.h" #include "chrome/common/extensions/extension.h" +#include "chrome/common/extensions/extension_file_util.h" #include "chrome/common/extensions/extension_resource.h" #include "chrome/common/url_constants.h" #include "googleurl/src/url_util.h" diff --git a/chrome/browser/extensions/extensions_service.cc b/chrome/browser/extensions/extensions_service.cc index 7b98410..d171767 100644 --- a/chrome/browser/extensions/extensions_service.cc +++ b/chrome/browser/extensions/extensions_service.cc @@ -18,7 +18,6 @@ #include "chrome/browser/extensions/extension_bookmarks_module.h" #include "chrome/browser/extensions/extension_browser_event_router.h" #include "chrome/browser/extensions/extension_dom_ui.h" -#include "chrome/browser/extensions/extension_file_util.h" #include "chrome/browser/extensions/extension_history_api.h" #include "chrome/browser/extensions/extension_host.h" #include "chrome/browser/extensions/extension_process_manager.h" @@ -33,6 +32,7 @@ #include "chrome/common/extensions/extension.h" #include "chrome/common/extensions/extension_constants.h" #include "chrome/common/extensions/extension_error_reporter.h" +#include "chrome/common/extensions/extension_file_util.h" #include "chrome/common/extensions/extension_l10n_util.h" #include "chrome/common/notification_service.h" #include "chrome/common/notification_type.h" diff --git a/chrome/browser/extensions/sandboxed_extension_unpacker.cc b/chrome/browser/extensions/sandboxed_extension_unpacker.cc index 9d004e3..a9d6966 100644 --- a/chrome/browser/extensions/sandboxed_extension_unpacker.cc +++ b/chrome/browser/extensions/sandboxed_extension_unpacker.cc @@ -14,14 +14,14 @@ #include "base/scoped_handle.h" #include "base/task.h" #include "chrome/browser/chrome_thread.h" -#include "chrome/browser/extensions/extension_file_util.h" #include "chrome/browser/extensions/extensions_service.h" #include "chrome/browser/renderer_host/resource_dispatcher_host.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/extensions/extension.h" #include "chrome/common/extensions/extension_constants.h" -#include "chrome/common/extensions/extension_unpacker.h" +#include "chrome/common/extensions/extension_file_util.h" #include "chrome/common/extensions/extension_l10n_util.h" +#include "chrome/common/extensions/extension_unpacker.h" #include "chrome/common/json_value_serializer.h" #include "third_party/skia/include/core/SkBitmap.h" diff --git a/chrome/browser/extensions/user_script_listener_unittest.cc b/chrome/browser/extensions/user_script_listener_unittest.cc index 546c734..79abdcf 100644 --- a/chrome/browser/extensions/user_script_listener_unittest.cc +++ b/chrome/browser/extensions/user_script_listener_unittest.cc @@ -4,7 +4,6 @@ #include "base/message_loop.h" #include "base/thread.h" -#include "chrome/browser/extensions/extension_file_util.h" #include "chrome/browser/extensions/extensions_service_unittest.h" #include "chrome/browser/extensions/user_script_listener.h" #include "chrome/browser/renderer_host/global_request_id.h" @@ -12,6 +11,7 @@ #include "chrome/browser/renderer_host/resource_handler.h" #include "chrome/browser/renderer_host/resource_queue.h" #include "chrome/common/chrome_paths.h" +#include "chrome/common/extensions/extension_file_util.h" #include "chrome/common/notification_service.h" #include "chrome/common/notification_type.h" #include "net/url_request/url_request.h" diff --git a/chrome/browser/metrics/histogram_synchronizer.cc b/chrome/browser/metrics/histogram_synchronizer.cc new file mode 100644 index 0000000..ff46199 --- /dev/null +++ b/chrome/browser/metrics/histogram_synchronizer.cc @@ -0,0 +1,278 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/metrics/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/chrome_constants.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& histograms) { + HistogramSynchronizer* current_synchronizer = + HistogramSynchronizer::CurrentSynchronizer(); + if (current_synchronizer == NULL) + return; + + DCHECK(current_synchronizer->IsOnIoThread()); + + for (std::vector::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_ = + chrome::kHistogramSynchronizerReservedSequenceNumber + 1; + } + DCHECK_NE(next_available_sequence_number_, + chrome::kHistogramSynchronizerReservedSequenceNumber); + 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/browser/metrics/histogram_synchronizer.h b/chrome/browser/metrics/histogram_synchronizer.h new file mode 100644 index 0000000..1a69afb --- /dev/null +++ b/chrome/browser/metrics/histogram_synchronizer.h @@ -0,0 +1,145 @@ +// 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_BROWSER_METRICS_HISTOGRAM_SYNCHRONIZER_H_ +#define CHROME_BROWSER_METRICS_HISTOGRAM_SYNCHRONIZER_H_ + +#include +#include + +#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 { + public: + + enum RendererHistogramRequester { + ASYNC_HISTOGRAMS, + SYNCHRONOUS_HISTOGRAMS + }; + + 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& 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_BROWSER_METRICS_HISTOGRAM_SYNCHRONIZER_H_ diff --git a/chrome/browser/metrics/metrics_service.cc b/chrome/browser/metrics/metrics_service.cc index dbd48fa..6b4ebbb 100644 --- a/chrome/browser/metrics/metrics_service.cc +++ b/chrome/browser/metrics/metrics_service.cc @@ -174,13 +174,13 @@ #include "chrome/browser/browser_process.h" #include "chrome/browser/load_notification_details.h" #include "chrome/browser/memory_details.h" +#include "chrome/browser/metrics/histogram_synchronizer.h" #include "chrome/browser/pref_service.h" #include "chrome/browser/profile.h" #include "chrome/browser/renderer_host/render_process_host.h" #include "chrome/browser/search_engines/template_url_model.h" #include "chrome/common/child_process_logging.h" #include "chrome/common/chrome_switches.h" -#include "chrome/common/histogram_synchronizer.h" #include "chrome/common/notification_service.h" #include "chrome/common/pref_names.h" #include "chrome/common/render_messages.h" diff --git a/chrome/browser/renderer_host/buffered_resource_handler.cc b/chrome/browser/renderer_host/buffered_resource_handler.cc index d58bed5..a7d36af 100644 --- a/chrome/browser/renderer_host/buffered_resource_handler.cc +++ b/chrome/browser/renderer_host/buffered_resource_handler.cc @@ -15,6 +15,7 @@ #include "chrome/browser/renderer_host/resource_dispatcher_host_request_info.h" #include "chrome/browser/renderer_host/x509_user_cert_resource_handler.h" #include "chrome/common/extensions/user_script.h" +#include "chrome/common/resource_response.h" #include "chrome/common/url_constants.h" #include "net/base/io_buffer.h" #include "net/base/mime_sniffer.h" diff --git a/chrome/browser/renderer_host/cross_site_resource_handler.h b/chrome/browser/renderer_host/cross_site_resource_handler.h index fc6bef2..ddb289f 100644 --- a/chrome/browser/renderer_host/cross_site_resource_handler.h +++ b/chrome/browser/renderer_host/cross_site_resource_handler.h @@ -6,6 +6,7 @@ #define CHROME_BROWSER_RENDERER_HOST_CROSS_SITE_RESOURCE_HANDLER_H_ #include "chrome/browser/renderer_host/resource_handler.h" +#include "net/url_request/url_request_status.h" class ResourceDispatcherHost; struct GlobalRequestID; diff --git a/chrome/browser/renderer_host/download_resource_handler.cc b/chrome/browser/renderer_host/download_resource_handler.cc index 1bbb757..e0aa870 100644 --- a/chrome/browser/renderer_host/download_resource_handler.cc +++ b/chrome/browser/renderer_host/download_resource_handler.cc @@ -10,6 +10,7 @@ #include "chrome/browser/download/download_manager.h" #include "chrome/browser/renderer_host/global_request_id.h" #include "chrome/browser/renderer_host/resource_dispatcher_host.h" +#include "chrome/common/resource_response.h" #include "net/base/io_buffer.h" #include "net/url_request/url_request_context.h" diff --git a/chrome/browser/renderer_host/download_throttling_resource_handler.cc b/chrome/browser/renderer_host/download_throttling_resource_handler.cc index 87314dc..4609a4c 100644 --- a/chrome/browser/renderer_host/download_throttling_resource_handler.cc +++ b/chrome/browser/renderer_host/download_throttling_resource_handler.cc @@ -7,6 +7,7 @@ #include "base/logging.h" #include "chrome/browser/renderer_host/download_resource_handler.h" #include "chrome/browser/renderer_host/resource_dispatcher_host.h" +#include "chrome/common/resource_response.h" #include "net/base/io_buffer.h" DownloadThrottlingResourceHandler::DownloadThrottlingResourceHandler( diff --git a/chrome/browser/renderer_host/resource_handler.h b/chrome/browser/renderer_host/resource_handler.h index 59f89c7..526c6a2 100644 --- a/chrome/browser/renderer_host/resource_handler.h +++ b/chrome/browser/renderer_host/resource_handler.h @@ -15,45 +15,14 @@ #include #include "chrome/browser/chrome_thread.h" -#include "chrome/common/filter_policy.h" -#include "net/url_request/url_request_status.h" -#include "webkit/glue/resource_loader_bridge.h" namespace net { class IOBuffer; } -// 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 { - ResourceResponseHead response_head; - - private: - friend class base::RefCounted; - - ~ResourceResponse() {} -}; +struct ResourceResponse; +class GURL; +class URLRequestStatus; // The resource dispatcher host uses this interface to push load events to the // renderer, allowing for differences in the types of IPC messages generated. diff --git a/chrome/browser/renderer_host/resource_message_filter.cc b/chrome/browser/renderer_host/resource_message_filter.cc index 9e9833c..2460db3 100644 --- a/chrome/browser/renderer_host/resource_message_filter.cc +++ b/chrome/browser/renderer_host/resource_message_filter.cc @@ -17,12 +17,12 @@ #include "chrome/browser/chrome_plugin_browsing_context.h" #include "chrome/browser/chrome_thread.h" #include "chrome/browser/download/download_file.h" -#include "chrome/browser/extensions/extension_file_util.h" #include "chrome/browser/extensions/extension_message_service.h" #include "chrome/browser/geolocation/geolocation_permission_context.h" #include "chrome/browser/geolocation/geolocation_dispatcher_host.h" #include "chrome/browser/host_zoom_map.h" #include "chrome/browser/in_process_webkit/dom_storage_dispatcher_host.h" +#include "chrome/browser/metrics/histogram_synchronizer.h" #include "chrome/browser/nacl_host/nacl_process_host.h" #include "chrome/browser/net/chrome_url_request_context.h" #include "chrome/browser/net/dns_global.h" @@ -49,8 +49,8 @@ #include "chrome/common/chrome_plugin_util.h" #include "chrome/common/chrome_switches.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/histogram_synchronizer.h" #include "chrome/common/notification_service.h" #include "chrome/common/pref_names.h" #include "chrome/common/render_messages.h" diff --git a/chrome/browser/renderer_host/save_file_resource_handler.cc b/chrome/browser/renderer_host/save_file_resource_handler.cc index b6584f0..c6f8de2 100644 --- a/chrome/browser/renderer_host/save_file_resource_handler.cc +++ b/chrome/browser/renderer_host/save_file_resource_handler.cc @@ -10,6 +10,7 @@ #include "chrome/browser/chrome_thread.h" #include "chrome/browser/download/save_file_manager.h" #include "net/base/io_buffer.h" +#include "net/url_request/url_request_status.h" SaveFileResourceHandler::SaveFileResourceHandler(int render_process_host_id, int render_view_id, diff --git a/chrome/browser/renderer_host/save_file_resource_handler.h b/chrome/browser/renderer_host/save_file_resource_handler.h index 07eca4d..825ad91 100644 --- a/chrome/browser/renderer_host/save_file_resource_handler.h +++ b/chrome/browser/renderer_host/save_file_resource_handler.h @@ -8,6 +8,7 @@ #include #include "chrome/browser/renderer_host/resource_handler.h" +#include "googleurl/src/gurl.h" class SaveFileManager; diff --git a/chrome/browser/renderer_host/sync_resource_handler.h b/chrome/browser/renderer_host/sync_resource_handler.h index cb2ae22..d15fe0d 100644 --- a/chrome/browser/renderer_host/sync_resource_handler.h +++ b/chrome/browser/renderer_host/sync_resource_handler.h @@ -9,6 +9,7 @@ #include "chrome/browser/renderer_host/resource_dispatcher_host.h" #include "chrome/browser/renderer_host/resource_handler.h" +#include "chrome/common/resource_response.h" #include "net/base/io_buffer.h" // Used to complete a synchronous resource request in response to resource load diff --git a/chrome/browser/renderer_host/x509_user_cert_resource_handler.cc b/chrome/browser/renderer_host/x509_user_cert_resource_handler.cc index 76dcedd..abf5541 100644 --- a/chrome/browser/renderer_host/x509_user_cert_resource_handler.cc +++ b/chrome/browser/renderer_host/x509_user_cert_resource_handler.cc @@ -10,6 +10,7 @@ #include "chrome/browser/download/download_file.h" #include "chrome/browser/renderer_host/resource_dispatcher_host.h" #include "chrome/browser/renderer_host/resource_dispatcher_host_request_info.h" +#include "chrome/common/resource_response.h" #include "chrome/common/url_constants.h" #include "net/base/cert_database.h" #include "net/base/io_buffer.h" diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index 61bb1eb..f0e0038 100755 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -848,8 +848,6 @@ 'browser/extensions/execute_code_in_tab_function.h', 'browser/extensions/extension_browser_event_router.cc', 'browser/extensions/extension_browser_event_router.h', - 'browser/extensions/extension_file_util.cc', - 'browser/extensions/extension_file_util.h', 'browser/extensions/extension_function.cc', 'browser/extensions/extension_function.h', 'browser/extensions/extension_function_dispatcher.cc', @@ -961,7 +959,7 @@ 'browser/geolocation/geolocation_permission_context.cc', 'browser/geolocation/geolocation_permission_context.h', 'browser/geolocation/geolocation_prefs.cc', - 'browser/geolocation/geolocation_prefs.h', + 'browser/geolocation/geolocation_prefs.h', 'browser/geolocation/location_arbitrator.cc', 'browser/geolocation/location_arbitrator.h', 'browser/geolocation/location_provider.cc', @@ -1365,6 +1363,8 @@ 'browser/message_box_handler.h', 'browser/meta_table_helper.cc', 'browser/meta_table_helper.h', + 'browser/metrics/histogram_synchronizer.cc', + 'browser/metrics/histogram_synchronizer.h', 'browser/metrics/metric_event_duration_details.h', 'browser/metrics/metrics_log.cc', 'browser/metrics/metrics_log.h', diff --git a/chrome/chrome_common.gypi b/chrome/chrome_common.gypi index 9f07af8..b2f0bd6 100644 --- a/chrome/chrome_common.gypi +++ b/chrome/chrome_common.gypi @@ -45,7 +45,7 @@ 'common/devtools_messages.h', 'common/devtools_messages_internal.h', 'common/geoposition.cc', - 'common/geoposition.h', + 'common/geoposition.h', 'common/gpu_messages.h', 'common/gpu_messages_internal.h', 'common/io_surface_support_mac.cc', @@ -75,6 +75,7 @@ 'common/property_bag.cc', 'common/property_bag.h', 'common/ref_counted_util.h', + 'common/resource_response.h', 'common/result_codes.h', 'common/sandbox_init_wrapper.h', 'common/sandbox_init_wrapper_linux.cc', @@ -143,14 +144,16 @@ 'common/desktop_notifications/active_notification_tracker.cc', 'common/extensions/extension.cc', 'common/extensions/extension.h', + 'common/extensions/extension_action.cc', + 'common/extensions/extension_action.h', 'common/extensions/extension_constants.cc', 'common/extensions/extension_constants.h', 'common/extensions/extension_error_reporter.cc', 'common/extensions/extension_error_reporter.h', 'common/extensions/extension_error_utils.cc', 'common/extensions/extension_error_utils.h', - 'common/extensions/extension_action.cc', - 'common/extensions/extension_action.h', + 'common/extensions/extension_file_util.cc', + 'common/extensions/extension_file_util.h', 'common/extensions/extension_l10n_util.cc', 'common/extensions/extension_l10n_util.h', 'common/extensions/extension_message_bundle.cc', @@ -211,8 +214,6 @@ 'common/gtk_tree.h', 'common/gtk_util.cc', 'common/gtk_util.h', - 'common/histogram_synchronizer.cc', - 'common/histogram_synchronizer.h', 'common/jstemplate_builder.cc', 'common/jstemplate_builder.h', 'common/libxml_utils.cc', diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi index 860ff88..3ec7ce8 100755 --- a/chrome/chrome_tests.gypi +++ b/chrome/chrome_tests.gypi @@ -706,7 +706,6 @@ 'browser/download/save_package_unittest.cc', 'browser/encoding_menu_controller_unittest.cc', 'browser/extensions/convert_user_script_unittest.cc', - 'browser/extensions/extension_file_util_unittest.cc', 'browser/extensions/extension_messages_unittest.cc', 'browser/extensions/extension_process_manager_unittest.cc', 'browser/extensions/extension_ui_unittest.cc', @@ -865,12 +864,13 @@ 'common/bzip2_unittest.cc', 'common/child_process_logging_mac_unittest.mm', 'common/common_param_traits_unittest.cc', - 'common/extensions/extension_resource_unittest.cc', - 'common/extensions/extension_unittest.cc', 'common/extensions/extension_action_unittest.cc', + 'common/extensions/extension_file_util_unittest.cc', 'common/extensions/extension_l10n_util_unittest.cc', 'common/extensions/extension_message_bundle_unittest.cc', 'common/extensions/extension_message_filter_peer_unittest.cc', + 'common/extensions/extension_resource_unittest.cc', + 'common/extensions/extension_unittest.cc', 'common/extensions/extension_unpacker_unittest.cc', 'common/extensions/update_manifest_unittest.cc', 'common/extensions/url_pattern_unittest.cc', 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 current_version( + Version::GetVersionFromString(current_version_str)); + scoped_ptr 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 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(root.get()); + + scoped_ptr 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::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 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::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& installed_ids, + const std::map& 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::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 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 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::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 +#include + +#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& installed_ids, + const std::map& 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_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_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_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_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& histograms) { - HistogramSynchronizer* current_synchronizer = - HistogramSynchronizer::CurrentSynchronizer(); - if (current_synchronizer == NULL) - return; - - DCHECK(current_synchronizer->IsOnIoThread()); - - for (std::vector::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 -#include - -#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 { - 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& 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 + +#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 { + ResourceResponseHead response_head; + + private: + friend class base::RefCounted; + + ~ResourceResponse() {} +}; + +#endif // CHROME_COMMON_RESOURCE_RESPONSE_H_ diff --git a/chrome/renderer/render_view.cc b/chrome/renderer/render_view.cc index c58b10b..74acd9c 100644 --- a/chrome/renderer/render_view.cc +++ b/chrome/renderer/render_view.cc @@ -29,7 +29,6 @@ #include "chrome/common/child_process_logging.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/chrome_constants.h" -#include "chrome/common/histogram_synchronizer.h" #include "chrome/common/extensions/extension_constants.h" #include "chrome/common/jstemplate_builder.h" #include "chrome/common/page_zoom.h" @@ -4261,7 +4260,7 @@ void RenderView::DumpLoadHistograms() const { // the next load. if (RenderThread::current()) { RenderThread::current()->SendHistograms( - HistogramSynchronizer::kReservedSequenceNumber); + chrome::kHistogramSynchronizerReservedSequenceNumber); } } -- cgit v1.1