summaryrefslogtreecommitdiffstats
path: root/chrome
diff options
context:
space:
mode:
authorgroby@chromium.org <groby@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-01-30 23:14:27 +0000
committergroby@chromium.org <groby@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-01-30 23:14:27 +0000
commit16958d88f010642e90a5bbf74eeeb7b5bc1fea5d (patch)
tree491742b6a4a6db1f2a8180de13375ae2b46616c5 /chrome
parent828ba9523d13b9c650c97197bb0189c3c6a31874 (diff)
downloadchromium_src-16958d88f010642e90a5bbf74eeeb7b5bc1fea5d.zip
chromium_src-16958d88f010642e90a5bbf74eeeb7b5bc1fea5d.tar.gz
chromium_src-16958d88f010642e90a5bbf74eeeb7b5bc1fea5d.tar.bz2
First version of CWS intents query support.
BUG= TEST=CWSIntentsRegistryTest.* Review URL: http://codereview.chromium.org/9253024 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@119759 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r--chrome/browser/intents/cws_intents_registry.cc136
-rw-r--r--chrome/browser/intents/cws_intents_registry.h79
-rw-r--r--chrome/browser/intents/cws_intents_registry_factory.cc39
-rw-r--r--chrome/browser/intents/cws_intents_registry_factory.h42
-rw-r--r--chrome/browser/intents/cws_intents_registry_unittest.cc132
-rw-r--r--chrome/chrome_browser.gypi4
-rw-r--r--chrome/chrome_tests.gypi1
7 files changed, 433 insertions, 0 deletions
diff --git a/chrome/browser/intents/cws_intents_registry.cc b/chrome/browser/intents/cws_intents_registry.cc
new file mode 100644
index 0000000..040ec2a
--- /dev/null
+++ b/chrome/browser/intents/cws_intents_registry.cc
@@ -0,0 +1,136 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/intents/cws_intents_registry.h"
+
+#include "base/callback.h"
+#include "base/json/json_value_serializer.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/stl_util.h"
+#include "base/string16.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/browser/net/browser_url_util.h"
+#include "chrome/browser/net/chrome_url_request_context.h"
+#include "chrome/browser/webdata/web_data_service.h"
+#include "content/public/common/url_fetcher.h"
+#include "net/base/mime_util.h"
+#include "net/base/load_flags.h"
+
+namespace {
+
+// URL for CWS intents API. TODO(groby): points to staging, fix for M18 release.
+const char kCWSIntentServiceURL[] =
+ "https://www-googleapis-staging.sandbox.google.com"
+ "/chromewebstore/v1.1b/items/intent";
+
+// Build a REST query URL to retrieve intent info from CWS.
+GURL BuildQueryURL(const string16& action, const string16& type) {
+ GURL request(kCWSIntentServiceURL);
+ request = chrome_browser_net::AppendQueryParameter(request, "intent",
+ UTF16ToUTF8(action));
+ return chrome_browser_net::AppendQueryParameter(request, "mime_types",
+ UTF16ToUTF8(type));
+}
+
+} // namespace
+
+// Internal object representing all data associated with a single query.
+struct CWSIntentsRegistry::IntentsQuery {
+ // Underlying URL request query.
+ scoped_ptr<content::URLFetcher> url_fetcher_;
+
+ // The callback - invoked on completed retrieval.
+ ResultsCallback callback_;
+};
+
+CWSIntentsRegistry::CWSIntentsRegistry(net::URLRequestContextGetter* context)
+ : request_context_(context) {
+}
+
+CWSIntentsRegistry::~CWSIntentsRegistry() {
+ // Cancel all pending queries, since we can't handle them any more.
+ STLDeleteValues(&queries_);
+}
+
+void CWSIntentsRegistry::OnURLFetchComplete(const content::URLFetcher* source) {
+ DCHECK(source);
+
+ URLFetcherHandle handle = reinterpret_cast<URLFetcherHandle>(source);
+ QueryMap::iterator it = queries_.find(handle);
+ DCHECK(it != queries_.end());
+ scoped_ptr<IntentsQuery> query(it->second);
+ DCHECK(query != NULL);
+ queries_.erase(it);
+
+ std::string response;
+ source->GetResponseAsString(&response);
+
+ // TODO(groby): Do we really only accept 200, or any 2xx codes?
+ if (source->GetResponseCode() != 200)
+ return;
+
+ std::string error;
+ scoped_ptr<Value> parsed_response;
+ JSONStringValueSerializer serializer(response);
+ parsed_response.reset(serializer.Deserialize(NULL, &error));
+ if (parsed_response == NULL)
+ return;
+
+ DictionaryValue* response_dict;
+ parsed_response->GetAsDictionary(&response_dict);
+ if (!response_dict)
+ return;
+ ListValue* items;
+ if (!response_dict->GetList("items",&items))
+ return;
+
+ IntentExtensionList intents;
+ for (ListValue::const_iterator iter(items->begin());
+ iter != items->end(); ++iter) {
+ DictionaryValue* item = static_cast<DictionaryValue*>(*iter);
+
+ // All fields are mandatory - skip this result if we can't find a field.
+ IntentExtensionInfo info;
+ if (!item->GetInteger("num_ratings", &info.num_ratings))
+ continue;
+
+ if (!item->GetDouble("average_rating", &info.average_rating))
+ continue;
+
+ if (!item->GetString("manifest", &info.manifest))
+ continue;
+
+ string16 url_string;
+ if (!item->GetString("icon_url", &url_string))
+ continue;
+ info.icon_url = GURL(url_string);
+
+ intents.push_back(info);
+ }
+
+ if (!query->callback_.is_null())
+ query->callback_.Run(intents);
+}
+
+void CWSIntentsRegistry::GetIntentProviders(
+ const string16& action, const string16& mimetype,
+ const ResultsCallback& cb) {
+ scoped_ptr<IntentsQuery> query(new IntentsQuery);
+ query->callback_ = cb;
+ query->url_fetcher_.reset(content::URLFetcher::Create(
+ 0, BuildQueryURL(action,mimetype), content::URLFetcher::GET, this));
+
+ if (query->url_fetcher_ == NULL)
+ return;
+
+ query->url_fetcher_->SetRequestContext(request_context_);
+ query->url_fetcher_->SetLoadFlags(
+ net::LOAD_DO_NOT_SEND_COOKIES | net::LOAD_DO_NOT_SAVE_COOKIES);
+
+ URLFetcherHandle handle = reinterpret_cast<URLFetcherHandle>(
+ query->url_fetcher_.get());
+ queries_[handle] = query.release();
+ queries_[handle]->url_fetcher_->Start();
+}
+
diff --git a/chrome/browser/intents/cws_intents_registry.h b/chrome/browser/intents/cws_intents_registry.h
new file mode 100644
index 0000000..3e3e4db
--- /dev/null
+++ b/chrome/browser/intents/cws_intents_registry.h
@@ -0,0 +1,79 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_INTENTS_CWS_INTENTS_REGISTRY_H_
+#define CHROME_BROWSER_INTENTS_CWS_INTENTS_REGISTRY_H_
+#pragma once
+
+#include "base/callback_forward.h"
+#include "base/gtest_prod_util.h"
+#include "base/hash_tables.h"
+#include "base/memory/ref_counted.h"
+#include "chrome/browser/profiles/profile_keyed_service.h"
+#include "content/public/common/url_fetcher_delegate.h"
+#include "googleurl/src/gurl.h"
+
+namespace net {
+class URLRequestContextGetter;
+}
+
+// Handles storing and retrieving of web intents in the web database.
+// The registry provides filtering logic to retrieve specific types of intents.
+class CWSIntentsRegistry : public ProfileKeyedService,
+ public content::URLFetcherDelegate {
+ public:
+ // Data returned from CWS for a single intent.
+ struct IntentExtensionInfo {
+ int num_ratings; // Number of ratings in CWS store.
+ double average_rating; // The average CWS rating.
+ string16 manifest; // The containing extension's manifest info.
+ GURL icon_url; // Where to retrieve an icon for this intent.
+ };
+
+ // List of Intent extensions, as returned by GetIntentProviders's |callback|
+ typedef std::vector<IntentExtensionInfo> IntentExtensionList;
+ // Callback to return results from GetIntentProviders upon completion.
+ typedef base::Callback<void(const IntentExtensionList&)> ResultsCallback;
+
+ // Requests all intent providers matching |action| and |mimetype|.
+ // |mimetype| must conform to definition as outlined for
+ // WebIntentsRegistry::GetIntentProviders.
+ // |callback| will be invoked upon retrieving results from CWS, returning
+ // a list of matching Intent extensions.
+ void GetIntentProviders(const string16& action,
+ const string16& mimetype,
+ const ResultsCallback& callback);
+
+ private:
+ // Make sure that only CWSIntentsRegistryFactory can create an instance of
+ // CWSIntentsRegistry.
+ friend class CWSIntentsRegistryFactory;
+ FRIEND_TEST_ALL_PREFIXES(CWSIntentsRegistryTest, ValidQuery);
+ FRIEND_TEST_ALL_PREFIXES(CWSIntentsRegistryTest, InvalidQuery);
+
+ // content::URLFetcherDelegate implementation.
+ virtual void OnURLFetchComplete(const content::URLFetcher* source) OVERRIDE;
+
+ // |context| is a profile-dependent URL request context. Must not be NULL.
+ explicit CWSIntentsRegistry(net::URLRequestContextGetter* context);
+ virtual ~CWSIntentsRegistry();
+
+ struct IntentsQuery;
+
+ // This is an opaque version of URLFetcher*, so we can use it as a hash key.
+ typedef intptr_t URLFetcherHandle;
+
+ // Maps URL fetchers to queries.
+ typedef base::hash_map<URLFetcherHandle, IntentsQuery*> QueryMap;
+
+ // Map for all in-flight web data requests/intent queries.
+ QueryMap queries_;
+
+ // Request context for any CWS requests.
+ scoped_refptr<net::URLRequestContextGetter> request_context_;
+
+ DISALLOW_COPY_AND_ASSIGN(CWSIntentsRegistry);
+};
+
+#endif // CHROME_BROWSER_INTENTS_CWS_INTENTS_REGISTRY_H_
diff --git a/chrome/browser/intents/cws_intents_registry_factory.cc b/chrome/browser/intents/cws_intents_registry_factory.cc
new file mode 100644
index 0000000..b833521
--- /dev/null
+++ b/chrome/browser/intents/cws_intents_registry_factory.cc
@@ -0,0 +1,39 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/intents/cws_intents_registry.h"
+#include "chrome/browser/intents/cws_intents_registry_factory.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_dependency_manager.h"
+
+// static
+CWSIntentsRegistry* CWSIntentsRegistryFactory::GetForProfile(Profile* profile) {
+ return static_cast<CWSIntentsRegistry*>(
+ GetInstance()->GetServiceForProfile(profile, true));
+}
+
+CWSIntentsRegistryFactory::CWSIntentsRegistryFactory()
+ : ProfileKeyedServiceFactory("CWSIntentsRegistry",
+ ProfileDependencyManager::GetInstance()) {
+}
+
+CWSIntentsRegistryFactory::~CWSIntentsRegistryFactory() {
+}
+
+// static
+CWSIntentsRegistryFactory* CWSIntentsRegistryFactory::GetInstance() {
+ return Singleton<CWSIntentsRegistryFactory>::get();
+}
+
+ProfileKeyedService* CWSIntentsRegistryFactory::BuildServiceInstanceFor(
+ Profile* profile) const {
+ CWSIntentsRegistry* registry = new CWSIntentsRegistry(
+ profile->GetRequestContext());
+ return registry;
+}
+
+bool CWSIntentsRegistryFactory::ServiceRedirectedInIncognito() {
+ // TODO(groby): Do we have CWS access in incognito?
+ return false;
+}
diff --git a/chrome/browser/intents/cws_intents_registry_factory.h b/chrome/browser/intents/cws_intents_registry_factory.h
new file mode 100644
index 0000000..28bff47
--- /dev/null
+++ b/chrome/browser/intents/cws_intents_registry_factory.h
@@ -0,0 +1,42 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_INTENTS_CWS_INTENTS_REGISTRY_FACTORY_H_
+#define CHROME_BROWSER_INTENTS_CWS_INTENTS_REGISTRY_FACTORY_H_
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/memory/singleton.h"
+#include "chrome/browser/profiles/profile_keyed_service_factory.h"
+
+class Profile;
+class CWSIntentsRegistry;
+
+// Singleton that owns all CWSIntentsRegistrys and associates each with
+// their respective profile. Listens for the profile's destruction notification
+// and cleans up the associated CWSIntentsRegistry.
+class CWSIntentsRegistryFactory : public ProfileKeyedServiceFactory {
+ public:
+ // Returns a weak pointer to the WebIntentsRegistry that provides intent
+ // registration for |profile|.
+ static CWSIntentsRegistry* GetForProfile(Profile* profile);
+
+ // Returns the singleton instance of the WebIntentsRegistryFactory.
+ static CWSIntentsRegistryFactory* GetInstance();
+
+ private:
+ friend struct DefaultSingletonTraits<CWSIntentsRegistryFactory>;
+
+ CWSIntentsRegistryFactory();
+ virtual ~CWSIntentsRegistryFactory();
+
+ // ProfileKeyedServiceFactory implementation.
+ virtual ProfileKeyedService* BuildServiceInstanceFor(
+ Profile* profile) const OVERRIDE;
+ virtual bool ServiceRedirectedInIncognito() OVERRIDE;
+
+ DISALLOW_COPY_AND_ASSIGN(CWSIntentsRegistryFactory);
+};
+
+#endif // CHROME_BROWSER_INTENTS_CWS_INTENTS_REGISTRY_FACTORY_H_
diff --git a/chrome/browser/intents/cws_intents_registry_unittest.cc b/chrome/browser/intents/cws_intents_registry_unittest.cc
new file mode 100644
index 0000000..40ff63d
--- /dev/null
+++ b/chrome/browser/intents/cws_intents_registry_unittest.cc
@@ -0,0 +1,132 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/intents/cws_intents_registry.h"
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/message_loop.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/test/base/test_url_request_context_getter.h"
+#include "content/test/test_url_fetcher_factory.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+const char kCWSQueryInvalid[] =
+ "https://www-googleapis-staging.sandbox.google.com"
+ "/chromewebstore/v1.1b/items/intent"
+ "?intent=foo&mime_types=foo";
+const char kCWSResponseInvalid[] =
+ "{\"error\":{\"errors\":[{\"domain\":\"global\",\"reason\":\"invalid\","
+ "\"message\":\"Invalid mimetype:foo\"}],\"code\":400,"
+ "\"message\":\"Invalid mimetype:foo\"}}\"";
+
+const char kCWSQueryValid[] =
+ "https://www-googleapis-staging.sandbox.google.com"
+ "/chromewebstore/v1.1b/items/intent"
+ "?intent=http%3A%2F%2Fwebintents.org%2Fedit&mime_types=*%2Fpng";
+const char kCWSResponseValid[] =
+ "{\"kind\":\"chromewebstore#itemList\",\"total_items\":1,"
+ "\"start_index\":0,\"items\":[{\"kind\":\"chromewebstore#item\","
+ "\"id\":\"nhkckhebbbncbkefhcpcgepcgfaclehe\",\"type\":\"APPLICATION\","
+ "\"num_ratings\":0,\"average_rating\":0.0,\"manifest\":"
+ "\"{\\n\\\"update_url\\\":\\"
+ "\"http://0.tbhome_staging.dserver.download-qa.td.borg.google.com/"
+ "service/update2/crx\\\",\\n \\\"name\\\": \\\"Sidd's Intent App\\\""
+ ",\\n \\\"description\\\": \\\"Do stuff\\\",\\n \\\"version\\\": "
+ "\\\"1.2.19\\\",\\n \\\"app\\\": {\\n \\\"urls\\\": [ \\n ],"
+ "\\n \\\"launch\\\": {\\n \\\"web_url\\\": \\"
+ "\"http://siddharthasaha.net/\\\"\\n }\\n },\\n \\\"icons\\\": "
+ "{\\n \\\"128\\\": \\\"icon128.png\\\"\\n },\\n \\\"permissions\\\":"
+ " [\\n \\\"unlimitedStorage\\\",\\n \\\"notifications\\\"\\n ],\\n"
+ " \\\"intents\\\": {\\n \\\"http://webintents.org/edit\\\" : {\\n "
+ "\\\"type\\\" : [\\\"image/png\\\", \\\"image/jpg\\\"],\\n \\\"path\\"
+ "\" : \\\"//services/edit\\\",\\n \\\"title\\\" : "
+ "\\\"Sample Editing Intent\\\",\\n \\\"disposition\\\" : \\\"inline\\"
+ "\"\\n },\\n \\\"http://webintents.org/share\\\" : "
+ "{\\n \\\"type\\\" : [\\\"text/plain\\\", \\\"image/jpg\\\"],"
+ "\\n \\\"path\\\" : \\\"//services/share\\\",\\n \\\"title\\\" : "
+ "\\\"Sample sharing Intent\\\",\\n \\\"disposition\\\" : "
+ "\\\"inline\\\"\\n }\\n }\\n}\\n\",\"family_safe\":true,\"icon_url\":"
+ "\"http://qa-lighthouse.sandbox.google.com/image/"
+ "QzPnRCYCBbBGI99ZkGxkp-NNJ488IkkiTyCgynFEeDTJHcw4tHl3csmjTQ\"}]}";
+const char kValidIconURL[]=
+ "http://qa-lighthouse.sandbox.google.com/image/"
+ "QzPnRCYCBbBGI99ZkGxkp-NNJ488IkkiTyCgynFEeDTJHcw4tHl3csmjTQ";
+const char kValidManifest[]=
+ "{\n\"update_url\":\"http://0.tbhome_staging.dserver.download-qa.td.borg."
+ "google.com/service/update2/crx\",\n \"name\": \"Sidd's Intent App\",\n"
+ " \"description\": \"Do stuff\",\n \"version\": \"1.2.19\",\n \"app\":"
+ " {\n \"urls\": [ \n ],\n \"launch\": {\n \"web_url\":"
+ " \"http://siddharthasaha.net/\"\n }\n },\n \"icons\": {\n "
+ "\"128\": \"icon128.png\"\n },\n \"permissions\": [\n "
+ "\"unlimitedStorage\",\n \"notifications\"\n ],\n \"intents\": "
+ "{\n \"http://webintents.org/edit\" : {\n \"type\" : ["
+ "\"image/png\", \"image/jpg\"],\n \"path\" : \"//services/edit\",\n"
+ " \"title\" : \"Sample Editing Intent\",\n \"disposition\" : "
+ "\"inline\"\n },\n \"http://webintents.org/share\" : {\n "
+ "\"type\" : [\"text/plain\", \"image/jpg\"],\n \"path\" : "
+ "\"//services/share\",\n \"title\" : \"Sample sharing Intent\",\n"
+ " \"disposition\" : \"inline\"\n }\n }\n}\n";
+
+class CWSIntentsRegistryTest : public testing::Test {
+ public:
+ CWSIntentsRegistryTest() : test_factory_(NULL) {}
+ virtual void TearDown() {
+ // Pump messages posted by the main thread.
+ ui_loop_.RunAllPending();
+ }
+
+ CWSIntentsRegistry::IntentExtensionList WaitForResults() {
+ ui_loop_.RunAllPending();
+ return extensions_;
+ }
+
+ void Callback(const CWSIntentsRegistry::IntentExtensionList& extensions) {
+ extensions_ = extensions;
+ }
+
+ CWSIntentsRegistry::IntentExtensionList extensions_;
+ FakeURLFetcherFactory test_factory_;
+
+ private:
+ MessageLoop ui_loop_;
+};
+
+} // namespace
+
+TEST_F(CWSIntentsRegistryTest, ValidQuery) {
+ TestURLRequestContextGetter context_getter;
+ test_factory_.SetFakeResponse(kCWSQueryValid, kCWSResponseValid, true);
+
+ CWSIntentsRegistry registry(&context_getter);
+ registry.GetIntentProviders(ASCIIToUTF16("http://webintents.org/edit"),
+ ASCIIToUTF16("*/png"),
+ base::Bind(&CWSIntentsRegistryTest::Callback,
+ base::Unretained(this)));
+
+ WaitForResults();
+ ASSERT_EQ(1UL, extensions_.size());
+
+ EXPECT_EQ(0, extensions_[0].num_ratings);
+ EXPECT_EQ(0.0, extensions_[0].average_rating);
+ EXPECT_EQ(std::string(kValidManifest), UTF16ToUTF8(extensions_[0].manifest));
+ EXPECT_EQ(std::string(kValidIconURL), extensions_[0].icon_url.spec());
+}
+
+TEST_F(CWSIntentsRegistryTest, InvalidQuery) {
+ TestURLRequestContextGetter context_getter;
+ test_factory_.SetFakeResponse(kCWSQueryInvalid, kCWSResponseInvalid, true);
+
+ CWSIntentsRegistry registry(&context_getter);
+ registry.GetIntentProviders(ASCIIToUTF16("foo"),
+ ASCIIToUTF16("foo"),
+ base::Bind(&CWSIntentsRegistryTest::Callback,
+ base::Unretained(this)));
+
+ WaitForResults();
+ EXPECT_EQ(0UL, extensions_.size());
+}
+
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index de2238b..de91944 100644
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -1550,6 +1550,10 @@
'browser/instant/instant_unload_handler.h',
'browser/instant/promo_counter.cc',
'browser/instant/promo_counter.h',
+ 'browser/intents/cws_intents_registry.cc',
+ 'browser/intents/cws_intents_registry.h',
+ 'browser/intents/cws_intents_registry_factory.cc',
+ 'browser/intents/cws_intents_registry_factory.h',
'browser/intents/register_intent_handler_infobar_delegate.cc',
'browser/intents/register_intent_handler_infobar_delegate.h',
'browser/intents/web_intents_registry.cc',
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi
index 1549df0..ff1a325 100644
--- a/chrome/chrome_tests.gypi
+++ b/chrome/chrome_tests.gypi
@@ -1507,6 +1507,7 @@
'browser/importer/safari_importer_unittest.mm',
'browser/importer/toolbar_importer_unittest.cc',
'browser/instant/promo_counter_unittest.cc',
+ 'browser/intents/cws_intents_registry_unittest.cc',
'browser/intents/register_intent_handler_infobar_delegate_unittest.cc',
'browser/intents/web_intents_registry_unittest.cc',
'browser/internal_auth_unittest.cc',