summaryrefslogtreecommitdiffstats
path: root/chrome/browser
diff options
context:
space:
mode:
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 =