Add ICU message format support
[chromium-blink-merge.git] / chrome / browser / push_messaging / push_messaging_app_identifier.cc
blobd21c50fbbbfe3c5b3411274c08ffc59d58d479b3
1 // Copyright 2014 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.
5 #include "chrome/browser/push_messaging/push_messaging_app_identifier.h"
7 #include <string.h>
9 #include "base/guid.h"
10 #include "base/logging.h"
11 #include "base/prefs/pref_service.h"
12 #include "base/prefs/scoped_user_pref_update.h"
13 #include "base/strings/string_number_conversions.h"
14 #include "base/strings/string_split.h"
15 #include "base/strings/string_util.h"
16 #include "base/values.h"
17 #include "chrome/browser/profiles/profile.h"
18 #include "chrome/common/pref_names.h"
19 #include "components/pref_registry/pref_registry_syncable.h"
21 const char kPushMessagingAppIdentifierPrefix[] = "wp:";
23 namespace {
25 // sizeof is strlen + 1 since it's null-terminated.
26 const size_t kPrefixLength = sizeof(kPushMessagingAppIdentifierPrefix) - 1;
28 const char kSeparator = '#'; // Ok as only the origin of the url is used.
29 const size_t kGuidLength = 36; // "%08X-%04X-%04X-%04X-%012llX"
31 std::string MakePrefValue(const GURL& origin,
32 int64_t service_worker_registration_id) {
33 return origin.spec() + kSeparator
34 + base::Int64ToString(service_worker_registration_id);
37 bool GetOriginAndSWRFromPrefValue(
38 const std::string& pref_value, GURL* origin,
39 int64_t* service_worker_registration_id) {
40 std::vector<std::string> parts = base::SplitString(
41 pref_value, std::string(1, kSeparator),
42 base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
43 if (parts.size() != 2)
44 return false;
46 if (!base::StringToInt64(parts[1], service_worker_registration_id))
47 return false;
49 *origin = GURL(parts[0]);
50 return origin->is_valid();
53 } // namespace
55 // static
56 void PushMessagingAppIdentifier::RegisterProfilePrefs(
57 user_prefs::PrefRegistrySyncable* registry) {
58 registry->RegisterDictionaryPref(prefs::kPushMessagingAppIdentifierMap);
61 // static
62 PushMessagingAppIdentifier PushMessagingAppIdentifier::Generate(
63 const GURL& origin, int64_t service_worker_registration_id)
65 std::string guid = base::GenerateGUID();
66 CHECK(!guid.empty());
67 std::string app_id = kPushMessagingAppIdentifierPrefix + origin.spec()
68 + kSeparator + guid;
70 PushMessagingAppIdentifier app_identifier(app_id, origin,
71 service_worker_registration_id);
72 app_identifier.DCheckValid();
73 return app_identifier;
76 // static
77 PushMessagingAppIdentifier PushMessagingAppIdentifier::FindByAppId(
78 Profile* profile, const std::string& app_id) {
79 if (!base::StartsWith(app_id, kPushMessagingAppIdentifierPrefix,
80 base::CompareCase::INSENSITIVE_ASCII)) {
81 return PushMessagingAppIdentifier();
84 // Since we now know this is a Push Messaging app_id, check the case hasn't
85 // been mangled (crbug.com/461867).
86 DCHECK_EQ(kPushMessagingAppIdentifierPrefix, app_id.substr(0, kPrefixLength));
87 DCHECK_GE(app_id.size(), kPrefixLength + kGuidLength);
88 DCHECK_EQ(app_id.substr(app_id.size() - kGuidLength),
89 base::ToUpperASCII(app_id.substr(app_id.size() - kGuidLength)));
91 const base::DictionaryValue* map =
92 profile->GetPrefs()->GetDictionary(prefs::kPushMessagingAppIdentifierMap);
94 std::string map_value;
95 if (!map->GetStringWithoutPathExpansion(app_id, &map_value))
96 return PushMessagingAppIdentifier();
98 GURL origin;
99 int64_t service_worker_registration_id;
100 if (!GetOriginAndSWRFromPrefValue(map_value, &origin,
101 &service_worker_registration_id)) {
102 NOTREACHED();
103 return PushMessagingAppIdentifier();
106 PushMessagingAppIdentifier app_identifier(app_id, origin,
107 service_worker_registration_id);
108 app_identifier.DCheckValid();
109 return app_identifier;
112 // static
113 PushMessagingAppIdentifier PushMessagingAppIdentifier::FindByServiceWorker(
114 Profile* profile, const GURL& origin,
115 int64_t service_worker_registration_id)
117 const base::StringValue pref_value =
118 base::StringValue(MakePrefValue(origin, service_worker_registration_id));
120 const base::DictionaryValue* map =
121 profile->GetPrefs()->GetDictionary(prefs::kPushMessagingAppIdentifierMap);
122 for (auto it = base::DictionaryValue::Iterator(*map); !it.IsAtEnd();
123 it.Advance()) {
124 if (it.value().Equals(&pref_value))
125 return FindByAppId(profile, it.key());
127 return PushMessagingAppIdentifier();
130 // static
131 std::vector<PushMessagingAppIdentifier> PushMessagingAppIdentifier::GetAll(
132 Profile* profile) {
133 std::vector<PushMessagingAppIdentifier> result;
135 const base::DictionaryValue* map =
136 profile->GetPrefs()->GetDictionary(prefs::kPushMessagingAppIdentifierMap);
137 for (auto it = base::DictionaryValue::Iterator(*map); !it.IsAtEnd();
138 it.Advance()) {
139 result.push_back(FindByAppId(profile, it.key()));
142 return result;
145 PushMessagingAppIdentifier::PushMessagingAppIdentifier()
146 : origin_(GURL::EmptyGURL()),
147 service_worker_registration_id_(-1) {
150 PushMessagingAppIdentifier::PushMessagingAppIdentifier(
151 const std::string& app_id,
152 const GURL& origin,
153 int64_t service_worker_registration_id)
154 : app_id_(app_id),
155 origin_(origin),
156 service_worker_registration_id_(service_worker_registration_id) {
159 PushMessagingAppIdentifier::~PushMessagingAppIdentifier() {
162 void PushMessagingAppIdentifier::PersistToPrefs(Profile* profile) const {
163 DCheckValid();
165 DictionaryPrefUpdate update(profile->GetPrefs(),
166 prefs::kPushMessagingAppIdentifierMap);
167 base::DictionaryValue* map = update.Get();
169 // Delete any stale entry with the same origin and Service Worker
170 // registration id (hence we ensure there is a 1:1 not 1:many mapping).
171 PushMessagingAppIdentifier old = FindByServiceWorker(
172 profile, origin_, service_worker_registration_id_);
173 if (!old.is_null())
174 map->RemoveWithoutPathExpansion(old.app_id_, nullptr /* out_value */);
176 map->SetStringWithoutPathExpansion(
177 app_id_, MakePrefValue(origin_, service_worker_registration_id_));
180 void PushMessagingAppIdentifier::DeleteFromPrefs(Profile* profile) const {
181 DCheckValid();
183 DictionaryPrefUpdate update(profile->GetPrefs(),
184 prefs::kPushMessagingAppIdentifierMap);
185 base::DictionaryValue* map = update.Get();
186 map->RemoveWithoutPathExpansion(app_id_, nullptr /* out_value */);
189 void PushMessagingAppIdentifier::DCheckValid() const {
190 DCHECK_GE(service_worker_registration_id_, 0);
192 DCHECK(origin_.is_valid());
193 DCHECK_EQ(origin_.GetOrigin(), origin_);
195 // "wp:"
196 DCHECK_EQ(kPushMessagingAppIdentifierPrefix,
197 app_id_.substr(0, kPrefixLength));
198 // Optional (origin.spec() + '#')
199 if (app_id_.size() != kPrefixLength + kGuidLength) {
200 const size_t suffix_length = 1 /* kSeparator */ + kGuidLength;
201 DCHECK(app_id_.size() > kPrefixLength + suffix_length);
202 DCHECK_EQ(origin_, GURL(app_id_.substr(
203 kPrefixLength, app_id_.size() - kPrefixLength - suffix_length)));
204 DCHECK_EQ(std::string(1, kSeparator),
205 app_id_.substr(app_id_.size() - suffix_length, 1));
207 // GUID
208 DCHECK(base::IsValidGUID(app_id_.substr(app_id_.size() - kGuidLength)));