summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorgroby@chromium.org <groby@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-09-23 00:35:13 +0000
committergroby@chromium.org <groby@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-09-23 00:35:13 +0000
commitbe5f00786d8da88985225d545395654e15bd3d9e (patch)
tree216ea5cc6bdb86e76727c64301516609c9927a77
parentea8455ce1976885d5d730b1349557e05c195d00d (diff)
downloadchromium_src-be5f00786d8da88985225d545395654e15bd3d9e.zip
chromium_src-be5f00786d8da88985225d545395654e15bd3d9e.tar.gz
chromium_src-be5f00786d8da88985225d545395654e15bd3d9e.tar.bz2
Extension loading extracts intents from Manifest data.
BUG=none TEST=ExtensionManifestTest.WebIntents Review URL: http://codereview.chromium.org/7917006 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@102409 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/extensions/extension_icon_manager_unittest.cc3
-rw-r--r--chrome/common/extensions/extension.cc73
-rw-r--r--chrome/common/extensions/extension.h7
-rw-r--r--chrome/common/extensions/extension_constants.cc19
-rw-r--r--chrome/common/extensions/extension_constants.h13
-rw-r--r--chrome/common/extensions/extension_manifests_unittest.cc45
-rw-r--r--chrome/test/data/extensions/manifest_tests/intent_invalid_1.json5
-rw-r--r--chrome/test/data/extensions/manifest_tests/intent_invalid_2.json7
-rw-r--r--chrome/test/data/extensions/manifest_tests/intent_invalid_3.json9
-rw-r--r--chrome/test/data/extensions/manifest_tests/intent_invalid_4.json9
-rw-r--r--chrome/test/data/extensions/manifest_tests/intent_invalid_5.json9
-rw-r--r--chrome/test/data/extensions/manifest_tests/intent_invalid_6.json9
-rw-r--r--chrome/test/data/extensions/manifest_tests/intent_valid.json12
-rw-r--r--chrome/test/data/extensions/manifest_tests/intent_valid_minimal.json8
14 files changed, 227 insertions, 1 deletions
diff --git a/chrome/browser/extensions/extension_icon_manager_unittest.cc b/chrome/browser/extensions/extension_icon_manager_unittest.cc
index a607704..8f81fd5 100644
--- a/chrome/browser/extensions/extension_icon_manager_unittest.cc
+++ b/chrome/browser/extensions/extension_icon_manager_unittest.cc
@@ -109,9 +109,10 @@ TEST_F(ExtensionIconManagerTest, LoadRemoveLoad) {
static_cast<DictionaryValue*>(serializer.Deserialize(NULL, NULL)));
ASSERT_TRUE(manifest.get() != NULL);
+ std::string error;
scoped_refptr<Extension> extension(Extension::Create(
manifest_path.DirName(), Extension::INVALID, *manifest.get(),
- Extension::STRICT_ERROR_CHECKS, NULL));
+ Extension::STRICT_ERROR_CHECKS, &error));
ASSERT_TRUE(extension.get());
TestIconManager icon_manager(this);
diff --git a/chrome/common/extensions/extension.cc b/chrome/common/extensions/extension.cc
index af1f538..e595749 100644
--- a/chrome/common/extensions/extension.cc
+++ b/chrome/common/extensions/extension.cc
@@ -44,6 +44,7 @@
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/resource/resource_bundle.h"
#include "webkit/glue/image_decoder.h"
+#include "webkit/glue/web_intent_service_data.h"
namespace keys = extension_manifest_keys;
namespace values = extension_manifest_values;
@@ -1162,6 +1163,74 @@ bool Extension::LoadAppIsolation(const DictionaryValue* manifest,
return true;
}
+bool Extension::LoadWebIntents(const base::DictionaryValue& manifest,
+ std::string* error) {
+ DCHECK(error);
+
+ if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnableWebIntents))
+ return true;
+
+ if (!manifest.HasKey(keys::kIntents))
+ return true;
+
+ DictionaryValue* all_intents = NULL;
+ if (!manifest.GetDictionary(keys::kIntents, &all_intents)) {
+ *error = errors::kInvalidIntents;
+ return false;
+ }
+
+ std::string value;
+ for (DictionaryValue::key_iterator iter(all_intents->begin_keys());
+ iter != all_intents->end_keys(); ++iter) {
+ WebIntentServiceData intent;
+
+ DictionaryValue* one_intent = NULL;
+ if (!all_intents->GetDictionaryWithoutPathExpansion(*iter, &one_intent)) {
+ *error = errors::kInvalidIntent;
+ return false;
+ }
+ intent.action = UTF8ToUTF16(*iter);
+
+ // TODO(groby): Support an array of types.
+ if (one_intent->HasKey(keys::kIntentType) &&
+ !one_intent->GetString(keys::kIntentType, &intent.type)) {
+ *error = errors::kInvalidIntentType;
+ return false;
+ }
+
+ if (one_intent->HasKey(keys::kIntentPath)) {
+ if (!one_intent->GetString(keys::kIntentPath, &value)) {
+ *error = errors::kInvalidIntentPath;
+ return false;
+ }
+ intent.service_url = GetResourceURL(value);
+ }
+
+ if (one_intent->HasKey(keys::kIntentTitle) &&
+ !one_intent->GetString(keys::kIntentTitle, &intent.title)) {
+ *error = errors::kInvalidIntentTitle;
+ return false;
+ }
+
+ if (one_intent->HasKey(keys::kIntentDisposition)) {
+ if (!one_intent->GetString(keys::kIntentDisposition, &value) ||
+ (value != values::kIntentDispositionWindow &&
+ value != values::kIntentDispositionInline)) {
+ *error = errors::kInvalidIntentDisposition;
+ return false;
+ }
+ if (value == values::kIntentDispositionInline)
+ intent.disposition = WebIntentServiceData::DISPOSITION_INLINE;
+ else
+ intent.disposition = WebIntentServiceData::DISPOSITION_WINDOW;
+ }
+
+ intents_.push_back(intent);
+ }
+ return true;
+}
+
+
bool Extension::EnsureNotHybridApp(const DictionaryValue* manifest,
std::string* error) {
if (web_extent().is_empty())
@@ -2272,6 +2341,10 @@ bool Extension::InitFromValue(const DictionaryValue& source, int flags,
}
}
+ // Initialize web intents (optional).
+ if (!LoadWebIntents(source, error))
+ return false;
+
// Initialize incognito behavior. Apps default to split mode, extensions
// default to spanning.
incognito_split_mode_ = is_app();
diff --git a/chrome/common/extensions/extension.h b/chrome/common/extensions/extension.h
index 215912e..19c9cbe 100644
--- a/chrome/common/extensions/extension.h
+++ b/chrome/common/extensions/extension.h
@@ -25,6 +25,7 @@
#include "chrome/common/extensions/url_pattern_set.h"
#include "googleurl/src/gurl.h"
#include "ui/gfx/size.h"
+#include "webkit/glue/web_intent_service_data.h"
class ExtensionAction;
class ExtensionResource;
@@ -533,6 +534,7 @@ class Extension : public base::RefCountedThreadSafe<Extension> {
bool incognito_split_mode() const { return incognito_split_mode_; }
bool offline_enabled() const { return offline_enabled_; }
const std::vector<TtsVoice>& tts_voices() const { return tts_voices_; }
+ const std::vector<WebIntentServiceData>& intents() const { return intents_; }
bool wants_file_access() const { return wants_file_access_; }
int creation_flags() const { return creation_flags_; }
@@ -641,6 +643,8 @@ class Extension : public base::RefCountedThreadSafe<Extension> {
std::string* error);
bool LoadAppIsolation(const base::DictionaryValue* manifest,
std::string* error);
+ bool LoadWebIntents(const base::DictionaryValue& manifest,
+ std::string* error);
bool EnsureNotHybridApp(const base::DictionaryValue* manifest,
std::string* error);
@@ -843,6 +847,9 @@ class Extension : public base::RefCountedThreadSafe<Extension> {
// List of text-to-speech voices that this extension provides, if any.
std::vector<TtsVoice> tts_voices_;
+ // List of intents that this extension provides, if any.
+ std::vector<WebIntentServiceData> intents_;
+
// Whether the extension has host permissions or user script patterns that
// imply access to file:/// scheme URLs (the user may not have actually
// granted it that access).
diff --git a/chrome/common/extensions/extension_constants.cc b/chrome/common/extensions/extension_constants.cc
index 242dae5..91000a5 100644
--- a/chrome/common/extensions/extension_constants.cc
+++ b/chrome/common/extensions/extension_constants.cc
@@ -38,6 +38,11 @@ const char* kId = "id";
const char* kIncognito = "incognito";
const char* kIncludeGlobs = "include_globs";
const char* kInputComponents = "input_components";
+const char* kIntents = "intents";
+const char* kIntentType = "type";
+const char* kIntentPath = "path";
+const char* kIntentTitle = "title";
+const char* kIntentDisposition = "disposition";
const char* kIsolation = "app.isolation";
const char* kJs = "js";
const char* kKeycode = "keyCode";
@@ -113,6 +118,8 @@ const char* kWebURLs = "app.urls";
namespace extension_manifest_values {
const char* kIncognitoSplit = "split";
const char* kIncognitoSpanning = "spanning";
+const char* kIntentDispositionWindow = "window";
+const char* kIntentDispositionInline = "inline";
const char* kIsolatedStorage = "storage";
const char* kRunAtDocumentStart = "document_start";
const char* kRunAtDocumentEnd = "document_end";
@@ -226,6 +233,18 @@ const char* kInvalidInputComponentShortcutKeycode =
"Invalid value for 'input_conponents[*].shortcutKey.keyCode";
const char* kInvalidInputComponentType =
"Invalid value for 'input_conponents[*].type";
+const char* kInvalidIntent =
+ "Invalid value for intents[*]";
+const char* kInvalidIntentDisposition =
+ "Invalid value for intents[*].disposition";
+const char* kInvalidIntentPath =
+ "Invalid value for intents[*].path";
+const char* kInvalidIntents =
+ "Invalid value for intents";
+const char* kInvalidIntentType =
+ "Invalid value for intents[*].type";
+const char* kInvalidIntentTitle =
+ "Invalid value for intents[*].title";
const char* kInvalidIsolation =
"Invalid value for 'app.isolation'.";
const char* kInvalidIsolationValue =
diff --git a/chrome/common/extensions/extension_constants.h b/chrome/common/extensions/extension_constants.h
index ba14dd5..8c52a33 100644
--- a/chrome/common/extensions/extension_constants.h
+++ b/chrome/common/extensions/extension_constants.h
@@ -39,6 +39,11 @@ namespace extension_manifest_keys {
extern const char* kIncognito;
extern const char* kIncludeGlobs;
extern const char* kInputComponents;
+ extern const char* kIntents;
+ extern const char* kIntentType;
+ extern const char* kIntentPath;
+ extern const char* kIntentTitle;
+ extern const char* kIntentDisposition;
extern const char* kIsolation;
extern const char* kJs;
extern const char* kKeycode;
@@ -115,6 +120,8 @@ namespace extension_manifest_keys {
namespace extension_manifest_values {
extern const char* kIncognitoSplit;
extern const char* kIncognitoSpanning;
+ extern const char* kIntentDispositionWindow;
+ extern const char* kIntentDispositionInline;
extern const char* kIsolatedStorage;
extern const char* kLaunchContainerPanel;
extern const char* kLaunchContainerTab;
@@ -176,6 +183,12 @@ namespace extension_manifest_errors {
extern const char* kInvalidInputComponentShortcutKey;
extern const char* kInvalidInputComponentShortcutKeycode;
extern const char* kInvalidInputComponentType;
+ extern const char* kInvalidIntent;
+ extern const char* kInvalidIntentDisposition;
+ extern const char* kInvalidIntentPath;
+ extern const char* kInvalidIntents;
+ extern const char* kInvalidIntentType;
+ extern const char* kInvalidIntentTitle;
extern const char* kInvalidIsolation;
extern const char* kInvalidIsolationValue;
extern const char* kInvalidJs;
diff --git a/chrome/common/extensions/extension_manifests_unittest.cc b/chrome/common/extensions/extension_manifests_unittest.cc
index 3d7ed44..7d89eae 100644
--- a/chrome/common/extensions/extension_manifests_unittest.cc
+++ b/chrome/common/extensions/extension_manifests_unittest.cc
@@ -747,6 +747,51 @@ TEST_F(ExtensionManifestTest, TtsEngine) {
EXPECT_EQ(3U, extension->tts_voices()[0].event_types.size());
}
+TEST_F(ExtensionManifestTest, WebIntents) {
+ CommandLine::ForCurrentProcess()->AppendSwitch("--enable-web-intents");
+
+ LoadAndExpectError("intent_invalid_1.json",
+ extension_manifest_errors::kInvalidIntents);
+ LoadAndExpectError("intent_invalid_2.json",
+ extension_manifest_errors::kInvalidIntent);
+ LoadAndExpectError("intent_invalid_3.json",
+ extension_manifest_errors::kInvalidIntentPath);
+ LoadAndExpectError("intent_invalid_4.json",
+ extension_manifest_errors::kInvalidIntentDisposition);
+ LoadAndExpectError("intent_invalid_5.json",
+ extension_manifest_errors::kInvalidIntentType);
+ LoadAndExpectError("intent_invalid_6.json",
+ extension_manifest_errors::kInvalidIntentTitle);
+
+ scoped_refptr<Extension> extension(
+ LoadAndExpectSuccess("intent_valid.json"));
+ ASSERT_TRUE(extension.get() != NULL);
+
+ ASSERT_EQ(1u, extension->intents().size());
+ EXPECT_EQ("image/png", UTF16ToUTF8(extension->intents()[0].type));
+ EXPECT_EQ("http://webintents.org/share",
+ UTF16ToUTF8(extension->intents()[0].action));
+ EXPECT_EQ("chrome-extension", extension->intents()[0].service_url.scheme());
+ EXPECT_EQ("///services/share", extension->intents()[0].service_url.path());
+ EXPECT_EQ("Sample Sharing Intent",
+ UTF16ToUTF8(extension->intents()[0].title));
+ EXPECT_EQ(WebIntentServiceData::DISPOSITION_INLINE,
+ extension->intents()[0].disposition);
+
+ // Verify that optional fields are filled with defaults.
+ extension = LoadAndExpectSuccess("intent_valid_minimal.json");
+ ASSERT_TRUE(extension.get() != NULL);
+
+ ASSERT_EQ(1u, extension->intents().size());
+ EXPECT_EQ("", UTF16ToUTF8(extension->intents()[0].type));
+ EXPECT_EQ("http://webintents.org/share",
+ UTF16ToUTF8(extension->intents()[0].action));
+ EXPECT_TRUE(extension->intents()[0].service_url.is_empty());
+ EXPECT_EQ("", UTF16ToUTF8(extension->intents()[0].title));
+ EXPECT_EQ(WebIntentServiceData::DISPOSITION_WINDOW,
+ extension->intents()[0].disposition);
+}
+
TEST_F(ExtensionManifestTest, ForbidPortsInPermissions) {
// Loading as a user would shoud not trigger an error.
LoadAndExpectSuccess("forbid_ports_in_permissions.json");
diff --git a/chrome/test/data/extensions/manifest_tests/intent_invalid_1.json b/chrome/test/data/extensions/manifest_tests/intent_invalid_1.json
new file mode 100644
index 0000000..ed16b37
--- /dev/null
+++ b/chrome/test/data/extensions/manifest_tests/intent_invalid_1.json
@@ -0,0 +1,5 @@
+{
+ "name": "test",
+ "version": "1",
+ "intents": "shouldBeADict"
+}
diff --git a/chrome/test/data/extensions/manifest_tests/intent_invalid_2.json b/chrome/test/data/extensions/manifest_tests/intent_invalid_2.json
new file mode 100644
index 0000000..b3c1850
--- /dev/null
+++ b/chrome/test/data/extensions/manifest_tests/intent_invalid_2.json
@@ -0,0 +1,7 @@
+{
+ "name": "test",
+ "version": "1",
+ "intents": {
+ "http://webintents.org/" : "shouldBeADict"
+ }
+}
diff --git a/chrome/test/data/extensions/manifest_tests/intent_invalid_3.json b/chrome/test/data/extensions/manifest_tests/intent_invalid_3.json
new file mode 100644
index 0000000..72f04c2
--- /dev/null
+++ b/chrome/test/data/extensions/manifest_tests/intent_invalid_3.json
@@ -0,0 +1,9 @@
+{
+ "name": "test",
+ "version": "1",
+ "intents": {
+ "http://webintents.org/intent/share" : {
+ "path" : { "shouldBeA" : "string" }
+ }
+ }
+}
diff --git a/chrome/test/data/extensions/manifest_tests/intent_invalid_4.json b/chrome/test/data/extensions/manifest_tests/intent_invalid_4.json
new file mode 100644
index 0000000..dfb2d51
--- /dev/null
+++ b/chrome/test/data/extensions/manifest_tests/intent_invalid_4.json
@@ -0,0 +1,9 @@
+{
+ "name": "test",
+ "version": "1",
+ "intents": {
+ "http://webintents.org/intent/share" : {
+ "disposition" : "gibberish"
+ }
+ }
+}
diff --git a/chrome/test/data/extensions/manifest_tests/intent_invalid_5.json b/chrome/test/data/extensions/manifest_tests/intent_invalid_5.json
new file mode 100644
index 0000000..6c0d5fc
--- /dev/null
+++ b/chrome/test/data/extensions/manifest_tests/intent_invalid_5.json
@@ -0,0 +1,9 @@
+{
+ "name": "test",
+ "version": "1",
+ "intents": {
+ "http://webintents.org/intent/share" : {
+ "type" : { "shouldBeA" : "string" }
+ }
+ }
+}
diff --git a/chrome/test/data/extensions/manifest_tests/intent_invalid_6.json b/chrome/test/data/extensions/manifest_tests/intent_invalid_6.json
new file mode 100644
index 0000000..585c408
--- /dev/null
+++ b/chrome/test/data/extensions/manifest_tests/intent_invalid_6.json
@@ -0,0 +1,9 @@
+{
+ "name": "test",
+ "version": "1",
+ "intents": {
+ "http://webintents.org/intent/share" : {
+ "title" : { "shouldBeA" : "string" }
+ }
+ }
+}
diff --git a/chrome/test/data/extensions/manifest_tests/intent_valid.json b/chrome/test/data/extensions/manifest_tests/intent_valid.json
new file mode 100644
index 0000000..9a62df8
--- /dev/null
+++ b/chrome/test/data/extensions/manifest_tests/intent_valid.json
@@ -0,0 +1,12 @@
+{
+ "name": "test",
+ "version": "1",
+ "intents": {
+ "http://webintents.org/share" : {
+ "type" : "image/png",
+ "path" : "//services/share",
+ "title" : "Sample Sharing Intent",
+ "disposition" : "inline"
+ }
+ }
+}
diff --git a/chrome/test/data/extensions/manifest_tests/intent_valid_minimal.json b/chrome/test/data/extensions/manifest_tests/intent_valid_minimal.json
new file mode 100644
index 0000000..22a9508
--- /dev/null
+++ b/chrome/test/data/extensions/manifest_tests/intent_valid_minimal.json
@@ -0,0 +1,8 @@
+{
+ "name": "test",
+ "version": "1",
+ "intents": {
+ "http://webintents.org/share" : {
+ }
+ }
+}