Refactor SharedMemory::Create and fix a rare file leak.
[chromium-blink-merge.git] / chrome / browser / push_messaging / push_messaging_app_identifier.cc
blob8d84fa293b659165d162ed933ecb6e25a5ce7b52
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;
41 base::SplitString(pref_value, kSeparator, &parts);
42 if (parts.size() != 2)
43 return false;
45 if (!base::StringToInt64(parts[1], service_worker_registration_id))
46 return false;
48 *origin = GURL(parts[0]);
49 return origin->is_valid();
52 } // namespace
54 // static
55 void PushMessagingAppIdentifier::RegisterProfilePrefs(
56 user_prefs::PrefRegistrySyncable* registry) {
57 registry->RegisterDictionaryPref(prefs::kPushMessagingAppIdentifierMap);
60 // static
61 PushMessagingAppIdentifier PushMessagingAppIdentifier::Generate(
62 const GURL& origin, int64_t service_worker_registration_id)
64 std::string guid = base::GenerateGUID();
65 CHECK(!guid.empty());
66 std::string app_id = kPushMessagingAppIdentifierPrefix + origin.spec()
67 + kSeparator + guid;
69 PushMessagingAppIdentifier app_identifier(app_id, origin,
70 service_worker_registration_id);
71 app_identifier.DCheckValid();
72 return app_identifier;
75 // static
76 PushMessagingAppIdentifier PushMessagingAppIdentifier::FindByAppId(
77 Profile* profile, const std::string& app_id) {
78 if (!StartsWithASCII(app_id, kPushMessagingAppIdentifierPrefix,
79 false /* case_sensitive */)) {
80 return PushMessagingAppIdentifier();
83 // Since we now know this is a Push Messaging app_id, check the case hasn't
84 // been mangled (crbug.com/461867).
85 DCHECK_EQ(kPushMessagingAppIdentifierPrefix, app_id.substr(0, kPrefixLength));
86 DCHECK_GE(app_id.size(), kPrefixLength + kGuidLength);
87 DCHECK_EQ(app_id.substr(app_id.size() - kGuidLength),
88 StringToUpperASCII(app_id.substr(app_id.size() - kGuidLength)));
90 const base::DictionaryValue* map =
91 profile->GetPrefs()->GetDictionary(prefs::kPushMessagingAppIdentifierMap);
93 std::string map_value;
94 if (!map->GetStringWithoutPathExpansion(app_id, &map_value))
95 return PushMessagingAppIdentifier();
97 GURL origin;
98 int64_t service_worker_registration_id;
99 if (!GetOriginAndSWRFromPrefValue(map_value, &origin,
100 &service_worker_registration_id)) {
101 NOTREACHED();
102 return PushMessagingAppIdentifier();
105 PushMessagingAppIdentifier app_identifier(app_id, origin,
106 service_worker_registration_id);
107 app_identifier.DCheckValid();
108 return app_identifier;
111 // static
112 PushMessagingAppIdentifier PushMessagingAppIdentifier::FindByServiceWorker(
113 Profile* profile, const GURL& origin,
114 int64_t service_worker_registration_id)
116 const base::StringValue pref_value =
117 base::StringValue(MakePrefValue(origin, service_worker_registration_id));
119 const base::DictionaryValue* map =
120 profile->GetPrefs()->GetDictionary(prefs::kPushMessagingAppIdentifierMap);
121 for (auto it = base::DictionaryValue::Iterator(*map); !it.IsAtEnd();
122 it.Advance()) {
123 if (it.value().Equals(&pref_value))
124 return FindByAppId(profile, it.key());
126 return PushMessagingAppIdentifier();
129 // static
130 std::vector<PushMessagingAppIdentifier> PushMessagingAppIdentifier::GetAll(
131 Profile* profile) {
132 std::vector<PushMessagingAppIdentifier> result;
134 const base::DictionaryValue* map =
135 profile->GetPrefs()->GetDictionary(prefs::kPushMessagingAppIdentifierMap);
136 for (auto it = base::DictionaryValue::Iterator(*map); !it.IsAtEnd();
137 it.Advance()) {
138 result.push_back(FindByAppId(profile, it.key()));
141 return result;
144 PushMessagingAppIdentifier::PushMessagingAppIdentifier()
145 : origin_(GURL::EmptyGURL()),
146 service_worker_registration_id_(-1) {
149 PushMessagingAppIdentifier::PushMessagingAppIdentifier(
150 const std::string& app_id,
151 const GURL& origin,
152 int64_t service_worker_registration_id)
153 : app_id_(app_id),
154 origin_(origin),
155 service_worker_registration_id_(service_worker_registration_id) {
158 PushMessagingAppIdentifier::~PushMessagingAppIdentifier() {
161 void PushMessagingAppIdentifier::PersistToPrefs(Profile* profile) const {
162 DCheckValid();
164 DictionaryPrefUpdate update(profile->GetPrefs(),
165 prefs::kPushMessagingAppIdentifierMap);
166 base::DictionaryValue* map = update.Get();
168 // Delete any stale entry with the same origin and Service Worker
169 // registration id (hence we ensure there is a 1:1 not 1:many mapping).
170 PushMessagingAppIdentifier old = FindByServiceWorker(
171 profile, origin_, service_worker_registration_id_);
172 if (!old.is_null())
173 map->RemoveWithoutPathExpansion(old.app_id_, nullptr /* out_value */);
175 map->SetStringWithoutPathExpansion(
176 app_id_, MakePrefValue(origin_, service_worker_registration_id_));
179 void PushMessagingAppIdentifier::DeleteFromPrefs(Profile* profile) const {
180 DCheckValid();
182 DictionaryPrefUpdate update(profile->GetPrefs(),
183 prefs::kPushMessagingAppIdentifierMap);
184 base::DictionaryValue* map = update.Get();
185 map->RemoveWithoutPathExpansion(app_id_, nullptr /* out_value */);
188 void PushMessagingAppIdentifier::DCheckValid() const {
189 DCHECK_GE(service_worker_registration_id_, 0);
191 DCHECK(origin_.is_valid());
192 DCHECK_EQ(origin_.GetOrigin(), origin_);
194 // "wp:"
195 DCHECK_EQ(kPushMessagingAppIdentifierPrefix,
196 app_id_.substr(0, kPrefixLength));
197 // Optional (origin.spec() + '#')
198 if (app_id_.size() != kPrefixLength + kGuidLength) {
199 const size_t suffix_length = 1 /* kSeparator */ + kGuidLength;
200 DCHECK(app_id_.size() > kPrefixLength + suffix_length);
201 DCHECK_EQ(origin_, GURL(app_id_.substr(
202 kPrefixLength, app_id_.size() - kPrefixLength - suffix_length)));
203 DCHECK_EQ(std::string(1, kSeparator),
204 app_id_.substr(app_id_.size() - suffix_length, 1));
206 // GUID
207 DCHECK(base::IsValidGUID(app_id_.substr(app_id_.size() - kGuidLength)));