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

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: 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
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..ac070fbd3433f2f9013c50708acf4acf1e1e9bb9 100644
--- a/google_apis/gcm/engine/gservices_settings.cc
+++ b/google_apis/gcm/engine/gservices_settings.cc
@@ -5,6 +5,7 @@
#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/stringprintf.h"
@@ -28,12 +29,23 @@ const int kDefaultMCSMainSecurePort = 5228;
const int kDefaultMCSFallbackSecurePort = 443;
const char kDefaultRegistrationURL[] =
"https://android.clients.google.com/c2dm/register3";
+const char kDeleteSettingPrefix[] = "delete_";
+const char kDigestVersionPrefix[] = "1-";
const char kMCSEnpointTemplate[] = "https://%s:%d";
std::string MakeMCSEndpoint(const std::string& mcs_hostname, int port) {
return base::StringPrintf(kMCSEnpointTemplate, mcs_hostname.c_str(), port);
}
+GURL DefaultMainMCSEndpoint() {
+ return GURL(MakeMCSEndpoint(kDefaultMCSHostname, kDefaultMCSMainSecurePort));
+}
+
+GURL DefaultFallbackMCSEndpoint() {
+ return GURL(
+ MakeMCSEndpoint(kDefaultMCSHostname, kDefaultMCSFallbackSecurePort));
+}
+
} // namespace
namespace gcm {
@@ -48,151 +60,281 @@ 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) {
+ char hash[base::kSHA1Length];
jianli 2014/05/13 21:41:52 Why not defining this as unsigned char array?
fgorski 2014/05/13 23:53:28 Done.
+ std::vector<char> data;
jianli 2014/05/13 21:41:52 It seems to be easier to use std::string, like:
fgorski 2014/05/13 23:53:28 Done.
+ for (SettingsMap::const_iterator iter = settings.begin();
+ iter != settings.end();
+ ++iter) {
+ data.insert(data.end(), iter->first.begin(), iter->first.end());
+ data.push_back((char)0);
jianli 2014/05/13 21:41:52 nit: '\0' to replace c type conversion
fgorski 2014/05/13 23:53:28 Done.
+ data.insert(data.end(), iter->second.begin(), iter->second.end());
+ data.push_back((char)0);
+ }
+ base::SHA1HashBytes(reinterpret_cast<const unsigned char*>(&data[0]),
+ data.size(),
+ reinterpret_cast<unsigned char*>(hash));
+ return kDigestVersionPrefix + base::HexEncode(hash, base::kSHA1Length);
jianli 2014/05/13 21:41:52 Just to confirm that this is not base64 encoded, r
fgorski 2014/05/13 23:53:28 HEX is expected.
+}
+
+GServicesSettings::GServicesSettings() : weak_ptr_factory_(this) {
+ settings_[kCheckinIntervalKey] = base::Int64ToString(kDefaultCheckinInterval);
+ settings_[kCheckinURLKey] = kDefaultCheckinURL;
+ settings_[kMCSHostnameKey] = kDefaultMCSHostname;
+ settings_[kMCSSecurePortKey] = base::IntToString(kDefaultMCSMainSecurePort);
+ settings_[kRegistrationURLKey] = kDefaultRegistrationURL;
+ digest_ = CalculateDigest(settings_);
}
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()) {
+ LOG(ERROR) << "Field settings_diff not set in response.";
return false;
}
- std::map<std::string, std::string> settings;
+ if (!checkin_response.has_digest()) {
+ LOG(ERROR) << "Field digest not set in response.";
+ return false;
+ }
+
+ 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 = GetSettingsMap();
+
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 (settings_diff && name.find(kDeleteSettingPrefix) == 0) {
jianli 2014/05/13 21:41:52 Consider adding the check for empty name.
fgorski 2014/05/13 23:53:28 Done.
+ std::string setting_to_delete =
+ name.substr(arraysize(kDeleteSettingPrefix));
+ new_settings.erase(setting_to_delete);
+ } else {
+ new_settings[name] = value;
+ }
}
- // 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 (!VerifySettings(new_settings))
+ return false;
+
+ std::string digest = CalculateDigest(new_settings);
+ if (digest != checkin_response.digest()) {
+ LOG(ERROR) << "Calculated digest does not match the original digest.";
jianli 2014/05/13 21:41:52 nit: combine all 3 logs into one, like: LOG(ERRO
fgorski 2014/05/13 23:53:28 Done.
+ LOG(ERROR) << "Expected G-Services settings digest: "
+ << checkin_response.digest();
+ LOG(ERROR) << "Calculated G-services settings digest: " << digest;
+ return false;
}
- return false;
+ if (digest == digest_)
+ return false;
+
+ settings_ = new_settings;
jianli 2014/05/13 21:41:52 nit: use swap for efficiency
fgorski 2014/05/13 23:53:28 Done.
+ digest_ = digest;
+ return true;
}
void GServicesSettings::UpdateFromLoadResult(
const GCMStore::LoadResult& load_result) {
- if (UpdateSettings(load_result.gservices_settings))
+ if (VerifySettings(load_result.gservices_settings) &&
+ VerifyDigest(load_result.gservices_settings,
+ load_result.gservices_digest)) {
+ settings_ = load_result.gservices_settings;
digest_ = load_result.gservices_digest;
+ }
+}
+
+GServicesSettings::SettingsMap GServicesSettings::GetSettingsMap() const {
jianli 2014/05/13 21:41:52 This can be defined as getter now.
fgorski 2014/05/13 23:53:28 Done.
+ return settings_;
+}
+
+base::TimeDelta GServicesSettings::checkin_interval() 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;
+ }
+
+ if (checkin_interval < kMinimumCheckinInterval)
+ checkin_interval = kMinimumCheckinInterval;
+
+ return base::TimeDelta::FromSeconds(checkin_interval);
+}
+
+GURL GServicesSettings::checkin_url() const {
+ SettingsMap::const_iterator iter = settings_.find(kCheckinURLKey);
+ if (iter == settings_.end() || iter->second.empty())
+ return GURL(kDefaultCheckinURL);
+ return GURL(iter->second);
+}
+
+GURL GServicesSettings::mcs_main_endpoint() const {
+ SettingsMap::const_iterator iter = settings_.find(kMCSHostnameKey);
+ if (iter == settings_.end() || iter->second.empty())
+ return DefaultMainMCSEndpoint();
+
+ std::string mcs_hostname = iter->second;
+
+ iter = settings_.find(kMCSSecurePortKey);
+ int mcs_secure_port = kDefaultMCSMainSecurePort;
+ if (iter == settings_.end() || iter->second.empty() ||
+ !base::StringToInt(iter->second, &mcs_secure_port))
+ return DefaultMainMCSEndpoint();
+
+ GURL mcs_endpoint(MakeMCSEndpoint(mcs_hostname, mcs_secure_port));
+
+ if (!mcs_endpoint.is_valid())
+ return DefaultMainMCSEndpoint();
+
+ return mcs_endpoint;
+}
+
+GURL GServicesSettings::mcs_fallback_endpoint() const {
+ SettingsMap::const_iterator iter = settings_.find(kMCSHostnameKey);
+ if (iter == settings_.end() || iter->second.empty())
+ return DefaultFallbackMCSEndpoint();
+
+ GURL mcs_endpoint(
+ MakeMCSEndpoint(iter->second, kDefaultMCSFallbackSecurePort));
+
+ if (!mcs_endpoint.is_valid())
+ return DefaultFallbackMCSEndpoint();
+
+ return mcs_endpoint;
}
-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;
+GURL GServicesSettings::registration_url() const {
+ SettingsMap::const_iterator iter = settings_.find(kRegistrationURLKey);
+ if (iter == settings_.end() || iter->second.empty())
+ return GURL(kDefaultRegistrationURL);
+ return GURL(iter->second);
}
-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);
+bool GServicesSettings::VerifyCheckinInterval(
+ const SettingsMap& settings) const {
+ SettingsMap::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)) {
+ int64 checkin_interval = kMinimumCheckinInterval;
+ if (!base::StringToInt64(iter->second, &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;
+ if (checkin_interval == std::numeric_limits<int64>::max()) {
+ LOG(ERROR) << "Checkin interval is too big: " << checkin_interval;
return false;
}
+ if (checkin_interval < kMinimumCheckinInterval) {
+ // This is emited as an error, but is not mean to fail verification.
+ LOG(ERROR) << "Checkin interval: " << checkin_interval
+ << " is less than allowed minimum: " << kMinimumCheckinInterval;
+ }
- std::string new_mcs_hostname;
- iter = settings.find(kMCSHostnameKey);
+ return true;
+}
+
+bool GServicesSettings::VerifyMCSEndpoint(const SettingsMap& settings) const {
+ SettingsMap::const_iterator iter = settings.find(kMCSHostnameKey);
+ std::string mcs_hostname;
if (iter == settings.end()) {
LOG(ERROR) << "Setting not found: " << kMCSHostnameKey;
return false;
}
- new_mcs_hostname = iter->second;
- if (new_mcs_hostname.empty()) {
+ mcs_hostname = iter->second;
+ if (iter->second.empty()) {
LOG(ERROR) << "Empty MCS hostname provided.";
return false;
}
- int new_mcs_secure_port = -1;
+ int 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)) {
+ if (!base::StringToInt(iter->second, &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;
+ if (mcs_secure_port < 0 || 65535 < mcs_secure_port) {
+ LOG(ERROR) << "Incorrect port value: " << mcs_secure_port;
return false;
}
- 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())
+ GURL mcs_main_endpoint(MakeMCSEndpoint(mcs_hostname, mcs_secure_port));
+ if (!mcs_main_endpoint.is_valid()) {
+ LOG(ERROR) << "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()) {
+ LOG(ERROR) << "Invalid fallback MCS endpoint: "
+ << mcs_fallback_endpoint.possibly_invalid_spec();
return false;
+ }
+
+ return true;
+}
- GURL new_checkin_url;
- iter = settings.find(kCheckinURLKey);
+bool GServicesSettings::VerifyCheckinURL(const SettingsMap& settings) const {
jianli 2014/05/13 21:41:52 It seems that this could be defined as static meth
fgorski 2014/05/13 23:53:28 Done.
+ SettingsMap::const_iterator 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()) {
+ GURL checkin_url(iter->second);
+ if (!checkin_url.is_valid()) {
LOG(ERROR) << "Invalid checkin URL provided: "
- << new_checkin_url.possibly_invalid_spec();
+ << checkin_url.possibly_invalid_spec();
return false;
}
- GURL new_registration_url;
- iter = settings.find(kRegistrationURLKey);
+ return true;
+}
+
+bool GServicesSettings::VerifyRegistrationURL(
+ const SettingsMap& settings) const {
+ SettingsMap::const_iterator 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()) {
+ GURL registration_url(iter->second);
+ if (!registration_url.is_valid()) {
LOG(ERROR) << "Invalid registration URL provided: "
- << new_registration_url.possibly_invalid_spec();
+ << registration_url.possibly_invalid_spec();
+ return false;
+ }
+
+ return true;
+}
+
+bool GServicesSettings::VerifySettings(const SettingsMap& settings) const {
+ return VerifyCheckinInterval(settings) && VerifyMCSEndpoint(settings) &&
+ VerifyCheckinURL(settings) && VerifyRegistrationURL(settings);
+}
+
+bool GServicesSettings::VerifyDigest(const SettingsMap& settings,
+ const std::string& expected_digest) const {
+ std::string calculated_digest = CalculateDigest(settings);
+ if (calculated_digest != expected_digest) {
+ LOG(ERROR) << "Calculated digest does not match the original digest.";
+ LOG(ERROR) << "Expected G-Services settings digest: " << expected_digest;
+ LOG(ERROR) << "Calculated G-services settings digest: "
+ << calculated_digest;
return false;
}
- // 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;
}

Powered by Google App Engine
This is Rietveld 408576698