blob: 38c11de9d9aa351218c59e4c74dc407c167669d4 [file] [log] [blame]
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/gcm_driver/registration_info.h"
#include <stddef.h>
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
namespace gcm {
namespace {
const char kInsanceIDSerializationPrefix[] = "iid-";
const int kInsanceIDSerializationPrefixLength =
sizeof(kInsanceIDSerializationPrefix) / sizeof(char) - 1;
} // namespace
// static
scoped_ptr<RegistrationInfo> RegistrationInfo::BuildFromString(
const std::string& serialized_key,
const std::string& serialized_value,
std::string* registration_id) {
scoped_ptr<RegistrationInfo> registration;
if (base::StartsWith(serialized_key, kInsanceIDSerializationPrefix,
base::CompareCase::SENSITIVE))
registration.reset(new InstanceIDTokenInfo);
else
registration.reset(new GCMRegistrationInfo);
if (!registration->Deserialize(serialized_key,
serialized_value,
registration_id)) {
registration.reset();
}
return registration;
}
RegistrationInfo::RegistrationInfo() {
}
RegistrationInfo::~RegistrationInfo() {
}
// static
const GCMRegistrationInfo* GCMRegistrationInfo::FromRegistrationInfo(
const RegistrationInfo* registration_info) {
if (!registration_info || registration_info->GetType() != GCM_REGISTRATION)
return NULL;
return static_cast<const GCMRegistrationInfo*>(registration_info);
}
// static
GCMRegistrationInfo* GCMRegistrationInfo::FromRegistrationInfo(
RegistrationInfo* registration_info) {
if (!registration_info || registration_info->GetType() != GCM_REGISTRATION)
return NULL;
return static_cast<GCMRegistrationInfo*>(registration_info);
}
GCMRegistrationInfo::GCMRegistrationInfo() {
}
GCMRegistrationInfo::~GCMRegistrationInfo() {
}
RegistrationInfo::RegistrationType GCMRegistrationInfo::GetType() const {
return GCM_REGISTRATION;
}
std::string GCMRegistrationInfo::GetSerializedKey() const {
// Multiple registrations are not supported for legacy GCM. So the key is
// purely based on the application id.
return app_id;
}
std::string GCMRegistrationInfo::GetSerializedValue(
const std::string& registration_id) const {
if (sender_ids.empty() || registration_id.empty())
return std::string();
// Serialize as:
// sender1,sender2,...=reg_id
std::string value;
for (std::vector<std::string>::const_iterator iter = sender_ids.begin();
iter != sender_ids.end(); ++iter) {
DCHECK(!iter->empty() &&
iter->find(',') == std::string::npos &&
iter->find('=') == std::string::npos);
if (!value.empty())
value += ",";
value += *iter;
}
value += '=';
value += registration_id;
return value;
}
bool GCMRegistrationInfo::Deserialize(
const std::string& serialized_key,
const std::string& serialized_value,
std::string* registration_id) {
if (serialized_key.empty() || serialized_value.empty())
return false;
// Application ID is same as the serialized key.
app_id = serialized_key;
// Sender IDs and registration ID are constructed from the serialized value.
size_t pos = serialized_value.find('=');
if (pos == std::string::npos)
return false;
std::string senders = serialized_value.substr(0, pos);
std::string registration_id_str = serialized_value.substr(pos + 1);
sender_ids = base::SplitString(
senders, ",", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
if (sender_ids.empty() || registration_id_str.empty()) {
sender_ids.clear();
registration_id_str.clear();
return false;
}
if (registration_id)
*registration_id = registration_id_str;
return true;
}
// static
const InstanceIDTokenInfo* InstanceIDTokenInfo::FromRegistrationInfo(
const RegistrationInfo* registration_info) {
if (!registration_info || registration_info->GetType() != INSTANCE_ID_TOKEN)
return NULL;
return static_cast<const InstanceIDTokenInfo*>(registration_info);
}
// static
InstanceIDTokenInfo* InstanceIDTokenInfo::FromRegistrationInfo(
RegistrationInfo* registration_info) {
if (!registration_info || registration_info->GetType() != INSTANCE_ID_TOKEN)
return NULL;
return static_cast<InstanceIDTokenInfo*>(registration_info);
}
InstanceIDTokenInfo::InstanceIDTokenInfo() {
}
InstanceIDTokenInfo::~InstanceIDTokenInfo() {
}
RegistrationInfo::RegistrationType InstanceIDTokenInfo::GetType() const {
return INSTANCE_ID_TOKEN;
}
std::string InstanceIDTokenInfo::GetSerializedKey() const {
DCHECK(authorized_entity.find(',') == std::string::npos &&
scope.find(',') == std::string::npos);
// Multiple registrations are supported for Instance ID. So the key is based
// on the combination of (app_id, authorized_entity, scope).
// Adds a prefix to differentiate easily with GCM registration key.
std::string key(kInsanceIDSerializationPrefix);
key += app_id;
key += ",";
key += authorized_entity;
key += ",";
key += scope;
return key;
}
std::string InstanceIDTokenInfo::GetSerializedValue(
const std::string& registration_id) const {
return registration_id;
}
bool InstanceIDTokenInfo::Deserialize(
const std::string& serialized_key,
const std::string& serialized_value,
std::string* registration_id) {
if (serialized_key.empty() || serialized_value.empty())
return false;
if (!base::StartsWith(serialized_key, kInsanceIDSerializationPrefix,
base::CompareCase::SENSITIVE))
return false;
std::vector<std::string> fields = base::SplitString(
serialized_key.substr(kInsanceIDSerializationPrefixLength),
",", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
if (fields.size() != 3 || fields[0].empty() ||
fields[1].empty() || fields[2].empty()) {
return false;
}
app_id = fields[0];
authorized_entity = fields[1];
scope = fields[2];
// Registration ID is same as the serialized value;
if (registration_id)
*registration_id = serialized_value;
return true;
}
bool RegistrationInfoComparer::operator()(
const linked_ptr<RegistrationInfo>& a,
const linked_ptr<RegistrationInfo>& b) const {
DCHECK(a.get() && b.get());
// For GCMRegistrationInfo, the comparison is based on app_id only.
// For InstanceIDTokenInfo, the comparison is bsaed on
// <app_id, authorized_entity, scope>.
if (a->app_id < b->app_id)
return true;
if (a->app_id > b->app_id)
return false;
InstanceIDTokenInfo* iid_a =
InstanceIDTokenInfo::FromRegistrationInfo(a.get());
InstanceIDTokenInfo* iid_b =
InstanceIDTokenInfo::FromRegistrationInfo(b.get());
// !iid_a && !iid_b => false.
// !iid_a && iid_b => true.
// This makes GCM record is sorted before InstanceID record.
if (!iid_a)
return iid_b != NULL;
// iid_a && !iid_b => false.
if (!iid_b)
return false;
// Otherwise, compare with authorized_entity and scope.
if (iid_a->authorized_entity < iid_b->authorized_entity)
return true;
if (iid_a->authorized_entity > iid_b->authorized_entity)
return false;
return iid_a->scope < iid_b->scope;
}
bool ExistsGCMRegistrationInMap(const RegistrationInfoMap& map,
const std::string& app_id) {
scoped_ptr<GCMRegistrationInfo> gcm_registration(new GCMRegistrationInfo);
gcm_registration->app_id = app_id;
return map.count(
make_linked_ptr<RegistrationInfo>(gcm_registration.release())) > 0;
}
} // namespace gcm