summaryrefslogtreecommitdiffstats
path: root/chrome/browser
diff options
context:
space:
mode:
authorjstritar@chromium.org <jstritar@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-09-08 03:05:55 +0000
committerjstritar@chromium.org <jstritar@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-09-08 03:05:55 +0000
commit808c096eeadb6b7d701a76fb660fd18c4b1a9497 (patch)
tree7d80a2097013588ab0e68d03c73f852ba4dacdb3 /chrome/browser
parent75185918cc565c908ce16346644d3008bb0ff91f (diff)
downloadchromium_src-808c096eeadb6b7d701a76fb660fd18c4b1a9497.zip
chromium_src-808c096eeadb6b7d701a76fb660fd18c4b1a9497.tar.gz
chromium_src-808c096eeadb6b7d701a76fb660fd18c4b1a9497.tar.bz2
Add support to download web store promo logos over https.
This lets you define apps promo logos as https URLs in the promo feed. The AppsPromoLogoDownloader only downloads the image over https and from *.google.com domains. AppsPromo caches the image until the URL changes in the promo feed. BUG=84506 TEST=*Promo* Review URL: http://codereview.chromium.org/7820003 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@100089 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser')
-rw-r--r--chrome/browser/extensions/apps_promo.cc225
-rw-r--r--chrome/browser/extensions/apps_promo.h100
-rw-r--r--chrome/browser/extensions/apps_promo_unittest.cc139
-rw-r--r--chrome/browser/ui/webui/ntp/app_launcher_handler.cc11
-rw-r--r--chrome/browser/web_resource/promo_resource_service.cc31
-rw-r--r--chrome/browser/web_resource/promo_resource_service.h26
-rw-r--r--chrome/browser/web_resource/promo_resource_service_unittest.cc196
7 files changed, 513 insertions, 215 deletions
diff --git a/chrome/browser/extensions/apps_promo.cc b/chrome/browser/extensions/apps_promo.cc
index a137bac..390b575 100644
--- a/chrome/browser/extensions/apps_promo.cc
+++ b/chrome/browser/extensions/apps_promo.cc
@@ -4,21 +4,44 @@
#include "chrome/browser/extensions/apps_promo.h"
+#include "base/base64.h"
#include "base/command_line.h"
#include "base/metrics/histogram.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/webui/ntp/shown_sections_handler.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/extensions/extension.h"
+#include "chrome/common/chrome_notification_types.h"
#include "chrome/common/pref_names.h"
+#include "content/common/url_constants.h"
+#include "content/common/notification_service.h"
+#include "net/base/load_flags.h"
+#include "net/url_request/url_request_status.h"
const int AppsPromo::kDefaultAppsCounterMax = 10;
namespace {
// The default logo for the promo.
-const char kDefaultPromoLogo[] = "chrome://theme/IDR_WEBSTORE_ICON";
+const char kDefaultLogo[] = "chrome://theme/IDR_WEBSTORE_ICON";
+
+// The default promo data (this is only used for testing with
+// --force-apps-promo-visible).
+const char kDefaultHeader[] = "Browse thousands of apps and games for Chrome";
+const char kDefaultButton[] = "Visit the Chrome Web Store";
+const char kDefaultExpire[] = "No thanks";
+const char kDefaultLink[] = "https://chrome.google.com/webstore";
+
+// Http success status code.
+const int kHttpSuccess = 200;
+
+// The match pattern for valid logo URLs.
+const char kValidLogoPattern[] = "https://*.google.com/*.png";
+
+// The prefix for 'data' URL images.
+const char kPNGDataURLPrefix[] = "data:image/png;base64,";
// Returns the string pref at |path|, using |fallback| as the default (if there
// is no pref value present). |fallback| is used for debugging in concert with
@@ -35,6 +58,24 @@ std::string GetStringPref(const char* path, const std::string& fallback) {
} // namespace
+AppsPromo::PromoData::PromoData() {}
+AppsPromo::PromoData::PromoData(const std::string& id,
+ const std::string& header,
+ const std::string& button,
+ const GURL& link,
+ const std::string& expire,
+ const GURL& logo,
+ const int user_group)
+ : id(id),
+ header(header),
+ button(button),
+ link(link),
+ expire(expire),
+ logo(logo),
+ user_group(user_group) {}
+
+AppsPromo::PromoData::~PromoData() {}
+
// static
void AppsPromo::RegisterPrefs(PrefService* local_state) {
std::string empty;
@@ -44,6 +85,7 @@ void AppsPromo::RegisterPrefs(PrefService* local_state) {
local_state->RegisterStringPref(prefs::kNTPWebStorePromoButton, empty);
local_state->RegisterStringPref(prefs::kNTPWebStorePromoLink, empty);
local_state->RegisterStringPref(prefs::kNTPWebStorePromoLogo, empty);
+ local_state->RegisterStringPref(prefs::kNTPWebStorePromoLogoSource, empty);
local_state->RegisterStringPref(prefs::kNTPWebStorePromoExpire, empty);
local_state->RegisterIntegerPref(prefs::kNTPWebStorePromoUserGroup, 0);
}
@@ -62,21 +104,8 @@ void AppsPromo::RegisterUserPrefs(PrefService* prefs) {
std::string(),
PrefService::UNSYNCABLE_PREF);
prefs->RegisterBooleanPref(prefs::kNTPHideWebStorePromo,
- false,
- PrefService::UNSYNCABLE_PREF);
-}
-
-// static
-void AppsPromo::ClearPromo() {
- PrefService* local_state = g_browser_process->local_state();
- local_state->ClearPref(prefs::kNTPWebStoreEnabled);
- local_state->ClearPref(prefs::kNTPWebStorePromoId);
- local_state->ClearPref(prefs::kNTPWebStorePromoHeader);
- local_state->ClearPref(prefs::kNTPWebStorePromoButton);
- local_state->ClearPref(prefs::kNTPWebStorePromoLink);
- local_state->ClearPref(prefs::kNTPWebStorePromoLogo);
- local_state->ClearPref(prefs::kNTPWebStorePromoExpire);
- local_state->ClearPref(prefs::kNTPWebStorePromoUserGroup);
+ false,
+ PrefService::UNSYNCABLE_PREF);
}
// static
@@ -100,68 +129,68 @@ bool AppsPromo::IsWebStoreSupportedForLocale() {
}
// static
-std::string AppsPromo::GetPromoButtonText() {
- return GetStringPref(prefs::kNTPWebStorePromoButton, "Click here now");
+void AppsPromo::SetWebStoreSupportedForLocale(bool supported) {
+ PrefService* local_state = g_browser_process->local_state();
+ local_state->SetBoolean(prefs::kNTPWebStoreEnabled, supported);
}
// static
-std::string AppsPromo::GetPromoId() {
- return GetStringPref(prefs::kNTPWebStorePromoId, "");
+void AppsPromo::ClearPromo() {
+ PrefService* local_state = g_browser_process->local_state();
+ local_state->ClearPref(prefs::kNTPWebStoreEnabled);
+ local_state->ClearPref(prefs::kNTPWebStorePromoId);
+ local_state->ClearPref(prefs::kNTPWebStorePromoHeader);
+ local_state->ClearPref(prefs::kNTPWebStorePromoButton);
+ local_state->ClearPref(prefs::kNTPWebStorePromoLink);
+ local_state->ClearPref(prefs::kNTPWebStorePromoLogo);
+ local_state->ClearPref(prefs::kNTPWebStorePromoLogoSource);
+ local_state->ClearPref(prefs::kNTPWebStorePromoExpire);
+ local_state->ClearPref(prefs::kNTPWebStorePromoUserGroup);
}
// static
-std::string AppsPromo::GetPromoHeaderText() {
- return GetStringPref(prefs::kNTPWebStorePromoHeader, "Get great apps!");
-}
+AppsPromo::PromoData AppsPromo::GetPromo() {
+ PromoData data;
+ PrefService* local_state = g_browser_process->local_state();
-// static
-GURL AppsPromo::GetPromoLink() {
- return GURL(GetStringPref(prefs::kNTPWebStorePromoLink,
- "https://chrome.google.com/webstore"));
-}
+ data.id = GetStringPref(prefs::kNTPWebStorePromoId, "");
+ data.link = GURL(GetStringPref(prefs::kNTPWebStorePromoLink, kDefaultLink));
+ data.user_group = local_state->GetInteger(prefs::kNTPWebStorePromoUserGroup);
+ data.header = GetStringPref(prefs::kNTPWebStorePromoHeader, kDefaultHeader);
+ data.button = GetStringPref(prefs::kNTPWebStorePromoButton, kDefaultButton);
+ data.expire = GetStringPref(prefs::kNTPWebStorePromoExpire, kDefaultExpire);
-// static
-GURL AppsPromo::GetPromoLogo() {
- PrefService* local_state = g_browser_process->local_state();
GURL logo_url(local_state->GetString(prefs::kNTPWebStorePromoLogo));
- if (logo_url.is_valid() && logo_url.SchemeIs("data"))
- return logo_url;
- return GURL(kDefaultPromoLogo);
-}
+ if (logo_url.is_valid() && logo_url.SchemeIs(chrome::kDataScheme))
+ data.logo = logo_url;
+ else
+ data.logo = GURL(kDefaultLogo);
-// static
-std::string AppsPromo::GetPromoExpireText() {
- return GetStringPref(prefs::kNTPWebStorePromoExpire, "No thanks.");
+ return data;
}
// static
-int AppsPromo::GetPromoUserGroup() {
+void AppsPromo::SetPromo(AppsPromo::PromoData data) {
PrefService* local_state = g_browser_process->local_state();
- return local_state->GetInteger(prefs::kNTPWebStorePromoUserGroup);
+ local_state->SetString(prefs::kNTPWebStorePromoId, data.id);
+ local_state->SetString(prefs::kNTPWebStorePromoButton, data.button);
+ local_state->SetString(prefs::kNTPWebStorePromoHeader, data.header);
+ local_state->SetString(prefs::kNTPWebStorePromoLink, data.link.spec());
+ local_state->SetString(prefs::kNTPWebStorePromoLogo, data.logo.spec());
+ local_state->SetString(prefs::kNTPWebStorePromoExpire, data.expire);
+ local_state->SetInteger(prefs::kNTPWebStorePromoUserGroup, data.user_group);
}
// static
-void AppsPromo::SetPromo(const std::string& id,
- const std::string& header_text,
- const std::string& button_text,
- const GURL& link,
- const std::string& expire_text,
- const GURL& logo,
- const int user_group) {
- PrefService* local_state = g_browser_process->local_state();
- local_state->SetString(prefs::kNTPWebStorePromoId, id);
- local_state->SetString(prefs::kNTPWebStorePromoButton, button_text);
- local_state->SetString(prefs::kNTPWebStorePromoHeader, header_text);
- local_state->SetString(prefs::kNTPWebStorePromoLink, link.spec());
- local_state->SetString(prefs::kNTPWebStorePromoLogo, logo.spec());
- local_state->SetString(prefs::kNTPWebStorePromoExpire, expire_text);
- local_state->SetInteger(prefs::kNTPWebStorePromoUserGroup, user_group);
+GURL AppsPromo::GetSourcePromoLogoURL() {
+ return GURL(GetStringPref(prefs::kNTPWebStorePromoLogoSource, ""));
}
// static
-void AppsPromo::SetWebStoreSupportedForLocale(bool supported) {
+void AppsPromo::SetSourcePromoLogoURL(GURL logo_source) {
PrefService* local_state = g_browser_process->local_state();
- local_state->SetBoolean(prefs::kNTPWebStoreEnabled, supported);
+ local_state->SetString(prefs::kNTPWebStorePromoLogoSource,
+ logo_source.spec());
}
AppsPromo::AppsPromo(PrefService* prefs)
@@ -246,15 +275,14 @@ void AppsPromo::ExpireDefaultApps() {
}
void AppsPromo::MaximizeAppsIfNecessary() {
- std::string promo_id = GetPromoId();
- int maximize_setting = GetPromoUserGroup();
+ PromoData promo = GetPromo();
// Maximize the apps section of the NTP if this is the first time viewing the
// specific promo and the current user group is targetted.
- if (GetLastPromoId() != promo_id) {
- if ((maximize_setting & GetCurrentUserGroup()) != 0)
+ if (GetLastPromoId() != promo.id) {
+ if ((promo.user_group & GetCurrentUserGroup()) != 0)
ShownSectionsHandler::SetShownSection(prefs_, APPS);
- SetLastPromoId(promo_id);
+ SetLastPromoId(promo.id);
}
}
@@ -297,3 +325,76 @@ AppsPromo::UserGroup AppsPromo::GetCurrentUserGroup() const {
CHECK(last_promo_id);
return last_promo_id->IsDefaultValue() ? USERS_NEW : USERS_EXISTING;
}
+
+AppsPromoLogoFetcher::AppsPromoLogoFetcher(
+ Profile* profile,
+ AppsPromo::PromoData promo_data)
+ : profile_(profile),
+ promo_data_(promo_data) {
+ if (SupportsLogoURL()) {
+ if (HaveCachedLogo()) {
+ promo_data_.logo = AppsPromo::GetPromo().logo;
+ SavePromo();
+ } else {
+ FetchLogo();
+ }
+ } else {
+ // We only care about the source URL when this fetches the logo.
+ AppsPromo::SetSourcePromoLogoURL(GURL());
+ SavePromo();
+ }
+}
+
+AppsPromoLogoFetcher::~AppsPromoLogoFetcher() {}
+
+void AppsPromoLogoFetcher::OnURLFetchComplete(const URLFetcher* source) {
+ std::string data;
+ std::string base64_data;
+
+ CHECK(source == url_fetcher_.get());
+ CHECK(source->GetResponseAsString(&data));
+
+ if (source->status().is_success() &&
+ source->response_code() == kHttpSuccess &&
+ base::Base64Encode(data, &base64_data)) {
+ AppsPromo::SetSourcePromoLogoURL(promo_data_.logo);
+ promo_data_.logo = GURL(kPNGDataURLPrefix + base64_data);
+ } else {
+ // The logo wasn't downloaded correctly or we failed to encode it in
+ // base64. Reset the source URL so we fetch it again next time. AppsPromo
+ // will revert to the default logo.
+ AppsPromo::SetSourcePromoLogoURL(GURL());
+ }
+
+ SavePromo();
+}
+
+void AppsPromoLogoFetcher::FetchLogo() {
+ CHECK(promo_data_.logo.scheme() == chrome::kHttpsScheme);
+
+ url_fetcher_.reset(URLFetcher::Create(
+ 0, promo_data_.logo, URLFetcher::GET, this));
+ url_fetcher_->set_request_context(
+ g_browser_process->system_request_context());
+ url_fetcher_->set_load_flags(net::LOAD_DO_NOT_SEND_COOKIES |
+ net::LOAD_DO_NOT_SAVE_COOKIES);
+ url_fetcher_->Start();
+}
+
+bool AppsPromoLogoFetcher::HaveCachedLogo() {
+ return promo_data_.logo == AppsPromo::GetSourcePromoLogoURL();
+}
+
+void AppsPromoLogoFetcher::SavePromo() {
+ AppsPromo::SetPromo(promo_data_);
+
+ NotificationService::current()->Notify(
+ chrome::NOTIFICATION_WEB_STORE_PROMO_LOADED,
+ Source<Profile>(profile_),
+ NotificationService::NoDetails());
+}
+
+bool AppsPromoLogoFetcher::SupportsLogoURL() {
+ URLPattern allowed_urls(URLPattern::SCHEME_HTTPS, kValidLogoPattern);
+ return allowed_urls.MatchesURL(promo_data_.logo);
+}
diff --git a/chrome/browser/extensions/apps_promo.h b/chrome/browser/extensions/apps_promo.h
index 1715180..28c5b03 100644
--- a/chrome/browser/extensions/apps_promo.h
+++ b/chrome/browser/extensions/apps_promo.h
@@ -11,8 +11,10 @@
#include "base/gtest_prod_util.h"
#include "chrome/common/extensions/extension.h"
+#include "content/common/url_fetcher.h"
class PrefService;
+class Profile;
// This encapsulates business logic for:
// - Whether to show the apps promo in the launcher
@@ -32,56 +34,55 @@ class AppsPromo {
USERS_EXISTING = 1 << 1,
};
+ // Holds all the data that specifies a promo for the apps section of the NTP.
+ struct PromoData {
+ PromoData();
+ PromoData(const std::string& id,
+ const std::string& header,
+ const std::string& button,
+ const GURL& link,
+ const std::string& expire,
+ const GURL& logo,
+ int user_group);
+ ~PromoData();
+
+ // See PromoResourceService::UnpackWebStoreSignal for descriptions of these
+ // fields.
+ std::string id;
+ std::string header;
+ std::string button;
+ GURL link;
+ std::string expire;
+ GURL logo;
+ int user_group;
+ };
+
// Register our preferences. Parts of the promo content are stored in Local
// State since they're independent of the user profile.
static void RegisterPrefs(PrefService* local_state);
static void RegisterUserPrefs(PrefService* prefs);
- // Removes the current promo data.
- static void ClearPromo();
-
// Returns true if a promo is available for the current locale.
static bool IsPromoSupportedForLocale();
// Returns true if the web store is active for the existing locale.
static bool IsWebStoreSupportedForLocale();
- // Gets the ID of the current promo.
- static std::string GetPromoId();
-
- // Gets the text for the promo button.
- static std::string GetPromoButtonText();
-
- // Gets the text for the promo header.
- static std::string GetPromoHeaderText();
-
- // Gets the promo link.
- static GURL GetPromoLink();
-
- // Gets the URL of the promo logo image.
- static GURL GetPromoLogo();
-
- // Gets the text for the promo "hide this" link.
- static std::string GetPromoExpireText();
-
- // Gets the user groups for which we should maximize the promo and apps
- // section. The return value is a bitwise OR of UserGroup enums.
- static int GetPromoUserGroup();
-
- // Called to set the current promo data. The default web store logo will be
- // used if |logo| is empty or not valid.
- static void SetPromo(const std::string& id,
- const std::string& header_text,
- const std::string& button_text,
- const GURL& link,
- const std::string& expire_text,
- const GURL& logo,
- const int user_group);
-
// Sets whether the web store and apps section is supported for the current
// locale.
static void SetWebStoreSupportedForLocale(bool supported);
+ // Accesses the current promo data. The default logo will be used if
+ // |promo_data.logo| is empty or not a valid 'data' URL.
+ static void ClearPromo();
+ static PromoData GetPromo();
+ static void SetPromo(PromoData promo_data);
+
+ // Gets the original URL of the logo. This should only be set when the logo
+ // was served over HTTPS.
+ static GURL GetSourcePromoLogoURL();
+ static void SetSourcePromoLogoURL(GURL original_url);
+
explicit AppsPromo(PrefService* prefs);
~AppsPromo();
@@ -145,4 +146,33 @@ class AppsPromo {
DISALLOW_COPY_AND_ASSIGN(AppsPromo);
};
+// Fetches logos over HTTPS, making sure we don't send cookies and that we
+// cache the image until its source URL changes.
+class AppsPromoLogoFetcher : public URLFetcher::Delegate {
+ public:
+ AppsPromoLogoFetcher(Profile* profile,
+ AppsPromo::PromoData promo_data);
+ virtual ~AppsPromoLogoFetcher();
+
+ virtual void OnURLFetchComplete(const URLFetcher* source) OVERRIDE;
+
+ private:
+ // Fetches the logo and stores the result as a data URL.
+ void FetchLogo();
+
+ // Checks if the logo was downloaded previously.
+ bool HaveCachedLogo();
+
+ // Sets the apps promo based on the current data and then issues the
+ // WEB_STORE_PROMO_LOADED notification so open NTPs can inject the promo.
+ void SavePromo();
+
+ // Checks if the promo logo matches https://*.google.com/*.png.
+ bool SupportsLogoURL();
+
+ Profile* profile_;
+ AppsPromo::PromoData promo_data_;
+ scoped_ptr<URLFetcher> url_fetcher_;
+};
+
#endif // CHROME_BROWSER_EXTENSIONS_APPS_PROMO_H_
diff --git a/chrome/browser/extensions/apps_promo_unittest.cc b/chrome/browser/extensions/apps_promo_unittest.cc
index 607da43..77d40ea 100644
--- a/chrome/browser/extensions/apps_promo_unittest.cc
+++ b/chrome/browser/extensions/apps_promo_unittest.cc
@@ -108,9 +108,10 @@ TEST_F(ExtensionAppsPromo, HappyPath) {
&promo_just_expired));
// Once the promo is set, we show both the promo and app launcher.
- AppsPromo::SetPromo(kPromoId, kPromoHeader, kPromoButton,
- GURL(kPromoLink), kPromoExpire, GURL(""),
- kPromoUserGroup);
+ AppsPromo::PromoData promo_data(kPromoId, kPromoHeader, kPromoButton,
+ GURL(kPromoLink), kPromoExpire, GURL(""),
+ kPromoUserGroup);
+ AppsPromo::SetPromo(promo_data);
AppsPromo::SetWebStoreSupportedForLocale(true);
EXPECT_TRUE(AppsPromo::IsPromoSupportedForLocale());
EXPECT_TRUE(apps_promo()->ShouldShowAppLauncher(installed_ids));
@@ -148,60 +149,56 @@ TEST_F(ExtensionAppsPromo, HappyPath) {
// Tests get and set of promo content.
TEST_F(ExtensionAppsPromo, PromoPrefs) {
// Store a promo....
- AppsPromo::SetPromo(kPromoId, kPromoHeader, kPromoButton,
- GURL(kPromoLink), kPromoExpire, GURL(""),
- kPromoUserGroup);
+ AppsPromo::PromoData promo_data(kPromoId, kPromoHeader, kPromoButton,
+ GURL(kPromoLink), kPromoExpire, GURL(""),
+ kPromoUserGroup);
+ AppsPromo::SetPromo(promo_data);
// ... then make sure AppsPromo can access it.
- EXPECT_EQ(kPromoId, AppsPromo::GetPromoId());
- EXPECT_EQ(kPromoHeader, AppsPromo::GetPromoHeaderText());
- EXPECT_EQ(kPromoButton, AppsPromo::GetPromoButtonText());
- EXPECT_EQ(GURL(kPromoLink), AppsPromo::GetPromoLink());
- EXPECT_EQ(kPromoExpire, AppsPromo::GetPromoExpireText());
- EXPECT_EQ(kPromoUserGroup, AppsPromo::GetPromoUserGroup());
+ AppsPromo::PromoData actual_data = AppsPromo::GetPromo();
+ EXPECT_EQ(kPromoId, actual_data.id);
+ EXPECT_EQ(kPromoHeader, actual_data.header);
+ EXPECT_EQ(kPromoButton, actual_data.button);
+ EXPECT_EQ(GURL(kPromoLink), actual_data.link);
+ EXPECT_EQ(kPromoExpire, actual_data.expire);
+ EXPECT_EQ(kPromoUserGroup, actual_data.user_group);
// The promo logo should be the default value.
- EXPECT_EQ(GURL(kPromoLogo), AppsPromo::GetPromoLogo());
+ EXPECT_EQ(GURL(kPromoLogo), actual_data.logo);
EXPECT_TRUE(AppsPromo::IsPromoSupportedForLocale());
AppsPromo::ClearPromo();
- EXPECT_EQ("", AppsPromo::GetPromoId());
- EXPECT_EQ("", AppsPromo::GetPromoHeaderText());
- EXPECT_EQ("", AppsPromo::GetPromoButtonText());
- EXPECT_EQ(GURL(""), AppsPromo::GetPromoLink());
- EXPECT_EQ("", AppsPromo::GetPromoExpireText());
- EXPECT_EQ(AppsPromo::USERS_NONE, AppsPromo::GetPromoUserGroup());
- EXPECT_EQ(GURL(kPromoLogo), AppsPromo::GetPromoLogo());
+ actual_data = AppsPromo::GetPromo();
+ EXPECT_EQ("", actual_data.id);
+ EXPECT_EQ("", actual_data.header);
+ EXPECT_EQ("", actual_data.button);
+ EXPECT_EQ(GURL(""), actual_data.link);
+ EXPECT_EQ("", actual_data.expire);
+ EXPECT_EQ(AppsPromo::USERS_NONE, actual_data.user_group);
+ EXPECT_EQ(GURL(kPromoLogo), actual_data.logo);
EXPECT_FALSE(AppsPromo::IsPromoSupportedForLocale());
// Make sure we can set the logo to something other than the default.
std::string promo_logo = "data:image/png;base64,iVBORw0kGgoAAAN";
- AppsPromo::SetPromo(kPromoId, kPromoHeader, kPromoButton,
- GURL(kPromoLink), kPromoExpire, GURL(promo_logo),
- kPromoUserGroup);
- EXPECT_EQ(GURL(promo_logo), AppsPromo::GetPromoLogo());
+ promo_data.logo = GURL(promo_logo);
+ AppsPromo::SetPromo(promo_data);
+ EXPECT_EQ(GURL(promo_logo), AppsPromo::GetPromo().logo);
EXPECT_TRUE(AppsPromo::IsPromoSupportedForLocale());
- // Verify that the default is returned instead of http or https URLs.
- promo_logo = "http://google.com/logo.png";
- AppsPromo::SetPromo(kPromoId, kPromoHeader, kPromoButton,
- GURL(kPromoLink), kPromoExpire, GURL(promo_logo),
- kPromoUserGroup);
- EXPECT_EQ(GURL(kPromoLogo), AppsPromo::GetPromoLogo());
+ // Verify that the default is returned instead of HTTP or HTTPS URLs.
+ promo_data.logo = GURL("http://google.com/logo.png");
+ AppsPromo::SetPromo(promo_data);
+ EXPECT_EQ(GURL(kPromoLogo), AppsPromo::GetPromo().logo);
EXPECT_TRUE(AppsPromo::IsPromoSupportedForLocale());
- promo_logo = "https://google.com/logo.png";
- AppsPromo::SetPromo(kPromoId, kPromoHeader, kPromoButton,
- GURL(kPromoLink), kPromoExpire, GURL(promo_logo),
- kPromoUserGroup);
- EXPECT_EQ(GURL(kPromoLogo), AppsPromo::GetPromoLogo());
+ promo_data.logo = GURL("https://google.com/logo.png");
+ AppsPromo::SetPromo(promo_data);
+ EXPECT_EQ(GURL(kPromoLogo), AppsPromo::GetPromo().logo);
EXPECT_TRUE(AppsPromo::IsPromoSupportedForLocale());
// Try an invalid URL.
- promo_logo = "sldkfjlsdn";
- AppsPromo::SetPromo(kPromoId, kPromoHeader, kPromoButton,
- GURL(kPromoLink), kPromoExpire, GURL(promo_logo),
- kPromoUserGroup);
- EXPECT_EQ(GURL(kPromoLogo), AppsPromo::GetPromoLogo());
+ promo_data.logo = GURL("sldkfjlsdn");
+ AppsPromo::SetPromo(promo_data);
+ EXPECT_EQ(GURL(kPromoLogo), AppsPromo::GetPromo().logo);
EXPECT_TRUE(AppsPromo::IsPromoSupportedForLocale());
// Try the web store supported flag.
@@ -210,6 +207,11 @@ TEST_F(ExtensionAppsPromo, PromoPrefs) {
EXPECT_TRUE(AppsPromo::IsWebStoreSupportedForLocale());
AppsPromo::SetWebStoreSupportedForLocale(false);
EXPECT_FALSE(AppsPromo::IsWebStoreSupportedForLocale());
+
+ // Try setting and getting the source logo URL.
+ GURL expected_source("https://www.google.com/images/test.png");
+ AppsPromo::SetSourcePromoLogoURL(expected_source);
+ EXPECT_EQ(expected_source, AppsPromo::GetSourcePromoLogoURL());
}
// Tests maximizing the promo for USERS_NONE.
@@ -218,16 +220,16 @@ TEST_F(ExtensionAppsPromo, UpdatePromoFocus_UsersNone) {
ExpectAppsSectionMaximized(prefs(), false);
// The promo shouldn't maximize for anyone.
- AppsPromo::SetPromo(kPromoId, kPromoHeader, kPromoButton,
- GURL(kPromoLink), kPromoExpire, GURL(""),
- AppsPromo::USERS_NONE);
+ AppsPromo::PromoData promo_data(kPromoId, kPromoHeader, kPromoButton,
+ GURL(kPromoLink), kPromoExpire, GURL(""),
+ AppsPromo::USERS_NONE);
+ AppsPromo::SetPromo(promo_data);
apps_promo()->MaximizeAppsIfNecessary();
ExpectAppsSectionMaximized(prefs(), false);
// The promo still shouldn't maximize if we change it's ID.
- AppsPromo::SetPromo("lkksdf", kPromoHeader, kPromoButton,
- GURL(kPromoLink), kPromoExpire, GURL(""),
- AppsPromo::USERS_NONE);
+ promo_data.id = "lkksdf";
+ AppsPromo::SetPromo(promo_data);
apps_promo()->MaximizeAppsIfNecessary();
ExpectAppsSectionMaximized(prefs(), false);
}
@@ -238,19 +240,17 @@ TEST_F(ExtensionAppsPromo, UpdatePromoFocus_UsersExisting) {
ExpectAppsSectionMaximized(prefs(), false);
// Set the promo content.
- AppsPromo::SetPromo(kPromoId, kPromoHeader, kPromoButton,
- GURL(kPromoLink), kPromoExpire, GURL(""),
- AppsPromo::USERS_EXISTING);
-
+ AppsPromo::PromoData promo_data(kPromoId, kPromoHeader, kPromoButton,
+ GURL(kPromoLink), kPromoExpire, GURL(""),
+ AppsPromo::USERS_EXISTING);
+ AppsPromo::SetPromo(promo_data);
// This is a new user so the apps section shouldn't maximize.
apps_promo()->MaximizeAppsIfNecessary();
ExpectAppsSectionMaximized(prefs(), false);
-
// Set a new promo and now it should maximize.
- AppsPromo::SetPromo("lksdf", kPromoHeader, kPromoButton,
- GURL(kPromoLink), kPromoExpire, GURL(""),
- AppsPromo::USERS_EXISTING);
+ promo_data.id = "lksdf";
+ AppsPromo::SetPromo(promo_data);
apps_promo()->MaximizeAppsIfNecessary();
ExpectAppsSectionMaximized(prefs(), true);
@@ -265,9 +265,10 @@ TEST_F(ExtensionAppsPromo, UpdatePromoFocus_UsersNew) {
ExpectAppsSectionMaximized(prefs(), false);
// The promo should maximize for new users.
- AppsPromo::SetPromo(kPromoId, kPromoHeader, kPromoButton,
- GURL(kPromoLink), kPromoExpire, GURL(""),
- AppsPromo::USERS_NEW);
+ AppsPromo::PromoData promo_data(kPromoId, kPromoHeader, kPromoButton,
+ GURL(kPromoLink), kPromoExpire, GURL(""),
+ AppsPromo::USERS_NEW);
+ AppsPromo::SetPromo(promo_data);
apps_promo()->MaximizeAppsIfNecessary();
ExpectAppsSectionMaximized(prefs(), true);
@@ -280,9 +281,8 @@ TEST_F(ExtensionAppsPromo, UpdatePromoFocus_UsersNew) {
ExpectAppsSectionMaximized(prefs(), false);
// Another promo targetting new users should not maximize.
- AppsPromo::SetPromo("lksdf", kPromoHeader, kPromoButton,
- GURL(kPromoLink), kPromoExpire, GURL(""),
- AppsPromo::USERS_NEW);
+ promo_data.id = "lksdf";
+ AppsPromo::SetPromo(promo_data);
apps_promo()->MaximizeAppsIfNecessary();
ExpectAppsSectionMaximized(prefs(), false);
}
@@ -293,9 +293,10 @@ TEST_F(ExtensionAppsPromo, UpdatePromoFocus_UsersAll) {
ExpectAppsSectionMaximized(prefs(), false);
// The apps section should maximize for all users.
- AppsPromo::SetPromo(kPromoId, kPromoHeader, kPromoButton,
- GURL(kPromoLink), kPromoExpire, GURL(""),
- AppsPromo::USERS_NEW | AppsPromo::USERS_EXISTING);
+ AppsPromo::PromoData promo_data(
+ kPromoId, kPromoHeader, kPromoButton, GURL(kPromoLink), kPromoExpire,
+ GURL(""), AppsPromo::USERS_NEW | AppsPromo::USERS_EXISTING);
+ AppsPromo::SetPromo(promo_data);
apps_promo()->MaximizeAppsIfNecessary();
ExpectAppsSectionMaximized(prefs(), true);
@@ -307,9 +308,8 @@ TEST_F(ExtensionAppsPromo, UpdatePromoFocus_UsersAll) {
ExpectAppsSectionMaximized(prefs(), false);
// A promo with a new ID should maximize though.
- AppsPromo::SetPromo("lkksdf", kPromoHeader, kPromoButton,
- GURL(kPromoLink), kPromoExpire, GURL(""),
- AppsPromo::USERS_NEW | AppsPromo::USERS_EXISTING);
+ promo_data.id = "lkksdf";
+ AppsPromo::SetPromo(promo_data);
apps_promo()->MaximizeAppsIfNecessary();
ExpectAppsSectionMaximized(prefs(), true);
}
@@ -320,9 +320,10 @@ TEST_F(ExtensionAppsPromo, PromoHiddenByPref) {
// When the "hide" pref is false, the promo should still appear.
prefs()->SetBoolean(prefs::kNTPHideWebStorePromo, false);
- AppsPromo::SetPromo(kPromoId, kPromoHeader, kPromoButton,
- GURL(kPromoLink), kPromoExpire, GURL(""),
- AppsPromo::USERS_NEW | AppsPromo::USERS_EXISTING);
+ AppsPromo::PromoData promo_data(
+ kPromoId, kPromoHeader, kPromoButton, GURL(kPromoLink), kPromoExpire,
+ GURL(""), AppsPromo::USERS_NEW | AppsPromo::USERS_EXISTING);
+ AppsPromo::SetPromo(promo_data);
bool just_expired;
bool show_promo = apps_promo()->ShouldShowPromo(
apps_promo()->old_default_apps(), &just_expired);
diff --git a/chrome/browser/ui/webui/ntp/app_launcher_handler.cc b/chrome/browser/ui/webui/ntp/app_launcher_handler.cc
index 9916ccd..6d08ef2 100644
--- a/chrome/browser/ui/webui/ntp/app_launcher_handler.cc
+++ b/chrome/browser/ui/webui/ntp/app_launcher_handler.cc
@@ -452,11 +452,12 @@ DictionaryValue* AppLauncherHandler::GetAppInfo(const Extension* extension) {
}
void AppLauncherHandler::FillPromoDictionary(DictionaryValue* dictionary) {
- dictionary->SetString("promoHeader", AppsPromo::GetPromoHeaderText());
- dictionary->SetString("promoButton", AppsPromo::GetPromoButtonText());
- dictionary->SetString("promoLink", AppsPromo::GetPromoLink().spec());
- dictionary->SetString("promoLogo", AppsPromo::GetPromoLogo().spec());
- dictionary->SetString("promoExpire", AppsPromo::GetPromoExpireText());
+ AppsPromo::PromoData data = AppsPromo::GetPromo();
+ dictionary->SetString("promoHeader", data.header);
+ dictionary->SetString("promoButton", data.button);
+ dictionary->SetString("promoLink", data.link.spec());
+ dictionary->SetString("promoLogo", data.logo.spec());
+ dictionary->SetString("promoExpire", data.expire);
}
void AppLauncherHandler::HandleGetApps(const ListValue* args) {
diff --git a/chrome/browser/web_resource/promo_resource_service.cc b/chrome/browser/web_resource/promo_resource_service.cc
index 09b0aee..1336fd0 100644
--- a/chrome/browser/web_resource/promo_resource_service.cc
+++ b/chrome/browser/web_resource/promo_resource_service.cc
@@ -316,13 +316,9 @@ void PromoResourceService::UnpackWebStoreSignal(
bool is_webstore_active = false;
bool signal_found = false;
- std::string promo_id = "";
- std::string promo_header = "";
- std::string promo_button = "";
+ AppsPromo::PromoData promo_data;
std::string promo_link = "";
- std::string promo_expire = "";
std::string promo_logo = "";
- int maximize_setting = 0;
int target_builds = 0;
if (!parsed_json.GetDictionary("topic", &topic_dict) ||
@@ -362,24 +358,26 @@ void PromoResourceService::UnpackWebStoreSignal(
name = name.substr(split+1);
split = name.find(':');
if (split == std::string::npos ||
- !base::StringToInt(name.substr(0, split), &maximize_setting))
+ !base::StringToInt(name.substr(0, split), &promo_data.user_group))
continue;
// (4) optional text that specifies a URL of a logo image
promo_logo = name.substr(split+1);
- if (!a_dic->GetString(kAnswerIdProperty, &promo_id) ||
- !a_dic->GetString(kWebStoreHeaderProperty, &promo_header) ||
- !a_dic->GetString(kWebStoreButtonProperty, &promo_button) ||
+ if (!a_dic->GetString(kAnswerIdProperty, &promo_data.id) ||
+ !a_dic->GetString(kWebStoreHeaderProperty, &promo_data.header) ||
+ !a_dic->GetString(kWebStoreButtonProperty, &promo_data.button) ||
!a_dic->GetString(kWebStoreLinkProperty, &promo_link) ||
- !a_dic->GetString(kWebStoreExpireProperty, &promo_expire))
+ !a_dic->GetString(kWebStoreExpireProperty, &promo_data.expire))
continue;
if (IsThisBuildTargeted(target_builds)) {
- // Store the first web store promo that targets the current build.
- AppsPromo::SetPromo(promo_id, promo_header, promo_button,
- GURL(promo_link), promo_expire, GURL(promo_logo),
- maximize_setting);
+ // The downloader will set the promo prefs and send the
+ // NOTIFICATION_WEB_STORE_PROMO_LOADED notification.
+ promo_data.link = GURL(promo_link);
+ promo_data.logo = GURL(promo_logo);
+ apps_promo_logo_fetcher_.reset(
+ new AppsPromoLogoFetcher(profile_, promo_data));
signal_found = true;
break;
}
@@ -392,11 +390,6 @@ void PromoResourceService::UnpackWebStoreSignal(
AppsPromo::SetWebStoreSupportedForLocale(is_webstore_active);
- NotificationService::current()->Notify(
- chrome::NOTIFICATION_WEB_STORE_PROMO_LOADED,
- Source<Profile>(profile_),
- NotificationService::NoDetails());
-
return;
}
diff --git a/chrome/browser/web_resource/promo_resource_service.h b/chrome/browser/web_resource/promo_resource_service.h
index 2350418..a68e2aa 100644
--- a/chrome/browser/web_resource/promo_resource_service.h
+++ b/chrome/browser/web_resource/promo_resource_service.h
@@ -11,6 +11,8 @@
#include "chrome/browser/web_resource/web_resource_service.h"
#include "chrome/common/chrome_version_info.h"
+class AppsPromoLogoFetcher;
+class PrefService;
class Profile;
namespace PromoResourceServiceUtil {
@@ -21,8 +23,6 @@ bool CanShowPromo(Profile* profile);
} // namespace PromoResourceServiceUtil
-class PrefService;
-
// A PromoResourceService fetches data from a web resource server to be used to
// dynamically change the appearance of the New Tab Page. For example, it has
// been used to fetch "tips" to be displayed on the NTP, or to display
@@ -52,6 +52,13 @@ class PromoResourceService
FRIEND_TEST_ALL_PREFIXES(PromoResourceServiceTest, UnpackWebStoreSignal);
FRIEND_TEST_ALL_PREFIXES(
PromoResourceServiceTest, UnpackPartialWebStoreSignal);
+ FRIEND_TEST_ALL_PREFIXES(
+ PromoResourceServiceTest, UnpackWebStoreSignalHttpsLogo);
+ FRIEND_TEST_ALL_PREFIXES(
+ PromoResourceServiceTest, UnpackWebStoreSignalHttpsLogoError);
+ FRIEND_TEST_ALL_PREFIXES(
+ PromoResourceServiceTest, UnpackWebStoreSignalHttpLogo);
+
// Identifies types of Chrome builds for promo targeting.
enum BuildType {
@@ -168,7 +175,7 @@ class PromoResourceService
// "answers": [
// {
// "answer_id": "1143011",
- // "name": "webstore_promo:15:",
+ // "name": "webstore_promo:15:1:https://www.google.com/logo.png",
// "question": "Browse thousands of apps and games for Chrome.",
// "inproduct_target": "Visit the Chrome Web Store",
// "inproduct": "https://chrome.google.com/webstore?hl=en",
@@ -184,11 +191,13 @@ class PromoResourceService
// inproduct_target: the promo button text
// inproduct: the promo button link
// tooltip: the text for the "hide this" link on the promo
- // name: starts with "webstore_promo" to identify the signal. the second
+ // name: starts with "webstore_promo" to identify the signal. The second
// part contains the release channels targeted (bitwise or of
- // BuildTypes). The third part is optional and specifies the URL of
- // the logo image. In the example above, the URL is empty so the
- // default webstore logo will be used.
+ // BuildTypes). The third part specifies what users should maximize
+ // the apps section of the NTP when first loading the promo (bitwise
+ // or of AppsPromo::UserGroup). The forth part is optional and
+ // specifies the URL of the logo image. If left out, the default
+ // webstore logo will be used. The logo can be an HTTPS or DATA URL.
// answer_id: the promo's id
void UnpackWebStoreSignal(const base::DictionaryValue& parsed_json);
@@ -202,6 +211,9 @@ class PromoResourceService
// Overrides the current Chrome release channel for testing purposes.
chrome::VersionInfo::Channel channel_;
+ // A helper that downloads the promo logo.
+ scoped_ptr<AppsPromoLogoFetcher> apps_promo_logo_fetcher_;
+
DISALLOW_COPY_AND_ASSIGN(PromoResourceService);
};
diff --git a/chrome/browser/web_resource/promo_resource_service_unittest.cc b/chrome/browser/web_resource/promo_resource_service_unittest.cc
index b196b12..a69385c 100644
--- a/chrome/browser/web_resource/promo_resource_service_unittest.cc
+++ b/chrome/browser/web_resource/promo_resource_service_unittest.cc
@@ -15,6 +15,7 @@
#include "chrome/test/base/testing_browser_process.h"
#include "chrome/test/base/testing_pref_service.h"
#include "chrome/test/base/testing_profile.h"
+#include "content/test/test_url_fetcher_factory.h"
#include "testing/gtest/include/gtest/gtest.h"
class PromoResourceServiceTest : public testing::Test {
@@ -28,6 +29,7 @@ class PromoResourceServiceTest : public testing::Test {
TestingProfile profile_;
ScopedTestingLocalState local_state_;
scoped_refptr<PromoResourceService> web_resource_service_;
+ MessageLoop loop_;
};
// Verifies that custom dates read from a web resource server are written to
@@ -131,9 +133,6 @@ TEST_F(PromoResourceServiceTest, UnpackPromoSignal) {
scoped_ptr<DictionaryValue> test_json(static_cast<DictionaryValue*>(
base::JSONReader::Read(json, false)));
- // Initialize a message loop for this to run on.
- MessageLoop loop;
-
// Check that prefs are set correctly.
web_resource_service_->UnpackPromoSignal(*(test_json.get()));
PrefService* prefs = profile_.GetPrefs();
@@ -187,22 +186,24 @@ TEST_F(PromoResourceServiceTest, UnpackWebStoreSignal) {
scoped_ptr<DictionaryValue> test_json(static_cast<DictionaryValue*>(
base::JSONReader::Read(json, false)));
- // Initialize a message loop for this to run on.
- MessageLoop loop;
+ // Set the source logo URL to verify that it gets cleared.
+ AppsPromo::SetSourcePromoLogoURL(GURL("https://www.google.com/test.png"));
// Check that prefs are set correctly.
web_resource_service_->UnpackWebStoreSignal(*(test_json.get()));
- PrefService* prefs = profile_.GetPrefs();
- ASSERT_TRUE(prefs != NULL);
- EXPECT_EQ("341252", AppsPromo::GetPromoId());
- EXPECT_EQ("The header!", AppsPromo::GetPromoHeaderText());
- EXPECT_EQ("The button label!", AppsPromo::GetPromoButtonText());
- EXPECT_EQ(GURL("http://link.com"), AppsPromo::GetPromoLink());
- EXPECT_EQ("No thanks, hide this.", AppsPromo::GetPromoExpireText());
- EXPECT_EQ(AppsPromo::USERS_NEW, AppsPromo::GetPromoUserGroup());
- EXPECT_EQ(GURL("chrome://theme/IDR_WEBSTORE_ICON"),
- AppsPromo::GetPromoLogo());
+ AppsPromo::PromoData actual_data = AppsPromo::GetPromo();
+ EXPECT_EQ("341252", actual_data.id);
+ EXPECT_EQ("The header!", actual_data.header);
+ EXPECT_EQ("The button label!", actual_data.button);
+ EXPECT_EQ(GURL("http://link.com"), actual_data.link);
+ EXPECT_EQ("No thanks, hide this.", actual_data.expire);
+ EXPECT_EQ(AppsPromo::USERS_NEW, actual_data.user_group);
+
+ // When we don't download a logo, we revert to the default and clear the
+ // source pref.
+ EXPECT_EQ(GURL("chrome://theme/IDR_WEBSTORE_ICON"), actual_data.logo);
+ EXPECT_EQ(GURL(""), AppsPromo::GetSourcePromoLogoURL());
}
// Tests that the "web store active" flag is set even when the web store promo
@@ -221,15 +222,174 @@ TEST_F(PromoResourceServiceTest, UnpackPartialWebStoreSignal) {
scoped_ptr<DictionaryValue> test_json(static_cast<DictionaryValue*>(
base::JSONReader::Read(json, false)));
- // Initialize a message loop for this to run on.
- MessageLoop loop;
-
// Check that prefs are set correctly.
web_resource_service_->UnpackWebStoreSignal(*(test_json.get()));
EXPECT_FALSE(AppsPromo::IsPromoSupportedForLocale());
EXPECT_TRUE(AppsPromo::IsWebStoreSupportedForLocale());
}
+// Tests that we can successfully unpack web store signals with HTTPS
+// logos.
+TEST_F(PromoResourceServiceTest, UnpackWebStoreSignalHttpsLogo) {
+ web_resource_service_->set_channel(chrome::VersionInfo::CHANNEL_DEV);
+
+ std::string logo_url = "https://www.google.com/image/test.png";
+ std::string png_data = "!$#%,./nvl;iadh9oh82";
+ std::string png_base64 = "data:image/png;base64,ISQjJSwuL252bDtpYWRoOW9oODI=";
+
+ FakeURLFetcherFactory factory;
+ factory.SetFakeResponse(logo_url, png_data, true);
+
+ std::string json =
+ "{ "
+ " \"topic\": {"
+ " \"answers\": ["
+ " {"
+ " \"answer_id\": \"340252\","
+ " \"name\": \"webstore_promo:15:1:" + logo_url + "\","
+ " \"question\": \"Header!\","
+ " \"inproduct_target\": \"The button label!\","
+ " \"inproduct\": \"http://link.com\","
+ " \"tooltip\": \"No thanks, hide this.\""
+ " }"
+ " ]"
+ " }"
+ "}";
+
+ scoped_ptr<DictionaryValue> test_json(static_cast<DictionaryValue*>(
+ base::JSONReader::Read(json, false)));
+
+ // Update the promo multiple times to verify the logo is cached correctly.
+ for (size_t i = 0; i < 2; ++i) {
+ web_resource_service_->UnpackWebStoreSignal(*(test_json.get()));
+
+ // We should only need to run the message loop the first time since the
+ // image is then cached.
+ if (i == 0)
+ loop_.RunAllPending();
+
+ // Reset this scoped_ptr to prevent a DCHECK.
+ web_resource_service_->apps_promo_logo_fetcher_.reset();
+
+ AppsPromo::PromoData actual_data = AppsPromo::GetPromo();
+ EXPECT_EQ("340252", actual_data.id);
+ EXPECT_EQ("Header!", actual_data.header);
+ EXPECT_EQ("The button label!", actual_data.button);
+ EXPECT_EQ(GURL("http://link.com"), actual_data.link);
+ EXPECT_EQ("No thanks, hide this.", actual_data.expire);
+ EXPECT_EQ(AppsPromo::USERS_NEW, actual_data.user_group);
+
+ // The logo should now be a base64 DATA URL.
+ EXPECT_EQ(GURL(png_base64), actual_data.logo);
+
+ // And the source pref should hold the source HTTPS URL.
+ EXPECT_EQ(GURL(logo_url), AppsPromo::GetSourcePromoLogoURL());
+ }
+}
+
+// Tests that we revert to the default logo when the fetch fails.
+TEST_F(PromoResourceServiceTest, UnpackWebStoreSignalHttpsLogoError) {
+ web_resource_service_->set_channel(chrome::VersionInfo::CHANNEL_DEV);
+
+ std::string logo_url = "https://www.google.com/image/test.png";
+ std::string png_data = "!$#%,./nvl;iadh9oh82";
+ std::string png_base64 = "ISQjJSwuL252bDtpYWRoOW9oODI=";
+
+ FakeURLFetcherFactory factory;
+
+ // Have URLFetcher return a 500 error.
+ factory.SetFakeResponse(logo_url, png_data, false);
+
+ std::string json =
+ "{ "
+ " \"topic\": {"
+ " \"answers\": ["
+ " {"
+ " \"answer_id\": \"340252\","
+ " \"name\": \"webstore_promo:15:1:" + logo_url + "\","
+ " \"question\": \"Header!\","
+ " \"inproduct_target\": \"The button label!\","
+ " \"inproduct\": \"http://link.com\","
+ " \"tooltip\": \"No thanks, hide this.\""
+ " }"
+ " ]"
+ " }"
+ "}";
+
+ scoped_ptr<DictionaryValue> test_json(static_cast<DictionaryValue*>(
+ base::JSONReader::Read(json, false)));
+
+ web_resource_service_->UnpackWebStoreSignal(*(test_json.get()));
+
+ loop_.RunAllPending();
+
+ // Reset this scoped_ptr to prevent a DCHECK.
+ web_resource_service_->apps_promo_logo_fetcher_.reset();
+
+ AppsPromo::PromoData actual_data = AppsPromo::GetPromo();
+ EXPECT_EQ("340252", actual_data.id);
+ EXPECT_EQ("Header!", actual_data.header);
+ EXPECT_EQ("The button label!", actual_data.button);
+ EXPECT_EQ(GURL("http://link.com"), actual_data.link);
+ EXPECT_EQ("No thanks, hide this.", actual_data.expire);
+ EXPECT_EQ(AppsPromo::USERS_NEW, actual_data.user_group);
+
+ // Logos are the default values.
+ EXPECT_EQ(GURL("chrome://theme/IDR_WEBSTORE_ICON"), actual_data.logo);
+ EXPECT_EQ(GURL(""), AppsPromo::GetSourcePromoLogoURL());
+}
+
+// Tests that we don't download images over HTTP.
+TEST_F(PromoResourceServiceTest, UnpackWebStoreSignalHttpLogo) {
+ web_resource_service_->set_channel(chrome::VersionInfo::CHANNEL_DEV);
+
+ // Use an HTTP URL.
+ std::string logo_url = "http://www.google.com/image/test.png";
+ std::string png_data = "!$#%,./nvl;iadh9oh82";
+ std::string png_base64 = "ISQjJSwuL252bDtpYWRoOW9oODI=";
+
+ FakeURLFetcherFactory factory;
+ factory.SetFakeResponse(logo_url, png_data, true);
+
+ std::string json =
+ "{ "
+ " \"topic\": {"
+ " \"answers\": ["
+ " {"
+ " \"answer_id\": \"340252\","
+ " \"name\": \"webstore_promo:15:1:" + logo_url + "\","
+ " \"question\": \"Header!\","
+ " \"inproduct_target\": \"The button label!\","
+ " \"inproduct\": \"http://link.com\","
+ " \"tooltip\": \"No thanks, hide this.\""
+ " }"
+ " ]"
+ " }"
+ "}";
+
+ scoped_ptr<DictionaryValue> test_json(static_cast<DictionaryValue*>(
+ base::JSONReader::Read(json, false)));
+
+ web_resource_service_->UnpackWebStoreSignal(*(test_json.get()));
+
+ loop_.RunAllPending();
+
+ // Reset this scoped_ptr to prevent a DCHECK.
+ web_resource_service_->apps_promo_logo_fetcher_.reset();
+
+ AppsPromo::PromoData actual_data = AppsPromo::GetPromo();
+ EXPECT_EQ("340252", actual_data.id);
+ EXPECT_EQ("Header!", actual_data.header);
+ EXPECT_EQ("The button label!", actual_data.button);
+ EXPECT_EQ(GURL("http://link.com"), actual_data.link);
+ EXPECT_EQ("No thanks, hide this.", actual_data.expire);
+ EXPECT_EQ(AppsPromo::USERS_NEW, actual_data.user_group);
+
+ // Logos should be the default values because HTTP URLs are not valid.
+ EXPECT_EQ(GURL("chrome://theme/IDR_WEBSTORE_ICON"), actual_data.logo);
+ EXPECT_EQ(GURL(""), AppsPromo::GetSourcePromoLogoURL());
+}
+
TEST_F(PromoResourceServiceTest, IsBuildTargeted) {
// canary
const chrome::VersionInfo::Channel canary =