diff options
author | aa@chromium.org <aa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-03-19 20:45:46 +0000 |
---|---|---|
committer | aa@chromium.org <aa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-03-19 20:45:46 +0000 |
commit | 867a73e1e2aad10f60952235da84f5d98cff9aa6 (patch) | |
tree | 5e977ff9c87a2cd3de2d7f50b057adbdad4c70bf /chrome/common/extensions | |
parent | 35de4be0f924ef6279a6a25fe840522524fa177b (diff) | |
download | chromium_src-867a73e1e2aad10f60952235da84f5d98cff9aa6.zip chromium_src-867a73e1e2aad10f60952235da84f5d98cff9aa6.tar.gz chromium_src-867a73e1e2aad10f60952235da84f5d98cff9aa6.tar.bz2 |
Resubmit 1025006: Refactor app-related manifest properties
so that they don't include the name 'app'.
TBR=erikkay@chromium.org
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@42146 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/common/extensions')
-rw-r--r-- | chrome/common/extensions/extension.cc | 258 | ||||
-rw-r--r-- | chrome/common/extensions/extension.h | 66 | ||||
-rw-r--r-- | chrome/common/extensions/extension_constants.cc | 51 | ||||
-rw-r--r-- | chrome/common/extensions/extension_constants.h | 39 | ||||
-rw-r--r-- | chrome/common/extensions/extension_extent.cc | 28 | ||||
-rw-r--r-- | chrome/common/extensions/extension_extent.h | 34 | ||||
-rw-r--r-- | chrome/common/extensions/extension_extent_unittest.cc | 57 | ||||
-rw-r--r-- | chrome/common/extensions/extension_manifests_unittest.cc | 162 | ||||
-rw-r--r-- | chrome/common/extensions/extension_unittest.cc | 59 |
9 files changed, 565 insertions, 189 deletions
diff --git a/chrome/common/extensions/extension.cc b/chrome/common/extensions/extension.cc index b12c764..81e15d1 100644 --- a/chrome/common/extensions/extension.cc +++ b/chrome/common/extensions/extension.cc @@ -488,98 +488,185 @@ bool Extension::ContainsNonThemeKeys(const DictionaryValue& source) { return false; } -// We're likely going to want to restrict apps away from certain APIs/features. -// TODO(erikkay) - figure out what APIs to block. -bool Extension::ContainsNonAppKeys(const DictionaryValue& source) { - return false; +bool Extension::CheckAppsAreEnabled(const DictionaryValue* manifest, + std::string* error) { + if (!apps_enabled_) { + if (manifest->HasKey(keys::kWebContent) || + manifest->HasKey(keys::kLaunch)) { + *error = errors::kAppsNotEnabled; + return false; + } + } + + return true; } -bool Extension::LoadAppHelper(const DictionaryValue* app, std::string* error) { - // launch URL - std::string launch_url_spec; - if (!app->GetString(keys::kAppLaunchUrl, &launch_url_spec)) { - *error = errors::kInvalidAppLaunchUrl; +bool Extension::LoadWebContentEnabled(const DictionaryValue* manifest, + std::string* error) { + Value* temp = NULL; + if (manifest->Get(keys::kWebContentEnabled, &temp)) { + if (!temp->GetAsBoolean(&web_content_enabled_)) { + *error = errors::kInvalidWebContentEnabled; + return false; + } + } + + // The enabled flag must be set to use the web_content dictionary at all. + if (!web_content_enabled_ && manifest->HasKey(keys::kWebContent)) { + *error = errors::kWebContentMustBeEnabled; return false; } - app_launch_url_ = GURL(launch_url_spec); - if (!app_launch_url_.is_valid()) { - *error = errors::kInvalidAppLaunchUrl; + + return true; +} + +bool Extension::LoadWebOrigin(const DictionaryValue* manifest, + std::string* error) { + Value* temp = NULL; + if (!manifest->Get(keys::kWebOrigin, &temp)) + return true; + + // Check datatype. + std::string origin_string; + if (!temp->GetAsString(&origin_string)) { + *error = errors::kInvalidWebOrigin; return false; } - // launch type - app_launch_type_ = LAUNCH_WINDOW; // TODO(erikkay) LAUNCH_TAB? - std::string launch_type_string; - if (app->GetString(keys::kAppLaunchType, &launch_type_string)) { - if (launch_type_string == std::string(values::kLaunchTypePanel)) { - app_launch_type_ = LAUNCH_PANEL; - } else if (launch_type_string == std::string(values::kLaunchTypeTab)) { - app_launch_type_ = LAUNCH_TAB; - } else if (launch_type_string != std::string(values::kLaunchTypeWindow)) { - *error = errors::kInvalidAppLaunchType; - return false; - } + // Origin must be a valid URL. + GURL origin_gurl(origin_string); + if (!origin_gurl.is_valid() || origin_gurl.is_empty()) { + *error = errors::kInvalidWebOrigin; + return false; } - // The launch URL is automatically added to the extent. - URLPattern pattern; - pattern.set_scheme(app_launch_url_.scheme()); - pattern.set_host(app_launch_url_.host()); - pattern.set_path(app_launch_url_.path()); - app_extent_.push_back(pattern); + // Origins can only be http or https. + if (!origin_gurl.SchemeIs(chrome::kHttpScheme) && + !origin_gurl.SchemeIs(chrome::kHttpsScheme)) { + *error = errors::kInvalidWebOrigin; + return false; + } + + // Check that the origin doesn't include any extraneous information. + if (origin_gurl.GetOrigin() != origin_gurl) { + *error = errors::kInvalidWebOrigin; + return false; + } + + web_extent_.set_origin(origin_gurl); + return true; +} + +bool Extension::LoadWebPaths(const DictionaryValue* manifest, + std::string* error) { + Value* temp = NULL; + if (!manifest->Get(keys::kWebPaths, &temp)) + return true; - // extent - if (app->HasKey(keys::kAppExtent)) { - ListValue* extent; - if (!app->GetList(keys::kAppExtent, &extent)) { - *error = errors::kInvalidAppExtent; + // Check datatype. + if (!temp->IsType(Value::TYPE_LIST)) { + *error = errors::kInvalidWebPaths; + return false; + } + + ListValue* web_paths = static_cast<ListValue*>(temp); + for (size_t i = 0; i < web_paths->GetSize(); ++i) { + // Get item and check datatype. + std::string item; + if (!web_paths->GetString(i, &item) || item.empty()) { + *error = ExtensionErrorUtils::FormatErrorMessage( + errors::kInvalidWebPath, IntToString(i)); return false; } - for (ListValue::const_iterator iter = extent->begin(); - iter != extent->end(); ++iter) { - std::string item; - if (!(*iter)->GetAsString(&item) || item.empty()) { - *error = ExtensionErrorUtils::FormatErrorMessage( - errors::kInvalidAppExtentPattern, item); - return false; - } - if (!pattern.Parse(item)) { - *error = ExtensionErrorUtils::FormatErrorMessage( - errors::kInvalidAppExtentPattern, item); - return false; - } - app_extent_.push_back(pattern); + + // Ensure the path is a valid relative URL by resolving it against the + // extension root. + // TODO(aa): This is hacky. Is there another way to know whether a string + // is a valid relative URL? + GURL resolved = extension_url_.Resolve(item); + if (!resolved.is_valid() || resolved.GetOrigin() != extension_url_) { + *error = ExtensionErrorUtils::FormatErrorMessage( + errors::kInvalidWebPath, IntToString(i)); + return false; } + + web_extent_.add_path(item); } - if (app->HasKey(keys::kAppOrigin)) { - std::string origin_string; - if (!app->GetString(keys::kAppOrigin, &origin_string)) { - *error = errors::kInvalidAppOrigin; + return true; +} + +bool Extension::LoadLaunchURL(const DictionaryValue* manifest, + std::string* error) { + Value* temp = NULL; + + // launch URL can be either local (to chrome-extension:// root) or web (either + // relative to the origin, or an absolute URL). + if (manifest->Get(keys::kLaunchLocalPath, &temp)) { + if (manifest->Get(keys::kLaunchWebURL, NULL)) { + *error = errors::kLaunchPathAndURLAreExclusive; + return false; + } + + std::string launch_path; + if (!temp->GetAsString(&launch_path)) { + *error = errors::kInvalidLaunchLocalPath; return false; } - // Origin must be a valid URL. - GURL origin_gurl(origin_string); - if (!origin_gurl.is_valid() || origin_gurl.is_empty()) { - *error = errors::kInvalidAppOrigin; + // Ensure the launch path is a valid relative URL. + GURL resolved = extension_url_.Resolve(launch_path); + if (!resolved.is_valid() || resolved.GetOrigin() != extension_url_) { + *error = errors::kInvalidLaunchLocalPath; return false; } - // Origins can only be http or https. - if (!origin_gurl.SchemeIs(chrome::kHttpScheme) && - !origin_gurl.SchemeIs(chrome::kHttpsScheme)) { - *error = errors::kInvalidAppOrigin; + launch_local_path_ = launch_path; + } else if (manifest->Get(keys::kLaunchWebURL, &temp)) { + std::string launch_url; + if (!temp->GetAsString(&launch_url)) { + *error = errors::kInvalidLaunchWebURL; return false; } - // Check that the origin doesn't include any extraneous information. - if (origin_gurl.GetOrigin() != origin_gurl) { - *error = errors::kInvalidAppOrigin; + // Ensure the launch URL is a valid relative or absolute URL. + if (!extension_url_.Resolve(launch_url).is_valid()) { + *error = errors::kInvalidLaunchWebURL; return false; } - app_origin_ = origin_gurl; + launch_web_url_ = launch_url; + } + + return true; +} + +bool Extension::LoadLaunchContainer(const DictionaryValue* manifest, + std::string* error) { + Value* temp = NULL; + if (!manifest->Get(keys::kLaunchContainer, &temp)) + return true; + + std::string launch_container_string; + if (!temp->GetAsString(&launch_container_string)) { + *error = errors::kInvalidLaunchContainer; + return false; + } + + if (launch_local_path_.empty() && launch_web_url_.empty()) { + *error = errors::kLaunchContainerWithoutURL; + return false; + } + + if (launch_container_string == values::kLaunchContainerPanel) { + launch_container_ = LAUNCH_PANEL; + } else if (launch_container_string == values::kLaunchContainerTab) { + launch_container_ = LAUNCH_TAB; + } else if (launch_container_string == values::kLaunchContainerWindow) { + launch_container_ = LAUNCH_WINDOW; + } else { + *error = errors::kInvalidLaunchContainer; + return false; } return true; @@ -588,9 +675,14 @@ bool Extension::LoadAppHelper(const DictionaryValue* app, std::string* error) { Extension::Extension(const FilePath& path) : converted_from_user_script_(false), is_theme_(false), + web_content_enabled_(false), + launch_container_(LAUNCH_TAB), background_page_ready_(false), being_upgraded_(false) { DCHECK(path.IsAbsolute()); + + apps_enabled_ = CommandLine::ForCurrentProcess()->HasSwitch( + switches::kEnableExtensionApps); location_ = INVALID; #if defined(OS_WIN) @@ -1293,20 +1385,13 @@ bool Extension::InitFromValue(const DictionaryValue& source, bool require_key, } } - // If it's an app, load the appropriate keys, etc. - if (source.HasKey(keys::kApp)) { - if (ContainsNonAppKeys(source)) { - *error = errors::kInvalidApp; - return false; - } - DictionaryValue* app; - if (!source.GetDictionary(keys::kApp, &app)) { - *error = errors::kInvalidApp; - return false; - } - if (!LoadAppHelper(app, error)) { - return false; - } + if (!CheckAppsAreEnabled(manifest_value_.get(), error) || + !LoadWebContentEnabled(manifest_value_.get(), error) || + !LoadWebOrigin(manifest_value_.get(), error) || + !LoadWebPaths(manifest_value_.get(), error) || + !LoadLaunchURL(manifest_value_.get(), error) || + !LoadLaunchContainer(manifest_value_.get(), error)) { + return false; } // Although |source| is passed in as a const, it's still possible to modify @@ -1360,6 +1445,21 @@ std::set<FilePath> Extension::GetBrowserImages() { return image_paths; } +GURL Extension::GetFullLaunchURL() const { + if (!launch_local_path_.empty()) { + return extension_url_.Resolve(launch_local_path_); + } else if (!launch_web_url_.empty()) { + // If there is a web origin, we interpret the launch URL relatively to that. + // Otherwise, hopefully it was an absolute URL. + if (web_extent_.origin().is_valid()) + return web_extent_.origin().Resolve(launch_web_url_); + else + return GURL(launch_web_url_); + } else { + return GURL(); + } +} + bool Extension::GetBackgroundPageReady() { return background_page_ready_ || background_url().is_empty(); } diff --git a/chrome/common/extensions/extension.h b/chrome/common/extensions/extension.h index 50fe957..418a01a 100644 --- a/chrome/common/extensions/extension.h +++ b/chrome/common/extensions/extension.h @@ -15,6 +15,7 @@ #include "base/values.h" #include "base/version.h" #include "chrome/common/extensions/extension_action.h" +#include "chrome/common/extensions/extension_extent.h" #include "chrome/common/extensions/extension_resource.h" #include "chrome/common/extensions/user_script.h" #include "chrome/common/extensions/url_pattern.h" @@ -67,12 +68,15 @@ class Extension { EXTENSION_ICON_BITTY = 16, }; - enum AppLaunchType { + enum LaunchContainer { LAUNCH_WINDOW, LAUNCH_PANEL, LAUNCH_TAB }; + bool apps_enabled() const { return apps_enabled_; } + void set_apps_enabled(bool val) { apps_enabled_ = val; } + // Icon sizes used by the extension system. static const int kIconSizes[]; @@ -288,12 +292,15 @@ class Extension { return chrome_url_overrides_; } - // App stuff. - const URLPatternList& app_extent() const { return app_extent_; } - const GURL& app_launch_url() const { return app_launch_url_; } - bool IsApp() const { return !app_launch_url_.is_empty(); } - AppLaunchType app_launch_type() { return app_launch_type_; } - const GURL& app_origin() const { return app_origin_; } + bool web_content_enabled() const { return web_content_enabled_; } + const ExtensionExtent& web_extent() const { return web_extent_; } + + const std::string& launch_local_path() const { return launch_local_path_; } + const std::string& launch_web_url() const { return launch_web_url_; } + const LaunchContainer launch_container() const { return launch_container_; } + + // Gets the fully resolved absolute launch URL. + GURL GetFullLaunchURL() const; // Runtime data: // Put dynamic data about the state of a running extension below. @@ -326,6 +333,18 @@ class Extension { void(UserScript::*add_method)(const std::string& glob), UserScript *instance); + // Checks that apps features are enabled if the manifest tries to use any of + // them. + bool CheckAppsAreEnabled(const DictionaryValue* manifest, std::string* error); + + // Helpers to load various chunks of the manifest. + bool LoadWebContentEnabled(const DictionaryValue* manifest, + std::string* error); + bool LoadWebOrigin(const DictionaryValue* manifest, std::string* error); + bool LoadWebPaths(const DictionaryValue* manifest, std::string* error); + bool LoadLaunchContainer(const DictionaryValue* manifest, std::string* error); + bool LoadLaunchURL(const DictionaryValue* manifest, std::string* error); + // Helper method to load an ExtensionAction from the page_action or // browser_action entries in the manifest. ExtensionAction* LoadExtensionActionHelper( @@ -335,13 +354,6 @@ class Extension { // don't want to allow scripts and such to be bundled with themes. bool ContainsNonThemeKeys(const DictionaryValue& source); - // Apps don't have access to all extension features. This enforces those - // restrictions. - bool ContainsNonAppKeys(const DictionaryValue& source); - - // Helper method to verify the app section of the manifest. - bool LoadAppHelper(const DictionaryValue* app, std::string* error); - // Returns true if the string is one of the known api permissions (see // kPermissionNames). bool IsAPIPermission(const std::string& permission); @@ -439,18 +451,26 @@ class Extension { // which override the handling of those URLs. URLOverrideMap chrome_url_overrides_; - // Describes the space of URLs that are displayed in the app's custom frame. - URLPatternList app_extent_; + // Whether apps-related features can be parsed during InitFromValue(). + // Defaults to the value from --enable-extension-apps. + bool apps_enabled_; + + // Whether the extension can contain live web content. Defaults to false. + bool web_content_enabled_; + + // Defines the set of URLs in the extension's web content. + ExtensionExtent web_extent_; + + // The local path inside the extension to use with the launcher. + std::string launch_local_path_; - // The URL an app should launch to. - GURL app_launch_url_; + // A web url to use with the launcher. Note that this might be relative or + // absolute. If relative, it is relative to web_origin_. + std::string launch_web_url_; - // How to start when the application is launched. - AppLaunchType app_launch_type_; + // The type of container to launch into. + LaunchContainer launch_container_; - // The web security origin associated with the app. This origin will be - // granted the permissions the app requests. - GURL app_origin_; // Runtime data: diff --git a/chrome/common/extensions/extension_constants.cc b/chrome/common/extensions/extension_constants.cc index 1c9c5c9..f28fad1 100644 --- a/chrome/common/extensions/extension_constants.cc +++ b/chrome/common/extensions/extension_constants.cc @@ -7,11 +7,6 @@ namespace extension_manifest_keys { const wchar_t* kAllFrames = L"all_frames"; -const wchar_t* kApp = L"app"; -const wchar_t* kAppExtent = L"extent"; -const wchar_t* kAppLaunchUrl = L"launch.url"; -const wchar_t* kAppLaunchType = L"launch.window_type"; // TODO(erikkay) rename -const wchar_t* kAppOrigin = L"origin"; const wchar_t* kBackground = L"background_page"; const wchar_t* kBrowserAction = L"browser_action"; const wchar_t* kChromeURLOverrides = L"chrome_url_overrides"; @@ -23,6 +18,10 @@ const wchar_t* kDefaultLocale = L"default_locale"; const wchar_t* kDescription = L"description"; const wchar_t* kIcons = L"icons"; const wchar_t* kJs = L"js"; +const wchar_t* kLaunch = L"launch"; +const wchar_t* kLaunchContainer = L"launch.container"; +const wchar_t* kLaunchLocalPath = L"launch.local_path"; +const wchar_t* kLaunchWebURL = L"launch.web_url"; const wchar_t* kMatches = L"matches"; const wchar_t* kMinimumChromeVersion = L"minimum_chrome_version"; const wchar_t* kIncludeGlobs = L"include_globs"; @@ -58,6 +57,10 @@ const wchar_t* kType = L"type"; const wchar_t* kVersion = L"version"; const wchar_t* kUpdateURL = L"update_url"; const wchar_t* kOptionsPage = L"options_page"; +const wchar_t* kWebContent = L"web_content"; +const wchar_t* kWebContentEnabled = L"web_content.enabled"; +const wchar_t* kWebOrigin = L"web_content.origin"; +const wchar_t* kWebPaths = L"web_content.paths"; } // namespace extension_manifest_keys namespace extension_manifest_values { @@ -66,9 +69,9 @@ const char* kRunAtDocumentEnd = "document_end"; const char* kRunAtDocumentIdle = "document_idle"; const char* kPageActionTypeTab = "tab"; const char* kPageActionTypePermanent = "permanent"; -const char* kLaunchTypePanel = "panel"; -const char* kLaunchTypeTab = "tab"; -const char* kLaunchTypeWindow = "window"; +const char* kLaunchContainerPanel = "panel"; +const char* kLaunchContainerTab = "tab"; +const char* kLaunchContainerWindow = "window"; } // namespace extension_manifest_values // Extension-related error messages. Some of these are simple patterns, where a @@ -76,21 +79,11 @@ const char* kLaunchTypeWindow = "window"; // printf because we want to unit test them and scanf is hard to make // cross-platform. namespace extension_manifest_errors { -const char* kAppsDisabled = "Apps are disabled."; +const char* kAppsNotEnabled = "Apps are not enabled."; const char* kChromeVersionTooLow = "This extension requires * version * or greater."; const char* kInvalidAllFrames = "Invalid value for 'content_scripts[*].all_frames'."; -const char* kInvalidApp = "Invalid app."; -const char* kInvalidAppExtent = "Invalid value for app.extent."; -const char* kInvalidAppExtentPattern = "Invalid value for app.extent[*]."; -const char* kInvalidAppLaunchType = - "Invalid value for 'app.launch.window_type'."; -const char* kInvalidAppLaunchUrl = - "Required value 'app.launch.url' is missing or invalid."; -const char* kInvalidAppOrigin = - "Invalid value for 'app.origin'. Value must be a URL of the form " - "scheme://host[:port]/ where scheme is http or https."; const char* kInvalidBrowserAction = "Invalid value for 'browser_action'."; const char* kInvalidChromeURLOverrides = @@ -117,6 +110,12 @@ const char* kInvalidJs = "Invalid value for 'content_scripts[*].js[*]'."; const char* kInvalidJsList = "Required value 'content_scripts[*].js' is invalid."; +const char* kInvalidLaunchContainer = + "Invalid value for 'launch.container'."; +const char* kInvalidLaunchLocalPath = + "Invalid value for 'launch.local_path'."; +const char* kInvalidLaunchWebURL = + "Invalid value for 'launch.web_url'."; const char* kInvalidKey = "Value 'key' is missing or invalid."; const char* kInvalidManifest = @@ -203,12 +202,24 @@ const char* kInvalidThemeTints = "Invalid value for theme images - tints must be decimal numbers."; const char* kInvalidUpdateURL = "Invalid value for update url: '[*]'."; +const char* kInvalidWebContentEnabled = + "Invalid value for 'web_content.enabled'."; +const char* kInvalidWebOrigin = + "Invalid value for 'web_content.origin'."; +const char* kInvalidWebPaths = + "Invalid value for 'web_content.paths'."; +const char* kInvalidWebPath = + "Invalid value for 'web_contents.paths[*]'."; const char* kInvalidDefaultLocale = "Invalid value for default locale - locale name must be a string."; const char* kOneUISurfaceOnly = "An extension cannot have both a page action and a browser action."; const char* kThemesCannotContainExtensions = "A theme cannot contain extensions code."; +const char* kLaunchContainerWithoutURL = + "Launch container specified, but no local_path or web_url to launch."; +const char* kLaunchPathAndURLAreExclusive = + "The 'launch.local_path' and 'launch.web_url' keys cannot both be set."; const char* kLocalesNoDefaultLocaleSpecified = "Localization used, but default_locale wasn't specified in the manifest."; const char* kLocalesNoDefaultMessages = @@ -226,6 +237,8 @@ const char* kReservedMessageFound = const char* kCannotAccessPage = "Cannot access contents of url \"*\". " "Extension manifest must request permission to access this host."; const char* kCannotScriptGallery = "The extensions gallery cannot be scripted."; +const char* kWebContentMustBeEnabled = "The 'web_content.enabled' property " + "must be set to true in order to use any other web content features."; } // namespace extension_manifest_errors namespace extension_urls { diff --git a/chrome/common/extensions/extension_constants.h b/chrome/common/extensions/extension_constants.h index 453fb1c..e3f1a0c 100644 --- a/chrome/common/extensions/extension_constants.h +++ b/chrome/common/extensions/extension_constants.h @@ -8,11 +8,6 @@ // Keys used in JSON representation of extensions. namespace extension_manifest_keys { extern const wchar_t* kAllFrames; - extern const wchar_t* kApp; - extern const wchar_t* kAppExtent; - extern const wchar_t* kAppLaunchUrl; - extern const wchar_t* kAppLaunchType; - extern const wchar_t* kAppOrigin; extern const wchar_t* kBackground; extern const wchar_t* kBrowserAction; extern const wchar_t* kMinimumChromeVersion; @@ -26,6 +21,10 @@ namespace extension_manifest_keys { extern const wchar_t* kExcludeGlobs; extern const wchar_t* kIcons; extern const wchar_t* kIncludeGlobs; + extern const wchar_t* kLaunch; + extern const wchar_t* kLaunchContainer; + extern const wchar_t* kLaunchLocalPath; + extern const wchar_t* kLaunchWebURL; extern const wchar_t* kJs; extern const wchar_t* kMatches; extern const wchar_t* kName; @@ -59,6 +58,11 @@ namespace extension_manifest_keys { extern const wchar_t* kVersion; extern const wchar_t* kUpdateURL; extern const wchar_t* kOptionsPage; + extern const wchar_t* kWebContent; + extern const wchar_t* kWebContentEnabled; + extern const wchar_t* kWebLaunchUrl; + extern const wchar_t* kWebOrigin; + extern const wchar_t* kWebPaths; } // namespace extension_manifest_keys // Some values expected in manifests. @@ -68,22 +72,16 @@ namespace extension_manifest_values { extern const char* kRunAtDocumentIdle; extern const char* kPageActionTypeTab; extern const char* kPageActionTypePermanent; - extern const char* kLaunchTypePanel; - extern const char* kLaunchTypeTab; - extern const char* kLaunchTypeWindow; + extern const char* kLaunchContainerPanel; + extern const char* kLaunchContainerTab; + extern const char* kLaunchContainerWindow; } // namespace extension_manifest_values // Error messages returned from Extension::InitFromValue(). namespace extension_manifest_errors { - extern const char* kAppsDisabled; + extern const char* kAppsNotEnabled; extern const char* kChromeVersionTooLow; extern const char* kInvalidAllFrames; - extern const char* kInvalidApp; - extern const char* kInvalidAppExtent; - extern const char* kInvalidAppExtentPattern; - extern const char* kInvalidAppLaunchType; - extern const char* kInvalidAppLaunchUrl; - extern const char* kInvalidAppOrigin; extern const char* kInvalidBackground; extern const char* kInvalidBrowserAction; extern const char* kInvalidChromeURLOverrides; @@ -99,6 +97,9 @@ namespace extension_manifest_errors { extern const char* kInvalidJs; extern const char* kInvalidJsList; extern const char* kInvalidKey; + extern const char* kInvalidLaunchContainer; + extern const char* kInvalidLaunchLocalPath; + extern const char* kInvalidLaunchWebURL; extern const char* kInvalidManifest; extern const char* kInvalidMatchCount; extern const char* kInvalidMatch; @@ -108,7 +109,6 @@ namespace extension_manifest_errors { extern const char* kInvalidPlugins; extern const char* kInvalidPluginsPath; extern const char* kInvalidPluginsPublic; - extern const char* kInvalidRunAt; extern const char* kInvalidSignature; extern const char* kInvalidToolstrip; @@ -135,6 +135,10 @@ namespace extension_manifest_errors { extern const char* kInvalidThemeImages; extern const char* kInvalidThemeColors; extern const char* kInvalidThemeTints; + extern const char* kInvalidWebContentEnabled; + extern const char* kInvalidWebOrigin; + extern const char* kInvalidWebPaths; + extern const char* kInvalidWebPath; extern const char* kOneUISurfaceOnly; extern const char* kThemesCannotContainExtensions; extern const char* kManifestParseError; @@ -142,6 +146,8 @@ namespace extension_manifest_errors { extern const char* kMissingFile; extern const char* kInvalidUpdateURL; extern const char* kInvalidDefaultLocale; + extern const char* kLaunchContainerWithoutURL; + extern const char* kLaunchPathAndURLAreExclusive; extern const char* kLocalesNoDefaultLocaleSpecified; extern const char* kLocalesNoDefaultMessages; extern const char* kLocalesNoValidLocaleNamesListed; @@ -151,6 +157,7 @@ namespace extension_manifest_errors { extern const char* kReservedMessageFound; extern const char* kCannotAccessPage; extern const char* kCannotScriptGallery; + extern const char* kWebContentMustBeEnabled; } // namespace extension_manifest_errors namespace extension_urls { diff --git a/chrome/common/extensions/extension_extent.cc b/chrome/common/extensions/extension_extent.cc new file mode 100644 index 0000000..310673e --- /dev/null +++ b/chrome/common/extensions/extension_extent.cc @@ -0,0 +1,28 @@ +// 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. + +#include "chrome/common/extensions/extension_extent.h" + +#include "base/string_util.h" + +bool ExtensionExtent::ContainsURL(const GURL& url) { + if (!url.is_valid()) + return false; + + if (url.GetOrigin() != origin_) + return false; + + if (paths_.empty()) + return true; + + for (size_t i = 0; i < paths_.size(); ++i) { + if (StartsWithASCII(url.path(), + std::string("/") + paths_[i], + false)) { // not case sensitive + return true; + } + } + + return false; +} diff --git a/chrome/common/extensions/extension_extent.h b/chrome/common/extensions/extension_extent.h new file mode 100644 index 0000000..76670ab --- /dev/null +++ b/chrome/common/extensions/extension_extent.h @@ -0,0 +1,34 @@ +// 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. + +#ifndef CHROME_COMMON_EXTENSIONS_EXTENSION_EXTENT_H_ +#define CHROME_COMMON_EXTENSIONS_EXTENSION_EXTENT_H_ + +#include <string> +#include <vector> + +#include "googleurl/src/gurl.h" + +// Represents the set of URLs an extension uses for web content. +class ExtensionExtent { + public: + const std::vector<std::string>& paths() const { return paths_; } + void add_path(const std::string& val) { paths_.push_back(val); } + void clear_paths() { paths_.clear(); } + + const GURL& origin() const { return origin_; } + void set_origin(const GURL& val) { origin_ = val; } + + bool ContainsURL(const GURL& url); + + private: + // The security origin (scheme+host+port) of the extent. + GURL origin_; + + // A set of path prefixes that further restrict the set of valid URLs below + // origin_. This may be empty. + std::vector<std::string> paths_; +}; + +#endif // CHROME_COMMON_EXTENSIONS_EXTENSION_EXTENT_H_ diff --git a/chrome/common/extensions/extension_extent_unittest.cc b/chrome/common/extensions/extension_extent_unittest.cc new file mode 100644 index 0000000..4e308fa --- /dev/null +++ b/chrome/common/extensions/extension_extent_unittest.cc @@ -0,0 +1,57 @@ +// 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. + +#include "chrome/common/extensions/extension.h" + +#include "googleurl/src/gurl.h" +#include "testing/gtest/include/gtest/gtest.h" + +TEST(ExtensionExtentTest, Empty) { + ExtensionExtent extent; + EXPECT_FALSE(extent.ContainsURL(GURL("http://www.foo.com/bar"))); + EXPECT_FALSE(extent.ContainsURL(GURL())); + EXPECT_FALSE(extent.ContainsURL(GURL("invalid"))); +} + +TEST(ExtensionExtentTest, OriginOnly) { + ExtensionExtent extent; + extent.set_origin(GURL("http://www.google.com/")); + + EXPECT_TRUE(extent.ContainsURL(GURL("http://www.google.com/"))); + EXPECT_TRUE(extent.ContainsURL(GURL("http://www.google.com/foo"))); + EXPECT_TRUE(extent.ContainsURL(GURL("http://www.google.com/foobar"))); + EXPECT_TRUE(extent.ContainsURL(GURL("http://www.google.com/foo/bar"))); + EXPECT_TRUE(extent.ContainsURL(GURL("http://www.google.com/?stuff#here"))); + + EXPECT_FALSE(extent.ContainsURL(GURL("https://www.google.com/"))); + EXPECT_FALSE(extent.ContainsURL(GURL("http://www.google.com:8080/"))); +} + +TEST(ExtensionExtentTest, OriginAndOnePath) { + ExtensionExtent extent; + extent.set_origin(GURL("http://www.google.com/")); + extent.add_path("foo"); + + EXPECT_FALSE(extent.ContainsURL(GURL("http://www.google.com/"))); + EXPECT_FALSE(extent.ContainsURL(GURL("http://www.google.com/fo"))); + + EXPECT_TRUE(extent.ContainsURL(GURL("http://www.google.com/foo"))); + EXPECT_TRUE(extent.ContainsURL(GURL("http://www.google.com/FOO"))); + EXPECT_TRUE(extent.ContainsURL(GURL("http://www.google.com/foobar"))); + EXPECT_TRUE(extent.ContainsURL(GURL("http://www.google.com/foo/bar"))); +} + +TEST(ExtensionExtentTest, OriginAndTwoPaths) { + ExtensionExtent extent; + extent.set_origin(GURL("http://www.google.com/")); + extent.add_path("foo"); + extent.add_path("hot"); + + EXPECT_FALSE(extent.ContainsURL(GURL("http://www.google.com/monkey"))); + + EXPECT_TRUE(extent.ContainsURL(GURL("http://www.google.com/foo"))); + EXPECT_TRUE(extent.ContainsURL(GURL("http://www.google.com/hot"))); + EXPECT_TRUE(extent.ContainsURL(GURL("http://www.google.com/foobar"))); + EXPECT_TRUE(extent.ContainsURL(GURL("http://www.google.com/hotdog"))); +} diff --git a/chrome/common/extensions/extension_manifests_unittest.cc b/chrome/common/extensions/extension_manifests_unittest.cc new file mode 100644 index 0000000..d7a5c2b --- /dev/null +++ b/chrome/common/extensions/extension_manifests_unittest.cc @@ -0,0 +1,162 @@ +// 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. + +#include "base/file_path.h" +#include "base/file_util.h" +#include "base/path_service.h" +#include "base/scoped_ptr.h" +#include "chrome/common/chrome_paths.h" +#include "chrome/common/extensions/extension.h" +#include "chrome/common/extensions/extension_constants.h" +#include "chrome/common/extensions/extension_error_utils.h" +#include "chrome/common/json_value_serializer.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace errors = extension_manifest_errors; + +class ManifestTest : public testing::Test { + public: + ManifestTest() : enable_apps_(true) {} + + protected: + Extension* LoadExtension(const std::string& name, + std::string* error) { + FilePath path; + PathService::Get(chrome::DIR_TEST_DATA, &path); + path = path.AppendASCII("extensions") + .AppendASCII("manifest_tests") + .AppendASCII(name.c_str()); + EXPECT_TRUE(file_util::PathExists(path)); + + JSONFileValueSerializer serializer(path); + scoped_ptr<DictionaryValue> value( + static_cast<DictionaryValue*>(serializer.Deserialize(error))); + if (!value.get()) + return NULL; + + scoped_ptr<Extension> extension(new Extension(path.DirName())); + if (enable_apps_) + extension->set_apps_enabled(true); + + if (!extension->InitFromValue(*value, false, error)) + return NULL; + + return extension.release(); + } + + Extension* LoadAndExpectSuccess(const std::string& name) { + std::string error; + Extension* extension = LoadExtension(name, &error); + EXPECT_TRUE(extension); + EXPECT_EQ("", error); + return extension; + } + + void LoadAndExpectError(const std::string& name, + const std::string& expected_error) { + std::string error; + scoped_ptr<Extension> extension(LoadExtension(name, &error)); + EXPECT_FALSE(extension.get()) << + "Expected failure loading extension '" << name << + "', but didn't get one."; + EXPECT_EQ(expected_error, error); + } + + bool enable_apps_; +}; + +TEST_F(ManifestTest, AppsDisabledByDefault) { + enable_apps_ = false; + LoadAndExpectError("web_content_disabled.json", errors::kAppsNotEnabled); + LoadAndExpectError("launch_local_path.json", errors::kAppsNotEnabled); +} + +TEST_F(ManifestTest, ValidApp) { + scoped_ptr<Extension> extension(LoadAndExpectSuccess("valid_app.json")); + EXPECT_TRUE(extension->web_content_enabled()); + EXPECT_EQ(GURL("http://www.google.com/"), extension->web_extent().origin()); + EXPECT_EQ(2u, extension->web_extent().paths().size()); + EXPECT_EQ("mail/", extension->web_extent().paths()[0]); + EXPECT_EQ("foobar/", extension->web_extent().paths()[1]); + EXPECT_EQ(Extension::LAUNCH_WINDOW, extension->launch_container()); + EXPECT_EQ("mail/", extension->launch_web_url()); +} + +TEST_F(ManifestTest, AppWebContentEnabled) { + LoadAndExpectError("web_content_enabled_invalid.json", + errors::kInvalidWebContentEnabled); + LoadAndExpectError("web_content_disabled.json", + errors::kWebContentMustBeEnabled); + LoadAndExpectError("web_content_not_enabled.json", + errors::kWebContentMustBeEnabled); +} + +TEST_F(ManifestTest, AppWebOrigin) { + LoadAndExpectError("web_origin_wrong_type.json", + errors::kInvalidWebOrigin); + LoadAndExpectError("web_origin_invalid_1.json", + errors::kInvalidWebOrigin); + LoadAndExpectError("web_origin_invalid_2.json", + errors::kInvalidWebOrigin); + LoadAndExpectError("web_origin_invalid_3.json", + errors::kInvalidWebOrigin); +} + +TEST_F(ManifestTest, AppWebPaths) { + LoadAndExpectError("web_paths_wrong_type.json", + errors::kInvalidWebPaths); + LoadAndExpectError("web_paths_invalid_path_1.json", + ExtensionErrorUtils::FormatErrorMessage( + errors::kInvalidWebPath, "0")); + LoadAndExpectError("web_paths_invalid_path_2.json", + ExtensionErrorUtils::FormatErrorMessage( + errors::kInvalidWebPath, "0")); +} + +TEST_F(ManifestTest, AppLaunchContainer) { + scoped_ptr<Extension> extension; + + extension.reset(LoadAndExpectSuccess("launch_tab.json")); + EXPECT_EQ(Extension::LAUNCH_TAB, extension->launch_container()); + + extension.reset(LoadAndExpectSuccess("launch_window.json")); + EXPECT_EQ(Extension::LAUNCH_WINDOW, extension->launch_container()); + + extension.reset(LoadAndExpectSuccess("launch_panel.json")); + EXPECT_EQ(Extension::LAUNCH_PANEL, extension->launch_container()); + + extension.reset(LoadAndExpectSuccess("launch_default.json")); + EXPECT_EQ(Extension::LAUNCH_TAB, extension->launch_container()); + + LoadAndExpectError("launch_container_invalid_type.json", + errors::kInvalidLaunchContainer); + LoadAndExpectError("launch_container_invalid_value.json", + errors::kInvalidLaunchContainer); + LoadAndExpectError("launch_container_without_launch_url.json", + errors::kLaunchContainerWithoutURL); +} + +TEST_F(ManifestTest, AppLaunchURL) { + LoadAndExpectError("launch_path_and_url.json", + errors::kLaunchPathAndURLAreExclusive); + LoadAndExpectError("launch_path_invalid_type.json", + errors::kInvalidLaunchLocalPath); + LoadAndExpectError("launch_path_invalid_value.json", + errors::kInvalidLaunchLocalPath); + LoadAndExpectError("launch_url_invalid_type.json", + errors::kInvalidLaunchWebURL); + + scoped_ptr<Extension> extension; + extension.reset(LoadAndExpectSuccess("launch_local_path.json")); + EXPECT_EQ(extension->url().spec() + "launch.html", + extension->GetFullLaunchURL().spec()); + + extension.reset(LoadAndExpectSuccess("launch_web_url_relative.json")); + EXPECT_EQ(GURL("http://www.google.com/launch.html"), + extension->GetFullLaunchURL()); + + extension.reset(LoadAndExpectSuccess("launch_web_url_absolute.json")); + EXPECT_EQ(GURL("http://www.google.com/launch.html"), + extension->GetFullLaunchURL()); +} diff --git a/chrome/common/extensions/extension_unittest.cc b/chrome/common/extensions/extension_unittest.cc index 4dbb7e3..d046503 100644 --- a/chrome/common/extensions/extension_unittest.cc +++ b/chrome/common/extensions/extension_unittest.cc @@ -36,6 +36,13 @@ TEST(ExtensionTest, LocationValuesTest) { ASSERT_EQ(5, Extension::COMPONENT); } + +// Please don't put any more manifest tests here!! +// Move them to extension_manifest_unittest.cc instead and make them use the +// more data-driven style there instead. +// Bug: http://crbug.com/38462 + + TEST(ExtensionTest, InitFromValueInvalid) { #if defined(OS_WIN) FilePath path(FILE_PATH_LITERAL("c:\\foo")); @@ -274,58 +281,6 @@ TEST(ExtensionTest, InitFromValueInvalid) { EXPECT_FALSE(extension.InitFromValue(*input_value, true, &error)); EXPECT_TRUE(MatchPatternASCII(error, errors::kChromeVersionTooLow)); #endif - - // Test invalid app. - input_value.reset(static_cast<DictionaryValue*>(valid_value->DeepCopy())); - input_value->Set(keys::kApp, Value::CreateIntegerValue(42)); - EXPECT_FALSE(extension.InitFromValue(*input_value, true, &error)); - EXPECT_EQ(errors::kInvalidApp, error); - - // Test invalid launch URLs. - DictionaryValue* app = new DictionaryValue(); - input_value->Set(keys::kApp, app); - - EXPECT_FALSE(extension.InitFromValue(*input_value, true, &error)); - EXPECT_EQ(errors::kInvalidAppLaunchUrl, error); - - Value* invalid_launch_urls[] = { - Value::CreateStringValue(""), - Value::CreateIntegerValue(42), - Value::CreateStringValue("foobar") - }; - - for (size_t i = 0; i < arraysize(invalid_launch_urls); ++i) { - app->Set(keys::kAppLaunchUrl, invalid_launch_urls[i]); - error.clear(); - EXPECT_FALSE(extension.InitFromValue(*input_value, true, &error)); - EXPECT_EQ(errors::kInvalidAppLaunchUrl, error); - } - - // Test valid launch URL. - app->Set(keys::kAppLaunchUrl, - Value::CreateStringValue("http://www.google.com/index.html")); - EXPECT_TRUE(extension.InitFromValue(*input_value, true, &error)); - - // Test invalid app origins. - Value* invalid_origins[] = { - Value::CreateStringValue(""), - Value::CreateIntegerValue(42), - Value::CreateStringValue("foobar"), - Value::CreateStringValue("file:///c:/foo.txt"), - Value::CreateStringValue("ftp://www.google.com/") - }; - - for (size_t i = 0; i < arraysize(invalid_origins); ++i) { - app->Set(keys::kAppOrigin, invalid_origins[i]); - error.clear(); - EXPECT_FALSE(extension.InitFromValue(*input_value, true, &error)); - EXPECT_EQ(errors::kInvalidAppOrigin, error); - } - - // Test valid origin. - app->Set(keys::kAppOrigin, - Value::CreateStringValue("http://www.google.com/")); - EXPECT_TRUE(extension.InitFromValue(*input_value, true, &error)); } TEST(ExtensionTest, InitFromValueValid) { |