summaryrefslogtreecommitdiffstats
path: root/chrome/common/extensions
diff options
context:
space:
mode:
authoraa@chromium.org <aa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-03-19 20:45:46 +0000
committeraa@chromium.org <aa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-03-19 20:45:46 +0000
commit867a73e1e2aad10f60952235da84f5d98cff9aa6 (patch)
tree5e977ff9c87a2cd3de2d7f50b057adbdad4c70bf /chrome/common/extensions
parent35de4be0f924ef6279a6a25fe840522524fa177b (diff)
downloadchromium_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.cc258
-rw-r--r--chrome/common/extensions/extension.h66
-rw-r--r--chrome/common/extensions/extension_constants.cc51
-rw-r--r--chrome/common/extensions/extension_constants.h39
-rw-r--r--chrome/common/extensions/extension_extent.cc28
-rw-r--r--chrome/common/extensions/extension_extent.h34
-rw-r--r--chrome/common/extensions/extension_extent_unittest.cc57
-rw-r--r--chrome/common/extensions/extension_manifests_unittest.cc162
-rw-r--r--chrome/common/extensions/extension_unittest.cc59
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) {