registration_info.cc 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  1. // Copyright 2015 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "components/gcm_driver/registration_info.h"
  5. #include <stddef.h>
  6. #include "base/format_macros.h"
  7. #include "base/strings/string_number_conversions.h"
  8. #include "base/strings/string_split.h"
  9. #include "base/strings/string_util.h"
  10. #include "base/strings/stringprintf.h"
  11. namespace gcm {
  12. namespace {
  13. constexpr char kInstanceIDSerializationPrefix[] = "iid-";
  14. constexpr char kSerializedValidationTimeSeparator = '#';
  15. constexpr char kSerializedKeySeparator = ',';
  16. constexpr int kInstanceIDSerializationPrefixLength =
  17. sizeof(kInstanceIDSerializationPrefix) / sizeof(char) - 1;
  18. } // namespace
  19. // static
  20. scoped_refptr<RegistrationInfo> RegistrationInfo::BuildFromString(
  21. const std::string& serialized_key,
  22. const std::string& serialized_value,
  23. std::string* registration_id) {
  24. scoped_refptr<RegistrationInfo> registration;
  25. if (base::StartsWith(serialized_key, kInstanceIDSerializationPrefix,
  26. base::CompareCase::SENSITIVE)) {
  27. registration = base::MakeRefCounted<InstanceIDTokenInfo>();
  28. } else {
  29. registration = base::MakeRefCounted<GCMRegistrationInfo>();
  30. }
  31. if (!registration->Deserialize(serialized_key, serialized_value,
  32. registration_id)) {
  33. registration.reset();
  34. }
  35. return registration;
  36. }
  37. RegistrationInfo::RegistrationInfo() = default;
  38. RegistrationInfo::~RegistrationInfo() = default;
  39. // static
  40. const GCMRegistrationInfo* GCMRegistrationInfo::FromRegistrationInfo(
  41. const RegistrationInfo* registration_info) {
  42. if (!registration_info || registration_info->GetType() != GCM_REGISTRATION)
  43. return nullptr;
  44. return static_cast<const GCMRegistrationInfo*>(registration_info);
  45. }
  46. // static
  47. GCMRegistrationInfo* GCMRegistrationInfo::FromRegistrationInfo(
  48. RegistrationInfo* registration_info) {
  49. if (!registration_info || registration_info->GetType() != GCM_REGISTRATION)
  50. return nullptr;
  51. return static_cast<GCMRegistrationInfo*>(registration_info);
  52. }
  53. GCMRegistrationInfo::GCMRegistrationInfo() = default;
  54. GCMRegistrationInfo::~GCMRegistrationInfo() = default;
  55. RegistrationInfo::RegistrationType GCMRegistrationInfo::GetType() const {
  56. return GCM_REGISTRATION;
  57. }
  58. std::string GCMRegistrationInfo::GetSerializedKey() const {
  59. // Multiple registrations are not supported for legacy GCM. So the key is
  60. // purely based on the application id.
  61. return app_id;
  62. }
  63. std::string GCMRegistrationInfo::GetSerializedValue(
  64. const std::string& registration_id) const {
  65. if (sender_ids.empty() || registration_id.empty())
  66. return std::string();
  67. // Serialize as:
  68. // sender1,sender2,...=reg_id#time_of_last_validation
  69. std::string value;
  70. for (auto iter = sender_ids.begin(); iter != sender_ids.end(); ++iter) {
  71. DCHECK(!iter->empty() &&
  72. iter->find(',') == std::string::npos &&
  73. iter->find('=') == std::string::npos);
  74. if (!value.empty())
  75. value += ",";
  76. value += *iter;
  77. }
  78. return base::StringPrintf("%s=%s%c%" PRId64, value.c_str(),
  79. registration_id.c_str(),
  80. kSerializedValidationTimeSeparator,
  81. last_validated.since_origin().InMicroseconds());
  82. }
  83. bool GCMRegistrationInfo::Deserialize(const std::string& serialized_key,
  84. const std::string& serialized_value,
  85. std::string* registration_id) {
  86. if (serialized_key.empty() || serialized_value.empty())
  87. return false;
  88. // Application ID is same as the serialized key.
  89. app_id = serialized_key;
  90. // Sender IDs and registration ID are constructed from the serialized value.
  91. size_t pos_equals = serialized_value.find('=');
  92. if (pos_equals == std::string::npos)
  93. return false;
  94. // Note that it's valid for pos_hash to be std::string::npos.
  95. size_t pos_hash = serialized_value.find(kSerializedValidationTimeSeparator);
  96. bool has_timestamp = pos_hash != std::string::npos;
  97. std::string senders = serialized_value.substr(0, pos_equals);
  98. std::string registration_id_str, last_validated_str;
  99. if (has_timestamp) {
  100. registration_id_str =
  101. serialized_value.substr(pos_equals + 1, pos_hash - pos_equals - 1);
  102. last_validated_str = serialized_value.substr(pos_hash + 1);
  103. } else {
  104. registration_id_str = serialized_value.substr(pos_equals + 1);
  105. }
  106. sender_ids = base::SplitString(
  107. senders, ",", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
  108. if (sender_ids.empty() || registration_id_str.empty()) {
  109. sender_ids.clear();
  110. registration_id_str.clear();
  111. return false;
  112. }
  113. if (registration_id)
  114. *registration_id = registration_id_str;
  115. int64_t last_validated_ms = 0;
  116. if (base::StringToInt64(last_validated_str, &last_validated_ms)) {
  117. // It's okay for |last_validated| to be the default base::Time() value
  118. // when there is no serialized timestamp value available.
  119. last_validated = base::Time() + base::Microseconds(last_validated_ms);
  120. }
  121. return true;
  122. }
  123. // static
  124. const InstanceIDTokenInfo* InstanceIDTokenInfo::FromRegistrationInfo(
  125. const RegistrationInfo* registration_info) {
  126. if (!registration_info || registration_info->GetType() != INSTANCE_ID_TOKEN)
  127. return nullptr;
  128. return static_cast<const InstanceIDTokenInfo*>(registration_info);
  129. }
  130. // static
  131. InstanceIDTokenInfo* InstanceIDTokenInfo::FromRegistrationInfo(
  132. RegistrationInfo* registration_info) {
  133. if (!registration_info || registration_info->GetType() != INSTANCE_ID_TOKEN)
  134. return nullptr;
  135. return static_cast<InstanceIDTokenInfo*>(registration_info);
  136. }
  137. InstanceIDTokenInfo::InstanceIDTokenInfo() = default;
  138. InstanceIDTokenInfo::~InstanceIDTokenInfo() = default;
  139. RegistrationInfo::RegistrationType InstanceIDTokenInfo::GetType() const {
  140. return INSTANCE_ID_TOKEN;
  141. }
  142. std::string InstanceIDTokenInfo::GetSerializedKey() const {
  143. DCHECK(app_id.find(',') == std::string::npos &&
  144. authorized_entity.find(',') == std::string::npos &&
  145. scope.find(',') == std::string::npos);
  146. // Multiple registrations are supported for Instance ID. So the key is based
  147. // on the combination of (app_id, authorized_entity, scope).
  148. // Adds a prefix to differentiate easily with GCM registration key.
  149. return base::StringPrintf("%s%s%c%s%c%s", kInstanceIDSerializationPrefix,
  150. app_id.c_str(), kSerializedKeySeparator,
  151. authorized_entity.c_str(), kSerializedKeySeparator,
  152. scope.c_str());
  153. }
  154. std::string InstanceIDTokenInfo::GetSerializedValue(
  155. const std::string& registration_id) const {
  156. int64_t last_validated_ms = last_validated.since_origin().InMicroseconds();
  157. return registration_id + kSerializedValidationTimeSeparator +
  158. base::NumberToString(last_validated_ms);
  159. }
  160. bool InstanceIDTokenInfo::Deserialize(const std::string& serialized_key,
  161. const std::string& serialized_value,
  162. std::string* registration_id) {
  163. if (serialized_key.empty() || serialized_value.empty())
  164. return false;
  165. if (!base::StartsWith(serialized_key, kInstanceIDSerializationPrefix,
  166. base::CompareCase::SENSITIVE))
  167. return false;
  168. std::vector<std::string> fields = base::SplitString(
  169. serialized_key.substr(kInstanceIDSerializationPrefixLength), ",",
  170. base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
  171. if (fields.size() != 3 || fields[0].empty() ||
  172. fields[1].empty() || fields[2].empty()) {
  173. return false;
  174. }
  175. app_id = fields[0];
  176. authorized_entity = fields[1];
  177. scope = fields[2];
  178. // Get Registration ID and last_validated from serialized value
  179. size_t pos_hash = serialized_value.find(kSerializedValidationTimeSeparator);
  180. bool has_timestamp = (pos_hash != std::string::npos);
  181. std::string registration_id_str, last_validated_str;
  182. if (has_timestamp) {
  183. registration_id_str = serialized_value.substr(0, pos_hash);
  184. last_validated_str = serialized_value.substr(pos_hash + 1);
  185. } else {
  186. registration_id_str = serialized_value;
  187. }
  188. if (registration_id)
  189. *registration_id = registration_id_str;
  190. int64_t last_validated_ms = 0;
  191. if (base::StringToInt64(last_validated_str, &last_validated_ms)) {
  192. // It's okay for last_validated to be the default base::Time() value
  193. // when there is no serialized timestamp available.
  194. last_validated += base::Microseconds(last_validated_ms);
  195. }
  196. return true;
  197. }
  198. bool RegistrationInfoComparer::operator()(
  199. const scoped_refptr<RegistrationInfo>& a,
  200. const scoped_refptr<RegistrationInfo>& b) const {
  201. DCHECK(a.get() && b.get());
  202. // For GCMRegistrationInfo, the comparison is based on app_id only.
  203. // For InstanceIDTokenInfo, the comparison is based on
  204. // <app_id, authorized_entity, scope>.
  205. if (a->app_id < b->app_id)
  206. return true;
  207. if (a->app_id > b->app_id)
  208. return false;
  209. InstanceIDTokenInfo* iid_a =
  210. InstanceIDTokenInfo::FromRegistrationInfo(a.get());
  211. InstanceIDTokenInfo* iid_b =
  212. InstanceIDTokenInfo::FromRegistrationInfo(b.get());
  213. // !iid_a && !iid_b => false.
  214. // !iid_a && iid_b => true.
  215. // This makes GCM record is sorted before InstanceID record.
  216. if (!iid_a)
  217. return iid_b != nullptr;
  218. // iid_a && !iid_b => false.
  219. if (!iid_b)
  220. return false;
  221. // Otherwise, compare with authorized_entity and scope.
  222. if (iid_a->authorized_entity < iid_b->authorized_entity)
  223. return true;
  224. if (iid_a->authorized_entity > iid_b->authorized_entity)
  225. return false;
  226. return iid_a->scope < iid_b->scope;
  227. }
  228. bool ExistsGCMRegistrationInMap(const RegistrationInfoMap& map,
  229. const std::string& app_id) {
  230. scoped_refptr<RegistrationInfo> gcm_registration =
  231. base::MakeRefCounted<GCMRegistrationInfo>();
  232. gcm_registration->app_id = app_id;
  233. return map.find(gcm_registration) != map.end();
  234. }
  235. } // namespace gcm