Make USB permissions work in the new permission message system
[chromium-blink-merge.git] / content / browser / notifications / notification_database.cc
blob9e64693b835c20a9ce9defc8e114f9aa17a135e5
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.
5 #include "content/browser/notifications/notification_database.h"
7 #include <string>
9 #include "base/files/file_util.h"
10 #include "base/strings/string_number_conversions.h"
11 #include "base/strings/stringprintf.h"
12 #include "content/browser/notifications/notification_database_data_conversions.h"
13 #include "content/common/service_worker/service_worker_types.h"
14 #include "content/public/browser/browser_thread.h"
15 #include "content/public/browser/notification_database_data.h"
16 #include "storage/common/database/database_identifier.h"
17 #include "third_party/leveldatabase/env_chromium.h"
18 #include "third_party/leveldatabase/src/helpers/memenv/memenv.h"
19 #include "third_party/leveldatabase/src/include/leveldb/db.h"
20 #include "third_party/leveldatabase/src/include/leveldb/env.h"
21 #include "third_party/leveldatabase/src/include/leveldb/filter_policy.h"
22 #include "third_party/leveldatabase/src/include/leveldb/write_batch.h"
23 #include "url/gurl.h"
25 // Notification LevelDB database schema (in alphabetized order)
26 // =======================
28 // key: "DATA:" <origin identifier> '\x00' <notification_id>
29 // value: String containing the NotificationDatabaseDataProto protocol buffer
30 // in serialized form.
32 // key: "NEXT_NOTIFICATION_ID"
33 // value: Decimal string which fits into an int64_t.
35 namespace content {
36 namespace {
38 // Keys of the fields defined in the database.
39 const char kNextNotificationIdKey[] = "NEXT_NOTIFICATION_ID";
40 const char kDataKeyPrefix[] = "DATA:";
42 // Separates the components of compound keys.
43 const char kKeySeparator = '\x00';
45 // The first notification id which to be handed out by the database.
46 const int64_t kFirstNotificationId = 1;
48 // Converts the LevelDB |status| to one of the notification database's values.
49 NotificationDatabase::Status LevelDBStatusToStatus(
50 const leveldb::Status& status) {
51 if (status.ok())
52 return NotificationDatabase::STATUS_OK;
53 else if (status.IsNotFound())
54 return NotificationDatabase::STATUS_ERROR_NOT_FOUND;
55 else if (status.IsCorruption())
56 return NotificationDatabase::STATUS_ERROR_CORRUPTED;
58 return NotificationDatabase::STATUS_ERROR_FAILED;
61 // Creates a prefix for the data entries based on |origin|.
62 std::string CreateDataPrefix(const GURL& origin) {
63 if (!origin.is_valid())
64 return kDataKeyPrefix;
66 return base::StringPrintf("%s%s%c",
67 kDataKeyPrefix,
68 storage::GetIdentifierFromOrigin(origin).c_str(),
69 kKeySeparator);
72 // Creates the compound data key in which notification data is stored.
73 std::string CreateDataKey(const GURL& origin, int64_t notification_id) {
74 DCHECK(origin.is_valid());
75 return CreateDataPrefix(origin) + base::Int64ToString(notification_id);
78 // Deserializes data in |serialized_data| to |notification_database_data|.
79 // Will return if the deserialization was successful.
80 NotificationDatabase::Status DeserializedNotificationData(
81 const std::string& serialized_data,
82 NotificationDatabaseData* notification_database_data) {
83 DCHECK(notification_database_data);
84 if (DeserializeNotificationDatabaseData(serialized_data,
85 notification_database_data)) {
86 return NotificationDatabase::STATUS_OK;
89 DLOG(ERROR) << "Unable to deserialize a notification's data.";
90 return NotificationDatabase::STATUS_ERROR_CORRUPTED;
93 } // namespace
95 NotificationDatabase::NotificationDatabase(const base::FilePath& path)
96 : path_(path) {
99 NotificationDatabase::~NotificationDatabase() {
100 DCHECK(sequence_checker_.CalledOnValidSequencedThread());
103 NotificationDatabase::Status NotificationDatabase::Open(
104 bool create_if_missing) {
105 DCHECK(sequence_checker_.CalledOnValidSequencedThread());
106 DCHECK_EQ(STATE_UNINITIALIZED, state_);
108 if (!create_if_missing) {
109 if (IsInMemoryDatabase() ||
110 !base::PathExists(path_) ||
111 base::IsDirectoryEmpty(path_)) {
112 return NotificationDatabase::STATUS_ERROR_NOT_FOUND;
116 filter_policy_.reset(leveldb::NewBloomFilterPolicy(10));
118 leveldb::Options options;
119 options.create_if_missing = create_if_missing;
120 options.paranoid_checks = true;
121 options.reuse_logs = leveldb_env::kDefaultLogReuseOptionValue;
122 options.filter_policy = filter_policy_.get();
123 if (IsInMemoryDatabase()) {
124 env_.reset(leveldb::NewMemEnv(leveldb::Env::Default()));
125 options.env = env_.get();
128 leveldb::DB* db = nullptr;
129 Status status = LevelDBStatusToStatus(
130 leveldb::DB::Open(options, path_.AsUTF8Unsafe(), &db));
131 if (status != STATUS_OK)
132 return status;
134 state_ = STATE_INITIALIZED;
135 db_.reset(db);
137 return ReadNextNotificationId();
140 NotificationDatabase::Status NotificationDatabase::ReadNotificationData(
141 int64_t notification_id,
142 const GURL& origin,
143 NotificationDatabaseData* notification_database_data) const {
144 DCHECK(sequence_checker_.CalledOnValidSequencedThread());
145 DCHECK_EQ(STATE_INITIALIZED, state_);
146 DCHECK_GE(notification_id, kFirstNotificationId);
147 DCHECK(origin.is_valid());
148 DCHECK(notification_database_data);
150 std::string key = CreateDataKey(origin, notification_id);
151 std::string serialized_data;
153 Status status = LevelDBStatusToStatus(
154 db_->Get(leveldb::ReadOptions(), key, &serialized_data));
155 if (status != STATUS_OK)
156 return status;
158 return DeserializedNotificationData(serialized_data,
159 notification_database_data);
162 NotificationDatabase::Status
163 NotificationDatabase::ReadAllNotificationData(
164 std::vector<NotificationDatabaseData>* notification_data_vector) const {
165 return ReadAllNotificationDataInternal(GURL() /* origin */,
166 kInvalidServiceWorkerRegistrationId,
167 notification_data_vector);
170 NotificationDatabase::Status
171 NotificationDatabase::ReadAllNotificationDataForOrigin(
172 const GURL& origin,
173 std::vector<NotificationDatabaseData>* notification_data_vector) const {
174 return ReadAllNotificationDataInternal(origin,
175 kInvalidServiceWorkerRegistrationId,
176 notification_data_vector);
179 NotificationDatabase::Status
180 NotificationDatabase::ReadAllNotificationDataForServiceWorkerRegistration(
181 const GURL& origin,
182 int64_t service_worker_registration_id,
183 std::vector<NotificationDatabaseData>* notification_data_vector) const {
184 return ReadAllNotificationDataInternal(origin,
185 service_worker_registration_id,
186 notification_data_vector);
189 NotificationDatabase::Status NotificationDatabase::WriteNotificationData(
190 const GURL& origin,
191 const NotificationDatabaseData& notification_database_data,
192 int64_t* notification_id) {
193 DCHECK(sequence_checker_.CalledOnValidSequencedThread());
194 DCHECK_EQ(STATE_INITIALIZED, state_);
195 DCHECK(notification_id);
196 DCHECK(origin.is_valid());
198 DCHECK_GE(next_notification_id_, kFirstNotificationId);
200 NotificationDatabaseData storage_data = notification_database_data;
201 storage_data.notification_id = next_notification_id_;
203 std::string serialized_data;
204 if (!SerializeNotificationDatabaseData(storage_data,
205 &serialized_data)) {
206 DLOG(ERROR) << "Unable to serialize data for a notification belonging "
207 << "to: " << origin;
208 return STATUS_ERROR_FAILED;
211 leveldb::WriteBatch batch;
212 batch.Put(CreateDataKey(origin, next_notification_id_), serialized_data);
213 batch.Put(kNextNotificationIdKey,
214 base::Int64ToString(next_notification_id_ + 1));
216 Status status = LevelDBStatusToStatus(
217 db_->Write(leveldb::WriteOptions(), &batch));
218 if (status != STATUS_OK)
219 return status;
221 *notification_id = next_notification_id_++;
222 return STATUS_OK;
225 NotificationDatabase::Status NotificationDatabase::DeleteNotificationData(
226 int64_t notification_id,
227 const GURL& origin) {
228 DCHECK(sequence_checker_.CalledOnValidSequencedThread());
229 DCHECK_EQ(STATE_INITIALIZED, state_);
230 DCHECK_GE(notification_id, kFirstNotificationId);
231 DCHECK(origin.is_valid());
233 std::string key = CreateDataKey(origin, notification_id);
234 return LevelDBStatusToStatus(db_->Delete(leveldb::WriteOptions(), key));
237 NotificationDatabase::Status
238 NotificationDatabase::DeleteAllNotificationDataForOrigin(
239 const GURL& origin,
240 std::set<int64_t>* deleted_notification_set) {
241 return DeleteAllNotificationDataInternal(origin,
242 kInvalidServiceWorkerRegistrationId,
243 deleted_notification_set);
246 NotificationDatabase::Status
247 NotificationDatabase::DeleteAllNotificationDataForServiceWorkerRegistration(
248 const GURL& origin,
249 int64_t service_worker_registration_id,
250 std::set<int64_t>* deleted_notification_set) {
251 return DeleteAllNotificationDataInternal(origin,
252 service_worker_registration_id,
253 deleted_notification_set);
256 NotificationDatabase::Status NotificationDatabase::Destroy() {
257 DCHECK(sequence_checker_.CalledOnValidSequencedThread());
259 leveldb::Options options;
260 if (IsInMemoryDatabase()) {
261 if (!env_)
262 return STATUS_OK; // The database has not been initialized.
264 options.env = env_.get();
267 state_ = STATE_DISABLED;
268 db_.reset();
270 return LevelDBStatusToStatus(
271 leveldb::DestroyDB(path_.AsUTF8Unsafe(), options));
274 NotificationDatabase::Status NotificationDatabase::ReadNextNotificationId() {
275 std::string value;
276 Status status = LevelDBStatusToStatus(
277 db_->Get(leveldb::ReadOptions(), kNextNotificationIdKey, &value));
279 if (status == STATUS_ERROR_NOT_FOUND) {
280 next_notification_id_ = kFirstNotificationId;
281 return STATUS_OK;
284 if (status != STATUS_OK)
285 return status;
287 if (!base::StringToInt64(value, &next_notification_id_) ||
288 next_notification_id_ < kFirstNotificationId) {
289 return STATUS_ERROR_CORRUPTED;
292 return STATUS_OK;
295 NotificationDatabase::Status
296 NotificationDatabase::ReadAllNotificationDataInternal(
297 const GURL& origin,
298 int64_t service_worker_registration_id,
299 std::vector<NotificationDatabaseData>* notification_data_vector) const {
300 DCHECK(sequence_checker_.CalledOnValidSequencedThread());
301 DCHECK(notification_data_vector);
303 const std::string prefix = CreateDataPrefix(origin);
305 leveldb::Slice prefix_slice(prefix);
307 NotificationDatabaseData notification_database_data;
308 scoped_ptr<leveldb::Iterator> iter(db_->NewIterator(leveldb::ReadOptions()));
309 for (iter->Seek(prefix_slice); iter->Valid(); iter->Next()) {
310 if (!iter->key().starts_with(prefix_slice))
311 break;
313 Status status = DeserializedNotificationData(iter->value().ToString(),
314 &notification_database_data);
315 if (status != STATUS_OK)
316 return status;
318 if (service_worker_registration_id != kInvalidServiceWorkerRegistrationId &&
319 notification_database_data.service_worker_registration_id !=
320 service_worker_registration_id) {
321 continue;
324 notification_data_vector->push_back(notification_database_data);
327 return LevelDBStatusToStatus(iter->status());
330 NotificationDatabase::Status
331 NotificationDatabase::DeleteAllNotificationDataInternal(
332 const GURL& origin,
333 int64_t service_worker_registration_id,
334 std::set<int64_t>* deleted_notification_set) {
335 DCHECK(sequence_checker_.CalledOnValidSequencedThread());
336 DCHECK(deleted_notification_set);
337 DCHECK(origin.is_valid());
339 const std::string prefix = CreateDataPrefix(origin);
341 leveldb::Slice prefix_slice(prefix);
342 leveldb::WriteBatch batch;
344 NotificationDatabaseData notification_database_data;
345 scoped_ptr<leveldb::Iterator> iter(db_->NewIterator(leveldb::ReadOptions()));
346 for (iter->Seek(prefix_slice); iter->Valid(); iter->Next()) {
347 if (!iter->key().starts_with(prefix_slice))
348 break;
350 if (service_worker_registration_id != kInvalidServiceWorkerRegistrationId) {
351 Status status = DeserializedNotificationData(iter->value().ToString(),
352 &notification_database_data);
353 if (status != STATUS_OK)
354 return status;
356 if (notification_database_data.service_worker_registration_id !=
357 service_worker_registration_id) {
358 continue;
362 leveldb::Slice notification_id_slice = iter->key();
363 notification_id_slice.remove_prefix(prefix_slice.size());
365 int64_t notification_id = 0;
366 if (!base::StringToInt64(notification_id_slice.ToString(),
367 &notification_id)) {
368 return STATUS_ERROR_CORRUPTED;
371 deleted_notification_set->insert(notification_id);
372 batch.Delete(iter->key());
375 if (deleted_notification_set->empty())
376 return STATUS_OK;
378 return LevelDBStatusToStatus(db_->Write(leveldb::WriteOptions(), &batch));
381 } // namespace content