blob: b03bbc29e9649cae2f24078a483aec492bfd1ab6 [file] [log] [blame]
Rayan Kanso296eb3d2019-06-26 11:32:041// Copyright 2019 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 "content/browser/content_index/content_index_database.h"
6
Rayan Kanso5e2ff0e2019-09-04 10:33:107#include <set>
Rayan Kanso296eb3d2019-06-26 11:32:048#include <string>
9
Rayan Kansob0f54fe2019-08-05 18:59:1410#include "base/barrier_closure.h"
Gabriel Charette9f60dd12020-03-06 20:48:0411#include "base/memory/ptr_util.h"
Rayan Kanso5e2ff0e2019-09-04 10:33:1012#include "base/stl_util.h"
Rayan Kanso296eb3d2019-06-26 11:32:0413#include "base/time/time.h"
Rayan Kanso837b7952019-07-01 10:31:2914#include "content/browser/background_fetch/storage/image_helpers.h"
Rayan Kanso296eb3d2019-06-26 11:32:0415#include "content/browser/content_index/content_index.pb.h"
Rayan Kanso9f3944a2019-07-30 12:18:0716#include "content/browser/content_index/content_index_metrics.h"
Rayan Kanso03a847b2019-06-27 21:00:0917#include "content/public/browser/browser_context.h"
Rayan Kanso24f7d412019-07-11 10:09:3018#include "content/public/browser/browser_task_traits.h"
Rayan Kanso296eb3d2019-06-26 11:32:0419#include "content/public/browser/browser_thread.h"
Anton Bikineevf62d1bf2021-05-15 17:56:0720#include "third_party/abseil-cpp/absl/types/optional.h"
Rayan Kanso37c08702019-07-12 17:07:4121#include "url/gurl.h"
Rayan Kansod33e2772019-06-27 16:52:4122#include "url/origin.h"
Rayan Kanso296eb3d2019-06-26 11:32:0423
Rayan Kanso837b7952019-07-01 10:31:2924// TODO(crbug.com/973844): Move image utility functions to common library.
25using content::background_fetch::DeserializeIcon;
26using content::background_fetch::SerializeIcon;
27
Rayan Kanso296eb3d2019-06-26 11:32:0428namespace content {
29
30namespace {
31
32constexpr char kEntryPrefix[] = "content_index:entry_";
Rayan Kanso837b7952019-07-01 10:31:2933constexpr char kIconPrefix[] = "content_index:icon_";
Rayan Kanso296eb3d2019-06-26 11:32:0434
35std::string EntryKey(const std::string& id) {
36 return kEntryPrefix + id;
37}
38
Rayan Kansob0f54fe2019-08-05 18:59:1439std::string IconsKey(const std::string& id) {
Rayan Kanso837b7952019-07-01 10:31:2940 return kIconPrefix + id;
41}
42
Rayan Kanso296eb3d2019-06-26 11:32:0443std::string CreateSerializedContentEntry(
Rayan Kanso03a847b2019-06-27 21:00:0944 const blink::mojom::ContentDescription& description,
Rayan Kanso37c08702019-07-12 17:07:4145 const GURL& launch_url,
Rayan Kanso03a847b2019-06-27 21:00:0946 base::Time entry_time) {
Rayan Kanso296eb3d2019-06-26 11:32:0447 // Convert description.
48 proto::ContentDescription description_proto;
Rayan Kanso475b85b2019-06-28 01:56:4449 description_proto.set_id(description.id);
50 description_proto.set_title(description.title);
51 description_proto.set_description(description.description);
Rayan Kanso03a847b2019-06-27 21:00:0952 description_proto.set_category(static_cast<int>(description.category));
Rayan Kanso35c07cf2019-08-20 18:46:0353
54 for (const auto& icon : description.icons) {
55 auto* icon_proto = description_proto.add_icons();
56 icon_proto->set_src(icon->src);
57 if (icon->sizes)
58 icon_proto->set_sizes(*icon->sizes);
59 if (icon->type)
60 icon_proto->set_type(*icon->type);
61 }
62
Rayan Kanso475b85b2019-06-28 01:56:4463 description_proto.set_launch_url(description.launch_url);
Rayan Kanso296eb3d2019-06-26 11:32:0464
65 // Create entry.
66 proto::ContentEntry entry;
67 *entry.mutable_description() = std::move(description_proto);
Rayan Kanso37c08702019-07-12 17:07:4168 entry.set_launch_url(launch_url.spec());
Rayan Kanso03a847b2019-06-27 21:00:0969 entry.set_timestamp(entry_time.ToDeltaSinceWindowsEpoch().InMicroseconds());
Rayan Kanso296eb3d2019-06-26 11:32:0470
71 return entry.SerializeAsString();
72}
73
74blink::mojom::ContentDescriptionPtr DescriptionFromProto(
75 const proto::ContentDescription& description) {
76 // Validate.
77 if (description.category() <
78 static_cast<int>(blink::mojom::ContentCategory::kMinValue) ||
79 description.category() >
80 static_cast<int>(blink::mojom::ContentCategory::kMaxValue)) {
81 return nullptr;
82 }
83
84 // Convert.
85 auto result = blink::mojom::ContentDescription::New();
86 result->id = description.id();
87 result->title = description.title();
88 result->description = description.description();
89 result->category =
90 static_cast<blink::mojom::ContentCategory>(description.category());
Rayan Kanso35c07cf2019-08-20 18:46:0391 for (const auto& icon : description.icons()) {
92 auto mojo_icon = blink::mojom::ContentIconDefinition::New();
93 mojo_icon->src = icon.src();
94 if (icon.has_sizes())
95 mojo_icon->sizes = icon.sizes();
96 if (icon.has_type())
97 mojo_icon->type = icon.type();
98 result->icons.push_back(std::move(mojo_icon));
99 }
100
Rayan Kanso475b85b2019-06-28 01:56:44101 result->launch_url = description.launch_url();
Rayan Kanso296eb3d2019-06-26 11:32:04102 return result;
103}
104
Anton Bikineevf62d1bf2021-05-15 17:56:07105absl::optional<ContentIndexEntry> EntryFromSerializedProto(
Rayan Kansoe147def2019-07-22 09:56:35106 int64_t service_worker_registration_id,
107 const std::string& serialized_proto) {
108 proto::ContentEntry entry_proto;
109 if (!entry_proto.ParseFromString(serialized_proto))
Anton Bikineevf62d1bf2021-05-15 17:56:07110 return absl::nullopt;
Rayan Kansoe147def2019-07-22 09:56:35111
112 GURL launch_url(entry_proto.launch_url());
113 if (!launch_url.is_valid())
Anton Bikineevf62d1bf2021-05-15 17:56:07114 return absl::nullopt;
Rayan Kansoe147def2019-07-22 09:56:35115
116 auto description = DescriptionFromProto(entry_proto.description());
117 base::Time registration_time = base::Time::FromDeltaSinceWindowsEpoch(
118 base::TimeDelta::FromMicroseconds(entry_proto.timestamp()));
119
120 return ContentIndexEntry(service_worker_registration_id,
121 std::move(description), std::move(launch_url),
122 registration_time);
123}
124
Rayan Kanso296eb3d2019-06-26 11:32:04125} // namespace
126
127ContentIndexDatabase::ContentIndexDatabase(
Rayan Kanso03a847b2019-06-27 21:00:09128 BrowserContext* browser_context,
Rayan Kanso296eb3d2019-06-26 11:32:04129 scoped_refptr<ServiceWorkerContextWrapper> service_worker_context)
Rayan Kansoba075802019-06-28 16:33:48130 : provider_(browser_context->GetContentIndexProvider()),
Jeremy Roman7c5cfabd2019-08-12 15:45:27131 service_worker_context_(std::move(service_worker_context)) {}
Rayan Kanso296eb3d2019-06-26 11:32:04132
133ContentIndexDatabase::~ContentIndexDatabase() = default;
134
135void ContentIndexDatabase::AddEntry(
136 int64_t service_worker_registration_id,
Rayan Kansod33e2772019-06-27 16:52:41137 const url::Origin& origin,
Rayan Kanso296eb3d2019-06-26 11:32:04138 blink::mojom::ContentDescriptionPtr description,
Rayan Kansob0f54fe2019-08-05 18:59:14139 const std::vector<SkBitmap>& icons,
Rayan Kanso37c08702019-07-12 17:07:41140 const GURL& launch_url,
Rayan Kanso296eb3d2019-06-26 11:32:04141 blink::mojom::ContentIndexService::AddCallback callback) {
Rayan Kanso7806f692019-08-21 12:30:44142 DCHECK_CURRENTLY_ON(BrowserThread::UI);
143
144 auto wrapped_callback = base::BindOnce(
145 [](blink::mojom::ContentIndexService::AddCallback callback,
146 blink::mojom::ContentIndexError error) {
Gabriel Charettee7cdc5cd2020-05-27 23:35:05147 GetUIThreadTaskRunner({})->PostTask(
148 FROM_HERE, base::BindOnce(std::move(callback), error));
Rayan Kanso7806f692019-08-21 12:30:44149 },
150 std::move(callback));
151
Matt Falkenhagen105efb822019-08-29 20:49:17152 RunOrPostTaskOnThread(
153 FROM_HERE, ServiceWorkerContext::GetCoreThreadId(),
154 base::BindOnce(&ContentIndexDatabase::AddEntryOnCoreThread,
155 weak_ptr_factory_core_.GetWeakPtr(),
156 service_worker_registration_id, origin,
157 std::move(description), icons, launch_url,
158 std::move(wrapped_callback)));
Rayan Kanso7806f692019-08-21 12:30:44159}
160
Matt Falkenhagen105efb822019-08-29 20:49:17161void ContentIndexDatabase::AddEntryOnCoreThread(
Rayan Kanso7806f692019-08-21 12:30:44162 int64_t service_worker_registration_id,
163 const url::Origin& origin,
164 blink::mojom::ContentDescriptionPtr description,
165 const std::vector<SkBitmap>& icons,
166 const GURL& launch_url,
167 blink::mojom::ContentIndexService::AddCallback callback) {
Matt Falkenhagen105efb822019-08-29 20:49:17168 DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
Rayan Kanso7806f692019-08-21 12:30:44169
Rayan Kanso394af702019-07-25 12:50:37170 if (blocked_origins_.count(origin)) {
171 // TODO(crbug.com/973844): Does this need a more specific error?
172 std::move(callback).Run(blink::mojom::ContentIndexError::STORAGE_ERROR);
Rayan Kanso9f3944a2019-07-30 12:18:07173 content_index::RecordRegistrationBlocked(description->category);
Rayan Kanso394af702019-07-25 12:50:37174 return;
175 }
176
Rayan Kanso947f56d2019-09-04 11:25:22177 auto* service_worker_registration =
178 service_worker_context_->GetLiveRegistration(
179 service_worker_registration_id);
180 if (!service_worker_registration ||
181 !service_worker_registration->active_version()) {
182 std::move(callback).Run(blink::mojom::ContentIndexError::NO_SERVICE_WORKER);
183 return;
184 }
185
Rayan Kansob0f54fe2019-08-05 18:59:14186 auto serialized_icons = std::make_unique<proto::SerializedIcons>();
187 proto::SerializedIcons* serialized_icons_ptr = serialized_icons.get();
188
189 auto barrier_closure = base::BarrierClosure(
190 icons.size(),
191 base::BindOnce(&ContentIndexDatabase::DidSerializeIcons,
Matt Falkenhagen105efb822019-08-29 20:49:17192 weak_ptr_factory_core_.GetWeakPtr(),
Rayan Kansob0f54fe2019-08-05 18:59:14193 service_worker_registration_id, origin,
194 std::move(description), launch_url,
195 std::move(serialized_icons), std::move(callback)));
196
197 for (const auto& icon : icons) {
198 SerializeIcon(icon,
199 base::BindOnce(
200 [](base::OnceClosure done_closure,
201 proto::SerializedIcons* icons, std::string icon) {
202 icons->add_icons()->set_icon(std::move(icon));
203 std::move(done_closure).Run();
204 },
205 barrier_closure, serialized_icons_ptr));
206 }
Rayan Kanso837b7952019-07-01 10:31:29207}
208
Rayan Kansob0f54fe2019-08-05 18:59:14209void ContentIndexDatabase::DidSerializeIcons(
Rayan Kanso837b7952019-07-01 10:31:29210 int64_t service_worker_registration_id,
211 const url::Origin& origin,
212 blink::mojom::ContentDescriptionPtr description,
Rayan Kanso37c08702019-07-12 17:07:41213 const GURL& launch_url,
Rayan Kansob0f54fe2019-08-05 18:59:14214 std::unique_ptr<proto::SerializedIcons> serialized_icons,
215 blink::mojom::ContentIndexService::AddCallback callback) {
Rayan Kanso03a847b2019-06-27 21:00:09216 base::Time entry_time = base::Time::Now();
Rayan Kanso837b7952019-07-01 10:31:29217 std::string entry_key = EntryKey(description->id);
Rayan Kansob0f54fe2019-08-05 18:59:14218 std::string icon_key = IconsKey(description->id);
Rayan Kanso837b7952019-07-01 10:31:29219 std::string entry_value =
Rayan Kanso37c08702019-07-12 17:07:41220 CreateSerializedContentEntry(*description, launch_url, entry_time);
Rayan Kansob0f54fe2019-08-05 18:59:14221 std::string icons_value = serialized_icons->SerializeAsString();
Rayan Kanso296eb3d2019-06-26 11:32:04222
Rayan Kanso03a847b2019-06-27 21:00:09223 // Entry to pass over to the provider.
224 ContentIndexEntry entry(service_worker_registration_id,
Rayan Kanso37c08702019-07-12 17:07:41225 std::move(description), launch_url, entry_time);
Rayan Kanso03a847b2019-06-27 21:00:09226
Rayan Kanso296eb3d2019-06-26 11:32:04227 service_worker_context_->StoreRegistrationUserData(
Nidhi Jaju18bd19e2020-09-11 04:43:16228 service_worker_registration_id, origin,
Rayan Kanso837b7952019-07-01 10:31:29229 {{std::move(entry_key), std::move(entry_value)},
Rayan Kansob0f54fe2019-08-05 18:59:14230 {std::move(icon_key), std::move(icons_value)}},
Rayan Kanso296eb3d2019-06-26 11:32:04231 base::BindOnce(&ContentIndexDatabase::DidAddEntry,
Matt Falkenhagen105efb822019-08-29 20:49:17232 weak_ptr_factory_core_.GetWeakPtr(), std::move(callback),
Rayan Kanso03a847b2019-06-27 21:00:09233 std::move(entry)));
Rayan Kanso296eb3d2019-06-26 11:32:04234}
235
236void ContentIndexDatabase::DidAddEntry(
237 blink::mojom::ContentIndexService::AddCallback callback,
Rayan Kanso03a847b2019-06-27 21:00:09238 ContentIndexEntry entry,
Rayan Kanso296eb3d2019-06-26 11:32:04239 blink::ServiceWorkerStatusCode status) {
Rayan Kanso9f3944a2019-07-30 12:18:07240 content_index::RecordDatabaseOperationStatus("Add", status);
241
Rayan Kanso03a847b2019-06-27 21:00:09242 if (status != blink::ServiceWorkerStatusCode::kOk) {
Rayan Kanso296eb3d2019-06-26 11:32:04243 std::move(callback).Run(blink::mojom::ContentIndexError::STORAGE_ERROR);
Rayan Kanso03a847b2019-06-27 21:00:09244 return;
245 }
246
247 std::move(callback).Run(blink::mojom::ContentIndexError::NONE);
248
Rayan Kanso24f7d412019-07-11 10:09:30249 std::vector<ContentIndexEntry> entries;
250 entries.push_back(std::move(entry));
Gabriel Charettee7cdc5cd2020-05-27 23:35:05251 GetUIThreadTaskRunner({})->PostTask(
252 FROM_HERE,
Rayan Kanso24f7d412019-07-11 10:09:30253 base::BindOnce(&ContentIndexDatabase::NotifyProviderContentAdded,
254 weak_ptr_factory_ui_.GetWeakPtr(), std::move(entries)));
Rayan Kanso296eb3d2019-06-26 11:32:04255}
256
257void ContentIndexDatabase::DeleteEntry(
258 int64_t service_worker_registration_id,
Rayan Kansoa42c3caf2019-07-19 17:21:20259 const url::Origin& origin,
Rayan Kanso296eb3d2019-06-26 11:32:04260 const std::string& entry_id,
261 blink::mojom::ContentIndexService::DeleteCallback callback) {
Rayan Kanso7806f692019-08-21 12:30:44262 DCHECK_CURRENTLY_ON(BrowserThread::UI);
263
264 auto wrapped_callback = base::BindOnce(
265 [](blink::mojom::ContentIndexService::DeleteCallback callback,
266 blink::mojom::ContentIndexError error) {
Gabriel Charettee7cdc5cd2020-05-27 23:35:05267 GetUIThreadTaskRunner({})->PostTask(
268 FROM_HERE, base::BindOnce(std::move(callback), error));
Rayan Kanso7806f692019-08-21 12:30:44269 },
270 std::move(callback));
271
Matt Falkenhagen105efb822019-08-29 20:49:17272 RunOrPostTaskOnThread(
273 FROM_HERE, ServiceWorkerContext::GetCoreThreadId(),
274 base::BindOnce(&ContentIndexDatabase::DeleteEntryOnCoreThread,
275 weak_ptr_factory_core_.GetWeakPtr(),
276 service_worker_registration_id, origin, entry_id,
277 std::move(wrapped_callback)));
Rayan Kanso7806f692019-08-21 12:30:44278}
279
Matt Falkenhagen105efb822019-08-29 20:49:17280void ContentIndexDatabase::DeleteEntryOnCoreThread(
Rayan Kanso7806f692019-08-21 12:30:44281 int64_t service_worker_registration_id,
282 const url::Origin& origin,
283 const std::string& entry_id,
284 blink::mojom::ContentIndexService::DeleteCallback callback) {
Matt Falkenhagen105efb822019-08-29 20:49:17285 DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
Rayan Kanso7806f692019-08-21 12:30:44286
Rayan Kanso296eb3d2019-06-26 11:32:04287 service_worker_context_->ClearRegistrationUserData(
Rayan Kansob0f54fe2019-08-05 18:59:14288 service_worker_registration_id, {EntryKey(entry_id), IconsKey(entry_id)},
Rayan Kanso24f7d412019-07-11 10:09:30289 base::BindOnce(&ContentIndexDatabase::DidDeleteEntry,
Matt Falkenhagen105efb822019-08-29 20:49:17290 weak_ptr_factory_core_.GetWeakPtr(),
Rayan Kansoa42c3caf2019-07-19 17:21:20291 service_worker_registration_id, origin, entry_id,
Rayan Kanso24f7d412019-07-11 10:09:30292 std::move(callback)));
Rayan Kanso296eb3d2019-06-26 11:32:04293}
294
295void ContentIndexDatabase::DidDeleteEntry(
Rayan Kanso03a847b2019-06-27 21:00:09296 int64_t service_worker_registration_id,
Rayan Kansoa42c3caf2019-07-19 17:21:20297 const url::Origin& origin,
Rayan Kanso03a847b2019-06-27 21:00:09298 const std::string& entry_id,
Rayan Kanso296eb3d2019-06-26 11:32:04299 blink::mojom::ContentIndexService::DeleteCallback callback,
300 blink::ServiceWorkerStatusCode status) {
Rayan Kanso9f3944a2019-07-30 12:18:07301 content_index::RecordDatabaseOperationStatus("Delete", status);
302
Rayan Kanso03a847b2019-06-27 21:00:09303 if (status != blink::ServiceWorkerStatusCode::kOk) {
Rayan Kanso296eb3d2019-06-26 11:32:04304 std::move(callback).Run(blink::mojom::ContentIndexError::STORAGE_ERROR);
Rayan Kanso03a847b2019-06-27 21:00:09305 return;
306 }
307
308 std::move(callback).Run(blink::mojom::ContentIndexError::NONE);
Rayan Kanso24f7d412019-07-11 10:09:30309
Gabriel Charettee7cdc5cd2020-05-27 23:35:05310 GetUIThreadTaskRunner({})->PostTask(
311 FROM_HERE,
Rayan Kanso24f7d412019-07-11 10:09:30312 base::BindOnce(&ContentIndexDatabase::NotifyProviderContentDeleted,
313 weak_ptr_factory_ui_.GetWeakPtr(),
Rayan Kansoa42c3caf2019-07-19 17:21:20314 service_worker_registration_id, origin, entry_id));
Rayan Kanso296eb3d2019-06-26 11:32:04315}
316
317void ContentIndexDatabase::GetDescriptions(
318 int64_t service_worker_registration_id,
319 blink::mojom::ContentIndexService::GetDescriptionsCallback callback) {
Rayan Kanso7806f692019-08-21 12:30:44320 DCHECK_CURRENTLY_ON(BrowserThread::UI);
321
322 auto wrapped_callback = base::BindOnce(
323 [](blink::mojom::ContentIndexService::GetDescriptionsCallback callback,
324 blink::mojom::ContentIndexError error,
325 std::vector<blink::mojom::ContentDescriptionPtr> descriptions) {
Gabriel Charettee7cdc5cd2020-05-27 23:35:05326 GetUIThreadTaskRunner({})->PostTask(
327 FROM_HERE, base::BindOnce(std::move(callback), error,
Rayan Kanso7806f692019-08-21 12:30:44328 std::move(descriptions)));
329 },
330 std::move(callback));
331
Matt Falkenhagen105efb822019-08-29 20:49:17332 RunOrPostTaskOnThread(
333 FROM_HERE, ServiceWorkerContext::GetCoreThreadId(),
334 base::BindOnce(&ContentIndexDatabase::GetDescriptionsOnCoreThread,
335 weak_ptr_factory_core_.GetWeakPtr(),
336 service_worker_registration_id,
337 std::move(wrapped_callback)));
Rayan Kanso7806f692019-08-21 12:30:44338}
339
Matt Falkenhagen105efb822019-08-29 20:49:17340void ContentIndexDatabase::GetDescriptionsOnCoreThread(
Rayan Kanso7806f692019-08-21 12:30:44341 int64_t service_worker_registration_id,
342 blink::mojom::ContentIndexService::GetDescriptionsCallback callback) {
Matt Falkenhagen105efb822019-08-29 20:49:17343 DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
Rayan Kanso7806f692019-08-21 12:30:44344
Rayan Kanso296eb3d2019-06-26 11:32:04345 service_worker_context_->GetRegistrationUserDataByKeyPrefix(
346 service_worker_registration_id, kEntryPrefix,
347 base::BindOnce(&ContentIndexDatabase::DidGetDescriptions,
Rayan Kanso5e2ff0e2019-09-04 10:33:10348 weak_ptr_factory_core_.GetWeakPtr(),
349 service_worker_registration_id, std::move(callback)));
Rayan Kanso296eb3d2019-06-26 11:32:04350}
351
352void ContentIndexDatabase::DidGetDescriptions(
Rayan Kanso5e2ff0e2019-09-04 10:33:10353 int64_t service_worker_registration_id,
Rayan Kanso296eb3d2019-06-26 11:32:04354 blink::mojom::ContentIndexService::GetDescriptionsCallback callback,
355 const std::vector<std::string>& data,
356 blink::ServiceWorkerStatusCode status) {
Rayan Kanso9f3944a2019-07-30 12:18:07357 content_index::RecordDatabaseOperationStatus("GetDescriptions", status);
358
Rayan Kanso296eb3d2019-06-26 11:32:04359 if (status == blink::ServiceWorkerStatusCode::kErrorNotFound) {
360 std::move(callback).Run(blink::mojom::ContentIndexError::NONE,
361 /* descriptions= */ {});
362 return;
363 } else if (status != blink::ServiceWorkerStatusCode::kOk) {
364 std::move(callback).Run(blink::mojom::ContentIndexError::STORAGE_ERROR,
365 /* descriptions= */ {});
366 return;
367 }
368
369 std::vector<blink::mojom::ContentDescriptionPtr> descriptions;
370 descriptions.reserve(data.size());
371
Rayan Kanso296eb3d2019-06-26 11:32:04372 for (const auto& serialized_entry : data) {
373 proto::ContentEntry entry;
374 if (!entry.ParseFromString(serialized_entry)) {
Rayan Kanso5e2ff0e2019-09-04 10:33:10375 ClearServiceWorkerDataOnCorruption(service_worker_registration_id);
Rayan Kanso296eb3d2019-06-26 11:32:04376 std::move(callback).Run(blink::mojom::ContentIndexError::STORAGE_ERROR,
377 /* descriptions= */ {});
378 return;
379 }
380
381 auto description = DescriptionFromProto(entry.description());
382 if (!description) {
Rayan Kanso5e2ff0e2019-09-04 10:33:10383 // Clear entry data.
384 service_worker_context_->ClearRegistrationUserData(
385 service_worker_registration_id,
386 {EntryKey(entry.description().id()),
387 IconsKey(entry.description().id())},
388 base::BindOnce(&content_index::RecordDatabaseOperationStatus,
389 "ClearCorruptedData"));
390 continue;
Rayan Kanso296eb3d2019-06-26 11:32:04391 }
392
393 descriptions.push_back(std::move(description));
394 }
395
396 std::move(callback).Run(blink::mojom::ContentIndexError::NONE,
397 std::move(descriptions));
398}
399
Rayan Kansob0f54fe2019-08-05 18:59:14400void ContentIndexDatabase::GetIcons(
Rayan Kanso03a847b2019-06-27 21:00:09401 int64_t service_worker_registration_id,
402 const std::string& description_id,
Rayan Kansob0f54fe2019-08-05 18:59:14403 ContentIndexContext::GetIconsCallback callback) {
Rayan Kanso7806f692019-08-21 12:30:44404 DCHECK_CURRENTLY_ON(BrowserThread::UI);
405
406 auto wrapped_callback = base::BindOnce(
407 [](ContentIndexContext::GetIconsCallback callback,
408 std::vector<SkBitmap> icons) {
Gabriel Charettee7cdc5cd2020-05-27 23:35:05409 GetUIThreadTaskRunner({})->PostTask(
410 FROM_HERE, base::BindOnce(std::move(callback), std::move(icons)));
Rayan Kanso7806f692019-08-21 12:30:44411 },
412 std::move(callback));
413
Matt Falkenhagen105efb822019-08-29 20:49:17414 RunOrPostTaskOnThread(
415 FROM_HERE, ServiceWorkerContext::GetCoreThreadId(),
416 base::BindOnce(&ContentIndexDatabase::GetIconsOnCoreThread,
417 weak_ptr_factory_core_.GetWeakPtr(),
418 service_worker_registration_id, description_id,
419 std::move(wrapped_callback)));
Rayan Kanso7806f692019-08-21 12:30:44420}
421
Matt Falkenhagen105efb822019-08-29 20:49:17422void ContentIndexDatabase::GetIconsOnCoreThread(
Rayan Kanso7806f692019-08-21 12:30:44423 int64_t service_worker_registration_id,
424 const std::string& description_id,
425 ContentIndexContext::GetIconsCallback callback) {
Matt Falkenhagen105efb822019-08-29 20:49:17426 DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
Rayan Kanso24f7d412019-07-11 10:09:30427
Rayan Kanso837b7952019-07-01 10:31:29428 service_worker_context_->GetRegistrationUserData(
Rayan Kansob0f54fe2019-08-05 18:59:14429 service_worker_registration_id, {IconsKey(description_id)},
430 base::BindOnce(&ContentIndexDatabase::DidGetSerializedIcons,
Rayan Kanso5e2ff0e2019-09-04 10:33:10431 weak_ptr_factory_core_.GetWeakPtr(),
432 service_worker_registration_id, std::move(callback)));
Rayan Kanso837b7952019-07-01 10:31:29433}
434
Rayan Kansob0f54fe2019-08-05 18:59:14435void ContentIndexDatabase::DidGetSerializedIcons(
Rayan Kanso5e2ff0e2019-09-04 10:33:10436 int64_t service_worker_registration_id,
Rayan Kansob0f54fe2019-08-05 18:59:14437 ContentIndexContext::GetIconsCallback callback,
Rayan Kanso837b7952019-07-01 10:31:29438 const std::vector<std::string>& data,
439 blink::ServiceWorkerStatusCode status) {
Matt Falkenhagen105efb822019-08-29 20:49:17440 DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
Rayan Kansob0f54fe2019-08-05 18:59:14441
Rayan Kanso9f3944a2019-07-30 12:18:07442 content_index::RecordDatabaseOperationStatus("GetIcon", status);
443
Rayan Kanso837b7952019-07-01 10:31:29444 if (status != blink::ServiceWorkerStatusCode::kOk || data.empty()) {
Rayan Kansob0f54fe2019-08-05 18:59:14445 std::move(callback).Run({});
Rayan Kanso837b7952019-07-01 10:31:29446 return;
447 }
448
449 DCHECK_EQ(data.size(), 1u);
Rayan Kansob0f54fe2019-08-05 18:59:14450 proto::SerializedIcons serialized_icons;
451 if (!serialized_icons.ParseFromString(data.front())) {
Rayan Kanso5e2ff0e2019-09-04 10:33:10452 ClearServiceWorkerDataOnCorruption(service_worker_registration_id);
Rayan Kansob0f54fe2019-08-05 18:59:14453 std::move(callback).Run({});
454 return;
455 }
Rayan Kanso837b7952019-07-01 10:31:29456
Rayan Kansob0f54fe2019-08-05 18:59:14457 if (serialized_icons.icons_size() == 0u) {
458 // There are no icons.
459 std::move(callback).Run({});
460 return;
461 }
462
463 auto icons = std::make_unique<std::vector<SkBitmap>>();
464 std::vector<SkBitmap>* icons_ptr = icons.get();
465
466 auto barrier_closure = base::BarrierClosure(
467 serialized_icons.icons_size(),
468 base::BindOnce(&ContentIndexDatabase::DidDeserializeIcons,
Matt Falkenhagen105efb822019-08-29 20:49:17469 weak_ptr_factory_core_.GetWeakPtr(), std::move(callback),
Rayan Kansob0f54fe2019-08-05 18:59:14470 std::move(icons)));
471
472 for (auto& serialized_icon : *serialized_icons.mutable_icons()) {
473 DeserializeIcon(base::WrapUnique(serialized_icon.release_icon()),
474 base::BindOnce(
475 [](base::OnceClosure done_closure,
476 std::vector<SkBitmap>* icons, SkBitmap icon) {
477 icons->push_back(std::move(icon));
478 std::move(done_closure).Run();
479 },
480 barrier_closure, icons_ptr));
481 }
482}
483
484void ContentIndexDatabase::DidDeserializeIcons(
485 ContentIndexContext::GetIconsCallback callback,
486 std::unique_ptr<std::vector<SkBitmap>> icons) {
Matt Falkenhagen105efb822019-08-29 20:49:17487 DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
Rayan Kansob0f54fe2019-08-05 18:59:14488
Matt Falkenhagen105efb822019-08-29 20:49:17489 RunOrPostTaskOnThread(FROM_HERE, BrowserThread::UI,
490 base::BindOnce(std::move(callback), std::move(*icons)));
Rayan Kanso03a847b2019-06-27 21:00:09491}
492
Rayan Kansoe147def2019-07-22 09:56:35493void ContentIndexDatabase::GetAllEntries(
494 ContentIndexContext::GetAllEntriesCallback callback) {
Rayan Kanso7806f692019-08-21 12:30:44495 DCHECK_CURRENTLY_ON(BrowserThread::UI);
496
497 auto wrapped_callback = base::BindOnce(
498 [](ContentIndexContext::GetAllEntriesCallback callback,
499 blink::mojom::ContentIndexError error,
500 std::vector<ContentIndexEntry> entries) {
Gabriel Charettee7cdc5cd2020-05-27 23:35:05501 GetUIThreadTaskRunner({})->PostTask(
502 FROM_HERE,
Rayan Kanso7806f692019-08-21 12:30:44503 base::BindOnce(std::move(callback), error, std::move(entries)));
504 },
505 std::move(callback));
506
Matt Falkenhagen105efb822019-08-29 20:49:17507 RunOrPostTaskOnThread(
508 FROM_HERE, ServiceWorkerContext::GetCoreThreadId(),
509 base::BindOnce(&ContentIndexDatabase::GetAllEntriesOnCoreThread,
510 weak_ptr_factory_core_.GetWeakPtr(),
511 std::move(wrapped_callback)));
Rayan Kanso7806f692019-08-21 12:30:44512}
513
Matt Falkenhagen105efb822019-08-29 20:49:17514void ContentIndexDatabase::GetAllEntriesOnCoreThread(
Rayan Kanso7806f692019-08-21 12:30:44515 ContentIndexContext::GetAllEntriesCallback callback) {
Matt Falkenhagen105efb822019-08-29 20:49:17516 DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
Rayan Kansoe147def2019-07-22 09:56:35517
518 service_worker_context_->GetUserDataForAllRegistrationsByKeyPrefix(
519 kEntryPrefix,
520 base::BindOnce(&ContentIndexDatabase::DidGetEntries,
Matt Falkenhagen105efb822019-08-29 20:49:17521 weak_ptr_factory_core_.GetWeakPtr(), std::move(callback)));
Rayan Kansoe147def2019-07-22 09:56:35522}
523
524void ContentIndexDatabase::DidGetEntries(
525 ContentIndexContext::GetAllEntriesCallback callback,
526 const std::vector<std::pair<int64_t, std::string>>& user_data,
527 blink::ServiceWorkerStatusCode status) {
Rayan Kanso9f3944a2019-07-30 12:18:07528 content_index::RecordDatabaseOperationStatus("GetAllEntries", status);
529
Rayan Kansoe147def2019-07-22 09:56:35530 if (status != blink::ServiceWorkerStatusCode::kOk) {
Rayan Kansoe147def2019-07-22 09:56:35531 std::move(callback).Run(blink::mojom::ContentIndexError::STORAGE_ERROR,
532 /* entries= */ {});
533 return;
534 }
535
536 if (user_data.empty()) {
537 std::move(callback).Run(blink::mojom::ContentIndexError::NONE,
538 /* entries= */ {});
539 return;
540 }
541
542 std::vector<ContentIndexEntry> entries;
543 entries.reserve(user_data.size());
Rayan Kanso5e2ff0e2019-09-04 10:33:10544 std::set<int64_t> corrupted_sw_ids;
Rayan Kansoe147def2019-07-22 09:56:35545
546 for (const auto& ud : user_data) {
547 auto entry = EntryFromSerializedProto(ud.first, ud.second);
548 if (!entry) {
Rayan Kanso5e2ff0e2019-09-04 10:33:10549 corrupted_sw_ids.insert(ud.first);
550 continue;
Rayan Kansoe147def2019-07-22 09:56:35551 }
552
553 entries.emplace_back(std::move(*entry));
554 }
555
Rayan Kanso5e2ff0e2019-09-04 10:33:10556 if (!corrupted_sw_ids.empty()) {
557 // Remove soon-to-be-deleted entries.
558 base::EraseIf(entries, [&corrupted_sw_ids](const auto& entry) {
559 return corrupted_sw_ids.count(entry.service_worker_registration_id);
560 });
561
562 for (int64_t service_worker_registration_id : corrupted_sw_ids)
563 ClearServiceWorkerDataOnCorruption(service_worker_registration_id);
564 }
565
Rayan Kansoe147def2019-07-22 09:56:35566 std::move(callback).Run(blink::mojom::ContentIndexError::NONE,
567 std::move(entries));
568}
569
570void ContentIndexDatabase::GetEntry(
571 int64_t service_worker_registration_id,
572 const std::string& description_id,
573 ContentIndexContext::GetEntryCallback callback) {
Rayan Kanso7806f692019-08-21 12:30:44574 DCHECK_CURRENTLY_ON(BrowserThread::UI);
575
576 auto wrapped_callback = base::BindOnce(
577 [](ContentIndexContext::GetEntryCallback callback,
Anton Bikineevf62d1bf2021-05-15 17:56:07578 absl::optional<ContentIndexEntry> entry) {
Gabriel Charettee7cdc5cd2020-05-27 23:35:05579 GetUIThreadTaskRunner({})->PostTask(
580 FROM_HERE, base::BindOnce(std::move(callback), std::move(entry)));
Rayan Kanso7806f692019-08-21 12:30:44581 },
582 std::move(callback));
583
Matt Falkenhagen105efb822019-08-29 20:49:17584 RunOrPostTaskOnThread(
585 FROM_HERE, ServiceWorkerContext::GetCoreThreadId(),
586 base::BindOnce(&ContentIndexDatabase::GetEntryOnCoreThread,
587 weak_ptr_factory_core_.GetWeakPtr(),
588 service_worker_registration_id, description_id,
589 std::move(wrapped_callback)));
Rayan Kanso7806f692019-08-21 12:30:44590}
591
Matt Falkenhagen105efb822019-08-29 20:49:17592void ContentIndexDatabase::GetEntryOnCoreThread(
Rayan Kanso7806f692019-08-21 12:30:44593 int64_t service_worker_registration_id,
594 const std::string& description_id,
595 ContentIndexContext::GetEntryCallback callback) {
Matt Falkenhagen105efb822019-08-29 20:49:17596 DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
Rayan Kanso7806f692019-08-21 12:30:44597
Rayan Kansoe147def2019-07-22 09:56:35598 service_worker_context_->GetRegistrationUserData(
599 service_worker_registration_id, {EntryKey(description_id)},
600 base::BindOnce(&ContentIndexDatabase::DidGetEntry,
Matt Falkenhagen105efb822019-08-29 20:49:17601 weak_ptr_factory_core_.GetWeakPtr(),
Rayan Kansoe147def2019-07-22 09:56:35602 service_worker_registration_id, std::move(callback)));
603}
604
605void ContentIndexDatabase::DidGetEntry(
606 int64_t service_worker_registration_id,
607 ContentIndexContext::GetEntryCallback callback,
608 const std::vector<std::string>& data,
609 blink::ServiceWorkerStatusCode status) {
Rayan Kanso9f3944a2019-07-30 12:18:07610 content_index::RecordDatabaseOperationStatus("GetEntry", status);
611
Rayan Kansoe147def2019-07-22 09:56:35612 if (status != blink::ServiceWorkerStatusCode::kOk) {
Anton Bikineevf62d1bf2021-05-15 17:56:07613 std::move(callback).Run(absl::nullopt);
Rayan Kansoe147def2019-07-22 09:56:35614 return;
615 }
616
617 DCHECK_EQ(data.size(), 1u);
618 std::move(callback).Run(
619 EntryFromSerializedProto(service_worker_registration_id, data.front()));
620}
621
Rayan Kanso5e2ff0e2019-09-04 10:33:10622void ContentIndexDatabase::ClearServiceWorkerDataOnCorruption(
623 int64_t service_worker_registration_id) {
624 DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
625
626 service_worker_context_->ClearRegistrationUserDataByKeyPrefixes(
627 service_worker_registration_id, {kEntryPrefix, kIconPrefix},
628 base::BindOnce(&content_index::RecordDatabaseOperationStatus,
629 "ClearCorruptedData"));
630}
631
Rayan Kanso7806f692019-08-21 12:30:44632void ContentIndexDatabase::DeleteItem(int64_t service_worker_registration_id,
633 const url::Origin& origin,
634 const std::string& description_id) {
635 DCHECK_CURRENTLY_ON(BrowserThread::UI);
636
Matt Falkenhagen105efb822019-08-29 20:49:17637 RunOrPostTaskOnThread(
638 FROM_HERE, ServiceWorkerContext::GetCoreThreadId(),
639 base::BindOnce(&ContentIndexDatabase::DeleteEntryOnCoreThread,
640 weak_ptr_factory_core_.GetWeakPtr(),
Rayan Kanso7806f692019-08-21 12:30:44641 service_worker_registration_id, origin, description_id,
642 base::BindOnce(&ContentIndexDatabase::DidDeleteItem,
Matt Falkenhagen105efb822019-08-29 20:49:17643 weak_ptr_factory_core_.GetWeakPtr(),
Rayan Kanso7806f692019-08-21 12:30:44644 service_worker_registration_id, origin,
645 description_id)));
646}
647
648void ContentIndexDatabase::DidDeleteItem(
649 int64_t service_worker_registration_id,
650 const url::Origin& origin,
651 const std::string& description_id,
652 blink::mojom::ContentIndexError error) {
Matt Falkenhagen105efb822019-08-29 20:49:17653 DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
Rayan Kanso7806f692019-08-21 12:30:44654
655 if (error != blink::mojom::ContentIndexError::NONE)
656 return;
657
658 service_worker_context_->FindReadyRegistrationForId(
Nidhi Jaju96d38092020-09-11 07:01:30659 service_worker_registration_id, origin,
Rayan Kanso7806f692019-08-21 12:30:44660 base::BindOnce(&ContentIndexDatabase::StartActiveWorkerForDispatch,
Matt Falkenhagen105efb822019-08-29 20:49:17661 weak_ptr_factory_core_.GetWeakPtr(), description_id));
Rayan Kanso7806f692019-08-21 12:30:44662}
663
664void ContentIndexDatabase::StartActiveWorkerForDispatch(
665 const std::string& description_id,
666 blink::ServiceWorkerStatusCode service_worker_status,
667 scoped_refptr<ServiceWorkerRegistration> registration) {
Matt Falkenhagen105efb822019-08-29 20:49:17668 DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
Rayan Kanso7806f692019-08-21 12:30:44669
670 content_index::RecordDisptachStatus("Find", service_worker_status);
671
672 if (service_worker_status != blink::ServiceWorkerStatusCode::kOk)
673 return;
674
675 ServiceWorkerVersion* service_worker_version = registration->active_version();
676 DCHECK(service_worker_version);
677
678 service_worker_version->RunAfterStartWorker(
679 ServiceWorkerMetrics::EventType::CONTENT_DELETE,
680 base::BindOnce(&ContentIndexDatabase::DeliverMessageToWorker,
Matt Falkenhagen105efb822019-08-29 20:49:17681 weak_ptr_factory_core_.GetWeakPtr(),
Rayan Kanso7806f692019-08-21 12:30:44682 base::WrapRefCounted(service_worker_version),
683 std::move(registration), description_id));
684}
685
686void ContentIndexDatabase::DeliverMessageToWorker(
687 scoped_refptr<ServiceWorkerVersion> service_worker,
688 scoped_refptr<ServiceWorkerRegistration> registration,
689 const std::string& description_id,
690 blink::ServiceWorkerStatusCode service_worker_status) {
Matt Falkenhagen105efb822019-08-29 20:49:17691 DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
Rayan Kanso7806f692019-08-21 12:30:44692
693 content_index::RecordDisptachStatus("Start", service_worker_status);
694
695 if (service_worker_status != blink::ServiceWorkerStatusCode::kOk)
696 return;
697
698 // Don't allow DB operations while the `contentdelete` event is firing.
699 // This is to prevent re-registering the deleted content within the event.
Nidhi Jajue3c7dd4d2020-09-11 03:34:27700 BlockOrigin(service_worker->origin());
Rayan Kanso7806f692019-08-21 12:30:44701
702 int request_id = service_worker->StartRequest(
703 ServiceWorkerMetrics::EventType::CONTENT_DELETE,
704 base::BindOnce(&ContentIndexDatabase::DidDispatchEvent,
Matt Falkenhagen105efb822019-08-29 20:49:17705 weak_ptr_factory_core_.GetWeakPtr(),
Nidhi Jajue3c7dd4d2020-09-11 03:34:27706 service_worker->origin()));
Rayan Kanso7806f692019-08-21 12:30:44707
708 service_worker->endpoint()->DispatchContentDeleteEvent(
709 description_id, service_worker->CreateSimpleEventCallback(request_id));
710}
711
712void ContentIndexDatabase::DidDispatchEvent(
713 const url::Origin& origin,
714 blink::ServiceWorkerStatusCode service_worker_status) {
Matt Falkenhagen105efb822019-08-29 20:49:17715 DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
Rayan Kanso7806f692019-08-21 12:30:44716
717 content_index::RecordDisptachStatus("Dispatch", service_worker_status);
718 UnblockOrigin(origin);
719}
720
Rayan Kanso394af702019-07-25 12:50:37721void ContentIndexDatabase::BlockOrigin(const url::Origin& origin) {
722 blocked_origins_[origin]++;
723}
724
725void ContentIndexDatabase::UnblockOrigin(const url::Origin& origin) {
726 DCHECK(blocked_origins_.count(origin));
727 auto it = blocked_origins_.find(origin);
728 if (it->second == 1)
729 blocked_origins_.erase(it);
730 else
731 it->second--;
732}
733
Rayan Kansoba075802019-06-28 16:33:48734void ContentIndexDatabase::Shutdown() {
Rayan Kanso24f7d412019-07-11 10:09:30735 DCHECK_CURRENTLY_ON(BrowserThread::UI);
Rayan Kansoba075802019-06-28 16:33:48736
737 provider_ = nullptr;
738}
739
Rayan Kanso24f7d412019-07-11 10:09:30740void ContentIndexDatabase::NotifyProviderContentAdded(
741 std::vector<ContentIndexEntry> entries) {
742 DCHECK_CURRENTLY_ON(BrowserThread::UI);
743
744 if (!provider_)
745 return;
746
Rayan Kansoa42c3caf2019-07-19 17:21:20747 for (auto& entry : entries)
748 provider_->OnContentAdded(std::move(entry));
Rayan Kanso24f7d412019-07-11 10:09:30749}
750
751void ContentIndexDatabase::NotifyProviderContentDeleted(
752 int64_t service_worker_registration_id,
Rayan Kansoa42c3caf2019-07-19 17:21:20753 const url::Origin& origin,
Rayan Kanso24f7d412019-07-11 10:09:30754 const std::string& entry_id) {
755 DCHECK_CURRENTLY_ON(BrowserThread::UI);
756
757 if (!provider_)
758 return;
759
Rayan Kansoa42c3caf2019-07-19 17:21:20760 provider_->OnContentDeleted(service_worker_registration_id, origin, entry_id);
Rayan Kanso24f7d412019-07-11 10:09:30761}
762
Rayan Kanso296eb3d2019-06-26 11:32:04763} // namespace content