blob: 4909212fcdb9505e7ace7ff3dd76208f35cbe47c [file] [log] [blame]
jianli7a0c9b62015-05-26 23:24:471// 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
5#include "components/gcm_driver/registration_info.h"
6
avi26062922015-12-26 00:14:187#include <stddef.h>
8
brettwb45192d2015-06-29 22:53:249#include "base/strings/string_split.h"
jianli7a0c9b62015-05-26 23:24:4710#include "base/strings/string_util.h"
11
12namespace gcm {
13
14namespace {
johnme627dc8c72016-08-19 21:49:3915const char kInstanceIDSerializationPrefix[] = "iid-";
16const int kInstanceIDSerializationPrefixLength =
17 sizeof(kInstanceIDSerializationPrefix) / sizeof(char) - 1;
jianli7a0c9b62015-05-26 23:24:4718} // namespace
19
20// static
dchenga77e28eb2016-04-21 21:34:3721std::unique_ptr<RegistrationInfo> RegistrationInfo::BuildFromString(
johnmedc5ddc42015-09-17 14:16:4422 const std::string& serialized_key,
23 const std::string& serialized_value,
jianli7a0c9b62015-05-26 23:24:4724 std::string* registration_id) {
dchenga77e28eb2016-04-21 21:34:3725 std::unique_ptr<RegistrationInfo> registration;
jianli7a0c9b62015-05-26 23:24:4726
johnme627dc8c72016-08-19 21:49:3927 if (base::StartsWith(serialized_key, kInstanceIDSerializationPrefix,
brettw95509312015-07-16 23:57:3328 base::CompareCase::SENSITIVE))
jianli7a0c9b62015-05-26 23:24:4729 registration.reset(new InstanceIDTokenInfo);
30 else
31 registration.reset(new GCMRegistrationInfo);
32
johnmedc5ddc42015-09-17 14:16:4433 if (!registration->Deserialize(serialized_key,
34 serialized_value,
jianli7a0c9b62015-05-26 23:24:4735 registration_id)) {
36 registration.reset();
37 }
dcheng51606352015-12-26 21:16:2338 return registration;
jianli7a0c9b62015-05-26 23:24:4739}
40
41RegistrationInfo::RegistrationInfo() {
42}
43
44RegistrationInfo::~RegistrationInfo() {
45}
46
47// static
48const GCMRegistrationInfo* GCMRegistrationInfo::FromRegistrationInfo(
49 const RegistrationInfo* registration_info) {
50 if (!registration_info || registration_info->GetType() != GCM_REGISTRATION)
Ivan Kotenkov75b1c3a2017-10-24 14:47:2451 return nullptr;
jianli7a0c9b62015-05-26 23:24:4752 return static_cast<const GCMRegistrationInfo*>(registration_info);
53}
54
55// static
56GCMRegistrationInfo* GCMRegistrationInfo::FromRegistrationInfo(
57 RegistrationInfo* registration_info) {
58 if (!registration_info || registration_info->GetType() != GCM_REGISTRATION)
Ivan Kotenkov75b1c3a2017-10-24 14:47:2459 return nullptr;
jianli7a0c9b62015-05-26 23:24:4760 return static_cast<GCMRegistrationInfo*>(registration_info);
61}
62
63GCMRegistrationInfo::GCMRegistrationInfo() {
64}
65
66GCMRegistrationInfo::~GCMRegistrationInfo() {
67}
68
69RegistrationInfo::RegistrationType GCMRegistrationInfo::GetType() const {
70 return GCM_REGISTRATION;
71}
72
73std::string GCMRegistrationInfo::GetSerializedKey() const {
74 // Multiple registrations are not supported for legacy GCM. So the key is
75 // purely based on the application id.
76 return app_id;
77}
78
79std::string GCMRegistrationInfo::GetSerializedValue(
80 const std::string& registration_id) const {
81 if (sender_ids.empty() || registration_id.empty())
82 return std::string();
83
84 // Serialize as:
85 // sender1,sender2,...=reg_id
86 std::string value;
87 for (std::vector<std::string>::const_iterator iter = sender_ids.begin();
88 iter != sender_ids.end(); ++iter) {
89 DCHECK(!iter->empty() &&
90 iter->find(',') == std::string::npos &&
91 iter->find('=') == std::string::npos);
92 if (!value.empty())
93 value += ",";
94 value += *iter;
95 }
96
97 value += '=';
98 value += registration_id;
99 return value;
100}
101
102bool GCMRegistrationInfo::Deserialize(
johnmedc5ddc42015-09-17 14:16:44103 const std::string& serialized_key,
104 const std::string& serialized_value,
jianli7a0c9b62015-05-26 23:24:47105 std::string* registration_id) {
johnmedc5ddc42015-09-17 14:16:44106 if (serialized_key.empty() || serialized_value.empty())
jianli7a0c9b62015-05-26 23:24:47107 return false;
108
109 // Application ID is same as the serialized key.
johnmedc5ddc42015-09-17 14:16:44110 app_id = serialized_key;
jianli7a0c9b62015-05-26 23:24:47111
112 // Sender IDs and registration ID are constructed from the serialized value.
johnmedc5ddc42015-09-17 14:16:44113 size_t pos = serialized_value.find('=');
jianli7a0c9b62015-05-26 23:24:47114 if (pos == std::string::npos)
115 return false;
116
johnmedc5ddc42015-09-17 14:16:44117 std::string senders = serialized_value.substr(0, pos);
118 std::string registration_id_str = serialized_value.substr(pos + 1);
jianli7a0c9b62015-05-26 23:24:47119
brettwb45192d2015-06-29 22:53:24120 sender_ids = base::SplitString(
121 senders, ",", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
jianli7a0c9b62015-05-26 23:24:47122 if (sender_ids.empty() || registration_id_str.empty()) {
123 sender_ids.clear();
124 registration_id_str.clear();
125 return false;
126 }
127
128 if (registration_id)
129 *registration_id = registration_id_str;
130
131 return true;
132}
133
134// static
135const InstanceIDTokenInfo* InstanceIDTokenInfo::FromRegistrationInfo(
136 const RegistrationInfo* registration_info) {
137 if (!registration_info || registration_info->GetType() != INSTANCE_ID_TOKEN)
Ivan Kotenkov75b1c3a2017-10-24 14:47:24138 return nullptr;
jianli7a0c9b62015-05-26 23:24:47139 return static_cast<const InstanceIDTokenInfo*>(registration_info);
140}
141
142// static
143InstanceIDTokenInfo* InstanceIDTokenInfo::FromRegistrationInfo(
144 RegistrationInfo* registration_info) {
145 if (!registration_info || registration_info->GetType() != INSTANCE_ID_TOKEN)
Ivan Kotenkov75b1c3a2017-10-24 14:47:24146 return nullptr;
jianli7a0c9b62015-05-26 23:24:47147 return static_cast<InstanceIDTokenInfo*>(registration_info);
148}
149
150InstanceIDTokenInfo::InstanceIDTokenInfo() {
151}
152
153InstanceIDTokenInfo::~InstanceIDTokenInfo() {
154}
155
156RegistrationInfo::RegistrationType InstanceIDTokenInfo::GetType() const {
157 return INSTANCE_ID_TOKEN;
158}
159
160std::string InstanceIDTokenInfo::GetSerializedKey() const {
johnme627dc8c72016-08-19 21:49:39161 DCHECK(app_id.find(',') == std::string::npos &&
162 authorized_entity.find(',') == std::string::npos &&
jianli7a0c9b62015-05-26 23:24:47163 scope.find(',') == std::string::npos);
164
165 // Multiple registrations are supported for Instance ID. So the key is based
166 // on the combination of (app_id, authorized_entity, scope).
167
168 // Adds a prefix to differentiate easily with GCM registration key.
johnme627dc8c72016-08-19 21:49:39169 std::string key(kInstanceIDSerializationPrefix);
jianli7a0c9b62015-05-26 23:24:47170 key += app_id;
171 key += ",";
172 key += authorized_entity;
173 key += ",";
174 key += scope;
175 return key;
176}
177
178std::string InstanceIDTokenInfo::GetSerializedValue(
179 const std::string& registration_id) const {
180 return registration_id;
181}
182
183bool InstanceIDTokenInfo::Deserialize(
184 const std::string& serialized_key,
185 const std::string& serialized_value,
186 std::string* registration_id) {
187 if (serialized_key.empty() || serialized_value.empty())
188 return false;
189
johnme627dc8c72016-08-19 21:49:39190 if (!base::StartsWith(serialized_key, kInstanceIDSerializationPrefix,
brettw95509312015-07-16 23:57:33191 base::CompareCase::SENSITIVE))
jianli7a0c9b62015-05-26 23:24:47192 return false;
193
brettwb45192d2015-06-29 22:53:24194 std::vector<std::string> fields = base::SplitString(
johnme627dc8c72016-08-19 21:49:39195 serialized_key.substr(kInstanceIDSerializationPrefixLength), ",",
196 base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
jianli7a0c9b62015-05-26 23:24:47197 if (fields.size() != 3 || fields[0].empty() ||
198 fields[1].empty() || fields[2].empty()) {
199 return false;
200 }
201 app_id = fields[0];
202 authorized_entity = fields[1];
203 scope = fields[2];
204
205 // Registration ID is same as the serialized value;
206 if (registration_id)
207 *registration_id = serialized_value;
208
209 return true;
210}
211
212bool RegistrationInfoComparer::operator()(
213 const linked_ptr<RegistrationInfo>& a,
214 const linked_ptr<RegistrationInfo>& b) const {
215 DCHECK(a.get() && b.get());
216
217 // For GCMRegistrationInfo, the comparison is based on app_id only.
johnme627dc8c72016-08-19 21:49:39218 // For InstanceIDTokenInfo, the comparison is based on
jianli7a0c9b62015-05-26 23:24:47219 // <app_id, authorized_entity, scope>.
220 if (a->app_id < b->app_id)
221 return true;
222 if (a->app_id > b->app_id)
223 return false;
224
225 InstanceIDTokenInfo* iid_a =
226 InstanceIDTokenInfo::FromRegistrationInfo(a.get());
227 InstanceIDTokenInfo* iid_b =
228 InstanceIDTokenInfo::FromRegistrationInfo(b.get());
229
230 // !iid_a && !iid_b => false.
231 // !iid_a && iid_b => true.
232 // This makes GCM record is sorted before InstanceID record.
233 if (!iid_a)
Ivan Kotenkov75b1c3a2017-10-24 14:47:24234 return iid_b != nullptr;
jianli7a0c9b62015-05-26 23:24:47235
236 // iid_a && !iid_b => false.
237 if (!iid_b)
238 return false;
239
240 // Otherwise, compare with authorized_entity and scope.
241 if (iid_a->authorized_entity < iid_b->authorized_entity)
242 return true;
243 if (iid_a->authorized_entity > iid_b->authorized_entity)
244 return false;
245 return iid_a->scope < iid_b->scope;
246}
247
248bool ExistsGCMRegistrationInMap(const RegistrationInfoMap& map,
249 const std::string& app_id) {
dchenga77e28eb2016-04-21 21:34:37250 std::unique_ptr<GCMRegistrationInfo> gcm_registration(
251 new GCMRegistrationInfo);
jianli7a0c9b62015-05-26 23:24:47252 gcm_registration->app_id = app_id;
253 return map.count(
254 make_linked_ptr<RegistrationInfo>(gcm_registration.release())) > 0;
255}
256
257} // namespace gcm