Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(3)

Unified Diff: google_apis/gcm/engine/gservices_settings.cc

Issue 288433002: G-services settings v3 implementation (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Addressing CR feedback Created 6 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « google_apis/gcm/engine/gservices_settings.h ('k') | google_apis/gcm/engine/gservices_settings_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: google_apis/gcm/engine/gservices_settings.cc
diff --git a/google_apis/gcm/engine/gservices_settings.cc b/google_apis/gcm/engine/gservices_settings.cc
index 55cfa391392373f3326e0a8d34842a4095f1e3c7..4e989724b7e7333abd7e4cf53dd64e6ee841d62a 100644
--- a/google_apis/gcm/engine/gservices_settings.cc
+++ b/google_apis/gcm/engine/gservices_settings.cc
@@ -5,7 +5,9 @@
#include "google_apis/gcm/engine/gservices_settings.h"
#include "base/bind.h"
+#include "base/sha1.h"
#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
namespace {
@@ -28,12 +30,142 @@ const int kDefaultMCSMainSecurePort = 5228;
const int kDefaultMCSFallbackSecurePort = 443;
const char kDefaultRegistrationURL[] =
"https://android.clients.google.com/c2dm/register3";
+// Settings that are to be deleted are marked with this prefix in checkin
+// response.
+const char kDeleteSettingPrefix[] = "delete_";
+// Settings digest starts with verison number followed by '-'.
+const char kDigestVersionPrefix[] = "1-";
const char kMCSEnpointTemplate[] = "https://%s:%d";
+const int kMaxSecurePort = 65535;
std::string MakeMCSEndpoint(const std::string& mcs_hostname, int port) {
return base::StringPrintf(kMCSEnpointTemplate, mcs_hostname.c_str(), port);
}
+// Default settings can be omitted, as GServicesSettings class provides
+// reasonable defaults.
+bool CanBeOmitted(const std::string& settings_name) {
+ return settings_name == kCheckinIntervalKey ||
+ settings_name == kCheckinURLKey ||
+ settings_name == kMCSHostnameKey ||
+ settings_name == kMCSSecurePortKey ||
+ settings_name == kRegistrationURLKey;
+}
+
+bool VerifyCheckinInterval(
+ const gcm::GServicesSettings::SettingsMap& settings) {
+ gcm::GServicesSettings::SettingsMap::const_iterator iter =
+ settings.find(kCheckinIntervalKey);
+ if (iter == settings.end())
+ return CanBeOmitted(kCheckinIntervalKey);
+
+ int64 checkin_interval = kMinimumCheckinInterval;
+ if (!base::StringToInt64(iter->second, &checkin_interval)) {
+ DVLOG(1) << "Failed to parse checkin interval: " << iter->second;
+ return false;
+ }
+ if (checkin_interval == std::numeric_limits<int64>::max()) {
+ DVLOG(1) << "Checkin interval is too big: " << checkin_interval;
+ return false;
+ }
+ if (checkin_interval < kMinimumCheckinInterval) {
+ DVLOG(1) << "Checkin interval: " << checkin_interval
+ << " is less than allowed minimum: " << kMinimumCheckinInterval;
+ }
+
+ return true;
+}
+
+bool VerifyMCSEndpoint(const gcm::GServicesSettings::SettingsMap& settings) {
+ std::string mcs_hostname;
+ gcm::GServicesSettings::SettingsMap::const_iterator iter =
+ settings.find(kMCSHostnameKey);
+ if (iter == settings.end()) {
+ // Because endpoint has 2 parts (hostname and port) we are defaulting and
+ // moving on with verification.
+ if (CanBeOmitted(kMCSHostnameKey))
+ mcs_hostname = kDefaultMCSHostname;
+ else
+ return false;
+ } else if (iter->second.empty()) {
+ DVLOG(1) << "Empty MCS hostname provided.";
+ return false;
+ } else {
+ mcs_hostname = iter->second;
+ }
+
+ int mcs_secure_port = 0;
+ iter = settings.find(kMCSSecurePortKey);
+ if (iter == settings.end()) {
+ // Simlarly we might have to default the port, when only hostname is
+ // provided.
+ if (CanBeOmitted(kMCSSecurePortKey))
+ mcs_secure_port = kDefaultMCSMainSecurePort;
+ else
+ return false;
+ } else if (!base::StringToInt(iter->second, &mcs_secure_port)) {
+ DVLOG(1) << "Failed to parse MCS secure port: " << iter->second;
+ return false;
+ }
+
+ if (mcs_secure_port < 0 || mcs_secure_port > kMaxSecurePort) {
+ DVLOG(1) << "Incorrect port value: " << mcs_secure_port;
+ return false;
+ }
+
+ GURL mcs_main_endpoint(MakeMCSEndpoint(mcs_hostname, mcs_secure_port));
+ if (!mcs_main_endpoint.is_valid()) {
+ DVLOG(1) << "Invalid main MCS endpoint: "
+ << mcs_main_endpoint.possibly_invalid_spec();
+ return false;
+ }
+ GURL mcs_fallback_endpoint(
+ MakeMCSEndpoint(mcs_hostname, kDefaultMCSFallbackSecurePort));
+ if (!mcs_fallback_endpoint.is_valid()) {
+ DVLOG(1) << "Invalid fallback MCS endpoint: "
+ << mcs_fallback_endpoint.possibly_invalid_spec();
+ return false;
+ }
+
+ return true;
+}
+
+bool VerifyCheckinURL(const gcm::GServicesSettings::SettingsMap& settings) {
+ gcm::GServicesSettings::SettingsMap::const_iterator iter =
+ settings.find(kCheckinURLKey);
+ if (iter == settings.end())
+ return CanBeOmitted(kCheckinURLKey);
+
+ GURL checkin_url(iter->second);
+ if (!checkin_url.is_valid()) {
+ DVLOG(1) << "Invalid checkin URL provided: " << iter->second;
+ return false;
+ }
+
+ return true;
+}
+
+bool VerifyRegistrationURL(
+ const gcm::GServicesSettings::SettingsMap& settings) {
+ gcm::GServicesSettings::SettingsMap::const_iterator iter =
+ settings.find(kRegistrationURLKey);
+ if (iter == settings.end())
+ return CanBeOmitted(kRegistrationURLKey);
+
+ GURL registration_url(iter->second);
+ if (!registration_url.is_valid()) {
+ DVLOG(1) << "Invalid registration URL provided: " << iter->second;
+ return false;
+ }
+
+ return true;
+}
+
+bool VerifySettings(const gcm::GServicesSettings::SettingsMap& settings) {
+ return VerifyCheckinInterval(settings) && VerifyMCSEndpoint(settings) &&
+ VerifyCheckinURL(settings) && VerifyRegistrationURL(settings);
+}
+
} // namespace
namespace gcm {
@@ -48,152 +180,163 @@ const GURL GServicesSettings::DefaultCheckinURL() {
return GURL(kDefaultCheckinURL);
}
-GServicesSettings::GServicesSettings()
- : checkin_interval_(base::TimeDelta::FromSeconds(kDefaultCheckinInterval)),
- checkin_url_(kDefaultCheckinURL),
- mcs_main_endpoint_(MakeMCSEndpoint(kDefaultMCSHostname,
- kDefaultMCSMainSecurePort)),
- mcs_fallback_endpoint_(MakeMCSEndpoint(kDefaultMCSHostname,
- kDefaultMCSFallbackSecurePort)),
- registration_url_(kDefaultRegistrationURL),
- weak_ptr_factory_(this) {
+// static
+std::string GServicesSettings::CalculateDigest(const SettingsMap& settings) {
+ unsigned char hash[base::kSHA1Length];
+ std::string data;
+ for (SettingsMap::const_iterator iter = settings.begin();
+ iter != settings.end();
+ ++iter) {
+ data += iter->first;
+ data += '\0';
+ data += iter->second;
+ data += '\0';
+ }
+ base::SHA1HashBytes(
+ reinterpret_cast<const unsigned char*>(&data[0]), data.size(), hash);
+ std::string digest =
+ kDigestVersionPrefix + base::HexEncode(hash, base::kSHA1Length);
+ digest = StringToLowerASCII(digest);
+ return digest;
+}
+
+GServicesSettings::GServicesSettings() : weak_ptr_factory_(this) {
+ digest_ = CalculateDigest(settings_);
}
-GServicesSettings::~GServicesSettings() {}
+GServicesSettings::~GServicesSettings() {
+}
bool GServicesSettings::UpdateFromCheckinResponse(
- const checkin_proto::AndroidCheckinResponse& checkin_response) {
- if (!checkin_response.has_digest() ||
- checkin_response.digest() == digest_) {
- // There are no changes as digest is the same or no settings provided.
+ const checkin_proto::AndroidCheckinResponse& checkin_response) {
+ if (!checkin_response.has_settings_diff()) {
+ DVLOG(1) << "Field settings_diff not set in response.";
return false;
}
- std::map<std::string, std::string> settings;
+ bool settings_diff = checkin_response.settings_diff();
+ SettingsMap new_settings;
+ // Only reuse the existing settings, if we are given a settings difference.
+ if (settings_diff)
+ new_settings = settings_map();
+
for (int i = 0; i < checkin_response.setting_size(); ++i) {
std::string name = checkin_response.setting(i).name();
- std::string value = checkin_response.setting(i).value();
- settings[name] = value;
- }
+ if (name.empty()) {
+ DVLOG(1) << "Setting name is empty";
+ return false;
+ }
- // Only update the settings in store and digest, if the settings actually
- // passed the verificaiton in update settings.
- if (UpdateSettings(settings)) {
- digest_ = checkin_response.digest();
- return true;
+ if (settings_diff && name.find(kDeleteSettingPrefix) == 0) {
+ std::string setting_to_delete =
+ name.substr(arraysize(kDeleteSettingPrefix) - 1);
+ new_settings.erase(setting_to_delete);
+ DVLOG(1) << "Setting deleted: " << setting_to_delete;
+ } else {
+ std::string value = checkin_response.setting(i).value();
+ new_settings[name] = value;
+ DVLOG(1) << "New setting: '" << name << "' : '" << value << "'";
+ }
}
- return false;
+ if (!VerifySettings(new_settings))
+ return false;
+
+ settings_.swap(new_settings);
+ digest_ = CalculateDigest(settings_);
+ return true;
}
void GServicesSettings::UpdateFromLoadResult(
const GCMStore::LoadResult& load_result) {
- if (UpdateSettings(load_result.gservices_settings))
- digest_ = load_result.gservices_digest;
-}
+ // No need to try to update settings when load_result is empty.
+ if (load_result.gservices_settings.empty())
+ return;
+ if (!VerifySettings(load_result.gservices_settings))
+ return;
+ std::string digest = CalculateDigest(load_result.gservices_settings);
+ if (digest != load_result.gservices_digest) {
+ DVLOG(1) << "G-services settings digest mismatch. "
+ << "Expected digest: " << load_result.gservices_digest
+ << ". Calculated digest is: " << digest;
+ return;
+ }
-std::map<std::string, std::string> GServicesSettings::GetSettingsMap() const {
- std::map<std::string, std::string> settings;
- settings[kCheckinIntervalKey] =
- base::Int64ToString(checkin_interval_.InSeconds());
- settings[kCheckinURLKey] = checkin_url_.spec();
- settings[kMCSHostnameKey] = mcs_main_endpoint_.host();
- settings[kMCSSecurePortKey] = mcs_main_endpoint_.port();
- settings[kRegistrationURLKey] = registration_url_.spec();
- return settings;
+ settings_ = load_result.gservices_settings;
+ digest_ = load_result.gservices_digest;
}
-bool GServicesSettings::UpdateSettings(
- const std::map<std::string, std::string>& settings) {
- int64 new_checkin_interval = kMinimumCheckinInterval;
- std::map<std::string, std::string>::const_iterator iter =
- settings.find(kCheckinIntervalKey);
- if (iter == settings.end()) {
- LOG(ERROR) << "Setting not found: " << kCheckinIntervalKey;
- return false;
- }
- if (!base::StringToInt64(iter->second, &new_checkin_interval)) {
- LOG(ERROR) << "Failed to parse checkin interval: " << iter->second;
- return false;
- }
- if (new_checkin_interval < kMinimumCheckinInterval) {
- LOG(ERROR) << "Checkin interval: " << new_checkin_interval
- << " is less than allowed minimum: " << kMinimumCheckinInterval;
- new_checkin_interval = kMinimumCheckinInterval;
- }
- if (new_checkin_interval == std::numeric_limits<int64>::max()) {
- LOG(ERROR) << "Checkin interval is too big: " << new_checkin_interval;
- return false;
+base::TimeDelta GServicesSettings::GetCheckinInterval() const {
+ int64 checkin_interval = kMinimumCheckinInterval;
+ SettingsMap::const_iterator iter = settings_.find(kCheckinIntervalKey);
+ if (iter == settings_.end() ||
+ !base::StringToInt64(iter->second, &checkin_interval)) {
+ checkin_interval = kDefaultCheckinInterval;
}
- std::string new_mcs_hostname;
- iter = settings.find(kMCSHostnameKey);
- if (iter == settings.end()) {
- LOG(ERROR) << "Setting not found: " << kMCSHostnameKey;
- return false;
- }
- new_mcs_hostname = iter->second;
- if (new_mcs_hostname.empty()) {
- LOG(ERROR) << "Empty MCS hostname provided.";
- return false;
- }
+ if (checkin_interval < kMinimumCheckinInterval)
+ checkin_interval = kMinimumCheckinInterval;
- int new_mcs_secure_port = -1;
- iter = settings.find(kMCSSecurePortKey);
- if (iter == settings.end()) {
- LOG(ERROR) << "Setting not found: " << kMCSSecurePortKey;
- return false;
- }
- if (!base::StringToInt(iter->second, &new_mcs_secure_port)) {
- LOG(ERROR) << "Failed to parse MCS secure port: " << iter->second;
- return false;
- }
- if (new_mcs_secure_port < 0 || 65535 < new_mcs_secure_port) {
- LOG(ERROR) << "Incorrect port value: " << new_mcs_secure_port;
- return false;
- }
+ return base::TimeDelta::FromSeconds(checkin_interval);
+}
- GURL new_mcs_main_endpoint =
- GURL(MakeMCSEndpoint(new_mcs_hostname, new_mcs_secure_port));
- GURL new_mcs_fallback_endpoint =
- GURL(MakeMCSEndpoint(new_mcs_hostname, kDefaultMCSFallbackSecurePort));
- if (!new_mcs_main_endpoint.is_valid() ||
- !new_mcs_fallback_endpoint.is_valid())
- return false;
+GURL GServicesSettings::GetCheckinURL() const {
+ SettingsMap::const_iterator iter = settings_.find(kCheckinURLKey);
+ if (iter == settings_.end() || iter->second.empty())
+ return GURL(kDefaultCheckinURL);
+ return GURL(iter->second);
+}
- GURL new_checkin_url;
- iter = settings.find(kCheckinURLKey);
- if (iter == settings.end()) {
- LOG(ERROR) << "Setting not found: " << kCheckinURLKey;
- return false;
- }
- new_checkin_url = GURL(iter->second);
- if (!new_checkin_url.is_valid()) {
- LOG(ERROR) << "Invalid checkin URL provided: "
- << new_checkin_url.possibly_invalid_spec();
- return false;
- }
+GURL GServicesSettings::GetMCSMainEndpoint() const {
+ // Get alternative hostname or use default.
+ std::string mcs_hostname;
+ SettingsMap::const_iterator iter = settings_.find(kMCSHostnameKey);
+ if (iter != settings_.end() && !iter->second.empty())
+ mcs_hostname = iter->second;
+ else
+ mcs_hostname = kDefaultMCSHostname;
- GURL new_registration_url;
- iter = settings.find(kRegistrationURLKey);
- if (iter == settings.end()) {
- LOG(ERROR) << "Setting not found: " << kRegistrationURLKey;
- return false;
- }
- new_registration_url = GURL(iter->second);
- if (!new_registration_url.is_valid()) {
- LOG(ERROR) << "Invalid registration URL provided: "
- << new_registration_url.possibly_invalid_spec();
- return false;
+ // Get alternative secure port or use defualt.
+ int mcs_secure_port = 0;
+ iter = settings_.find(kMCSSecurePortKey);
+ if (iter == settings_.end() || iter->second.empty() ||
+ !base::StringToInt(iter->second, &mcs_secure_port)) {
+ mcs_secure_port = kDefaultMCSMainSecurePort;
}
- // We only update the settings once all of them are correct.
- checkin_interval_ = base::TimeDelta::FromSeconds(new_checkin_interval);
- mcs_main_endpoint_ = new_mcs_main_endpoint;
- mcs_fallback_endpoint_ = new_mcs_fallback_endpoint;
- checkin_url_ = new_checkin_url;
- registration_url_ = new_registration_url;
- return true;
+ // If constructed address makes sense use it.
+ GURL mcs_endpoint(MakeMCSEndpoint(mcs_hostname, mcs_secure_port));
+ if (mcs_endpoint.is_valid())
+ return mcs_endpoint;
+
+ // Otherwise use default settings.
+ return GURL(MakeMCSEndpoint(kDefaultMCSHostname, kDefaultMCSMainSecurePort));
+}
+
+GURL GServicesSettings::GetMCSFallbackEndpoint() const {
+ // Get alternative hostname or use default.
+ std::string mcs_hostname;
+ SettingsMap::const_iterator iter = settings_.find(kMCSHostnameKey);
+ if (iter != settings_.end() && !iter->second.empty())
+ mcs_hostname = iter->second;
+ else
+ mcs_hostname = kDefaultMCSHostname;
+
+ // If constructed address makes sense use it.
+ GURL mcs_endpoint(
+ MakeMCSEndpoint(mcs_hostname, kDefaultMCSFallbackSecurePort));
+ if (mcs_endpoint.is_valid())
+ return mcs_endpoint;
+
+ return GURL(
+ MakeMCSEndpoint(kDefaultMCSHostname, kDefaultMCSFallbackSecurePort));
+}
+
+GURL GServicesSettings::GetRegistrationURL() const {
+ SettingsMap::const_iterator iter = settings_.find(kRegistrationURLKey);
+ if (iter == settings_.end() || iter->second.empty())
+ return GURL(kDefaultRegistrationURL);
+ return GURL(iter->second);
}
} // namespace gcm
« no previous file with comments | « google_apis/gcm/engine/gservices_settings.h ('k') | google_apis/gcm/engine/gservices_settings_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698