jianli | 7a0c9b6 | 2015-05-26 23:24:47 | [diff] [blame] | 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 | |
| 5 | #include "components/gcm_driver/registration_info.h" |
| 6 | |
avi | 2606292 | 2015-12-26 00:14:18 | [diff] [blame] | 7 | #include <stddef.h> |
| 8 | |
brettw | b45192d | 2015-06-29 22:53:24 | [diff] [blame] | 9 | #include "base/strings/string_split.h" |
jianli | 7a0c9b6 | 2015-05-26 23:24:47 | [diff] [blame] | 10 | #include "base/strings/string_util.h" |
| 11 | |
| 12 | namespace gcm { |
| 13 | |
| 14 | namespace { |
johnme | 627dc8c7 | 2016-08-19 21:49:39 | [diff] [blame] | 15 | const char kInstanceIDSerializationPrefix[] = "iid-"; |
| 16 | const int kInstanceIDSerializationPrefixLength = |
| 17 | sizeof(kInstanceIDSerializationPrefix) / sizeof(char) - 1; |
jianli | 7a0c9b6 | 2015-05-26 23:24:47 | [diff] [blame] | 18 | } // namespace |
| 19 | |
| 20 | // static |
dcheng | a77e28eb | 2016-04-21 21:34:37 | [diff] [blame] | 21 | std::unique_ptr<RegistrationInfo> RegistrationInfo::BuildFromString( |
johnme | dc5ddc4 | 2015-09-17 14:16:44 | [diff] [blame] | 22 | const std::string& serialized_key, |
| 23 | const std::string& serialized_value, |
jianli | 7a0c9b6 | 2015-05-26 23:24:47 | [diff] [blame] | 24 | std::string* registration_id) { |
dcheng | a77e28eb | 2016-04-21 21:34:37 | [diff] [blame] | 25 | std::unique_ptr<RegistrationInfo> registration; |
jianli | 7a0c9b6 | 2015-05-26 23:24:47 | [diff] [blame] | 26 | |
johnme | 627dc8c7 | 2016-08-19 21:49:39 | [diff] [blame] | 27 | if (base::StartsWith(serialized_key, kInstanceIDSerializationPrefix, |
brettw | 9550931 | 2015-07-16 23:57:33 | [diff] [blame] | 28 | base::CompareCase::SENSITIVE)) |
jianli | 7a0c9b6 | 2015-05-26 23:24:47 | [diff] [blame] | 29 | registration.reset(new InstanceIDTokenInfo); |
| 30 | else |
| 31 | registration.reset(new GCMRegistrationInfo); |
| 32 | |
johnme | dc5ddc4 | 2015-09-17 14:16:44 | [diff] [blame] | 33 | if (!registration->Deserialize(serialized_key, |
| 34 | serialized_value, |
jianli | 7a0c9b6 | 2015-05-26 23:24:47 | [diff] [blame] | 35 | registration_id)) { |
| 36 | registration.reset(); |
| 37 | } |
dcheng | 5160635 | 2015-12-26 21:16:23 | [diff] [blame] | 38 | return registration; |
jianli | 7a0c9b6 | 2015-05-26 23:24:47 | [diff] [blame] | 39 | } |
| 40 | |
| 41 | RegistrationInfo::RegistrationInfo() { |
| 42 | } |
| 43 | |
| 44 | RegistrationInfo::~RegistrationInfo() { |
| 45 | } |
| 46 | |
| 47 | // static |
| 48 | const GCMRegistrationInfo* GCMRegistrationInfo::FromRegistrationInfo( |
| 49 | const RegistrationInfo* registration_info) { |
| 50 | if (!registration_info || registration_info->GetType() != GCM_REGISTRATION) |
Ivan Kotenkov | 75b1c3a | 2017-10-24 14:47:24 | [diff] [blame^] | 51 | return nullptr; |
jianli | 7a0c9b6 | 2015-05-26 23:24:47 | [diff] [blame] | 52 | return static_cast<const GCMRegistrationInfo*>(registration_info); |
| 53 | } |
| 54 | |
| 55 | // static |
| 56 | GCMRegistrationInfo* GCMRegistrationInfo::FromRegistrationInfo( |
| 57 | RegistrationInfo* registration_info) { |
| 58 | if (!registration_info || registration_info->GetType() != GCM_REGISTRATION) |
Ivan Kotenkov | 75b1c3a | 2017-10-24 14:47:24 | [diff] [blame^] | 59 | return nullptr; |
jianli | 7a0c9b6 | 2015-05-26 23:24:47 | [diff] [blame] | 60 | return static_cast<GCMRegistrationInfo*>(registration_info); |
| 61 | } |
| 62 | |
| 63 | GCMRegistrationInfo::GCMRegistrationInfo() { |
| 64 | } |
| 65 | |
| 66 | GCMRegistrationInfo::~GCMRegistrationInfo() { |
| 67 | } |
| 68 | |
| 69 | RegistrationInfo::RegistrationType GCMRegistrationInfo::GetType() const { |
| 70 | return GCM_REGISTRATION; |
| 71 | } |
| 72 | |
| 73 | std::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 | |
| 79 | std::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 | |
| 102 | bool GCMRegistrationInfo::Deserialize( |
johnme | dc5ddc4 | 2015-09-17 14:16:44 | [diff] [blame] | 103 | const std::string& serialized_key, |
| 104 | const std::string& serialized_value, |
jianli | 7a0c9b6 | 2015-05-26 23:24:47 | [diff] [blame] | 105 | std::string* registration_id) { |
johnme | dc5ddc4 | 2015-09-17 14:16:44 | [diff] [blame] | 106 | if (serialized_key.empty() || serialized_value.empty()) |
jianli | 7a0c9b6 | 2015-05-26 23:24:47 | [diff] [blame] | 107 | return false; |
| 108 | |
| 109 | // Application ID is same as the serialized key. |
johnme | dc5ddc4 | 2015-09-17 14:16:44 | [diff] [blame] | 110 | app_id = serialized_key; |
jianli | 7a0c9b6 | 2015-05-26 23:24:47 | [diff] [blame] | 111 | |
| 112 | // Sender IDs and registration ID are constructed from the serialized value. |
johnme | dc5ddc4 | 2015-09-17 14:16:44 | [diff] [blame] | 113 | size_t pos = serialized_value.find('='); |
jianli | 7a0c9b6 | 2015-05-26 23:24:47 | [diff] [blame] | 114 | if (pos == std::string::npos) |
| 115 | return false; |
| 116 | |
johnme | dc5ddc4 | 2015-09-17 14:16:44 | [diff] [blame] | 117 | std::string senders = serialized_value.substr(0, pos); |
| 118 | std::string registration_id_str = serialized_value.substr(pos + 1); |
jianli | 7a0c9b6 | 2015-05-26 23:24:47 | [diff] [blame] | 119 | |
brettw | b45192d | 2015-06-29 22:53:24 | [diff] [blame] | 120 | sender_ids = base::SplitString( |
| 121 | senders, ",", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY); |
jianli | 7a0c9b6 | 2015-05-26 23:24:47 | [diff] [blame] | 122 | 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 |
| 135 | const InstanceIDTokenInfo* InstanceIDTokenInfo::FromRegistrationInfo( |
| 136 | const RegistrationInfo* registration_info) { |
| 137 | if (!registration_info || registration_info->GetType() != INSTANCE_ID_TOKEN) |
Ivan Kotenkov | 75b1c3a | 2017-10-24 14:47:24 | [diff] [blame^] | 138 | return nullptr; |
jianli | 7a0c9b6 | 2015-05-26 23:24:47 | [diff] [blame] | 139 | return static_cast<const InstanceIDTokenInfo*>(registration_info); |
| 140 | } |
| 141 | |
| 142 | // static |
| 143 | InstanceIDTokenInfo* InstanceIDTokenInfo::FromRegistrationInfo( |
| 144 | RegistrationInfo* registration_info) { |
| 145 | if (!registration_info || registration_info->GetType() != INSTANCE_ID_TOKEN) |
Ivan Kotenkov | 75b1c3a | 2017-10-24 14:47:24 | [diff] [blame^] | 146 | return nullptr; |
jianli | 7a0c9b6 | 2015-05-26 23:24:47 | [diff] [blame] | 147 | return static_cast<InstanceIDTokenInfo*>(registration_info); |
| 148 | } |
| 149 | |
| 150 | InstanceIDTokenInfo::InstanceIDTokenInfo() { |
| 151 | } |
| 152 | |
| 153 | InstanceIDTokenInfo::~InstanceIDTokenInfo() { |
| 154 | } |
| 155 | |
| 156 | RegistrationInfo::RegistrationType InstanceIDTokenInfo::GetType() const { |
| 157 | return INSTANCE_ID_TOKEN; |
| 158 | } |
| 159 | |
| 160 | std::string InstanceIDTokenInfo::GetSerializedKey() const { |
johnme | 627dc8c7 | 2016-08-19 21:49:39 | [diff] [blame] | 161 | DCHECK(app_id.find(',') == std::string::npos && |
| 162 | authorized_entity.find(',') == std::string::npos && |
jianli | 7a0c9b6 | 2015-05-26 23:24:47 | [diff] [blame] | 163 | 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. |
johnme | 627dc8c7 | 2016-08-19 21:49:39 | [diff] [blame] | 169 | std::string key(kInstanceIDSerializationPrefix); |
jianli | 7a0c9b6 | 2015-05-26 23:24:47 | [diff] [blame] | 170 | key += app_id; |
| 171 | key += ","; |
| 172 | key += authorized_entity; |
| 173 | key += ","; |
| 174 | key += scope; |
| 175 | return key; |
| 176 | } |
| 177 | |
| 178 | std::string InstanceIDTokenInfo::GetSerializedValue( |
| 179 | const std::string& registration_id) const { |
| 180 | return registration_id; |
| 181 | } |
| 182 | |
| 183 | bool 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 | |
johnme | 627dc8c7 | 2016-08-19 21:49:39 | [diff] [blame] | 190 | if (!base::StartsWith(serialized_key, kInstanceIDSerializationPrefix, |
brettw | 9550931 | 2015-07-16 23:57:33 | [diff] [blame] | 191 | base::CompareCase::SENSITIVE)) |
jianli | 7a0c9b6 | 2015-05-26 23:24:47 | [diff] [blame] | 192 | return false; |
| 193 | |
brettw | b45192d | 2015-06-29 22:53:24 | [diff] [blame] | 194 | std::vector<std::string> fields = base::SplitString( |
johnme | 627dc8c7 | 2016-08-19 21:49:39 | [diff] [blame] | 195 | serialized_key.substr(kInstanceIDSerializationPrefixLength), ",", |
| 196 | base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY); |
jianli | 7a0c9b6 | 2015-05-26 23:24:47 | [diff] [blame] | 197 | 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 | |
| 212 | bool 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. |
johnme | 627dc8c7 | 2016-08-19 21:49:39 | [diff] [blame] | 218 | // For InstanceIDTokenInfo, the comparison is based on |
jianli | 7a0c9b6 | 2015-05-26 23:24:47 | [diff] [blame] | 219 | // <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 Kotenkov | 75b1c3a | 2017-10-24 14:47:24 | [diff] [blame^] | 234 | return iid_b != nullptr; |
jianli | 7a0c9b6 | 2015-05-26 23:24:47 | [diff] [blame] | 235 | |
| 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 | |
| 248 | bool ExistsGCMRegistrationInMap(const RegistrationInfoMap& map, |
| 249 | const std::string& app_id) { |
dcheng | a77e28eb | 2016-04-21 21:34:37 | [diff] [blame] | 250 | std::unique_ptr<GCMRegistrationInfo> gcm_registration( |
| 251 | new GCMRegistrationInfo); |
jianli | 7a0c9b6 | 2015-05-26 23:24:47 | [diff] [blame] | 252 | gcm_registration->app_id = app_id; |
| 253 | return map.count( |
| 254 | make_linked_ptr<RegistrationInfo>(gcm_registration.release())) > 0; |
| 255 | } |
| 256 | |
| 257 | } // namespace gcm |